py api: add restrict state context manager (thats python's context not blenders context),
authorCampbell Barton <ideasman42@gmail.com>
Thu, 20 Dec 2012 03:56:22 +0000 (03:56 +0000)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 20 Dec 2012 03:56:22 +0000 (03:56 +0000)
which restricts bpy.context and bpy.data.

enable this for loading scripts in 'startup' too.

release/scripts/modules/addon_utils.py
release/scripts/modules/bpy/utils.py
release/scripts/modules/bpy_restrict_state.py [new file with mode: 0644]

index 3d705a0cf79e8a8cb21147683b3a5c072b85afe5..65ea91cf8ce8d3bde820db31ced8945d5330403b 100644 (file)
@@ -31,14 +31,6 @@ __all__ = (
 import bpy as _bpy
 _user_preferences = _bpy.context.user_preferences
 
-class _RestrictedContext():
-    __slots__ = ()
-    @property
-    def window_manager(self):
-        return _bpy.data.window_managers[0]
-_ctx_restricted = _RestrictedContext()
-
-
 error_duplicates = False
 error_encoding = False
 addons_fake_modules = {}
@@ -240,6 +232,7 @@ def enable(module_name, default_set=True, persistent=False):
 
     import os
     import sys
+    from bpy_restrict_state import RestrictBlend
 
     def handle_error():
         import traceback
@@ -267,37 +260,31 @@ def enable(module_name, default_set=True, persistent=False):
     # Split registering up into 3 steps so we can undo
     # if it fails par way through.
 
-    # first disable the context, using the context at all is
+    # disable the context, using the context at all is
     # really bad while loading an addon, don't do it!
-    ctx = _bpy.context
-    _bpy.context = _ctx_restricted
+    with RestrictBlend():
 
-    # 1) try import
-    try:
-        mod = __import__(module_name)
-        mod.__time__ = os.path.getmtime(mod.__file__)
-        mod.__addon_enabled__ = False
-    except:
-        handle_error()
-        _bpy.context = ctx
-        return None
-
-    # 2) try register collected modules
-    # removed, addons need to handle own registration now.
-
-    # 3) try run the modules register function
-    try:
-        mod.register()
-    except:
-        print("Exception in module register(): %r" %
-              getattr(mod, "__file__", module_name))
-        handle_error()
-        del sys.modules[module_name]
-        _bpy.context = ctx
-        return None
-
-    # finally restore the context
-    _bpy.context = ctx
+        # 1) try import
+        try:
+            mod = __import__(module_name)
+            mod.__time__ = os.path.getmtime(mod.__file__)
+            mod.__addon_enabled__ = False
+        except:
+            handle_error()
+            return None
+
+        # 2) try register collected modules
+        # removed, addons need to handle own registration now.
+
+        # 3) try run the modules register function
+        try:
+            mod.register()
+        except:
+            print("Exception in module register(): %r" %
+                  getattr(mod, "__file__", module_name))
+            handle_error()
+            del sys.modules[module_name]
+            return None
 
     # * OK loaded successfully! *
     if default_set:
index 58646a708a2fd2622dbc9d9a656849f6743f9537..25fe6c1d4e5d3fa3759d175f61e849be09fe9db8 100644 (file)
@@ -217,18 +217,21 @@ def load_scripts(reload_scripts=False, refresh_scripts=False):
 
         del _global_loaded_modules[:]
 
-    for base_path in script_paths():
-        for path_subdir in _script_module_dirs:
-            path = _os.path.join(base_path, path_subdir)
-            if _os.path.isdir(path):
-                _sys_path_ensure(path)
+    from bpy_restrict_state import RestrictBlend
+
+    with RestrictBlend():
+        for base_path in script_paths():
+            for path_subdir in _script_module_dirs:
+                path = _os.path.join(base_path, path_subdir)
+                if _os.path.isdir(path):
+                    _sys_path_ensure(path)
 
-                # only add this to sys.modules, don't run
-                if path_subdir == "modules":
-                    continue
+                    # only add this to sys.modules, don't run
+                    if path_subdir == "modules":
+                        continue
 
-                for mod in modules_from_path(path, loaded_modules):
-                    test_register(mod)
+                    for mod in modules_from_path(path, loaded_modules):
+                        test_register(mod)
 
     # deal with addons separately
     _addon_utils.reset_all(reload_scripts)
diff --git a/release/scripts/modules/bpy_restrict_state.py b/release/scripts/modules/bpy_restrict_state.py
new file mode 100644 (file)
index 0000000..21c6921
--- /dev/null
@@ -0,0 +1,57 @@
+# ##### BEGIN GPL LICENSE BLOCK #####
+#
+#  This program is free software; you can redistribute it and/or
+#  modify it under the terms of the GNU General Public License
+#  as published by the Free Software Foundation; either version 2
+#  of the License, or (at your option) any later version.
+#
+#  This program is distributed in the hope that it will be useful,
+#  but WITHOUT ANY WARRANTY; without even the implied warranty of
+#  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+#  GNU General Public License for more details.
+#
+#  You should have received a copy of the GNU General Public License
+#  along with this program; if not, write to the Free Software Foundation,
+#  Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# ##### END GPL LICENSE BLOCK #####
+
+# <pep8-80 compliant>
+
+"""
+This module contains RestrictBlend context manager.
+"""
+
+__all__ = (
+    "RestrictBlend",
+    )
+
+import bpy as _bpy
+
+class _RestrictContext():
+    __slots__ = ()
+    _real_data = _bpy.data
+    @property
+    def window_manager(self):
+        return self._real_data.window_managers[0]
+
+
+class _RestrictData():
+    __slots__ = ()
+
+
+_context_restrict = _RestrictContext()
+_data_restrict = _RestrictData()
+
+
+class RestrictBlend():
+    __slots__ = ("context", "data")
+    def __enter__(self):
+        self.data = _bpy.data
+        self.context = _bpy.context
+        _bpy.data = _data_restrict
+        _bpy.context = _context_restrict
+
+    def __exit__(self, type, value, traceback):
+        _bpy.data = self.data
+        _bpy.context = self.context