Copy ``elem`` into ``out_parent``, recursively expanding any descendants in place. Handles both and include roots and rewrites asset file= paths to stay valid from root_dir.
(out_parent, elem, src_dir: Path, root_dir: Path,
meshdir: str, texturedir: str, assetdir: str, visited: set)
| 159 | |
| 160 | |
| 161 | def _append_expanded(out_parent, elem, src_dir: Path, root_dir: Path, |
| 162 | meshdir: str, texturedir: str, assetdir: str, visited: set): |
| 163 | """Copy ``elem`` into ``out_parent``, recursively expanding any <include> |
| 164 | descendants in place. Handles both <mujoco> and <mujocoinclude> include roots |
| 165 | and rewrites asset file= paths to stay valid from root_dir.""" |
| 166 | if elem.tag == "include": |
| 167 | inc_file = elem.get("file") |
| 168 | if not inc_file: |
| 169 | return |
| 170 | inc_path = (src_dir / inc_file).resolve() |
| 171 | if inc_path in visited: |
| 172 | print(f" [include] cycle/duplicate skipped: {inc_path}") |
| 173 | return |
| 174 | if not inc_path.exists(): |
| 175 | print(f" x [include] file not found, leaving unresolved: {inc_path}") |
| 176 | return |
| 177 | visited.add(inc_path) |
| 178 | inc_root = ET.parse(str(inc_path)).getroot() |
| 179 | inc_dir = inc_path.parent |
| 180 | imd, itxd, iad = _compiler_dirs(inc_root) |
| 181 | # Splice the included root's children directly into the current parent. |
| 182 | for child in list(inc_root): |
| 183 | _append_expanded(out_parent, child, inc_dir, root_dir, imd, itxd, iad, visited) |
| 184 | return |
| 185 | |
| 186 | # Regular element: shallow-copy attributes, then recurse into children. |
| 187 | new_elem = ET.SubElement(out_parent, elem.tag, dict(elem.attrib)) |
| 188 | new_elem.text = elem.text |
| 189 | new_elem.tail = elem.tail |
| 190 | |
| 191 | if elem.tag in _ASSET_FILE_TAGS: |
| 192 | _rewrite_asset_path(new_elem, src_dir, root_dir, meshdir, texturedir, assetdir) |
| 193 | elif elem.tag == "compiler": |
| 194 | # Paths are now baked into each file=, so clear the dir prefixes. |
| 195 | for attr in ("meshdir", "texturedir", "assetdir"): |
| 196 | new_elem.attrib.pop(attr, None) |
| 197 | |
| 198 | for child in list(elem): |
| 199 | _append_expanded(new_elem, child, src_dir, root_dir, |
| 200 | meshdir, texturedir, assetdir, visited) |
| 201 | |
| 202 | |
| 203 | def flatten_includes(root, root_dir: Path): |
no test coverage detected