Skip to content

Instantly share code, notes, and snippets.

@florianfelix
Created August 15, 2019 12:12
Show Gist options
  • Save florianfelix/2f7c22c5f9f7d85b37c3bf3568466ef0 to your computer and use it in GitHub Desktop.
Save florianfelix/2f7c22c5f9f7d85b37c3bf3568466ef0 to your computer and use it in GitHub Desktop.
import os
import bpy
import sys
import typing
import inspect
import pkgutil
import importlib
from pathlib import Path
from collections import OrderedDict
__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():
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 = OrderedDict()
classes_to_register = list(iter_classes_to_register(modules))
for cls in classes_to_register:
deps_dict[cls] = list(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 = []
for module in modules:
classes.extend(sorted_classes_in_module(module))
return classes
def iter_classes_in_module(module):
for value in module.__dict__.values():
if inspect.isclass(value):
yield value
def sorted_classes_in_module(module):
classes = []
for value in module.__dict__.values():
if inspect.isclass(value):
classes.append(value)
print([cls.__name__ for cls in classes])
classes = sorted(classes, key=lambda cls: cls.__name__)
print([cls.__name__ for cls in classes])
return classes
def get_register_base_types():
return list(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 = list()
while len(deps_dict) > 0:
unsorted = []
for value, deps in deps_dict.items():
if len(deps) == 0:
sorted_list.append(value)
sorted_values.append(value)
else:
unsorted.append(value)
deps_dict = {value : deps_dict[value] - sorted_values for value in unsorted}
return sorted_list
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment