|
132 | 132 | CURLY_PATTERN = re.compile(r"^{(.+)}$") |
133 | 133 |
|
134 | 134 | # 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 |
144 | 141 | } |
| 142 | + |
145 | 143 | # 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 |
152 | 146 |
|
153 | 147 |
|
154 | 148 | def build_bt_index(root: ET.Element) -> dict[str, ET.Element]: |
@@ -770,28 +764,35 @@ def build_tree_from_xml( |
770 | 764 | } |
771 | 765 | node = py_trees.composites.Parallel( |
772 | 766 | name=node_name, |
773 | | - policy=mapping.get(policy, py_trees.common.ParallelPolicy.SuccessOnAll)(), # type: ignore |
| 767 | + policy=mapping[policy](), # type: ignore |
774 | 768 | children=children, |
775 | 769 | ) |
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. |
778 | 772 | constructor_kwargs: dict[str, Any] = {} |
779 | | - cls = get_class_from_registry(elem.tag, node_registry) |
| 773 | + cls = DECORATOR_NODES[tag] |
780 | 774 | if issubclass(cls, py_trees.decorators.Decorator): |
781 | 775 | if not len(children) == 1: |
782 | 776 | raise ValueError(f"Decorator '{elem.tag}' must have exactly one child, but got {len(children)}.") |
783 | 777 | constructor_kwargs["child"] = children[0] if children else None |
784 | 778 | else: |
785 | 779 | 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 | + |
795 | 796 | else: |
796 | 797 | raise NotImplementedError(f"Unknown composite tag: {tag}") |
797 | 798 |
|
|
0 commit comments