[Bf-blender-cvs] [657204dfcef] functions: use auto load for registration

Jacques Lucke noreply at git.blender.org
Sun Mar 10 16:28:30 CET 2019


Commit: 657204dfcefd78ae41111a4c2e52e232e341bc55
Author: Jacques Lucke
Date:   Sun Mar 10 13:57:37 2019 +0100
Branches: functions
https://developer.blender.org/rB657204dfcefd78ae41111a4c2e52e232e341bc55

use auto load for registration

===================================================================

M	release/scripts/startup/function_nodes/__init__.py
A	release/scripts/startup/function_nodes/auto_load.py
M	release/scripts/startup/function_nodes/menu.py
M	release/scripts/startup/function_nodes/node_operators.py
M	release/scripts/startup/function_nodes/nodes/__init__.py
M	release/scripts/startup/function_nodes/nodes/clamp.py
M	release/scripts/startup/function_nodes/nodes/combine_vector.py
M	release/scripts/startup/function_nodes/nodes/float_math.py
M	release/scripts/startup/function_nodes/nodes/function_input.py
M	release/scripts/startup/function_nodes/nodes/function_output.py
M	release/scripts/startup/function_nodes/nodes/map_range.py
M	release/scripts/startup/function_nodes/nodes/object_transforms.py
M	release/scripts/startup/function_nodes/nodes/random_number.py
M	release/scripts/startup/function_nodes/nodes/separate_vector.py
M	release/scripts/startup/function_nodes/nodes/vector_distance.py
M	release/scripts/startup/function_nodes/sockets.py

===================================================================

diff --git a/release/scripts/startup/function_nodes/__init__.py b/release/scripts/startup/function_nodes/__init__.py
index 8877382c5fc..bc085e4ce94 100644
--- a/release/scripts/startup/function_nodes/__init__.py
+++ b/release/scripts/startup/function_nodes/__init__.py
@@ -1,7 +1,4 @@
+from . auto_load import init, register, unregister
 
