From ef665b3d1899669ca680400bbb0045706d784f2a Mon Sep 17 00:00:00 2001 From: Campbell Barton Date: Wed, 19 Dec 2012 07:27:23 +0000 Subject: [PATCH] dissallow access to the context while addons import and register. Since the window manager is needed for keymaps this is kept as an exception. some addons will need updating, but in every case I've seen addons should not be accessing the context while registering. (bad stuff! - declaring the scene as a global variable - which crashes when the users loads a new file, manipulating the active object or scene... tsk tsk) --- release/scripts/modules/addon_utils.py | 26 ++++++++++++++++++++++---- release/scripts/modules/bpy/utils.py | 9 ++++----- 2 files changed, 26 insertions(+), 9 deletions(-) diff --git a/release/scripts/modules/addon_utils.py b/release/scripts/modules/addon_utils.py index 6bf81d73f8b..3d705a0cf79 100644 --- a/release/scripts/modules/addon_utils.py +++ b/release/scripts/modules/addon_utils.py @@ -29,6 +29,14 @@ __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 @@ -201,7 +209,7 @@ def check(module_name): :rtype: tuple of booleans """ import sys - loaded_default = module_name in _bpy.context.user_preferences.addons + loaded_default = module_name in _user_preferences.addons mod = sys.modules.get(module_name) loaded_state = mod and getattr(mod, "__addon_enabled__", Ellipsis) @@ -259,6 +267,11 @@ 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 + # really bad while loading an addon, don't do it! + ctx = _bpy.context + _bpy.context = _ctx_restricted + # 1) try import try: mod = __import__(module_name) @@ -266,6 +279,7 @@ def enable(module_name, default_set=True, persistent=False): mod.__addon_enabled__ = False except: handle_error() + _bpy.context = ctx return None # 2) try register collected modules @@ -279,14 +293,18 @@ def enable(module_name, default_set=True, persistent=False): getattr(mod, "__file__", module_name)) handle_error() del sys.modules[module_name] + _bpy.context = ctx return None + # finally restore the context + _bpy.context = ctx + # * OK loaded successfully! * if default_set: # just in case its enabled already - ext = _bpy.context.user_preferences.addons.get(module_name) + ext = _user_preferences.addons.get(module_name) if not ext: - ext = _bpy.context.user_preferences.addons.new() + ext = _user_preferences.addons.new() ext.module = module_name mod.__addon_enabled__ = True @@ -327,7 +345,7 @@ def disable(module_name, default_set=True): (module_name, "disabled" if mod is None else "loaded")) # could be in more then once, unlikely but better do this just in case. - addons = _bpy.context.user_preferences.addons + addons = _user_preferences.addons if default_set: while module_name in addons: diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py index 4ad00eb267e..58646a708a2 100644 --- a/release/scripts/modules/bpy/utils.py +++ b/release/scripts/modules/bpy/utils.py @@ -57,6 +57,7 @@ import sys as _sys import addon_utils as _addon_utils +_user_preferences = _bpy.context.user_preferences _script_module_dirs = "startup", "modules" @@ -132,8 +133,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): """ use_time = _bpy.app.debug_python - prefs = _bpy.context.user_preferences - if use_time: import time t_main = time.time() @@ -150,7 +149,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): # to reload. note that they will only actually reload of the # modification time changes. This `won't` work for packages so... # its not perfect. - for module_name in [ext.module for ext in prefs.addons]: + for module_name in [ext.module for ext in _user_preferences.addons]: _addon_utils.disable(module_name, default_set=False) def register_module_call(mod): @@ -235,7 +234,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): _addon_utils.reset_all(reload_scripts) # run the active integration preset - filepath = preset_find(prefs.inputs.active_keyconfig, "keyconfig") + filepath = preset_find(_user_preferences.inputs.active_keyconfig, "keyconfig") if filepath: keyconfig_set(filepath) @@ -264,7 +263,7 @@ def script_path_user(): def script_path_pref(): """returns the user preference or None""" - path = _bpy.context.user_preferences.filepaths.script_directory + path = _user_preferences.filepaths.script_directory return _os.path.normpath(path) if path else None