mirror of
https://github.com/IfcOpenShell/IfcOpenShell.git
synced 2026-09-16 21:42:19 +00:00
Move all reflection logic inside helper module
This commit is contained in:
@@ -1,14 +1,40 @@
|
|||||||
import typing
|
import typing
|
||||||
import inspect
|
import inspect
|
||||||
import collections
|
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
|
||||||
|
|
||||||
def extract_docs(patcher, boilerplate_args=None):
|
: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(cls, method_name, boilerplate_args):
|
||||||
inputs = collections.OrderedDict()
|
inputs = collections.OrderedDict()
|
||||||
function_init = patcher.__init__
|
method = getattr(cls, method_name)
|
||||||
node_data = {"patcher": patcher}
|
node_data = {"class": cls}
|
||||||
|
|
||||||
signature = inspect.signature(function_init)
|
signature = inspect.signature(method)
|
||||||
for name, parameter in signature.parameters.items():
|
for name, parameter in signature.parameters.items():
|
||||||
if name == "self":
|
if name == "self":
|
||||||
continue
|
continue
|
||||||
@@ -16,7 +42,7 @@ def extract_docs(patcher, boilerplate_args=None):
|
|||||||
if isinstance(parameter.default, (str, float, int, bool)):
|
if isinstance(parameter.default, (str, float, int, bool)):
|
||||||
inputs[name]["default"] = parameter.default
|
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():
|
for name, socket_data in inputs.items():
|
||||||
type_hint = type_hints.get(name, None)
|
type_hint = type_hints.get(name, None)
|
||||||
if type_hint is None: # The argument is not type-hinted. (Or hinted to 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__
|
inputs[name]["type"] = type_hint.__name__
|
||||||
|
|
||||||
description = ""
|
description = ""
|
||||||
doc = function_init.__doc__
|
doc = method.__doc__
|
||||||
if doc is not None:
|
if doc is not None:
|
||||||
for i, line in enumerate(doc.split("\n")):
|
for i, line in enumerate(doc.split("\n")):
|
||||||
line = line.strip()
|
line = line.strip()
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import os
|
import os
|
||||||
import bpy
|
import bpy
|
||||||
import json
|
import json
|
||||||
|
import ifcpatch
|
||||||
from .helper import extract_docs
|
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]
|
return os.path.isfile(input_file) and "ifc" in os.path.splitext(input_file)[1]
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
import ifcpatch
|
|
||||||
|
|
||||||
ifcpatch.execute(
|
ifcpatch.execute(
|
||||||
{
|
{
|
||||||
@@ -73,37 +74,22 @@ class PopulatePatchArguments(bpy.types.Operator):
|
|||||||
recipe: bpy.props.StringProperty()
|
recipe: bpy.props.StringProperty()
|
||||||
|
|
||||||
def execute(self, context):
|
def execute(self, context):
|
||||||
import importlib
|
|
||||||
import ifcpatch
|
|
||||||
|
|
||||||
patch_args = context.scene.BIMPatchProperties.ifc_patch_args_attr
|
patch_args = context.scene.BIMPatchProperties.ifc_patch_args_attr
|
||||||
patch_args.clear()
|
patch_args.clear()
|
||||||
recipe = self.recipe
|
docs = extract_docs(ifcpatch, self.recipe, "Patcher", "__init__", ("src", "file", "logger", "args"))
|
||||||
spec = importlib.util.spec_from_file_location(recipe, f"{ifcpatch.__path__[0]}/recipes/{recipe}.py")
|
if "inputs" in docs:
|
||||||
patcher = importlib.util.module_from_spec(spec)
|
for arg_name in docs["inputs"]:
|
||||||
try:
|
arg_info = docs["inputs"][arg_name]
|
||||||
spec.loader.exec_module(patcher)
|
new_attr = patch_args.add()
|
||||||
try:
|
new_attr.data_type = self.TYPE_BINDINGS[arg_info["type"]]
|
||||||
docs = extract_docs(patcher.Patcher, boilerplate_args=("src", "file", "logger", "args"))
|
new_attr.name = arg_name
|
||||||
if "inputs" in docs:
|
if new_attr.data_type == "string":
|
||||||
for arg_name in docs["inputs"]:
|
new_attr.string_value = arg_info.get("default", "")
|
||||||
arg_info = docs["inputs"][arg_name]
|
elif new_attr.data_type == "float":
|
||||||
new_attr = patch_args.add()
|
new_attr.float_value = arg_info.get("default", 0)
|
||||||
new_attr.data_type = self.TYPE_BINDINGS[arg_info["type"]]
|
elif new_attr.data_type == "integer":
|
||||||
new_attr.name = arg_name
|
new_attr.int_value = arg_info.get("default", 0)
|
||||||
if new_attr.data_type == "string":
|
elif new_attr.data_type == "boolean":
|
||||||
new_attr.string_value = arg_info.get("default", "")
|
new_attr.bool_value = arg_info.get("default", False)
|
||||||
elif new_attr.data_type == "float":
|
new_attr.description = arg_info.get("description", "")
|
||||||
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))
|
|
||||||
return {"FINISHED"}
|
return {"FINISHED"}
|
||||||
|
|||||||
@@ -26,15 +26,7 @@ class BIM_PT_patch(bpy.types.Panel):
|
|||||||
|
|
||||||
recipe = props.ifc_patch_recipes
|
recipe = props.ifc_patch_recipes
|
||||||
|
|
||||||
spec = importlib.util.spec_from_file_location(recipe, f"{ifcpatch.__path__[0]}/recipes/{recipe}.py")
|
docs = extract_docs(ifcpatch, recipe, "Patcher", "__init__", ("src", "file", "logger", "args"))
|
||||||
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:
|
|
||||||
for line in docs["description"].split("\n"):
|
for line in docs["description"].split("\n"):
|
||||||
layout.label(text=line)
|
layout.label(text=line)
|
||||||
except AttributeError as e:
|
except AttributeError as e:
|
||||||
|
|||||||
Reference in New Issue
Block a user