Fix coordinate precision and per-schematic sidecar isolation
Reduce _rc() and transform_pin_to_schematic() rounding from 3 to 2 decimal places to match KiCad's 0.01mm coordinate quantum — prevents union-find misses when wire endpoints and sexp-parsed pin positions differ at the sub-quantum level. Use schematic stem as subdirectory inside .mckicad/ so multi-sheet analysis outputs (connectivity.json, etc.) don't collide.
This commit is contained in:
parent
b347679c67
commit
52ff054f43
@ -92,9 +92,11 @@ def _require_kicad_cli() -> tuple[str, None] | tuple[None, dict[str, Any]]:
|
||||
|
||||
|
||||
def _sidecar_dir(schematic_path: str) -> str:
|
||||
"""Return the .mckicad/ directory next to a schematic, creating it if needed."""
|
||||
parent = os.path.dirname(os.path.abspath(schematic_path))
|
||||
sidecar = os.path.join(parent, ".mckicad")
|
||||
"""Return the .mckicad/{stem}/ directory next to a schematic, creating it if needed."""
|
||||
abs_sch = os.path.abspath(schematic_path)
|
||||
parent = os.path.dirname(abs_sch)
|
||||
stem = os.path.splitext(os.path.basename(abs_sch))[0]
|
||||
sidecar = os.path.join(parent, ".mckicad", stem)
|
||||
os.makedirs(sidecar, exist_ok=True)
|
||||
return sidecar
|
||||
|
||||
@ -150,7 +152,7 @@ def _build_connectivity(
|
||||
|
||||
def _rc(x: float, y: float) -> tuple[float, float]:
|
||||
"""Round coordinates for stable floating-point comparison."""
|
||||
return (round(x, 3), round(y, 3))
|
||||
return (round(x, 2), round(y, 2))
|
||||
|
||||
def _coord_from_point(pt: Any) -> tuple[float, float]:
|
||||
"""Extract (x, y) from a Point-like object or sequence."""
|
||||
|
||||
@ -18,7 +18,12 @@ def write_detail_file(schematic_path: str | None, filename: str, data: Any) -> s
|
||||
"""Write large result data to a .mckicad/ sidecar directory.
|
||||
|
||||
When ``schematic_path`` is provided, the sidecar directory is created
|
||||
next to the schematic file. When ``None``, falls back to CWD.
|
||||
next to the schematic file, inside a subdirectory named after the
|
||||
schematic's stem (e.g. ``.mckicad/power/connectivity.json``). This
|
||||
prevents multi-sheet designs from overwriting each other's output.
|
||||
|
||||
When ``None``, falls back to a flat ``.mckicad/`` in CWD (used for
|
||||
search results that have no schematic context).
|
||||
|
||||
Args:
|
||||
schematic_path: Path to a .kicad_sch file (sidecar dir created next to it),
|
||||
@ -29,8 +34,13 @@ def write_detail_file(schematic_path: str | None, filename: str, data: Any) -> s
|
||||
Returns:
|
||||
Absolute path to the written file.
|
||||
"""
|
||||
parent_dir = os.path.dirname(os.path.abspath(schematic_path)) if schematic_path else os.getcwd()
|
||||
sidecar_dir = os.path.join(parent_dir, ".mckicad")
|
||||
if schematic_path:
|
||||
abs_sch = os.path.abspath(schematic_path)
|
||||
parent_dir = os.path.dirname(abs_sch)
|
||||
stem = os.path.splitext(os.path.basename(abs_sch))[0]
|
||||
sidecar_dir = os.path.join(parent_dir, ".mckicad", stem)
|
||||
else:
|
||||
sidecar_dir = os.path.join(os.getcwd(), ".mckicad")
|
||||
os.makedirs(sidecar_dir, exist_ok=True)
|
||||
|
||||
out_path = os.path.join(sidecar_dir, filename)
|
||||
|
||||
@ -162,7 +162,7 @@ def transform_pin_to_schematic(
|
||||
ry = px * sin_r + py * cos_r
|
||||
|
||||
# Apply position offset
|
||||
return (round(comp_x + rx, 3), round(comp_y + ry, 3))
|
||||
return (round(comp_x + rx, 2), round(comp_y + ry, 2))
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
from tests.conftest import requires_sch_api
|
||||
|
||||
|
||||
@ -120,7 +121,7 @@ def test_get_schematic_hierarchy(populated_schematic):
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_file_output_infrastructure(tmp_output_dir):
|
||||
"""write_detail_file should create .mckicad sidecar directory and file."""
|
||||
"""write_detail_file should create .mckicad/{stem}/ sidecar directory and file."""
|
||||
from mckicad.utils.file_utils import write_detail_file
|
||||
|
||||
fake_sch = os.path.join(tmp_output_dir, "test.kicad_sch")
|
||||
@ -132,12 +133,12 @@ def test_file_output_infrastructure(tmp_output_dir):
|
||||
|
||||
assert os.path.isfile(path)
|
||||
assert ".mckicad" in path
|
||||
assert path.endswith("test_output.json")
|
||||
assert os.path.join(".mckicad", "test", "test_output.json") in path
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_file_output_cwd_fallback(tmp_output_dir, monkeypatch):
|
||||
"""write_detail_file with None path should use CWD."""
|
||||
"""write_detail_file with None path should use flat CWD/.mckicad/."""
|
||||
from mckicad.utils.file_utils import write_detail_file
|
||||
|
||||
monkeypatch.chdir(tmp_output_dir)
|
||||
@ -145,3 +146,25 @@ def test_file_output_cwd_fallback(tmp_output_dir, monkeypatch):
|
||||
|
||||
assert os.path.isfile(path)
|
||||
assert ".mckicad" in path
|
||||
# None path stays flat — no stem subdirectory
|
||||
assert path.endswith(os.path.join(".mckicad", "test_cwd.json"))
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
def test_sidecar_per_schematic_isolation(tmp_output_dir):
|
||||
"""Detail files for different schematics land in separate subdirectories."""
|
||||
from mckicad.utils.file_utils import write_detail_file
|
||||
|
||||
sch_a = os.path.join(tmp_output_dir, "power.kicad_sch")
|
||||
sch_b = os.path.join(tmp_output_dir, "esp32_p4_core.kicad_sch")
|
||||
open(sch_a, "w").close()
|
||||
open(sch_b, "w").close()
|
||||
|
||||
path_a = write_detail_file(sch_a, "connectivity.json", {"nets": {}})
|
||||
path_b = write_detail_file(sch_b, "connectivity.json", {"nets": {}})
|
||||
|
||||
assert os.path.isfile(path_a)
|
||||
assert os.path.isfile(path_b)
|
||||
assert path_a != path_b
|
||||
assert os.path.join(".mckicad", "power", "connectivity.json") in path_a
|
||||
assert os.path.join(".mckicad", "esp32_p4_core", "connectivity.json") in path_b
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user