Skip to content

Parse .kicad_pcb on a real s-expression parser (KiCad 5-10)#21

Open
prat96 wants to merge 1 commit into
bbenchoff:mainfrom
GhostRoboticsLab:pr2-kicad10-parser
Open

Parse .kicad_pcb on a real s-expression parser (KiCad 5-10)#21
prat96 wants to merge 1 commit into
bbenchoff:mainfrom
GhostRoboticsLab:pr2-kicad10-parser

Conversation

@prat96

@prat96 prat96 commented Jul 2, 2026

Copy link
Copy Markdown

What

Replaces the regex .kicad_pcb loader with a real s-expression parser that
reads every KiCad dialect from 5 through 10.

Why

KiCad 8/9/10 dropped the numbered net table and moved references into
(property "Reference" ...). The old regex loader returns 0 nets / 0 pads
on those files, so loading a board directly from disk (the cli and headless
paths) is effectively broken on any modern board.

What's in it

  • sexpr.py — a small, dependency-free balanced-paren parser (Python 3.9
    clean) plus byte-exact, idempotent top-level strip helpers.
  • file_parser.py — structural pad/net/layer extraction across both dialects:
    legacy numbered-net + (module ...), and modern net-table-free
    (footprint ...)/property with name-only (net "NAME") synthesis.
    Footprint rotation is CCW-positive in KiCad's Y-down frame and back-side pad
    offsets carry no extra mirror — verified pad-exact (≤1 µm) against
    pcbnew 10.0.4. Copper-layer counting excludes Edge.Cuts; design rules are
    merged from a sibling .kicad_pro when present.
  • Small fixes ridden along: pad_escape_planner reads drill with a
    drill_size fallback; rich_kicad_interface imports KiCad from kipy
    (matching the rest of the codebase).

Tests

Small, self-contained synthetic boards (no external board files):

  • test_sexpr — parser round-trips + idempotent strip helpers.
  • test_file_parser — both dialects: legacy numbered-net (module ...), and
    modern net-table-free (footprint ...)/property with name-only net
    synthesis, back-side pad placement, and Edge.Cuts exclusion.
$ python -m pytest tests/test_sexpr.py tests/test_file_parser.py
27 passed

Notes for review

  • This replaces a core input path. Happy to gate it behind an issue/discussion
    first if you'd prefer — opened as a PR because the old path returns nothing
    on current KiCad files, so it's arguably a bug fix.
  • Pad-transform correctness was validated pad-exact against pcbnew 10.0.4 on
    real multi-layer boards (front/back, rot 0/90/180/270). The shipped tests pin
    the same transform on synthetic boards so the suite stays fixture-free.

Checklist

  • Tests pass locally (27 passed on a clean clone)
  • No new runtime dependencies (stdlib only)
  • Preserves KiCad 5–7 parsing (legacy dialect is tested)
  • Google-style docstrings on new code

The regex loader returned 0 nets/0 pads on KiCad 8/9/10 files (no net
table; references in (property "Reference" ...)), so loading a board
from a file was broken. Replace it with a dependency-free s-expression
parser (sexpr.py) and a structural extractor (file_parser.py) handling
every dialect through KiCad 10 (format 20260206): name-only net
synthesis, footprint rotation and back-side pad transform (verified
pad-exact vs pcbnew 10.0.4), Edge.Cuts excluded from the copper count,
design rules merged from the sibling .kicad_pro. Tests use small
self-contained synthetic boards (both dialects). Also: pad_escape_planner
drill/drill_size fallback and rich_kicad_interface kipy import fix.

Re-include tests/*.py (the .gitignore blocked the suite).

Signed-off-by: Pratheek Balakrishna <pratheekb96@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant