skidl.schematics.backend module

Tool-agnostic schematic backend interface.

This module defines the dependency surface that the tool-agnostic decision layer (schematics/decisions.py, schematics/snap.py) needs from a concrete schematic backend (e.g. tools/kicad9). It is deliberately tool-agnostic: it imports nothing from any skidl.tools.* package, and the KiCad coordinate convention / S-expression syntax never leaks across this boundary.

The split is: the agnostic layer decides (which pins overlap, which power pins form a bus, how labels deconflict), expressed entirely in render-mm coordinates as returned by backend.pin_render_pos; the backend measures (geometry queries) and writes (emission primitives).

See ARCHITECTURE-snap-backend-split.md (branch docs/snap-backend-split) for the full design, especially sections 2, 3, 5 and 7.

skidl.schematics.backend.Element

alias of object

class skidl.schematics.backend.LabelPlacement(anchor_xy: Tuple[float, float], text_xy: Tuple[float, float], deconflictable: bool)[source]

Bases: object

A resolved net-label / power-symbol placement (render-mm).

anchor_xy is the electrical connection point and is FIXED on the pin (in KiCad the label/power-symbol at is the connection point). text_xy is where the label text renders and may be nudged by deconfliction. deconflictable is False for power symbols, whose anchor must not move (moving it disconnects the net).

anchor_xy: Tuple[float, float]
deconflictable: bool
text_xy: Tuple[float, float]
skidl.schematics.backend.PinDir

alias of str

class skidl.schematics.backend.RenderContext(backend: SchematicBackend)[source]

Bases: object

Memoizes pin_render_pos / pin_render_dir for a backend.

Per architecture doc section 7, item 6: the cache key cannot be just (pin, sheet_tx) because snap mutates part.tx mid-pipeline. The simplest safe discipline (adopted here) is to only use the cache once snap has finalized all part.tx values; snap’s own pre-finalization measurements go straight to the backend and are not cached.

The key folds in the part’s transform coefficients so that any part.tx mutation invalidates a stale entry automatically.

invalidate()[source]

Drop all cached geometry (call after any phase that moves parts).

pin_render_dir(pin, sheet_tx) str[source]
pin_render_pos(pin, sheet_tx) Tuple[float, float][source]
class skidl.schematics.backend.SchematicBackend(*args, **kwargs)[source]

Bases: Protocol

The geometry + emission surface a backend exposes to the agnostic layer.

Geometry queries answer “where/which-way does the tool draw this?” in the tool’s own flip/mirror/rotate convention. Emission primitives write the tool’s native elements. See the architecture doc, section 3.

emit_junction(x, y) object[source]
emit_label(pin, sheet_tx, *, at=None, angle=None, force: bool = False) object | None[source]
emit_no_connect(x, y) object[source]
emit_part(part, sheet_tx, uuid_path) object[source]
emit_power_symbol(pin, net_name, sheet_tx) object | None[source]
emit_wire(x1, y1, x2, y2, *, net_name: str | None = None) object[source]
is_power_net_name(name: str) bool[source]

True if name matches a tool power-symbol.

label_bbox(text: str) Tuple[float, float][source]

(width, height) in mm of a rendered net-label box for text.

pin_render_dir(pin, sheet_tx) str[source]

Which way the pin points AFTER the tool’s transform.

pin_render_pos(pin, sheet_tx) Tuple[float, float][source]

(x, y) in mm where the tool will actually DRAW this pin.

render_xy(lx, ly, part, sheet_tx) Tuple[float, float][source]

Render-mm position of an arbitrary part-local point (e.g. a body bbox corner) under the tool’s transform convention. Same convention as pin_render_pos but for non-pin points; needed by power-bus body-crossing checks.

round_mm(val) float[source]

Round a coordinate to the tool’s grid precision (KiCad: 2 dp).

solve_snap_tx(part, my_pin, target_render_xy, extend_dir, sheet_tx)[source]

Return a new part.tx so my_pin renders at the target.

supports_snap: bool