From b93aabd7e12778206a89e21b6f2194db36ae004e Mon Sep 17 00:00:00 2001 From: alexguirre Date: Mon, 22 Apr 2024 23:08:39 +0200 Subject: [PATCH] fix: support Blender's "Reload Scripts" operator Now all Sollumz modules are properly reloaded when "Reload Scripts" is invoked, and no exceptions are raised. Now we can edit the source code and test the changes without restarting Blender (finally). --- __init__.py | 35 +++++++++++++++++++++++++++++++---- auto_load.py | 23 +++++++---------------- 2 files changed, 38 insertions(+), 20 deletions(-) diff --git a/__init__.py b/__init__.py index c229fb47..29672862 100644 --- a/__init__.py +++ b/__init__.py @@ -11,10 +11,6 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -from . import auto_load -from . import sollumz_debug -from . import sollumz_tool - bl_info = { "name": "Sollumz", @@ -28,6 +24,37 @@ } +def reload_sollumz_modules(): + import sys + + print("Reloading Sollumz modules") + + # Remove the packages imported in this module from the scope, so they are loaded again when imported below + global auto_load, sollumz_tool, sollumz_debug + del sollumz_tool + del sollumz_debug + del auto_load + + # Remove from `sys.modules` all Sollumz modules, so they are loaded again by auto_load + sz_module_prefix = f"{__package__}." + module_names = list(sys.modules.keys()) + for name in module_names: + if name.startswith(sz_module_prefix): + del sys.modules[name] + + +if "auto_load" in locals(): + # If an imported name already exists before imports, it means that the addon has been reloaded by Blender. + # Blender only reloads the main __init__.py file, so we reload all our modules now. + reload_sollumz_modules() + + +# These need to be here, not at the top of the file, to handle reload +from . import sollumz_tool # noqa: E402 +from . import sollumz_debug # noqa: E402 +from . import auto_load # noqa: E402 + + sollumz_debug.init_debug() # first in case we need to debug initialization code auto_load.init() diff --git a/auto_load.py b/auto_load.py index 5d99abb0..943f474f 100644 --- a/auto_load.py +++ b/auto_load.py @@ -11,8 +11,6 @@ "unregister", ) -blender_version = bpy.app.version - modules = None ordered_classes = None @@ -37,15 +35,15 @@ def register(): def unregister(): - called = [] + called = set() for module in modules: if module.__name__ == __name__: continue if hasattr(module, "unregister"): # Check if unregister method has already been called - if not module.unregister in called: + if module.unregister not in called: module.unregister() - called.append(module.unregister) + called.add(module.unregister) for cls in reversed(ordered_classes): bpy.utils.unregister_class(cls) @@ -83,13 +81,11 @@ def get_ordered_classes_to_register(modules): def get_register_deps_dict(modules): my_classes = set(iter_my_classes(modules)) - my_classes_by_idname = { - cls.bl_idname: cls for cls in my_classes if hasattr(cls, "bl_idname")} + my_classes_by_idname = {cls.bl_idname: cls for cls in my_classes if hasattr(cls, "bl_idname")} deps_dict = {} for cls in my_classes: - deps_dict[cls] = set(iter_my_register_deps( - cls, my_classes, my_classes_by_idname)) + deps_dict[cls] = set(iter_my_register_deps(cls, my_classes, my_classes_by_idname)) return deps_dict @@ -107,13 +103,8 @@ def iter_my_deps_from_annotations(cls, my_classes): def get_dependency_from_annotation(value): - if blender_version >= (2, 93): - if isinstance(value, bpy.props._PropertyDeferred): - return value.keywords.get("type") - else: - if isinstance(value, tuple) and len(value) == 2: - if value[0] in (bpy.props.PointerProperty, bpy.props.CollectionProperty): - return value[1]["type"] + if isinstance(value, bpy.props._PropertyDeferred): + return value.keywords.get("type") return None