Join KiCad hierarchical PNM/MPN when the BOM CSV omits a designator.
Child-sheet symbol fields fill graph mpn; empty sheet fields stay empty. A sibling .kicad_sch next to a PADS netlist is used the same way.
This commit is contained in:
@@ -417,3 +417,112 @@ def test_cyclic_sheet_include_is_rejected(tmp_path: Path):
|
||||
))
|
||||
with pytest.raises(ValueError, match="[Cc]yclic"):
|
||||
parse_kicad(root)
|
||||
|
||||
|
||||
def _ic_symbol(ref: str, value: str, *, pnm: str = "", mpn: str = "", x: float = 0, y: float = 0) -> str:
|
||||
uid = "aaaaaaaa-aaaa-aaaa-aaaa-" + ref.encode().hex()[:12].ljust(12, "0")
|
||||
extra = ""
|
||||
if pnm:
|
||||
extra += (
|
||||
f' (property "PNM" "{pnm}" (at 0 0 0) '
|
||||
f'(effects (font (size 1.27 1.27))))\n'
|
||||
)
|
||||
if mpn:
|
||||
extra += (
|
||||
f' (property "MPN" "{mpn}" (at 0 0 0) '
|
||||
f'(effects (font (size 1.27 1.27))))\n'
|
||||
)
|
||||
return f"""
|
||||
(symbol
|
||||
(lib_id "Device:R")
|
||||
(at {x} {y} 0)
|
||||
(unit 1)
|
||||
(uuid "{uid}")
|
||||
(property "Reference" "{ref}" (at 0 0 0) (effects (font (size 1.27 1.27))))
|
||||
(property "Value" "{value}" (at 0 0 0) (effects (font (size 1.27 1.27))))
|
||||
{extra} (pin "1" (uuid "p1{ref}"))
|
||||
(pin "2" (uuid "p2{ref}"))
|
||||
)
|
||||
"""
|
||||
|
||||
|
||||
def _hier_root_with_child(tmp_path: Path, child_body: str) -> Path:
|
||||
child = tmp_path / "codec.kicad_sch"
|
||||
child.write_text(_sch(
|
||||
child_body,
|
||||
"""
|
||||
(global_label "GND" (at 0 3.81 0) (uuid "cccccccccccccccccccccccccccccccccccc"))
|
||||
""",
|
||||
))
|
||||
root = tmp_path / "root.kicad_sch"
|
||||
root.write_text(_sch(
|
||||
_resistor("R1", "10k"),
|
||||
"""
|
||||
(global_label "GND" (at 0 3.81 0) (uuid "bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"))
|
||||
(sheet
|
||||
(at 50 0)
|
||||
(size 20 20)
|
||||
(property "Sheetname" "Codec" (at 50 0 0) (effects (font (size 1.27 1.27))))
|
||||
(property "Sheetfile" "codec.kicad_sch" (at 50 0 0) (effects (font (size 1.27 1.27))))
|
||||
)
|
||||
""",
|
||||
))
|
||||
return root
|
||||
|
||||
|
||||
def test_hierarchical_pnm_fills_graph_when_bom_omits_ref(tmp_path: Path):
|
||||
from backend.periscopex.graph import build_graph
|
||||
|
||||
root = _hier_root_with_child(
|
||||
tmp_path,
|
||||
_ic_symbol("U13", "TPD2E007DCKR", pnm="TPD2E007DCKR"),
|
||||
)
|
||||
bom = tmp_path / "bom.csv"
|
||||
bom.write_text(
|
||||
"Reference,Value,Footprint,PNM\n"
|
||||
"R1,10k,0603,\n"
|
||||
'"U9,U14,U26",TPD2E007DCKR,SOT23,TPD2E007DCKR\n'
|
||||
)
|
||||
g = build_graph(
|
||||
root, bom, tmp_path / "ex", tmp_path / "pat", tmp_path / "mod",
|
||||
mpn_col="Manufacturer Part Number",
|
||||
)
|
||||
assert "U13" not in (bom.read_text())
|
||||
assert g.components["U13"].mpn == "TPD2E007DCKR"
|
||||
assert g.schematic_fields["U13"]["cad_sheet"] == "codec.kicad_sch"
|
||||
|
||||
|
||||
def test_hierarchical_empty_fields_do_not_invent_mpn(tmp_path: Path):
|
||||
from backend.periscopex.graph import build_graph
|
||||
|
||||
root = _hier_root_with_child(tmp_path, _ic_symbol("U15", "", pnm="", mpn=""))
|
||||
bom = tmp_path / "bom.csv"
|
||||
bom.write_text("Reference,Value,PNM\nR1,10k,\n")
|
||||
g = build_graph(
|
||||
root, bom, tmp_path / "ex", tmp_path / "pat", tmp_path / "mod",
|
||||
mpn_col="Manufacturer Part Number",
|
||||
)
|
||||
assert g.components["U15"].mpn in (None, "")
|
||||
assert not (g.components["U15"].mpn or "").strip()
|
||||
|
||||
|
||||
def test_pads_netlist_joins_sibling_hierarchical_sch(tmp_path: Path):
|
||||
from backend.periscopex.graph import build_graph
|
||||
|
||||
_hier_root_with_child(
|
||||
tmp_path,
|
||||
_ic_symbol("U13", "TPD2E007DCKR", pnm="TPD2E007DCKR"),
|
||||
)
|
||||
asc = tmp_path / "netlist.asc"
|
||||
asc.write_text(
|
||||
"*PADS-PCB*\n*PART*\nU13 SOT23\nR1 0603\n*NET*\n"
|
||||
"*SIGNAL* GND\nU13.1 R1.1\n*END*\n"
|
||||
)
|
||||
bom = tmp_path / "bom.csv"
|
||||
bom.write_text("Reference,Value,PNM\nR1,10k,\n")
|
||||
g = build_graph(
|
||||
asc, bom, tmp_path / "ex", tmp_path / "pat", tmp_path / "mod",
|
||||
mpn_col="Manufacturer Part Number",
|
||||
)
|
||||
assert g.components["U13"].mpn == "TPD2E007DCKR"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user