fix(edit_schematic_component): update (reference "...") inside (instances) on rename (#186)

Closes #126.

A placed schematic symbol carries its reference designator in two places:

  (symbol
    (property "Reference" "R5" …)        ← what eeschema renders
    (instances
      (project "MyProject"
        (path "/sheet-uuid/symbol-uuid"
          (reference "R5")               ← what netlist + PCB sync read
          (unit 1) )))
    …)

Before this change, `edit_schematic_component` with `newReference` updated
only the (property "Reference" …) field. The (reference "…") leaves inside
(instances) → (project) → (path) kept the old value. eeschema rendered the
new reference correctly and ERC passed, but `kicad-cli sch export netlist`
and "Update PCB from Schematic" both read from the (instances) block and
silently used the OLD reference — producing destructive PCB-sync diffs on
what users thought was a clean rename. Severity was high for anyone running
batch renames because the symptom only surfaces at PCB-sync time, by which
point many renames may be queued.

Walk the (instances) subtree within the matched symbol block after the
property update and replace every `(reference "OLD")` leaf with the new
value. The regex matches `(reference "X")` specifically (not
`(property "Reference" "X"`), and the walk is constrained to the
(instances …) range via the existing _find_matching_paren helper so other
(reference …) tokens elsewhere in the file can't be affected.

Adds tests/test_edit_schematic_component_instances.py covering:
  - Single-instance rename updates both property and instances leaf
  - Hierarchical case with multiple (path …) entries all updated atomically
  - No-instances-block schematics don't crash (older KiCad / partial files)
  - The regex doesn't clobber (property "Reference" …) on the instances pass
  - Other field values (Value, Footprint) are left intact
  - The response payload's updated.reference reflects the new ref

All 6 tests fail on main without the fix (3 fully, 3 on the instances
assertions only) and pass on this branch.

The pre-existing TestAddComponentMirrorParam failures in
test_add_schematic_component.py are unrelated and present on main —
documented in inktomi's PR #169.

Co-authored-by: mixelpixx <11727006+mixelpixx@users.noreply.github.com>
This commit is contained in:
mixelpixx
2026-05-18 14:55:54 -04:00
committed by GitHub
parent 40d6d6bba1
commit c538714743
2 changed files with 301 additions and 0 deletions

View File

@@ -1471,6 +1471,28 @@ class KiCADInterface:
rf'\1"{escaped_r}"',
block_text,
)
# Also update the (reference "...") leaves inside the symbol's
# (instances) → (project) → (path) subtree. KiCad reads those
# entries — not the (property "Reference" ...) field — when
# generating netlists and syncing the PCB via "Update PCB from
# Schematic", so leaving them stale produces a silent
# reference mismatch where eeschema shows the new ref but ERC
# / netlist export / PCB sync all use the old one. See #126.
instances_pos = block_text.find("(instances")
if instances_pos >= 0:
instances_end = self._find_matching_paren(block_text, instances_pos)
if instances_end >= 0:
instances_block = block_text[instances_pos : instances_end + 1]
updated_instances = re.sub(
r'(\(reference\s+)"' + re.escape(reference) + r'"',
rf'\1"{escaped_r}"',
instances_block,
)
block_text = (
block_text[:instances_pos]
+ updated_instances
+ block_text[instances_end + 1 :]
)
if field_positions is not None:
for field_name, pos in field_positions.items():
x = pos.get("x", 0)