Loads symbols from a bundle file (Symbols.svg, one per symbol in ). Call add_user_library() afterward to load additional SVGs from any directory. Call inject_into_component_item() to publish all loaded metadata into the component_item module-level dicts.
| 291 | |
| 292 | |
| 293 | class SymbolLibrary: |
| 294 | """ |
| 295 | Loads symbols from a bundle file (Symbols.svg, one <g id> per symbol in |
| 296 | <defs>). |
| 297 | |
| 298 | Call add_user_library() afterward to load additional SVGs from any |
| 299 | directory. Call inject_into_component_item() to publish all loaded |
| 300 | metadata into the component_item module-level dicts. |
| 301 | """ |
| 302 | |
| 303 | def __init__(self, svg_path: Path): |
| 304 | self._symbols: dict[str, Symbol] = {} |
| 305 | self._load_bundle(svg_path) |
| 306 | |
| 307 | # ── loading ─────────────────────────────────────────────────────────────── |
| 308 | |
| 309 | def _add_g(self, g, source: str, override: bool) -> None: |
| 310 | if not g.get("id"): |
| 311 | return |
| 312 | if not override and g.get("id") in self._symbols: |
| 313 | return |
| 314 | sym = Symbol(g, source) |
| 315 | self._symbols[sym.name] = sym |
| 316 | |
| 317 | def _load_bundle(self, path: Path) -> None: |
| 318 | parser = ET.XMLParser(target=ET.TreeBuilder(insert_comments=True)) |
| 319 | root = ET.parse(path, parser).getroot() |
| 320 | defs = root.find(f"{{{SVG_NS}}}defs") |
| 321 | if defs is None: |
| 322 | return |
| 323 | for g in defs.findall(f"{{{SVG_NS}}}g"): |
| 324 | self._add_g(g, path.name, override=False) |
| 325 | |
| 326 | def add_bundle(self, path) -> list[str]: |
| 327 | """Overlay a frozen <name>.symbols bundle: its symbols OVERRIDE the |
| 328 | system ones of the same name (a schematic renders with the symbols it was |
| 329 | drawn with, and user-defined symbols win). |
| 330 | |
| 331 | The bundle is a cache, so a symbol that no longer parses (e.g. an |
| 332 | outdated metadata format) is skipped rather than aborting the load — the |
| 333 | already-loaded system definition is used in its place. Returns the names |
| 334 | of any skipped symbols so the caller can report them.""" |
| 335 | skipped: list[str] = [] |
| 336 | if not path or not Path(path).is_file(): |
| 337 | return skipped |
| 338 | parser = ET.XMLParser(target=ET.TreeBuilder(insert_comments=True)) |
| 339 | try: |
| 340 | root = ET.parse(str(path), parser).getroot() |
| 341 | except ET.ParseError: |
| 342 | return skipped |
| 343 | for g in root.iter(f"{{{SVG_NS}}}g"): |
| 344 | if g.get("id") and g.get("data-prefix"): |
| 345 | try: |
| 346 | self._add_g(g, Path(path).name, override=True) |
| 347 | except SymbolError: |
| 348 | skipped.append(g.get("id")) |
| 349 | return skipped |
| 350 |
no outgoing calls
no test coverage detected