@@ -83,6 +83,30 @@ def duration_value_ms(self) -> Any:
8383 return self .get_input (self .INPUT_DURATION_MS_PORT )
8484
8585
86+ class EchoCtorArgs (BehaviourWithPorts ):
87+ """Behaviour that tests interpreting constructor type hints for type coercion from XML ports."""
88+ @classmethod
89+ def input_ports (cls ) -> dict :
90+ return {"in" : PortInformation (data_type = str , required = False )} # not used here
91+
92+ @classmethod
93+ def output_ports (cls ) -> dict :
94+ return {"out" : PortInformation (data_type = str , required = False )} # not used here
95+
96+ def __init__ (self , name : str , greeting : str , times : float | None , flag : bool , ** kwargs : Any ) -> None :
97+ super ().__init__ (name , ** kwargs )
98+ self .greeting = greeting
99+ self .times = times
100+ self .flag = flag
101+
102+ class EchoCtorArgsChild (EchoCtorArgs ):
103+ """
104+ Behaviour that tests interpreting constructor type hints for type coercion from XML ports,
105+ but from its parent class.
106+ """
107+ def __init__ (self , ** kwargs ):
108+ super ().__init__ (** kwargs )
109+
86110@dataclass
87111class RobotData :
88112 type : str
@@ -471,25 +495,37 @@ def test_ctor_args_passed_as_kwargs(self) -> None:
471495 Values are automatically converted based on the type hints in the constructor.
472496 """
473497
474- class EchoCtorArgs (BehaviourWithPorts ):
475- @classmethod
476- def input_ports (cls ) -> dict :
477- return {"in" : PortInformation (data_type = str , required = False )} # not used here
498+ xml = """<root main_tree_to_execute="Main">
499+ <BehaviorTree ID="Main">
500+ <Sequence>
501+ <EchoCtorArgs name="E1" greeting="hello" times="3" flag="true"/>
502+ </Sequence>
503+ </BehaviorTree>
504+ </root>"""
478505
479- @ classmethod
480- def output_ports ( cls ) -> dict :
481- return { "out" : PortInformation ( data_type = str , required = False )} # not used here
506+ with tempfile . NamedTemporaryFile ( delete = False , mode = "w" , suffix = ".xml" ) as tf :
507+ tf . write ( xml )
508+ path = tf . name
482509
483- def __init__ (self , name : str , greeting : str , times : float | None , flag : bool , ** kwargs : Any ) -> None :
484- super ().__init__ (name , ** kwargs )
485- self .greeting = greeting
486- self .times = times
487- self .flag = flag
510+ root = parse_behaviour_tree_xml (path , logger = StdoutLogger ())
511+ node = find_node_by_class (root , EchoCtorArgs )
512+ self .assertIsNotNone (node )
513+ self .assertEqual (node .greeting , "hello" )
514+ self .assertEqual (node .times , 3.0 )
515+ self .assertEqual (node .flag , True )
516+
517+ os .unlink (path )
518+
519+ def test_ctor_args_passed_as_kwargs_in_parent_class (self ) -> None :
520+ """
521+ Non-port XML attributes must be passed as constructor kwargs.
522+ Values are automatically converted based on the type hints in the parent class constructor.
523+ """
488524
489525 xml = """<root main_tree_to_execute="Main">
490526 <BehaviorTree ID="Main">
491527 <Sequence>
492- <EchoCtorArgs name="E1" greeting="hello" times="3" flag="true"/>
528+ <EchoCtorArgsChild name="E1" greeting="hello" times="3" flag="true"/>
493529 </Sequence>
494530 </BehaviorTree>
495531 </root>"""
@@ -499,7 +535,7 @@ def __init__(self, name: str, greeting: str, times: float | None, flag: bool, **
499535 path = tf .name
500536
501537 root = parse_behaviour_tree_xml (path , logger = StdoutLogger ())
502- node = find_node_by_class (root , EchoCtorArgs )
538+ node = find_node_by_class (root , EchoCtorArgsChild )
503539 self .assertIsNotNone (node )
504540 self .assertEqual (node .greeting , "hello" )
505541 self .assertEqual (node .times , 3.0 )
0 commit comments