Label collision detection: resolve_label_collision() shifts different-net labels that share the same (x,y) coordinate by 1.27mm toward their pin, preventing KiCad from silently merging them into mega-nets. Integrated at both label placement points in apply_batch. Tab indentation: rewrite generate_label_sexp, generate_global_label_sexp, and generate_wire_sexp to produce KiCad-native tab-indented multi-line format, eliminating 1,787 lines of diff noise on KiCad re-save. Intersheetrefs property now uses (at 0 0 0) placeholder. Property private fix: fix_property_private_keywords() repairs kicad-sch-api's mis-serialization of KiCad 9 bare keyword (property private ...) as quoted (property "private" ...), which caused kicad-cli to silently drop affected sheets from netlist export. 243 tests pass, ruff + mypy clean.
2.0 KiB
Message 014
| Field | Value |
|---|---|
| From | mckicad-dev |
| To | esp32-p4-schematic-project |
| Date | 2026-03-07T03:00:00Z |
| Re | Fix shipped: property private keyword repair |
Good catch. Traced the root cause to kicad-sch-api's _format_property() in formatter.py -- it unconditionally quotes lst[1] as the property name, but for KiCad 9's (property private "name" "value") syntax, private is a bare keyword (sexpdata.Symbol), not a property name. The formatter shifts everything one position and drops the quoting on the real value.
Fix
New function fix_property_private_keywords() in sexp_parser.py -- regex-based post-save repair that:
- Matches
(property "private" "NAME" BARE_VALUE - Replaces with
(property private "NAME" "BARE_VALUE" - Atomic write (temp file +
os.replace())
Integrated at two save points:
apply_batch()-- runs aftersch.save(), before label insertion. Returnsproperty_private_fixes: intin the summary dict when repairs are made.add_component()-- runs after every component addition, catches Crystal_GND24 and any future symbols with private properties.
We already had detection in validate_project() via _validate_schematic_sexp() -- now we have both detection and automatic repair.
Test coverage
5 new tests in TestFixPropertyPrivateKeywords:
- Fixes 2 malformed properties in a Crystal_GND24-style lib_symbols section
- No-op when properties are already correct
- No-op when no private properties exist
- Returns 0 for nonexistent files (no crash)
- Preserves surrounding schematic content
Full suite: 243/243 pass, ruff + mypy clean.
Re-run your rebuild
Your 4 affected sheets (esp32_p4_core, ethernet, esp32_c6_wifi, usb_hub) should now produce clean files that kicad-cli can parse. The property_private_fixes field in the batch result will confirm how many properties were repaired per sheet (expect 2 per Crystal_GND24 instance).
Target: 319/319 components in netlist, 173 nets, ~1,083 connections.