[Pather] move render check from __del__ to __exit__ and use render= enum instead of auto_render

This commit is contained in:
Jan Petykiewicz 2026-07-09 12:28:05 -07:00
commit 9a39a436b2
13 changed files with 277 additions and 126 deletions

View file

@ -117,7 +117,7 @@ class CountingPathTool(PathTool):
def test_pather_jog_failed_two_bend_route_is_atomic() -> None:
lib = Library()
tool = PathTool(layer='M1', width=2, ptype='wire')
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, render='immediate')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
with pytest.raises(BuildError, match='S-bend'):
@ -130,7 +130,7 @@ def test_pather_jog_failed_two_bend_route_is_atomic() -> None:
def test_pather_jog_accepts_sub_width_offset_when_length_is_sufficient() -> None:
lib = Library()
tool = PathTool(layer='M1', width=2, ptype='wire')
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, render='immediate')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
p.jog('A', 1.5, length=5)
@ -139,10 +139,10 @@ def test_pather_jog_accepts_sub_width_offset_when_length_is_sufficient() -> None
assert p.pattern.ports['A'].rotation == 0
assert len(p._paths['A']) == 0
def test_pather_auto_render_batches_multi_step_selected_route_once() -> None:
def test_pather_immediate_render_batches_multi_step_selected_route_once() -> None:
lib = Library()
tool = CountingPathTool(layer='M1', width=2, ptype='wire')
p = Pather(lib, tools=tool, auto_render=True)
p = Pather(lib, tools=tool, render='immediate')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
p.jog('A', 4, length=10)
@ -169,7 +169,7 @@ def test_pather_jog_length_solved_from_single_position_bound() -> None:
def test_pather_positional_bound_requires_port_rotation() -> None:
p = Pather(Library(), tools=PathTool(layer='M1', width=1, ptype='wire'), auto_render=False)
p = Pather(Library(), tools=PathTool(layer='M1', width=1, ptype='wire'), render='deferred')
p.pattern.ports['A'] = Port((0, 0), rotation=None, ptype='wire')
with pytest.raises(BuildError, match='Ports must have rotation'):
@ -179,7 +179,7 @@ def test_pather_positional_bound_requires_port_rotation() -> None:
def test_pather_jog_omitted_length_uses_minimum_length_route() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1, ptype='wire')
p = Pather(lib, tools=tool, auto_render=False)
p = Pather(lib, tools=tool, render='deferred')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
p.jog('A', 2)
@ -195,7 +195,7 @@ def test_pather_jog_omitted_length_uses_minimum_length_route() -> None:
def test_pather_trace_omitted_length_uses_minimum_offer() -> None:
lib = Library()
tool = PathTool(layer='M1', width=2, ptype='wire')
p = Pather(lib, tools=tool, auto_render=False)
p = Pather(lib, tools=tool, render='deferred')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
p.trace('A', None)
@ -211,7 +211,7 @@ def test_pather_trace_omitted_length_uses_minimum_offer() -> None:
def test_pather_trace_to_without_bound_uses_single_port_trace_minimum() -> None:
lib = Library()
tool = PathTool(layer='M1', width=2, ptype='wire')
p = Pather(lib, tools=tool, auto_render=False)
p = Pather(lib, tools=tool, render='deferred')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
p.trace_to('A', False)
@ -229,7 +229,7 @@ def test_pather_trace_to_rejects_conflicting_position_bounds() -> None:
with pytest.raises(BuildError, match='exactly one positional bound'):
p.trace_to('A', None, **kwargs)
p = Pather(Library(), tools=tool)
p = Pather(Library(), tools=tool, render='deferred')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
with pytest.raises(BuildError, match='length cannot be combined'):
p.trace_to('A', None, x=-5, length=3)
@ -261,7 +261,7 @@ def test_planner_constrained_bend_requires_jog() -> None:
def test_pather_trace_each_plans_all_ports_before_mutation() -> None:
tool = FirstPortOnlyTraceTool()
p = Pather(Library(), tools=tool, auto_render=False)
p = Pather(Library(), tools=tool)
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
p.pattern.ports['B'] = Port((-2, 5), rotation=0, ptype='blocked')
@ -277,7 +277,7 @@ def test_pather_trace_each_plans_all_ports_before_mutation() -> None:
def test_pather_bundle_trace_plans_all_ports_before_mutation_or_render() -> None:
tool = FirstPortOnlyTraceTool()
p = Pather(Library(), tools=tool, auto_render=True)
p = Pather(Library(), tools=tool, render='immediate')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
p.pattern.ports['B'] = Port((0, 4), rotation=0, ptype='blocked')
@ -343,7 +343,7 @@ def test_pather_route_commit_failure_is_atomic_for_multi_port_trace() -> None:
return tree
tool = CommitFailureTool()
p = Pather(Library(), tools=tool, auto_render=True)
p = Pather(Library(), tools=tool, render='immediate')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
p.pattern.ports['B'] = Port((0, 4), rotation=0, ptype='bad')
@ -433,7 +433,7 @@ def test_pather_uturn_does_not_use_direct_planl_fallback() -> None:
jog = -1
return Port((length, jog), rotation=rotation, ptype=in_ptype or 'wire'), {'ccw': ccw, 'length': length}
p = Pather(Library(), tools=PlanLOnlyTool(), auto_render=False)
p = Pather(Library(), tools=PlanLOnlyTool(), render='deferred')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
with pytest.raises(BuildError, match='No legal primitive offer for omitted-length U-turn'):
@ -476,7 +476,7 @@ def test_pather_su_topology_rejects_out_ptype_sensitive_planl_jog() -> None:
ptype = out_ptype or in_ptype or 'wire'
return Port((length, jog), rotation=rotation, ptype=ptype), {'ccw': ccw, 'length': length}
p = Pather(Library(), tools=OutPtypeSensitiveTool(), auto_render=False)
p = Pather(Library(), tools=OutPtypeSensitiveTool(), render='deferred')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
with pytest.raises((BuildError, NotImplementedError)):
@ -509,7 +509,7 @@ def test_pather_two_l_planl_only_uturn_is_not_supported() -> None:
jog = -1
return Port((length, jog), rotation=rotation, ptype=in_ptype or 'wire'), {'ccw': ccw, 'length': length}
p = Pather(Library(), tools=PlanLOnlyTool(), auto_render=False)
p = Pather(Library(), tools=PlanLOnlyTool(), render='deferred')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
with pytest.raises((BuildError, NotImplementedError)):
@ -543,7 +543,7 @@ def test_pather_two_l_planl_only_jog_is_not_supported() -> None:
jog = -1
return Port((length, jog), rotation=rotation, ptype=in_ptype or 'wire'), {'ccw': ccw, 'length': length}
p = Pather(Library(), tools=PlanLOnlyTool(), auto_render=False)
p = Pather(Library(), tools=PlanLOnlyTool(), render='deferred')
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
with pytest.raises((BuildError, NotImplementedError)):