diff --git a/pylasu/model/model.py b/pylasu/model/model.py index d529775..ce7cb90 100644 --- a/pylasu/model/model.py +++ b/pylasu/model/model.py @@ -5,8 +5,7 @@ from .position import Position, Source from .reflection import Multiplicity, PropertyDescription -from ..reflection import getannotations -from ..reflection.reflection import is_sequence_type, get_type_arguments +from ..reflection import getannotations, get_type_arguments, is_sequence_type class internal_property(property): @@ -177,3 +176,17 @@ def _fields(self): @internal_property def node_type(self): return type(self) + + +def concept_of(node): + properties = dir(node) + if "__concept__" in properties: + node_type = node.__concept__ + elif "node_type" in properties: + node_type = node.node_type + else: + node_type = type(node) + if isinstance(node_type, Concept): + return node_type + else: + raise Exception(f"Not a concept: {node_type} of {node}") diff --git a/pylasu/reflection/__init__.py b/pylasu/reflection/__init__.py index c0d0ce1..415e17e 100644 --- a/pylasu/reflection/__init__.py +++ b/pylasu/reflection/__init__.py @@ -1 +1 @@ -from .reflection import getannotations +from .reflection import getannotations, get_type_arguments, is_sequence_type diff --git a/pylasu/transformation/transformation.py b/pylasu/transformation/transformation.py index fe06fdd..c09991b 100644 --- a/pylasu/transformation/transformation.py +++ b/pylasu/transformation/transformation.py @@ -5,6 +5,7 @@ from pylasu.model import Node, Origin from pylasu.model.errors import GenericErrorNode +from pylasu.model.model import concept_of from pylasu.model.reflection import PropertyDescription from pylasu.transformation.generic_nodes import GenericNode from pylasu.validation import Issue, IssueSeverity @@ -32,7 +33,7 @@ def set(self, node: Node, value): class NodeFactory(Generic[Source, Output]): constructor: node_factory_constructor_type children: Dict[str, "ChildNodeFactory[Source, Any, Any]"] = field(default_factory=dict) - finalizer: Callable[[Source], None] = lambda _: None + finalizer: Callable[[Source], None] = field(default=lambda _: None) def with_child( self, @@ -104,7 +105,7 @@ def transform_into_nodes(self, source: Optional[Any], parent: Optional[Node] = N if factory: nodes = self.make_nodes(factory, source) for node in nodes: - for pd in type(node).node_properties: + for pd in concept_of(node).node_properties: self.process_child(source, node, pd, factory) factory.finalizer(node) node.parent = parent @@ -134,7 +135,7 @@ def process_child(self, source, node, pd, factory): if child_node_factory != NO_CHILD_NODE: self.set_child(child_node_factory, source, node, pd) else: - # TODO should we support @Mapped? + # TODO should we support @Mapped / dot-notation? factory.children[child_key] = NO_CHILD_NODE def as_origin(self, source: Any) -> Optional[Origin]: