diff --git a/src/blenderbim/blenderbim/bim/module/patch/helper.py b/src/blenderbim/blenderbim/bim/module/patch/helper.py index bf67b540a7..20b84bc6b3 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/helper.py +++ b/src/blenderbim/blenderbim/bim/module/patch/helper.py @@ -1,14 +1,40 @@ import typing import inspect import collections +import importlib +from types import ModuleType +def extract_docs( + module: ModuleType, + submodule_name: str, + cls_name: str, + method_name: str, + boilerplate_args : typing.Iterable[str]=None): + """Extract class docstrings and method arguments + + :param module: Parent module from which to extract the submodule class + :param submodule_name: Submodule from which to extract the class + :param cls_name: Class from which to extract the docstring and method arguments + :param method_name: Class Method name from which to extract arguments + :param boilerplate_args: String iterable containing arguments that shall not be parsed + """ + spec = importlib.util.spec_from_file_location(submodule_name, f"{module.__path__[0]}/recipes/{submodule_name}.py") + submodule = importlib.util.module_from_spec(spec) + try: + spec.loader.exec_module(submodule) + try: + return _extract_docs(getattr(submodule, cls_name), method_name, boilerplate_args) + except AttributeError as e: + print(e) + except ModuleNotFoundError as e: + print("Error : " + str(e) + "in " + str(submodule)) -def extract_docs(patcher, boilerplate_args=None): +def _extract_docs(cls, method_name, boilerplate_args): inputs = collections.OrderedDict() - function_init = patcher.__init__ - node_data = {"patcher": patcher} + method = getattr(cls, method_name) + node_data = {"class": cls} - signature = inspect.signature(function_init) + signature = inspect.signature(method) for name, parameter in signature.parameters.items(): if name == "self": continue @@ -16,7 +42,7 @@ def extract_docs(patcher, boilerplate_args=None): if isinstance(parameter.default, (str, float, int, bool)): inputs[name]["default"] = parameter.default - type_hints = typing.get_type_hints(function_init) + type_hints = typing.get_type_hints(method) for name, socket_data in inputs.items(): type_hint = type_hints.get(name, None) if type_hint is None: # The argument is not type-hinted. (Or hinted to None ??) @@ -27,7 +53,7 @@ def extract_docs(patcher, boilerplate_args=None): inputs[name]["type"] = type_hint.__name__ description = "" - doc = function_init.__doc__ + doc = method.__doc__ if doc is not None: for i, line in enumerate(doc.split("\n")): line = line.strip() diff --git a/src/blenderbim/blenderbim/bim/module/patch/operator.py b/src/blenderbim/blenderbim/bim/module/patch/operator.py index e07a9f17cb..3752f12feb 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/operator.py +++ b/src/blenderbim/blenderbim/bim/module/patch/operator.py @@ -1,6 +1,7 @@ import os import bpy import json +import ifcpatch from .helper import extract_docs @@ -47,7 +48,7 @@ class ExecuteIfcPatch(bpy.types.Operator): return os.path.isfile(input_file) and "ifc" in os.path.splitext(input_file)[1] def execute(self, context): - import ifcpatch + ifcpatch.execute( { @@ -73,37 +74,22 @@ class PopulatePatchArguments(bpy.types.Operator): recipe: bpy.props.StringProperty() def execute(self, context): - import importlib - import ifcpatch - patch_args = context.scene.BIMPatchProperties.ifc_patch_args_attr patch_args.clear() - recipe = self.recipe - spec = importlib.util.spec_from_file_location(recipe, f"{ifcpatch.__path__[0]}/recipes/{recipe}.py") - patcher = importlib.util.module_from_spec(spec) - try: - spec.loader.exec_module(patcher) - try: - docs = extract_docs(patcher.Patcher, boilerplate_args=("src", "file", "logger", "args")) - if "inputs" in docs: - for arg_name in docs["inputs"]: - arg_info = docs["inputs"][arg_name] - new_attr = patch_args.add() - new_attr.data_type = self.TYPE_BINDINGS[arg_info["type"]] - new_attr.name = arg_name - if new_attr.data_type == "string": - new_attr.string_value = arg_info.get("default", "") - elif new_attr.data_type == "float": - new_attr.float_value = arg_info.get("default", 0) - elif new_attr.data_type == "integer": - new_attr.int_value = arg_info.get("default", 0) - elif new_attr.data_type == "boolean": - new_attr.bool_value = arg_info.get("default", False) - - new_attr.description =arg_info.get("description", "") - - except AttributeError as e: - print(e) - except ModuleNotFoundError as e: - print("Error : " + str(e) + "in " + str(patcher)) + docs = extract_docs(ifcpatch, self.recipe, "Patcher", "__init__", ("src", "file", "logger", "args")) + if "inputs" in docs: + for arg_name in docs["inputs"]: + arg_info = docs["inputs"][arg_name] + new_attr = patch_args.add() + new_attr.data_type = self.TYPE_BINDINGS[arg_info["type"]] + new_attr.name = arg_name + if new_attr.data_type == "string": + new_attr.string_value = arg_info.get("default", "") + elif new_attr.data_type == "float": + new_attr.float_value = arg_info.get("default", 0) + elif new_attr.data_type == "integer": + new_attr.int_value = arg_info.get("default", 0) + elif new_attr.data_type == "boolean": + new_attr.bool_value = arg_info.get("default", False) + new_attr.description = arg_info.get("description", "") return {"FINISHED"} diff --git a/src/blenderbim/blenderbim/bim/module/patch/ui.py b/src/blenderbim/blenderbim/bim/module/patch/ui.py index 91b39f47c9..87d875088b 100644 --- a/src/blenderbim/blenderbim/bim/module/patch/ui.py +++ b/src/blenderbim/blenderbim/bim/module/patch/ui.py @@ -26,15 +26,7 @@ class BIM_PT_patch(bpy.types.Panel): recipe = props.ifc_patch_recipes - spec = importlib.util.spec_from_file_location(recipe, f"{ifcpatch.__path__[0]}/recipes/{recipe}.py") - patcher = importlib.util.module_from_spec(spec) - try: - spec.loader.exec_module(patcher) - try: - docs = extract_docs(patcher.Patcher, boilerplate_args=("src", "file", "logger", "args")) - if "name" in docs: - layout.label(text=docs["name"]) - if "description" in docs: + docs = extract_docs(ifcpatch, recipe, "Patcher", "__init__", ("src", "file", "logger", "args")) for line in docs["description"].split("\n"): layout.label(text=line) except AttributeError as e: