1818try :
1919 import yaml
2020except ImportError :
21- print ("Error: PyYAML is required. Install with: pip install pyyaml" , file = sys .stderr )
21+ print (
22+ "Error: PyYAML is required. Install with: pip install pyyaml" , file = sys .stderr
23+ )
2224 sys .exit (1 )
2325
2426
@@ -67,11 +69,13 @@ def discover_configs(workspace_path: Path) -> List[Dict[str, str]]:
6769 name_elem = root_elem .find ("name" )
6870 if name_elem is not None :
6971 package_name = name_elem .text .strip ()
70- configs .append ({
71- "name" : package_name ,
72- "path" : root ,
73- "config_path" : str (config_yaml ),
74- })
72+ configs .append (
73+ {
74+ "name" : package_name ,
75+ "path" : root ,
76+ "config_path" : str (config_yaml ),
77+ }
78+ )
7579 except Exception :
7680 continue
7781
@@ -136,7 +140,14 @@ def extract_behaviors_used_in_objectives(
136140
137141 package_path = find_package_share_path (package_name , workspace_path )
138142 if not package_path :
139- install_path = workspace_path / "install" / package_name / "share" / package_name / relative_path
143+ install_path = (
144+ workspace_path
145+ / "install"
146+ / package_name
147+ / "share"
148+ / package_name
149+ / relative_path
150+ )
140151 if install_path .exists ():
141152 package_path = install_path .parent .parent .parent .parent / "src"
142153 package_path = find_package_share_path (package_name , package_path )
@@ -170,13 +181,17 @@ def extract_behaviors_used_in_objectives(
170181 behavior_id_lower = normalize_behavior_id (behavior_id )
171182 if behavior_id_lower not in behavior_to_objectives :
172183 behavior_to_objectives [behavior_id_lower ] = []
173- behavior_to_objectives [behavior_id_lower ].append ({
174- "config" : config_name ,
175- "objective_id" : objective_id ,
176- "objective_file" : str (objective_file .relative_to (workspace_path )),
177- "usage_type" : "SubTree" ,
178- "source_type" : "objective_usage" ,
179- })
184+ behavior_to_objectives [behavior_id_lower ].append (
185+ {
186+ "config" : config_name ,
187+ "objective_id" : objective_id ,
188+ "objective_file" : str (
189+ objective_file .relative_to (workspace_path )
190+ ),
191+ "usage_type" : "SubTree" ,
192+ "source_type" : "objective_usage" ,
193+ }
194+ )
180195
181196 # 2. Action nodes
182197 for action in behavior_tree .findall (".//Action[@ID]" ):
@@ -185,13 +200,17 @@ def extract_behaviors_used_in_objectives(
185200 behavior_id_lower = normalize_behavior_id (behavior_id )
186201 if behavior_id_lower not in behavior_to_objectives :
187202 behavior_to_objectives [behavior_id_lower ] = []
188- behavior_to_objectives [behavior_id_lower ].append ({
189- "config" : config_name ,
190- "objective_id" : objective_id ,
191- "objective_file" : str (objective_file .relative_to (workspace_path )),
192- "usage_type" : "Action" ,
193- "source_type" : "objective_usage" ,
194- })
203+ behavior_to_objectives [behavior_id_lower ].append (
204+ {
205+ "config" : config_name ,
206+ "objective_id" : objective_id ,
207+ "objective_file" : str (
208+ objective_file .relative_to (workspace_path )
209+ ),
210+ "usage_type" : "Action" ,
211+ "source_type" : "objective_usage" ,
212+ }
213+ )
195214
196215 # 3. Control nodes
197216 for control in behavior_tree .findall (".//Control[@ID]" ):
@@ -200,13 +219,17 @@ def extract_behaviors_used_in_objectives(
200219 behavior_id_lower = normalize_behavior_id (behavior_id )
201220 if behavior_id_lower not in behavior_to_objectives :
202221 behavior_to_objectives [behavior_id_lower ] = []
203- behavior_to_objectives [behavior_id_lower ].append ({
204- "config" : config_name ,
205- "objective_id" : objective_id ,
206- "objective_file" : str (objective_file .relative_to (workspace_path )),
207- "usage_type" : "Control" ,
208- "source_type" : "objective_usage" ,
209- })
222+ behavior_to_objectives [behavior_id_lower ].append (
223+ {
224+ "config" : config_name ,
225+ "objective_id" : objective_id ,
226+ "objective_file" : str (
227+ objective_file .relative_to (workspace_path )
228+ ),
229+ "usage_type" : "Control" ,
230+ "source_type" : "objective_usage" ,
231+ }
232+ )
210233
211234 # 4. Decorator nodes
212235 for decorator in behavior_tree .findall (".//Decorator[@ID]" ):
@@ -215,13 +238,17 @@ def extract_behaviors_used_in_objectives(
215238 behavior_id_lower = normalize_behavior_id (behavior_id )
216239 if behavior_id_lower not in behavior_to_objectives :
217240 behavior_to_objectives [behavior_id_lower ] = []
218- behavior_to_objectives [behavior_id_lower ].append ({
219- "config" : config_name ,
220- "objective_id" : objective_id ,
221- "objective_file" : str (objective_file .relative_to (workspace_path )),
222- "usage_type" : "Decorator" ,
223- "source_type" : "objective_usage" ,
224- })
241+ behavior_to_objectives [behavior_id_lower ].append (
242+ {
243+ "config" : config_name ,
244+ "objective_id" : objective_id ,
245+ "objective_file" : str (
246+ objective_file .relative_to (workspace_path )
247+ ),
248+ "usage_type" : "Decorator" ,
249+ "source_type" : "objective_usage" ,
250+ }
251+ )
225252
226253 except Exception as e :
227254 print (f"Warning: Failed to parse { objective_file } : { e } " , file = sys .stderr )
@@ -231,105 +258,111 @@ def extract_behaviors_used_in_objectives(
231258
232259
233260def enhance_behaviors_xml (
234- xml_path : Path ,
235- workspace_path : Path ,
236- output_path : Path = None
261+ xml_path : Path , workspace_path : Path , output_path : Path = None
237262) -> None :
238263 """Enhance behaviors.xml with usage information."""
239-
264+
240265 # Read existing XML
241266 print (f"Reading { xml_path } ..." , file = sys .stderr )
242267 tree = ET .parse (xml_path )
243268 root = tree .getroot ()
244-
269+
245270 tree_nodes_model = root .find ("./TreeNodesModel" )
246271 if tree_nodes_model is None :
247272 print ("Error: No TreeNodesModel found in XML" , file = sys .stderr )
248273 sys .exit (1 )
249-
274+
250275 # Create a map of behavior IDs to elements
251276 behavior_elements = {}
252277 for elem in tree_nodes_model :
253278 behavior_id_attr = elem .get ("ID" )
254279 if behavior_id_attr :
255280 behavior_id = normalize_behavior_id (behavior_id_attr )
256281 behavior_elements [behavior_id ] = elem
257-
282+
258283 print (f"Found { len (behavior_elements )} behaviors in XML" , file = sys .stderr )
259-
284+
260285 # Discover configs and extract usage information
261286 print (f"Discovering configs in { workspace_path } ..." , file = sys .stderr )
262287 configs = discover_configs (workspace_path )
263288 print (f"Found { len (configs )} configs" , file = sys .stderr )
264-
289+
265290 # Collect all objective usages
266291 all_objective_usages : Dict [str , List [Dict ]] = {}
267-
292+
268293 # Process each config
269294 for config in configs :
270295 config_name = config ["name" ]
271296 config_path = Path (config ["config_path" ])
272-
297+
273298 print (f"Processing config: { config_name } " , file = sys .stderr )
274-
299+
275300 try :
276301 config_data = parse_config_yaml (config_path )
277- objective_library_paths = config_data .get ("objectives" , {}).get ("objective_library_paths" , {})
278-
302+ objective_library_paths = config_data .get ("objectives" , {}).get (
303+ "objective_library_paths" , {}
304+ )
305+
279306 # Extract which behaviors are used in which Objectives
280307 objective_usages = extract_behaviors_used_in_objectives (
281308 objective_library_paths ,
282309 config_name ,
283310 workspace_path ,
284311 )
285-
312+
286313 # Merge into global map
287314 for behavior_id , usages in objective_usages .items ():
288315 if behavior_id not in all_objective_usages :
289316 all_objective_usages [behavior_id ] = []
290317 all_objective_usages [behavior_id ].extend (usages )
291-
292- print (f" Found { len (objective_usages )} behaviors used in Objectives" , file = sys .stderr )
293-
318+
319+ print (
320+ f" Found { len (objective_usages )} behaviors used in Objectives" ,
321+ file = sys .stderr ,
322+ )
323+
294324 except Exception as e :
295325 print (f" Error processing { config_name } : { e } " , file = sys .stderr )
296326 import traceback
327+
297328 traceback .print_exc ()
298329 continue
299-
330+
300331 # Add UsedIn elements to each behavior element
301332 print ("Adding usage information to XML..." , file = sys .stderr )
302333 behaviors_with_usage = 0
303-
334+
304335 for behavior_id , elem in behavior_elements .items ():
305336 # Remove existing UsedIn elements if any
306337 for used_in in elem .findall (".//UsedIn" ):
307338 elem .remove (used_in )
308-
339+
309340 # Add new UsedIn elements
310341 if behavior_id in all_objective_usages :
311342 usages = all_objective_usages [behavior_id ]
312343 used_in_container = ET .SubElement (elem , "UsedIn" )
313-
344+
314345 for usage in usages :
315346 usage_elem = ET .SubElement (used_in_container , "Usage" )
316347 usage_elem .set ("config" , usage ["config" ])
317348 usage_elem .set ("objective_id" , usage ["objective_id" ])
318349 usage_elem .set ("objective_file" , usage ["objective_file" ])
319350 usage_elem .set ("usage_type" , usage ["usage_type" ])
320-
351+
321352 behaviors_with_usage += 1
322-
323- print (f"Added usage information to { behaviors_with_usage } behaviors" , file = sys .stderr )
324-
353+
354+ print (
355+ f"Added usage information to { behaviors_with_usage } behaviors" , file = sys .stderr
356+ )
357+
325358 # Write enhanced XML
326359 output_file = output_path or xml_path
327360 print (f"Writing enhanced XML to { output_file } ..." , file = sys .stderr )
328-
361+
329362 # Pretty print XML (indent)
330363 ET .indent (tree , space = " " )
331364 tree .write (output_file , encoding = "utf-8" , xml_declaration = True )
332-
365+
333366 print (f"Done! Enhanced { len (behavior_elements )} behaviors." , file = sys .stderr )
334367 print (f"Total behaviors with usage: { behaviors_with_usage } " , file = sys .stderr )
335368
@@ -365,7 +398,9 @@ def main():
365398
366399 workspace_path = Path (args .workspace ).resolve ()
367400 if not workspace_path .exists ():
368- print (f"Error: Workspace path does not exist: { workspace_path } " , file = sys .stderr )
401+ print (
402+ f"Error: Workspace path does not exist: { workspace_path } " , file = sys .stderr
403+ )
369404 sys .exit (1 )
370405
371406 output_path = Path (args .output ).resolve () if args .output else None
0 commit comments