diff options
Diffstat (limited to 'release/scripts/modules/bpy/utils.py')
-rw-r--r-- | release/scripts/modules/bpy/utils.py | 170 |
1 files changed, 130 insertions, 40 deletions
diff --git a/release/scripts/modules/bpy/utils.py b/release/scripts/modules/bpy/utils.py index 1792425268b..e3e93203235 100644 --- a/release/scripts/modules/bpy/utils.py +++ b/release/scripts/modules/bpy/utils.py @@ -23,12 +23,16 @@ This module contains utility functions specific to blender but not assosiated with blenders internal data. """ -import bpy as _bpy -import os as _os -import sys as _sys +from _bpy import register_class +from _bpy import unregister_class from _bpy import blend_paths from _bpy import script_paths as _bpy_script_paths +from _bpy import user_resource as _user_resource + +import bpy as _bpy +import os as _os +import sys as _sys def _test_import(module_name, loaded_modules): @@ -99,9 +103,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): import traceback import time - # must be set back to True on exits - _bpy_types._register_immediate = False - t_main = time.time() loaded_modules = set() @@ -111,7 +112,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): if reload_scripts: _bpy_types.TypeMap.clear() - _bpy_types.PropertiesMap.clear() # just unload, dont change user defaults, this means we can sync to reload. # note that they will only actually reload of the modification time changes. @@ -120,7 +120,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): addon_disable(module_name, default_set=False) def register_module_call(mod): - _bpy_types._register_module(mod.__name__) register = getattr(mod, "register", None) if register: try: @@ -131,7 +130,6 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): print("\nWarning! '%s' has no register function, this is now a requirement for registerable scripts." % mod.__file__) def unregister_module_call(mod): - _bpy_types._unregister_module(mod.__name__) unregister = getattr(mod, "unregister", None) if unregister: try: @@ -140,6 +138,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): traceback.print_exc() def test_reload(mod): + import imp # reloading this causes internal errors # because the classes from this module are stored internally # possibly to refresh internal references too but for now, best not to. @@ -147,7 +146,7 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): return mod try: - return reload(mod) + return imp.reload(mod) except: traceback.print_exc() @@ -197,18 +196,14 @@ def load_scripts(reload_scripts=False, refresh_scripts=False): for mod in modules_from_path(path, loaded_modules): test_register(mod) - _bpy_types._register_immediate = True - # deal with addons seperately - addon_reset_all() - + addon_reset_all(reload_scripts) # run the active integration preset filepath = preset_find(_bpy.context.user_preferences.inputs.active_keyconfig, "keyconfig") if filepath: keyconfig_set(filepath) - if reload_scripts: import gc print("gc.collect() -> %d" % gc.collect()) @@ -339,7 +334,14 @@ def addon_check(module_name): loaded_default = module_name in _bpy.context.user_preferences.addons mod = _sys.modules.get(module_name) - loaded_state = mod and getattr(mod, "__addon_enabled__") + loaded_state = mod and getattr(mod, "__addon_enabled__", Ellipsis) + + if loaded_state is Ellipsis: + print("Warning: addon-module %r found module but without" + " __addon_enabled__ field, possible name collision from file: %r" % + (module_name, getattr(mod, "__file__", "<unknown>"))) + + loaded_state = False return loaded_default, loaded_state @@ -358,15 +360,11 @@ def addon_enable(module_name, default_set=True): import os import sys import bpy_types as _bpy_types - - - _bpy_types._register_immediate = False + import imp def handle_error(): import traceback traceback.print_exc() - _bpy_types._register_immediate = True - # reload if the mtime changes mod = sys.modules.get(module_name) @@ -378,7 +376,7 @@ def addon_enable(module_name, default_set=True): print("module changed on disk:", mod.__file__, "reloading...") try: - reload(mod) + imp.reload(mod) except: handle_error() del sys.modules[module_name] @@ -396,19 +394,13 @@ def addon_enable(module_name, default_set=True): return None # 2) try register collected modules - try: - _bpy_types._register_module(module_name) - except: - handle_error() - del sys.modules[module_name] - return None + # removed, addons need to handle own registration now. # 3) try run the modules register function try: mod.register() except: handle_error() - _bpy_types._unregister_module(module_name) del sys.modules[module_name] return None @@ -419,12 +411,11 @@ def addon_enable(module_name, default_set=True): if not ext: ext = _bpy.context.user_preferences.addons.new() ext.module = module_name - - _bpy_types._register_immediate = True mod.__addon_enabled__ = True - print("\tbpy.utils.addon_enable", mod.__name__) + if _bpy.app.debug: + print("\tbpy.utils.addon_enable", mod.__name__) return mod @@ -447,7 +438,6 @@ def addon_disable(module_name, default_set=True): mod.__addon_enabled__ = False try: - _bpy_types._unregister_module(module_name, free=False) # dont free because we may want to enable again. mod.unregister() except: traceback.print_exc() @@ -462,21 +452,37 @@ def addon_disable(module_name, default_set=True): addon = addons.get(module_name) if addon: addons.remove(addon) - - print("\tbpy.utils.addon_disable", module_name) + + if _bpy.app.debug: + print("\tbpy.utils.addon_disable", module_name) -def addon_reset_all(): +def addon_reset_all(reload_scripts=False): """ Sets the addon state based on the user preferences. """ + import imp - paths = script_paths("addons") + script_paths("addons_contrib") + # RELEASE SCRIPTS: official scripts distributed in Blender releases + paths = script_paths("addons") + + # CONTRIB SCRIPTS: good for testing but not official scripts yet + paths += script_paths("addons_contrib") + + # EXTERN SCRIPTS: external projects scripts + paths += script_paths("addons_extern") for path in paths: _sys_path_ensure(path) for mod_name, mod_path in _bpy.path.module_names(path): is_enabled, is_loaded = addon_check(mod_name) + + # first check if reload is needed before changing state. + if reload_scripts: + mod = _sys.modules.get(mod_name) + if mod: + imp.reload(mod) + if is_enabled == is_loaded: pass elif is_enabled: @@ -485,12 +491,13 @@ def addon_reset_all(): print("\taddon_reset_all unloading", mod_name) addon_disable(mod_name) + def preset_find(name, preset_path, display_name=False): if not name: return None - + for directory in preset_paths(preset_path): - + if display_name: filename = "" for fn in _os.listdir(directory): @@ -533,8 +540,91 @@ def keyconfig_set(filepath): keyconfigs.remove(kc_dupe) else: break - + kc_new.name = name keyconfigs.active = kc_new +def user_resource(type, path="", create=False): + """ + Return a user resource path (normally from the users home directory). + + :arg type: Resource type in ['DATAFILES', 'CONFIG', 'SCRIPTS', 'AUTOSAVE']. + :type type: string + :arg subdir: Optional subdirectory. + :type subdir: string + :arg create: Treat the path as a directory and create it if its not existing. + :type create: boolean + :return: a path. + :rtype: string + """ + + target_path = _user_resource(type, path) + + if create: + # should always be true. + if target_path: + # create path if not existing. + if not _os.path.exists(target_path): + try: + _os.makedirs(target_path) + except: + import traceback + traceback.print_exc() + target_path = "" + elif not _os.path.isdir(target_path): + print("Path %r found but isn't a directory!" % target_path) + target_path = "" + + return target_path + + +def _bpy_module_classes(module, is_registered=False): + typemap_list = _bpy_types.TypeMap.get(module, ()) + i = 0 + while i < len(typemap_list): + cls_weakref, path, line = typemap_list[i] + cls = cls_weakref() + + if cls is None: + del typemap_list[i] + else: + if is_registered == ("bl_rna" in cls.__dict__): + yield (cls, path, line) + i += 1 + + +def register_module(module, verbose=False): + import traceback + if verbose: + print("bpy.utils.register_module(%r): ..." % module) + for cls, path, line in _bpy_module_classes(module, is_registered=False): + if verbose: + print(" %s of %s:%s" % (cls, path, line)) + try: + register_class(cls) + except: + print("bpy.utils.register_module(): failed to registering class '%s.%s'" % (cls.__module__, cls.__name__)) + print("\t", path, "line", line) + traceback.print_exc() + if verbose: + print("done.\n") + if "cls" not in locals(): + raise Exception("register_module(%r): defines no classes" % module) + + +def unregister_module(module, verbose=False): + import traceback + if verbose: + print("bpy.utils.unregister_module(%r): ..." % module) + for cls, path, line in _bpy_module_classes(module, is_registered=True): + if verbose: + print(" %s of %s:%s" % (cls, path, line)) + try: + unregister_class(cls) + except: + print("bpy.utils.unregister_module(): failed to unregistering class '%s.%s'" % (cls.__module__, cls.__name__)) + print("\t", path, "line", line) + traceback.print_exc() + if verbose: + print("done.\n")
\ No newline at end of file |