-def register():
-    from . import base
-    from . import sockets
-    from . import nodes
-    from . import menu
-    from . import node_operators
\ No newline at end of file
+init()
+print("INIT")
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/auto_load.py b/release/scripts/startup/function_nodes/auto_load.py
new file mode 100644
index 00000000000..6aef4a00924
--- /dev/null
+++ b/release/scripts/startup/function_nodes/auto_load.py
@@ -0,0 +1,139 @@
+import os
+import bpy
+import sys
+import typing
+import inspect
+import pkgutil
+import importlib
+from pathlib import Path
+
+__all__ = (
+    "init",
+    "register",
+    "unregister",
+)
+
+modules = None
+ordered_classes = None
+
+def init():
+    global modules
+    global ordered_classes
+
+    modules = get_all_submodules(Path(__file__).parent)
+    ordered_classes = get_ordered_classes_to_register(modules)
+
+def register():
+    print("REGISTER")
+    for cls in ordered_classes:
+        bpy.utils.register_class(cls)
+
+    for module in modules:
+        if module.__name__ == __name__:
+            continue
+        if hasattr(module, "register"):
+            module.register()
+
+def unregister():
+    for cls in reversed(ordered_classes):
+        bpy.utils.unregister_class(cls)
+
+    for module in modules:
+        if module.__name__ == __name__:
+            continue
+        if hasattr(module, "unregister"):
+            module.unregister()
+
+
+# Import modules
+#################################################
+
+def get_all_submodules(directory):
+    return list(iter_submodules(directory, directory.name))
+
+def iter_submodules(path, package_name):
+    for name in sorted(iter_submodule_names(path)):
+        yield importlib.import_module("." + name, package_name)
+
+def iter_submodule_names(path, root=""):
+    for _, module_name, is_package in pkgutil.iter_modules([str(path)]):
+        if is_package:
+            sub_path = path / module_name
+            sub_root = root + module_name + "."
+            yield from iter_submodule_names(sub_path, sub_root)
+        else:
+            yield root + module_name
+
+
+# Find classes to register
+#################################################
+
+def get_ordered_classes_to_register(modules):
+    return toposort(get_register_deps_dict(modules))
+
+def get_register_deps_dict(modules):
+    deps_dict = {}
+    classes_to_register = set(iter_classes_to_register(modules))
+    for cls in classes_to_register:
+        deps_dict[cls] = set(iter_own_register_deps(cls, classes_to_register))
+    return deps_dict
+
+def iter_own_register_deps(cls, own_classes):
+    yield from (dep for dep in iter_register_deps(cls) if dep in own_classes)
+
+def iter_register_deps(cls):
+    for value in typing.get_type_hints(cls, {}, {}).values():
+        dependency = get_dependency_from_annotation(value)
+        if dependency is not None:
+            yield dependency
+
+def get_dependency_from_annotation(value):
+    if isinstance(value, tuple) and len(value) == 2:
+        if value[0] in (bpy.props.PointerProperty, bpy.props.CollectionProperty):
+            return value[1]["type"]
+    return None
+
+def iter_classes_to_register(modules):
+    base_types = get_register_base_types()
+    for cls in get_classes_in_modules(modules):
+        if any(base in base_types for base in cls.__bases__):
+            if not getattr(cls, "is_registered", False):
+                yield cls
+
+def get_classes_in_modules(modules):
+    classes = set()
+    for module in modules:
+        for cls in iter_classes_in_module(module):
+            classes.add(cls)
+    return classes
+
+def iter_classes_in_module(module):
+    for value in module.__dict__.values():
+        if inspect.isclass(value):
+            yield value
+
+def get_register_base_types():
+    return set(getattr(bpy.types, name) for name in [
+        "Panel", "Operator", "PropertyGroup",
+        "AddonPreferences", "Header", "Menu",
+        "Node", "NodeSocket", "NodeTree",
+        "UIList", "RenderEngine"
+    ])
+
+
+# Find order to register to solve dependencies
+#################################################
+
+def toposort(deps_dict):
+    sorted_list = []
+    sorted_values = set()
+    while len(deps_dict) > 0:
+        unsorted = []
+        for value, deps in deps_dict.items():
+            if len(deps) == 0:
+                sorted_list.append(value)
+                sorted_values.add(value)
+            else:
+                unsorted.append(value)
+        deps_dict = {value : deps_dict[value] - sorted_values for value in unsorted}
+    return sorted_list
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/menu.py b/release/scripts/startup/function_nodes/menu.py
index 47fc6e8bdc6..da5a318f8e9 100644
--- a/release/scripts/startup/function_nodes/menu.py
+++ b/release/scripts/startup/function_nodes/menu.py
@@ -31,4 +31,6 @@ def insert_node(layout, type, text, settings = {}, icon = "NONE"):
         item.value = value
     return operator
 
-bpy.types.NODE_MT_add.append(draw_menu)
\ No newline at end of file
+
+def register():
+    bpy.types.NODE_MT_add.append(draw_menu)
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/node_operators.py b/release/scripts/startup/function_nodes/node_operators.py
index ea9919b3962..5c6aa24991e 100644
--- a/release/scripts/startup/function_nodes/node_operators.py
+++ b/release/scripts/startup/function_nodes/node_operators.py
@@ -24,6 +24,4 @@ class NodeOperator(bpy.types.Operator):
         settings = eval(self.settings_repr)
         function(*settings)
 
