Skip to content

Commit aa5b020

Browse files
committed
Fixes
1 parent 86a8690 commit aa5b020

File tree

3 files changed

+100
-66
lines changed

3 files changed

+100
-66
lines changed

scripts/README_SCRIPTS.md

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -88,4 +88,3 @@ python3 scripts/enhance_behaviors_xml.py --xml scripts/behaviors.xml --workspace
8888
# 3. In PickNik website repo - Convert to JSON
8989
python scripts/update_behaviors_from_xml.py _data/behaviors_enhanced.xml
9090
```
91-

scripts/behaviors_enhanced.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10270,4 +10270,4 @@
1027010270
</MetadataFields>
1027110271
</SubTree>
1027210272
</TreeNodesModel>
10273-
</root>
10273+
</root>

scripts/enhance_behaviors_xml.py

Lines changed: 99 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,9 @@
1818
try:
1919
import yaml
2020
except 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

233260
def 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

Comments
 (0)