style: apply Black formatting to changed files

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
Eugene Mikhantyev
2026-03-15 23:17:25 +00:00
parent be11948a44
commit 59bd4c4acf
5 changed files with 731 additions and 610 deletions

View File

@@ -39,7 +39,6 @@ from commands.schematic_analysis import (
find_wires_crossing_symbols,
)
# ---------------------------------------------------------------------------
# Helpers
# ---------------------------------------------------------------------------
@@ -127,6 +126,7 @@ def _make_led_sexp(ref: str, x: float, y: float, rotation: float = 0) -> str:
# Unit tests — geometry helpers
# ===================================================================
class TestGeometryHelpers:
"""Test low-level geometry utilities."""
@@ -174,6 +174,7 @@ class TestGeometryHelpers:
# Unit tests — S-expression parsers
# ===================================================================
class TestSexpParsers:
"""Test S-expression parsing functions with synthetic data."""
@@ -223,6 +224,7 @@ class TestSexpParsers:
# Unit tests — analysis functions with mocked PinLocator
# ===================================================================
class TestAABBOverlap:
"""Test AABB overlap helper."""
@@ -254,14 +256,18 @@ class TestFindOverlappingElements:
def test_overlapping_symbols_detected(self):
# Two resistors at nearly the same position — bboxes fully overlap
extra = _make_resistor_sexp("R1", 100, 100) + _make_resistor_sexp("R2", 100.1, 100)
extra = _make_resistor_sexp("R1", 100, 100) + _make_resistor_sexp(
"R2", 100.1, 100
)
tmp = _make_temp_schematic(extra)
result = find_overlapping_elements(tmp, tolerance=0.5)
assert result["totalOverlaps"] >= 1
assert len(result["overlappingSymbols"]) >= 1
def test_well_separated_symbols_not_flagged(self):
extra = _make_resistor_sexp("R1", 100, 100) + _make_resistor_sexp("R2", 200, 200)
extra = _make_resistor_sexp("R1", 100, 100) + _make_resistor_sexp(
"R2", 200, 200
)
tmp = _make_temp_schematic(extra)
result = find_overlapping_elements(tmp, tolerance=0.5)
assert result["totalOverlaps"] == 0
@@ -288,7 +294,9 @@ class TestFindOverlappingElements:
"""
# R1 at y=100, R2 at y=105 — pin spans [96.19, 103.81] and [101.19, 108.81]
# These overlap in Y from 101.19 to 103.81
extra = _make_resistor_sexp("R1", 100, 100) + _make_resistor_sexp("R2", 100, 105)
extra = _make_resistor_sexp("R1", 100, 100) + _make_resistor_sexp(
"R2", 100, 105
)
tmp = _make_temp_schematic(extra)
result = find_overlapping_elements(tmp, tolerance=0.5)
assert result["totalOverlaps"] >= 1, (
@@ -302,7 +310,9 @@ class TestFindOverlappingElements:
R pins at y ±3.81, but different X positions far enough apart.
"""
extra = _make_resistor_sexp("R1", 100, 100) + _make_resistor_sexp("R2", 110, 100)
extra = _make_resistor_sexp("R1", 100, 100) + _make_resistor_sexp(
"R2", 110, 100
)
tmp = _make_temp_schematic(extra)
result = find_overlapping_elements(tmp, tolerance=0.5)
assert result["totalOverlaps"] == 0
@@ -355,6 +365,7 @@ class TestComputeSymbolBbox:
def test_returns_none_for_unknown_symbol(self):
tmp = _make_temp_schematic()
from commands.pin_locator import PinLocator
locator = PinLocator()
result = compute_symbol_bbox(tmp, "NONEXISTENT", locator)
assert result is None
@@ -409,8 +420,7 @@ class TestIntegrationFindWiresCrossingSymbols:
result = find_wires_crossing_symbols(tmp)
# The wire must not be reported against the far-away R? at (200, 100)
collisions_at_200 = [
c for c in result
if abs(c["component"]["position"]["x"] - 200) < 0.5
c for c in result if abs(c["component"]["position"]["x"] - 200) < 0.5
]
assert len(collisions_at_200) == 0, (
"Wire at x≈100 must not be flagged against the R? at x=200; "
@@ -431,9 +441,9 @@ class TestIntegrationFindWiresCrossingSymbols:
tmp = _make_temp_schematic(extra)
result = find_wires_crossing_symbols(tmp)
d1_crossings = [c for c in result if c["component"]["reference"] == "D1"]
assert len(d1_crossings) >= 1, (
"Wire starting at pin but passing through body must be detected"
)
assert (
len(d1_crossings) >= 1
), "Wire starting at pin but passing through body must be detected"
def test_wire_terminating_at_pin_from_outside(self):
"""A wire that arrives at a pin from outside the component body
@@ -448,17 +458,17 @@ class TestIntegrationFindWiresCrossingSymbols:
tmp = _make_temp_schematic(extra)
result = find_wires_crossing_symbols(tmp)
d1_crossings = [c for c in result if c["component"]["reference"] == "D1"]
assert len(d1_crossings) == 0, (
"Wire terminating at pin from outside should not be flagged"
)
assert (
len(d1_crossings) == 0
), "Wire terminating at pin from outside should not be flagged"
def test_wire_shorts_component_pins_detected_as_collision(self):
"""Regression: a wire connecting pin1→pin2 of the same component
must be reported even though both endpoints land on pins."""
r_sexp = _make_resistor_sexp("R_short", 100.0, 100.0)
wire_sexp = (
'(wire (pts (xy 100 103.81) (xy 100 96.19))\n'
' (stroke (width 0) (type default))\n'
"(wire (pts (xy 100 103.81) (xy 100 96.19))\n"
" (stroke (width 0) (type default))\n"
' (uuid "aaaaaaaa-0000-0000-0000-000000000001"))'
)
sch = _make_temp_schematic(r_sexp + "\n" + wire_sexp)
@@ -511,6 +521,7 @@ class TestIntegrationGetElementsInRegion:
# Unit tests — _check_wire_overlap
# ===================================================================
class TestCheckWireOverlap:
"""Test wire overlap detection for horizontal, vertical, and diagonal cases."""
@@ -613,6 +624,7 @@ class TestIntegrationDiagonalWireOverlap:
# Unit tests — _extract_lib_symbols
# ===================================================================
class TestExtractLibSymbols:
"""Test _extract_lib_symbols helper."""
@@ -684,6 +696,7 @@ class TestExtractLibSymbols:
# Unit tests — _parse_lib_symbol_graphics
# ===================================================================
class TestParseLibSymbolGraphics:
"""Test graphics extraction from lib_symbol definitions."""
@@ -745,6 +758,7 @@ class TestParseLibSymbolGraphics:
# Unit tests — _transform_local_point
# ===================================================================
class TestTransformLocalPoint:
"""Test local→absolute coordinate transform."""
@@ -776,6 +790,7 @@ class TestTransformLocalPoint:
# Unit tests — _compute_symbol_bbox_direct with graphics
# ===================================================================
class TestComputeSymbolBboxWithGraphics:
"""Test that bounding box computation uses graphics points when available."""
@@ -783,14 +798,36 @@ class TestComputeSymbolBboxWithGraphics:
"""Device:R rectangle is (-1.016, -2.54) to (1.016, 2.54) in local coords.
Pins at (0, ±3.81). Placed at (100, 100) with no rotation.
Bbox should span from pin-to-pin in Y and use rectangle width in X."""
sym = {"x": 100.0, "y": 100.0, "rotation": 0, "mirror_x": False, "mirror_y": False}
sym = {
"x": 100.0,
"y": 100.0,
"rotation": 0,
"mirror_x": False,
"mirror_y": False,
}
pin_defs = {
"1": {"x": 0, "y": 3.81, "angle": 270, "length": 1.27, "name": "~", "type": "passive"},
"2": {"x": 0, "y": -3.81, "angle": 90, "length": 1.27, "name": "~", "type": "passive"},
"1": {
"x": 0,
"y": 3.81,
"angle": 270,
"length": 1.27,
"name": "~",
"type": "passive",
},
"2": {
"x": 0,
"y": -3.81,
"angle": 90,
"length": 1.27,
"name": "~",
"type": "passive",
},
}
graphics_points = [(-1.016, -2.54), (1.016, 2.54)]
bbox = _compute_symbol_bbox_direct(sym, pin_defs, graphics_points=graphics_points)
bbox = _compute_symbol_bbox_direct(
sym, pin_defs, graphics_points=graphics_points
)
assert bbox is not None
min_x, min_y, max_x, max_y = bbox
# X should come from rectangle: 100 ± 1.016
@@ -802,10 +839,30 @@ class TestComputeSymbolBboxWithGraphics:
def test_fallback_without_graphics(self):
"""Without graphics_points, should use the old degenerate expansion."""
sym = {"x": 100.0, "y": 100.0, "rotation": 0, "mirror_x": False, "mirror_y": False}
sym = {
"x": 100.0,
"y": 100.0,
"rotation": 0,
"mirror_x": False,
"mirror_y": False,
}
pin_defs = {
"1": {"x": 0, "y": 3.81, "angle": 270, "length": 1.27, "name": "~", "type": "passive"},
"2": {"x": 0, "y": -3.81, "angle": 90, "length": 1.27, "name": "~", "type": "passive"},
"1": {
"x": 0,
"y": 3.81,
"angle": 270,
"length": 1.27,
"name": "~",
"type": "passive",
},
"2": {
"x": 0,
"y": -3.81,
"angle": 90,
"length": 1.27,
"name": "~",
"type": "passive",
},
}
bbox = _compute_symbol_bbox_direct(sym, pin_defs)
@@ -817,15 +874,37 @@ class TestComputeSymbolBboxWithGraphics:
def test_rotated_symbol_graphics(self):
"""Graphics points should be rotated along with the symbol."""
sym = {"x": 100.0, "y": 100.0, "rotation": 90, "mirror_x": False, "mirror_y": False}
sym = {
"x": 100.0,
"y": 100.0,
"rotation": 90,
"mirror_x": False,
"mirror_y": False,
}
pin_defs = {
"1": {"x": 0, "y": 3.81, "angle": 270, "length": 1.27, "name": "~", "type": "passive"},
"2": {"x": 0, "y": -3.81, "angle": 90, "length": 1.27, "name": "~", "type": "passive"},
"1": {
"x": 0,
"y": 3.81,
"angle": 270,
"length": 1.27,
"name": "~",
"type": "passive",
},
"2": {
"x": 0,
"y": -3.81,
"angle": 90,
"length": 1.27,
"name": "~",
"type": "passive",
},
}
# Rectangle corners in local coords
graphics_points = [(-1.016, -2.54), (1.016, 2.54)]
bbox = _compute_symbol_bbox_direct(sym, pin_defs, graphics_points=graphics_points)
bbox = _compute_symbol_bbox_direct(
sym, pin_defs, graphics_points=graphics_points
)
assert bbox is not None
min_x, min_y, max_x, max_y = bbox
# After 90° rotation, X and Y swap roles
@@ -856,7 +935,9 @@ class TestIntegrationGraphicsBbox:
assert len(graphics_points) >= 2, "Should have extracted rectangle points"
bbox = _compute_symbol_bbox_direct(r1, pin_defs, graphics_points=graphics_points)
bbox = _compute_symbol_bbox_direct(
r1, pin_defs, graphics_points=graphics_points
)
assert bbox is not None
min_x, min_y, max_x, max_y = bbox
# Rectangle is ±1.016 in X, NOT ±1.5 from degenerate expansion