-        return {"FINISHED"}
-
-bpy.utils.register_class(NodeOperator)
\ No newline at end of file
+        return {"FINISHED"}
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/nodes/__init__.py b/release/scripts/startup/function_nodes/nodes/__init__.py
index 56ead29f394..e69de29bb2d 100644
--- a/release/scripts/startup/function_nodes/nodes/__init__.py
+++ b/release/scripts/startup/function_nodes/nodes/__init__.py
@@ -1,13 +0,0 @@
-from . import (
-    function_input,
-    function_output,
-
-    float_math,
-    combine_vector,
-    separate_vector,
-    object_transforms,
-    vector_distance,
-    clamp,
-    random_number,
-    map_range,
-)
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/nodes/clamp.py b/release/scripts/startup/function_nodes/nodes/clamp.py
index 92f7a19046c..5f8cead91b2 100644
--- a/release/scripts/startup/function_nodes/nodes/clamp.py
+++ b/release/scripts/startup/function_nodes/nodes/clamp.py
@@ -12,6 +12,4 @@ class ClampNode(bpy.types.Node, FunctionNode):
             ("fn_FloatSocket", "Max"),
         ], [
             ("fn_FloatSocket", "Result"),
-        ]
-
-bpy.utils.register_class(ClampNode)
\ No newline at end of file
+        ]
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/nodes/combine_vector.py b/release/scripts/startup/function_nodes/nodes/combine_vector.py
index cebd9f266f0..055491b9b86 100644
--- a/release/scripts/startup/function_nodes/nodes/combine_vector.py
+++ b/release/scripts/startup/function_nodes/nodes/combine_vector.py
@@ -12,6 +12,4 @@ class CombineVectorNode(bpy.types.Node, FunctionNode):
             ("fn_FloatSocket", "Z"),
         ], [
             ("fn_VectorSocket", "Result"),
-        ]
-
-bpy.utils.register_class(CombineVectorNode)
\ No newline at end of file
+        ]
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/nodes/float_math.py b/release/scripts/startup/function_nodes/nodes/float_math.py
index f6b506529cb..7951925e496 100644
--- a/release/scripts/startup/function_nodes/nodes/float_math.py
+++ b/release/scripts/startup/function_nodes/nodes/float_math.py
@@ -27,6 +27,4 @@ class FloatMathNode(bpy.types.Node, FunctionNode):
         ]
 
     def draw(self, layout):
-        layout.prop(self, "operation", text="")
-
-bpy.utils.register_class(FloatMathNode)
\ No newline at end of file
+        layout.prop(self, "operation", text="")
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/nodes/function_input.py b/release/scripts/startup/function_nodes/nodes/function_input.py
index 4b57ad473b1..ea92fbf21e9 100644
--- a/release/scripts/startup/function_nodes/nodes/function_input.py
+++ b/release/scripts/startup/function_nodes/nodes/function_input.py
@@ -30,6 +30,3 @@ class FunctionInputNode(BaseNode, bpy.types.Node):
 
     def remove_socket(self, index):
         self.outputs.remove(self.outputs[index])
-
-
-bpy.utils.register_class(FunctionInputNode)
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/nodes/function_output.py b/release/scripts/startup/function_nodes/nodes/function_output.py
index 562fe636987..0fa485724d2 100644
--- a/release/scripts/startup/function_nodes/nodes/function_output.py
+++ b/release/scripts/startup/function_nodes/nodes/function_output.py
@@ -29,6 +29,4 @@ class FunctionOutputNode(BaseNode, bpy.types.Node):
         self.inputs.new(idname, "Output")
 
     def remove_socket(self, index):
-        self.inputs.remove(self.inputs[index])
-
-bpy.utils.register_class(FunctionOutputNode)
\ No newline at end of file
+        self.inputs.remove(self.inputs[index])
\ No newline at end of file
diff --git a/release/scripts/startup/function_nodes/nodes/map_range.py b/release/scripts/startup/function_nodes/nodes/map_range.py
index f05a9fd9aa6..a8b971dfeeb 100644
--- a/release/scripts/startup/function_nodes/nodes/map_range.py
+++ b/release/scripts/startup/function_nodes/nodes/map_range.py
@@ -15,6 +15,4 @@ class MapRangeNode(bpy.types.Node, FunctionNode):
             ("fn_FloatSocket", "To Max"),
         ], [
             ("fn_FloatSocket", "Value"),
-        ]
-
-bpy.utils.register_class(MapRangeNode)
\ No newline at end 

@@ Diff output truncated at 10240 characters. @@



More information about the Bf-blender-cvs mailing list