[Builder / RenderPather] BREAKING remove aliases to old names

This commit is contained in:
Jan Petykiewicz 2026-04-08 23:08:26 -07:00
commit 778b3d9be7
18 changed files with 131 additions and 153 deletions

View file

@ -73,10 +73,8 @@ from .ports import (
)
from .abstract import Abstract as Abstract
from .builder import (
Builder as Builder,
Tool as Tool,
Pather as Pather,
RenderPather as RenderPather,
RenderStep as RenderStep,
SimpleTool as SimpleTool,
AutoTool as AutoTool,

View file

@ -1,8 +1,6 @@
from .pather import (
Pather as Pather,
PortPather as PortPather,
Builder as Builder,
RenderPather as RenderPather,
)
from .utils import ell as ell
from .tools import (

View file

@ -1,5 +1,5 @@
"""
Logging and operation decorators for Builder/Pather
Logging and operation decorators for Pather
"""
from typing import TYPE_CHECKING, Any
from collections.abc import Iterator, Sequence, Callable
@ -31,7 +31,7 @@ def _format_log_args(**kwargs) -> str:
class PatherLogger:
"""
Encapsulates state for Pather/Builder diagnostic logging.
Encapsulates state for Pather diagnostic logging.
"""
debug: bool
indent: int
@ -90,7 +90,7 @@ def logged_op(
portspec_getter: Callable[[dict[str, Any]], str | Sequence[str] | None] | None = None,
) -> Callable[[Callable[..., Any]], Callable[..., Any]]:
"""
Decorator to wrap Builder methods with logging.
Decorator to wrap Pather methods with logging.
"""
def decorator(func: Callable[..., Any]) -> Callable[..., Any]:
sig = inspect.signature(func)

View file

@ -38,11 +38,9 @@ class Pather(PortList):
The `Pather` holds context in the form of a `Library`, its underlying
pattern, and a set of `Tool`s for generating routing segments.
Routing operations (`trace`, `jog`, `uturn`, etc.) are by default
deferred: they record the intended path but do not immediately generate
geometry. `render()` must be called to generate the final layout.
Alternatively, setting `auto_render=True` in the constructor will
cause geometry to be generated incrementally after each routing step.
Routing operations (`trace`, `jog`, `uturn`, etc.) are rendered
incrementally by default. Set `auto_render=False` to defer geometry
generation until an explicit call to `render()`.
Examples: Creating a Pather
===========================
@ -58,8 +56,8 @@ class Pather(PortList):
connects port 'A' of the current pattern to port 'C' of `subdevice`.
- `pather.trace('my_port', ccw=True, length=100)` plans a 100-unit bend
starting at 'my_port'. If `auto_render=True`, geometry is added
immediately. Otherwise, call `pather.render()` later.
starting at 'my_port'. Geometry is added immediately by default.
Set `auto_render=False` to defer and call `pather.render()` later.
"""
__slots__ = (
'pattern', 'library', 'tools', 'paths',
@ -118,7 +116,7 @@ class Pather(PortList):
tools: Tool | MutableMapping[str | None, Tool] | None = None,
name: str | None = None,
debug: bool = False,
auto_render: bool = False,
auto_render: bool = True,
auto_render_append: bool = True,
) -> None:
"""
@ -1358,53 +1356,3 @@ class PortPather:
self.pather.rename_ports({name: None})
self.ports = [pp for pp in self.ports if pp != name]
return self
class Builder(Pather):
"""
Backward-compatible wrapper for Pather with auto_render=True.
"""
def __init__(
self,
library: ILibrary,
*,
pattern: Pattern | None = None,
ports: str | Mapping[str, Port] | None = None,
tools: Tool | MutableMapping[str | None, Tool] | None = None,
name: str | None = None,
debug: bool = False,
) -> None:
super().__init__(
library=library,
pattern=pattern,
ports=ports,
tools=tools,
name=name,
debug=debug,
auto_render=True,
)
class RenderPather(Pather):
"""
Backward-compatible wrapper for Pather with auto_render=False.
"""
def __init__(
self,
library: ILibrary,
*,
pattern: Pattern | None = None,
ports: str | Mapping[str, Port] | None = None,
tools: Tool | MutableMapping[str | None, Tool] | None = None,
name: str | None = None,
debug: bool = False,
) -> None:
super().__init__(
library=library,
pattern=pattern,
ports=ports,
tools=tools,
name=name,
debug=debug,
auto_render=False,
)

View file

@ -25,8 +25,8 @@ from ..error import BuildError
@dataclass(frozen=True, slots=True)
class RenderStep:
"""
Representation of a single saved operation, used by `RenderPather` and passed
to `Tool.render()` when `RenderPather.render()` is called.
Representation of a single saved operation, used by deferred `Pather`
instances and passed to `Tool.render()` when `Pather.render()` is called.
"""
opcode: Literal['L', 'S', 'U', 'P']
""" What operation is being performed.
@ -128,7 +128,7 @@ class Tool:
Create a wire or waveguide that travels exactly `length` distance along the axis
of its input port.
Used by `Pather` and `RenderPather`.
Used by `Pather`.
The output port must be exactly `length` away along the input port's axis, but
may be placed an additional (unspecified) distance away along the perpendicular
@ -174,7 +174,7 @@ class Tool:
of its input port, and `jog` distance on the perpendicular axis.
`jog` is positive when moving left of the direction of travel (from input to ouput port).
Used by `Pather` and `RenderPather`.
Used by `Pather`.
The output port should be rotated to face the input port (i.e. plugging the device
into a port will move that port but keep its orientation).
@ -214,7 +214,7 @@ class Tool:
Plan a wire or waveguide that travels exactly `length` distance along the axis
of its input port.
Used by `RenderPather`.
Used by `Pather` when `auto_render=False`.
The output port must be exactly `length` away along the input port's axis, but
may be placed an additional (unspecified) distance away along the perpendicular
@ -266,7 +266,7 @@ class Tool:
Plan a wire or waveguide that travels exactly `length` distance along the axis
of its input port and `jog` distance along the perpendicular axis (i.e. an S-bend).
Used by `RenderPather`.
Used by `Pather` when `auto_render=False`.
The output port must have an orientation rotated by pi from the input port.
@ -315,7 +315,7 @@ class Tool:
Create a wire or waveguide that travels exactly `jog` distance along the axis
perpendicular to its input port (i.e. a U-bend).
Used by `Pather` and `RenderPather`. Tools may leave this unimplemented if they
Used by `Pather`. Tools may leave this unimplemented if they
do not support a native U-bend primitive.
The output port must have an orientation identical to the input port.
@ -354,7 +354,7 @@ class Tool:
Plan a wire or waveguide that travels exactly `jog` distance along the axis
perpendicular to its input port (i.e. a U-bend).
Used by `RenderPather`. This is an optional native-planning hook: tools may
Used by `Pather` when `auto_render=False`. This is an optional native-planning hook: tools may
implement it when they can represent a U-turn directly, otherwise they may rely
on `traceU()` or let `Pather` synthesize the route from simpler primitives.
@ -1323,7 +1323,7 @@ class PathTool(Tool, metaclass=ABCMeta):
# Transform the batch so the first port is local (at 0,0) but retains its global rotation.
# This allows the path to be rendered with its original orientation, simplified by
# translation to the origin. RenderPather.render will handle the final placement
# translation to the origin. Pather.render will handle the final placement
# (including rotation alignment) via `pat.plug`.
first_port = batch[0].start_port
translation = -first_port.offset

View file

@ -38,8 +38,8 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
or provide equivalent functions.
`Pattern` also stores a dict of `Port`s, which can be used to "snap" together points.
See `Pattern.plug()` and `Pattern.place()`, as well as the helper classes
`builder.Builder`, `builder.Pather`, `builder.RenderPather`, and `ports.PortsList`.
See `Pattern.plug()` and `Pattern.place()`, as well as `builder.Pather`
and `ports.PortsList`.
For convenience, ports can be read out using square brackets:
- `pattern['A'] == Port((0, 0), 0)`
@ -1664,7 +1664,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
current device.
Args:
source: A collection of ports (e.g. Pattern, Builder, or dict)
source: A collection of ports (e.g. Pattern, Pather, or dict)
from which to create the interface.
in_prefix: Prepended to port names for newly-created ports with
reversed directions compared to the current device.

View file

@ -6,7 +6,7 @@ from masque.builder.tools import AutoTool
from masque.pattern import Pattern
from masque.ports import Port
from masque.library import Library
from masque.builder.pather import Pather, RenderPather
from masque.builder.pather import Pather
def make_straight(length, width=2, ptype="wire"):
pat = Pattern()
@ -166,7 +166,7 @@ def test_autotool_planS_pure_sbend_with_transition_dx() -> None:
def test_renderpather_autotool_double_L(multi_bend_tool) -> None:
tool, lib = multi_bend_tool
rp = RenderPather(lib, tools=tool)
rp = Pather(lib, tools=tool, auto_render=False)
rp.ports["A"] = Port((0,0), 0, ptype="wire")
# This should trigger double-L fallback in planS

View file

@ -3,7 +3,7 @@ import pytest
from numpy.testing import assert_equal, assert_allclose
from numpy import pi
from ..builder import Builder
from ..builder import Pather
from ..builder.utils import ell
from ..error import BuildError
from ..library import Library
@ -13,7 +13,7 @@ from ..ports import Port
def test_builder_init() -> None:
lib = Library()
b = Builder(lib, name="mypat")
b = Pather(lib, name="mypat")
assert b.pattern is lib["mypat"]
assert b.library is lib
@ -24,7 +24,7 @@ def test_builder_place() -> None:
child.ports["A"] = Port((0, 0), 0)
lib["child"] = child
b = Builder(lib)
b = Pather(lib)
b.place("child", offset=(10, 20), port_map={"A": "child_A"})
assert "child_A" in b.ports
@ -40,7 +40,7 @@ def test_builder_plug() -> None:
wire.ports["out"] = Port((10, 0), pi)
lib["wire"] = wire
b = Builder(lib)
b = Pather(lib)
b.ports["start"] = Port((100, 100), 0)
# Plug wire's "in" port into builder's "start" port
@ -64,7 +64,7 @@ def test_builder_interface() -> None:
source.ports["P1"] = Port((0, 0), 0)
lib["source"] = source
b = Builder.interface("source", library=lib, name="iface")
b = Pather.interface("source", library=lib, name="iface")
assert "in_P1" in b.ports
assert "P1" in b.ports
assert b.pattern is lib["iface"]
@ -73,7 +73,7 @@ def test_builder_interface() -> None:
def test_builder_set_dead() -> None:
lib = Library()
lib["sub"] = Pattern()
b = Builder(lib)
b = Pather(lib)
b.set_dead()
b.place("sub")
@ -84,7 +84,7 @@ def test_builder_dead_ports() -> None:
lib = Library()
pat = Pattern()
pat.ports['A'] = Port((0, 0), 0)
b = Builder(lib, pattern=pat)
b = Pather(lib, pattern=pat)
b.set_dead()
# Attempt to plug a device where ports don't line up
@ -107,7 +107,7 @@ def test_dead_plug_best_effort() -> None:
lib = Library()
pat = Pattern()
pat.ports['A'] = Port((0, 0), 0)
b = Builder(lib, pattern=pat)
b = Pather(lib, pattern=pat)
b.set_dead()
# Device with multiple ports, none of which line up correctly

View file

@ -3,14 +3,14 @@ from typing import Any
import pytest
import numpy
from numpy import pi
from masque import Pather, RenderPather, Library, Pattern, Port
from masque import Pather, Library, Pattern, Port
from masque.builder.tools import PathTool, Tool
from masque.error import BuildError, PortError, PatternError
def test_pather_trace_basic() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000)
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
# Port rotation 0 points in +x (INTO device).
# To extend it, we move in -x direction.
@ -35,7 +35,7 @@ def test_pather_trace_basic() -> None:
def test_pather_trace_to() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000)
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
p.pattern.ports['A'] = Port((0, 0), rotation=0)
@ -50,7 +50,7 @@ def test_pather_trace_to() -> None:
def test_pather_bundle_trace() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000)
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
p.pattern.ports['A'] = Port((0, 0), rotation=0)
p.pattern.ports['B'] = Port((0, 2000), rotation=0)
@ -74,7 +74,7 @@ def test_pather_bundle_trace() -> None:
def test_pather_each_bound() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000)
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
p.pattern.ports['A'] = Port((0, 0), rotation=0)
p.pattern.ports['B'] = Port((-1000, 2000), rotation=0)
@ -198,7 +198,7 @@ def test_rename() -> None:
def test_renderpather_uturn_fallback() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000)
rp = RenderPather(lib, tools=tool)
rp = Pather(lib, tools=tool, auto_render=False)
rp.pattern.ports['A'] = Port((0, 0), rotation=0)
# PathTool doesn't implement planU, so it should fall back to two planL calls
@ -239,7 +239,7 @@ def test_autotool_uturn() -> None:
default_out_ptype='wire'
)
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
p.pattern.ports['A'] = Port((0, 0), 0)
# CW U-turn (jog < 0)
@ -261,7 +261,7 @@ def test_autotool_uturn() -> None:
def test_pather_trace_into() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000)
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
# 1. Straight connector
p.pattern.ports['A'] = Port((0, 0), rotation=0)
@ -313,7 +313,7 @@ def test_pather_trace_into() -> None:
def test_pather_trace_into_dead_updates_ports_without_geometry() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000, ptype='wire')
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
p.pattern.ports['B'] = Port((-10000, 0), rotation=pi, ptype='wire')
p.set_dead()
@ -332,7 +332,7 @@ def test_pather_trace_into_dead_updates_ports_without_geometry() -> None:
def test_pather_dead_fallback_preserves_out_ptype() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000, ptype='wire')
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
p.pattern.ports['A'] = Port((0, 0), rotation=0, ptype='wire')
p.set_dead()
@ -674,7 +674,7 @@ def test_pather_uturn_failed_fallback_is_atomic() -> None:
def test_renderpather_rename_to_none_keeps_pending_geometry_without_port() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000)
rp = RenderPather(lib, tools=tool)
rp = Pather(lib, tools=tool, auto_render=False)
rp.pattern.ports['A'] = Port((0, 0), rotation=0)
rp.at('A').straight(5000)
@ -722,7 +722,7 @@ def test_pather_plug_treeview_resolves_once() -> None:
def test_pather_failed_plug_does_not_add_break_marker() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000)
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
p.pattern.annotations = {'k': [1]}
p.pattern.ports['A'] = Port((0, 0), rotation=0)
@ -744,7 +744,7 @@ def test_pather_failed_plug_does_not_add_break_marker() -> None:
def test_pather_place_reused_deleted_name_keeps_break_marker() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000)
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
p.pattern.ports['A'] = Port((0, 0), rotation=0)
p.at('A').straight(5000)
@ -765,7 +765,7 @@ def test_pather_place_reused_deleted_name_keeps_break_marker() -> None:
def test_pather_plug_reused_deleted_name_keeps_break_marker() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000)
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
p.pattern.ports['A'] = Port((0, 0), rotation=0)
p.pattern.ports['B'] = Port((0, 0), rotation=0)
@ -793,7 +793,7 @@ def test_pather_plug_reused_deleted_name_keeps_break_marker() -> None:
def test_pather_failed_plugged_does_not_add_break_marker() -> None:
lib = Library()
tool = PathTool(layer='M1', width=1000)
p = Pather(lib, tools=tool)
p = Pather(lib, tools=tool, auto_render=False)
p.pattern.ports['A'] = Port((0, 0), rotation=0)
p.at('A').straight(5000)

View file

@ -3,7 +3,7 @@ from typing import cast, TYPE_CHECKING
from numpy.testing import assert_allclose
from numpy import pi
from ..builder import RenderPather
from ..builder import Pather
from ..builder.tools import PathTool
from ..library import Library
from ..ports import Port
@ -13,15 +13,15 @@ if TYPE_CHECKING:
@pytest.fixture
def rpather_setup() -> tuple[RenderPather, PathTool, Library]:
def rpather_setup() -> tuple[Pather, PathTool, Library]:
lib = Library()
tool = PathTool(layer=(1, 0), width=2, ptype="wire")
rp = RenderPather(lib, tools=tool)
rp = Pather(lib, tools=tool, auto_render=False)
rp.ports["start"] = Port((0, 0), pi / 2, ptype="wire")
return rp, tool, lib
def test_renderpather_basic(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
def test_renderpather_basic(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
rp, tool, lib = rpather_setup
# Plan two segments
rp.at("start").straight(10).straight(10)
@ -46,7 +46,7 @@ def test_renderpather_basic(rpather_setup: tuple[RenderPather, PathTool, Library
assert_allclose(path_shape.vertices, [[0, 0], [0, -10], [0, -20]], atol=1e-10)
def test_renderpather_bend(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
def test_renderpather_bend(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
rp, tool, lib = rpather_setup
# Plan straight then bend
rp.at("start").straight(10).cw(10)
@ -65,7 +65,7 @@ def test_renderpather_bend(rpather_setup: tuple[RenderPather, PathTool, Library]
assert_allclose(path_shape.vertices, [[0, 0], [0, -10], [0, -20], [-1, -20]], atol=1e-10)
def test_renderpather_mirror_preserves_planned_bend_geometry(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
def test_renderpather_mirror_preserves_planned_bend_geometry(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
rp, tool, lib = rpather_setup
rp.at("start").straight(10).cw(10)
@ -76,7 +76,7 @@ def test_renderpather_mirror_preserves_planned_bend_geometry(rpather_setup: tupl
assert_allclose(path_shape.vertices, [[0, 0], [0, 10], [0, 20], [-1, 20]], atol=1e-10)
def test_renderpather_retool(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
def test_renderpather_retool(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
rp, tool1, lib = rpather_setup
tool2 = PathTool(layer=(2, 0), width=4, ptype="wire")
@ -90,7 +90,7 @@ def test_renderpather_retool(rpather_setup: tuple[RenderPather, PathTool, Librar
assert len(rp.pattern.shapes[(2, 0)]) == 1
def test_portpather_translate_only_affects_future_steps(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
def test_portpather_translate_only_affects_future_steps(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
rp, tool, lib = rpather_setup
pp = rp.at("start")
pp.straight(10)
@ -109,7 +109,7 @@ def test_portpather_translate_only_affects_future_steps(rpather_setup: tuple[Ren
def test_renderpather_dead_ports() -> None:
lib = Library()
tool = PathTool(layer=(1, 0), width=1)
rp = RenderPather(lib, ports={"in": Port((0, 0), 0)}, tools=tool)
rp = Pather(lib, ports={"in": Port((0, 0), 0)}, tools=tool, auto_render=False)
rp.set_dead()
# Impossible path
@ -126,7 +126,7 @@ def test_renderpather_dead_ports() -> None:
assert not rp.pattern.has_shapes()
def test_renderpather_rename_port(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
def test_renderpather_rename_port(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
rp, tool, lib = rpather_setup
rp.at("start").straight(10)
# Rename port while path is planned
@ -148,7 +148,7 @@ def test_renderpather_rename_port(rpather_setup: tuple[RenderPather, PathTool, L
assert_allclose(rp.ports["new_start"].offset, [0, -20], atol=1e-10)
def test_renderpather_drop_keeps_pending_geometry_without_port(rpather_setup: tuple[RenderPather, PathTool, Library]) -> None:
def test_renderpather_drop_keeps_pending_geometry_without_port(rpather_setup: tuple[Pather, PathTool, Library]) -> None:
rp, tool, lib = rpather_setup
rp.at("start").straight(10).drop()