v2.4.1
v2.4.1
Eight merges since v2.4.0. The headline is infrastructural, and it is worth stating plainly: CI had never once passed in this repository's history. 32 failed runs, 1 cancelled, 0 successes — and GitHub Actions had been disabled repo-wide since January. Seven months of merges landed with no automated gating at all.
That is fixed, and it paid for itself on the first real run.
CI now actually gates the test suite (#334)
The python-tests job was a no-op in four independent ways:
- Every gate ended in
|| echo "... not configured yet"— black, mypy, pylint and pytest all reported success regardless of outcome. pytest python/pointed at the source tree. An explicit path argument overridespytest.ini'stestpaths, so it collected 7 tests from a stray file while the real suite never ran.- No JRE was installed, so the freerouting suites would have failed environmentally.
- Actions was off, so none of it executed anyway.
All 1551 Python and 63 TypeScript tests now gate every push, across Python 3.9–3.12 on two Ubuntu versions, TypeScript on four OSes, and integration tests against KiCAD 8/9/10.
Format and type checks deliberately run once rather than per matrix entry: pip install black resolves a different build per interpreter (black ≥25.12 requires Python ≥3.10, so the 3.9 runner silently gets 25.1.0 and disagrees with 26.x on three files).
Three tools that were registered but had no backend now work
assign_net_to_class, check_clearance (#315) and set_layer_constraints (#323) each had a full schema and a router entry but no dispatch handler, so every call returned Unknown command. Found by a documentation-coverage audit rather than by anyone using them — thanks @boovaragan.
Per-layer constraints are written to a project-scoped .kicad_dru custom-rules file, which kicad-cli pcb drc and the GUI both auto-discover; there is no pcbnew API for them.
Silent failures removed
create_zonewas broken on the IPC backend — it assigned kipy's read-onlyZone.fill_mode, raisingAttributeErroron every call. Invisible locally because kipy is absent from a bare dev environment, so mypy typed itAny. Caught by the new CI gate.autoroutewas abandoned at 30 s (#251) while Freerouting was still running, reporting failure against a valid.sesthat existed on disk. Its timeout now derives from thetimeoutandattemptsyou pass, rather than a fixed ceiling —timeoutis per-attempt and best-of-N multiplies it.get_board_2d_viewproduced no file at all (#235) when no layers were given, because KiCad 9+ refusespcb export svgwithout--layers. Fix authored by @stefangordon.replace_schematic_componentcorruptedlib_symbolswhile restoring fields, anddelete_schematic_net_labelsilently removed the first match on an ambiguous bare-name delete (#332). Thanks @Euter2.
New part-sourcing tools
- Open parts registry (#329, closes #297):
search_parts_registry,get_registry_part,download_registry_part— reuse a verified existing footprint or symbol instead of generating one. Downloads are host-allowlisted, extension-checked and capped at 50 MB. Thanks @mingyo186 for both the request and the implementation. - Live JLCPCB lookup (#326):
get_jlcpcb_partreturns real-time stock and tiered pricing when Open Platform credentials are configured, falling back to the local snapshot with asourcefield showing which path answered. Thanks @ravishivt.
One note for anyone tracking assign_net_to_class
As first written it did not work on any real project: a freshly written .kicad_pro carries "netclass_assignments": null, and setdefault returns that None rather than replacing it, so the write raised and degraded to a silent no-op. It was caught by a round-trip test across the boundary this shares with #302's DSN exporter — two features, one on-disk key, and both sides had green suites that never crossed it. That seam now has a permanent test.
Issues closed
Full details in CHANGELOG.md.