Skip to content

Commit 7f3376f

Browse files
committed
Improve handling of decorator nodes in XML parser
1 parent 4e1cb3a commit 7f3376f

1 file changed

Lines changed: 29 additions & 28 deletions

File tree

py_trees/parsers/behaviour_tree_xml.py

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -132,23 +132,17 @@
132132
CURLY_PATTERN = re.compile(r"^{(.+)}$")
133133

134134
# All composite or decorator tags which can have children and have ports (case-insensitive)
135-
# Migration note: this hard-coded set is a known limitation.
136-
# A follow-up should replace it with dynamic PortsMixin detection.
137-
PARENT_NODES_WITH_PORTS_TAGS = {
138-
"ifelse",
139-
"repeat",
140-
"retry",
141-
"caseswitch",
142-
"ifdataavailable",
143-
"ifnodataavailable",
135+
DECORATOR_NODES = {
136+
name.lower(): obj
137+
for name, obj in inspect.getmembers(py_trees.decorators, inspect.isclass)
138+
if obj.__module__ == py_trees.decorators.__name__
139+
and issubclass(obj, py_trees.decorators.Decorator)
140+
and obj is not py_trees.decorators
144141
}
142+
145143
# All composite or decorator tags which can have children (case-insensitive)
146-
PARENT_NODES_TAGS = set(PARENT_NODES_WITH_PORTS_TAGS) | {
147-
"sequence",
148-
"selector",
149-
"fallback",
150-
"parallel",
151-
}
144+
COMPOSITE_NODES_TAGS = {"sequence", "selector", "fallback", "parallel"}
145+
PARENT_NODES_TAGS = set(DECORATOR_NODES) | COMPOSITE_NODES_TAGS
152146

153147

154148
def build_bt_index(root: ET.Element) -> dict[str, ET.Element]:
@@ -770,28 +764,35 @@ def build_tree_from_xml(
770764
}
771765
node = py_trees.composites.Parallel(
772766
name=node_name,
773-
policy=mapping.get(policy, py_trees.common.ParallelPolicy.SuccessOnAll)(), # type: ignore
767+
policy=mapping[policy](), # type: ignore
774768
children=children,
775769
)
776-
elif tag in PARENT_NODES_WITH_PORTS_TAGS:
777-
# Instantiate ports-enabled composite
770+
elif tag in DECORATOR_NODES:
771+
# Instantiate built-in decorators, including extracting constructor arguments using type hints.
778772
constructor_kwargs: dict[str, Any] = {}
779-
cls = get_class_from_registry(elem.tag, node_registry)
773+
cls = DECORATOR_NODES[tag]
780774
if issubclass(cls, py_trees.decorators.Decorator):
781775
if not len(children) == 1:
782776
raise ValueError(f"Decorator '{elem.tag}' must have exactly one child, but got {len(children)}.")
783777
constructor_kwargs["child"] = children[0] if children else None
784778
else:
785779
constructor_kwargs["children"] = children
786-
node = instantiate_ports_node(
787-
elem=elem,
788-
node_registry=node_registry,
789-
remapping_table=remapping_table,
790-
subtree_namespace=subtree_namespace,
791-
logger=logger,
792-
constructor_kwargs=constructor_kwargs,
793-
parent_names_str=parent_names_str,
794-
)
780+
781+
for key in elem.keys():
782+
if key == "name":
783+
continue
784+
constructor_kwargs[key] = elem.attrib.get(key)
785+
786+
ignore_keys = {"child", "children", "behaviour_class_name"}
787+
constructor_kwargs, success = apply_type_hints(cls, constructor_kwargs, logger=logger, ignore=ignore_keys)
788+
if not success:
789+
logger.warning(
790+
"Failed to apply type hints to constructor arguments. See error log. " \
791+
"Proceeding, but leaving the conversion to the constructors."
792+
)
793+
794+
node = cls(name=node_name, **constructor_kwargs)
795+
795796
else:
796797
raise NotImplementedError(f"Unknown composite tag: {tag}")
797798

0 commit comments

Comments
 (0)