kicad_interface.py had grown to 8,596 lines. Most domains already delegate to
classes in commands/, but the schematic domain (43 _handle_* methods + the
schematic-only _svg_to_png helper, ~3,100 lines) was still inline. Move it into
commands/schematic_handlers.py as SchematicHandlersMixin and have KiCADInterface
inherit from it.
Pure mechanical relocation — no logic change:
- Methods stay bound to the same instance via the mixin, so every self.board,
self._auto_save_board(), cross-handler call, and the command_routes table
resolve exactly as before.
- Verified all 159 functions/methods (116 kept + 43 moved + _svg_to_png) are
AST-identical between the original and the split.
- tests/test_sync_schematic_to_board_footprints.py patch targets updated to
follow the moved module (commands.schematic_handlers.pcbnew).
- Full suite at the exact current main baseline (8 failed / 1044 passed; the 8
are the pre-existing Java-not-installed freerouting/autoroute set).
Regenerated against main after the June merge wave (#226-229, #231-234, #238,
#252, #253); deliberately excludes the 19 _handle_export_* kicad-cli handlers
from #253 and the datasheet delegators.
The handler iterated `board.GetFootprints()` and assigned nets to existing
pads, but had no path to *add* footprints for schematic symbols whose
Reference was not yet on the board. New parts placed on the schematic
landed in the net list with no PCB representation — the rats nest had
nowhere to terminate, and place_component / route_pad_to_pad would fail
because the target footprint did not exist.
KiCad's "Update PCB from Schematic" (F8) implicitly adds the missing
footprints; bring the MCP's behaviour in line.
Implementation:
* `_extract_components_from_schematic` runs `kicad-cli sch export netlist
--format kicadxml` (the same path `_handle_generate_netlist` already
uses) and returns a flat `[{reference, value, footprint}]` list. Walks
hierarchical sub-sheets transparently because kicad-cli does.
* `_add_missing_footprints_from_schematic` resolves each missing component
against the project's fp-lib-table via `LibraryManager`, calls
`pcbnew.FootprintLoad`, sets reference / value / FPID, and places the
footprint at the board origin (the user / autoplacer can position it).
Power and flag references (`#PWR…`, `#FLG…`) are excluded — they have
no PCB footprint.
* The pad-net assignment loop now runs *after* the add path, so newly
placed footprints get their nets assigned in the same call.
* Response payload gains `footprints_added` and `footprints_skipped`
diagnostic lists. The textual `message` field reports both the new
footprint count and the existing net / pad counts.
Adds tests/test_sync_schematic_to_board_footprints.py — 9 unit tests
covering the add path (missing ref, already-present ref, power refs,
empty footprint, unknown library) and the kicad-cli helper (XML parse,
missing kicad-cli, non-zero exit).