diff --git a/MIGRATION.md b/MIGRATION.md index 5ab568c..818b133 100644 --- a/MIGRATION.md +++ b/MIGRATION.md @@ -18,11 +18,17 @@ The biggest migration point is that the old routing verbs were renamed: | `Pather.path(...)` | `Pather.trace(...)` | | `Pather.path_to(...)` | `Pather.trace_to(...)` | | `Pather.mpath(...)` | `Pather.trace(...)` / `Pather.trace_to(...)` with multiple ports | +| `Pather.pathS(...)` | `Pather.jog(...)` | +| `Pather.pathU(...)` | `Pather.uturn(...)` | | `Pather.path_into(...)` | `Pather.trace_into(...)` | -| `RenderPather.path(...)` | `RenderPather.trace(...)` | -| `RenderPather.path_to(...)` | `RenderPather.trace_to(...)` | -| `RenderPather.mpath(...)` | `RenderPather.trace(...)` / `RenderPather.trace_to(...)` | -| `RenderPather.path_into(...)` | `RenderPather.trace_into(...)` | +| `Pather.path_from(src, dst)` | `Pather.at(src).trace_into(dst)` | +| `RenderPather.path(...)` | `Pather(..., auto_render=False).trace(...)` | +| `RenderPather.path_to(...)` | `Pather(..., auto_render=False).trace_to(...)` | +| `RenderPather.mpath(...)` | `Pather(..., auto_render=False).trace(...)` / `Pather(..., auto_render=False).trace_to(...)` | +| `RenderPather.pathS(...)` | `Pather(..., auto_render=False).jog(...)` | +| `RenderPather.pathU(...)` | `Pather(..., auto_render=False).uturn(...)` | +| `RenderPather.path_into(...)` | `Pather(..., auto_render=False).trace_into(...)` | +| `RenderPather.path_from(src, dst)` | `Pather(..., auto_render=False).at(src).trace_into(dst)` | There are also new convenience wrappers: @@ -43,13 +49,19 @@ that still calls `pather.path(...)` must be renamed. pather.path('VCC', False, 6_000) pather.path_to('VCC', None, x=0) pather.mpath(['GND', 'VCC'], True, xmax=-10_000, spacing=5_000) +pather.pathS('VCC', offset=-2_000, length=8_000) +pather.pathU('VCC', offset=4_000, length=5_000) pather.path_into('src', 'dst') +pather.path_from('src', 'dst') # new pather.cw('VCC', 6_000) pather.straight('VCC', x=0) pather.ccw(['GND', 'VCC'], xmax=-10_000, spacing=5_000) +pather.jog('VCC', offset=-2_000, length=8_000) +pather.uturn('VCC', offset=4_000, length=5_000) pather.trace_into('src', 'dst') +pather.at('src').trace_into('dst') ``` If you prefer the more explicit spelling, `trace(...)` and `trace_to(...)` @@ -73,11 +85,30 @@ Routing can now be written in a fluent style via `.at(...)`, which returns a ``` This is additive, not required for migration. Existing code can stay with the -non-fluent `Pather`/`RenderPather` methods after renaming the verbs above. +non-fluent `Pather` methods after renaming the verbs above. + +Old `PortPather` helper names were also cleaned up: + +| Old API | New API | +| --- | --- | +| `save_copy(...)` | `mark(...)` | +| `rename_to(...)` | `rename(...)` | + +Example: + +```python +# old +pp.save_copy('branch') +pp.rename_to('feed') + +# new +pp.mark('branch') +pp.rename('feed') +``` ## Imports and module layout -`Builder`, `Pather`, and `RenderPather` now live together in +`Pather` now provides the remaining builder/routing surface in `masque/builder/pather.py`. The old module files `masque/builder/builder.py` and `masque/builder/renderpather.py` were removed. @@ -89,14 +120,17 @@ from masque.builder.builder import Builder from masque.builder.renderpather import RenderPather # new -from masque.builder import Builder, RenderPather +from masque.builder import Pather + +builder = Pather(...) +deferred = Pather(..., auto_render=False) ``` Top-level imports from `masque` also continue to work. -`Builder` is now a thin compatibility wrapper over the unified `Pather` -implementation with `auto_render=True`. `RenderPather` is the same wrapper with -`auto_render=False`. +`Pather` now defaults to `auto_render=True`, so plain construction replaces the +old `Builder` behavior. Use `Pather(..., auto_render=False)` where you +previously used `RenderPather`. ## `BasicTool` was replaced diff --git a/README.md b/README.md index 6ebc5ab..71c37f0 100644 --- a/README.md +++ b/README.md @@ -145,7 +145,7 @@ References are accomplished by listing the target's name, not its `Pattern` obje in order to create a reference, but they also need to access the pattern's ports. * One way to provide this data is through an `Abstract`, generated via `Library.abstract()` or through a `Library.abstract_view()`. - * Another way is use `Builder.place()` or `Builder.plug()`, which automatically creates + * Another way is use `Pather.place()` or `Pather.plug()`, which automatically creates an `Abstract` from its internally-referenced `Library`. @@ -193,8 +193,8 @@ my_pattern.ref(new_name, ...) # instantiate the cell # In practice, you may do lots of my_pattern.ref(lib << make_tree(...), ...) -# With a `Builder` and `place()`/`plug()` the `lib <<` portion can be implicit: -my_builder = Builder(library=lib, ...) +# With a `Pather` and `place()`/`plug()` the `lib <<` portion can be implicit: +my_builder = Pather(library=lib, ...) ... my_builder.place(make_tree(...)) ``` diff --git a/examples/tutorial/README.md b/examples/tutorial/README.md index ea4471f..749915b 100644 --- a/examples/tutorial/README.md +++ b/examples/tutorial/README.md @@ -17,7 +17,7 @@ Contents * Build hierarchical photonic-crystal example devices * Reference other patterns * Add ports to a pattern - * Use `Builder` to snap ports together into a circuit + * Use `Pather` to snap ports together into a circuit * Check for dangling references - [library](library.py) * Continue from `devices.py` using a lazy library @@ -29,7 +29,7 @@ Contents * Use `AutoTool` to generate paths * Use `AutoTool` to automatically transition between path types - [renderpather](renderpather.py) - * Use `RenderPather` and `PathTool` to build a layout similar to the one in [pather](pather.py), + * Use `Pather(auto_render=False)` and `PathTool` to build a layout similar to the one in [pather](pather.py), but using `Path` shapes instead of `Polygon`s. - [port_pather](port_pather.py) * Use `PortPather` and the `.at()` syntax for more concise routing diff --git a/examples/tutorial/devices.py b/examples/tutorial/devices.py index d6beb2a..955e786 100644 --- a/examples/tutorial/devices.py +++ b/examples/tutorial/devices.py @@ -1,5 +1,5 @@ """ -Tutorial: building hierarchical devices with `Pattern`, `Port`, and `Builder`. +Tutorial: building hierarchical devices with `Pattern`, `Port`, and `Pather`. This file uses photonic-crystal components as the concrete example, so some of the geometry-generation code is domain-specific. The tutorial value is in the @@ -12,7 +12,7 @@ import numpy from numpy import pi from masque import ( - layer_t, Pattern, Ref, Builder, Port, Polygon, + layer_t, Pattern, Ref, Pather, Port, Polygon, Library, ) from masque.utils import ports2data @@ -261,8 +261,8 @@ def main(interactive: bool = True) -> None: # # Build a circuit # - # Create a `Builder`, and register the resulting top cell as "my_circuit". - circ = Builder(library=lib, name='my_circuit') + # Create a `Pather`, and register the resulting top cell as "my_circuit". + circ = Pather(library=lib, name='my_circuit') # Start by placing a waveguide and renaming its ports to match the circuit-level # names we want to use while assembling the design. @@ -278,7 +278,7 @@ def main(interactive: bool = True) -> None: # lib['my_circuit'] = circ_pat # circ_pat.place(lib.abstract('wg10'), ...) # circ_pat.plug(lib.abstract('wg10'), ...) - # but `Builder` removes some repeated `lib.abstract(...)` boilerplate and keeps + # but `Pather` removes some repeated `lib.abstract(...)` boilerplate and keeps # the assembly code focused on port-level intent. # Attach a y-splitter to the signal path. diff --git a/examples/tutorial/library.py b/examples/tutorial/library.py index faaa5a1..1b9a1da 100644 --- a/examples/tutorial/library.py +++ b/examples/tutorial/library.py @@ -1,5 +1,5 @@ """ -Tutorial: using `LazyLibrary` and `Builder.interface()`. +Tutorial: using `LazyLibrary` and `Pather.interface()`. This example assumes you have already read `devices.py` and generated the `circuit.gds` file it writes. The goal here is not the photonic-crystal geometry @@ -10,7 +10,7 @@ from typing import Any from pprint import pformat -from masque import Builder, LazyLibrary +from masque import Pather, LazyLibrary from masque.file.gdsii import writefile, load_libraryfile import basic_shapes @@ -64,10 +64,10 @@ def main() -> None: # Start a new design by copying the ports from an existing library cell. # This gives `circ2` the same external interface as `tri_l3cav`. - circ2 = Builder(library=lib, ports='tri_l3cav') + circ2 = Pather(library=lib, ports='tri_l3cav') # First way to specify what we are plugging in: request an explicit abstract. - # This works with `Pattern` methods directly as well as with `Builder`. + # This works with `Pattern` methods directly as well as with `Pather`. circ2.plug(lib.abstract('wg10'), {'input': 'right'}) # Second way: use an `AbstractView`, which behaves like a mapping of names @@ -75,7 +75,7 @@ def main() -> None: abstracts = lib.abstract_view() circ2.plug(abstracts['wg10'], {'output': 'left'}) - # Third way: let `Builder` resolve a pattern name through its own library. + # Third way: let `Pather` resolve a pattern name through its own library. # This shorthand is convenient, but it is specific to helpers that already # carry a library reference. circ2.plug('tri_wg10', {'input': 'right'}) @@ -89,10 +89,10 @@ def main() -> None: # Build a second device that is explicitly designed to mate with `circ2`. # - # `Builder.interface()` makes a new pattern whose ports mirror an existing + # `Pather.interface()` makes a new pattern whose ports mirror an existing # design's external interface. That is useful when you want to design an # adapter, continuation, or mating structure. - circ3 = Builder.interface(source=circ2) + circ3 = Pather.interface(source=circ2) # Continue routing outward from those inherited ports. circ3.plug('tri_bend0', {'input': 'right'}) diff --git a/examples/tutorial/pather.py b/examples/tutorial/pather.py index 386384a..5cc5a61 100644 --- a/examples/tutorial/pather.py +++ b/examples/tutorial/pather.py @@ -204,9 +204,9 @@ def prepare_tools() -> tuple[Library, Tool, Tool]: # # Now we can start building up our library (collection of static cells) and pathing tools. # -# If any of the operations below are confusing, you can cross-reference against the `RenderPather` -# tutorial, which handles some things more explicitly (e.g. via placement) and simplifies others -# (e.g. geometry definition). +# If any of the operations below are confusing, you can cross-reference against the deferred +# `Pather` tutorial, which handles some things more explicitly (e.g. via placement) and simplifies +# others (e.g. geometry definition). # def main() -> None: library, M1_tool, M2_tool = prepare_tools() diff --git a/examples/tutorial/port_pather.py b/examples/tutorial/port_pather.py index 6d41a39..ab942d7 100644 --- a/examples/tutorial/port_pather.py +++ b/examples/tutorial/port_pather.py @@ -1,7 +1,7 @@ """ PortPather tutorial: Using .at() syntax """ -from masque import RenderPather, Pattern, Port, R90 +from masque import Pather, Pattern, Port, R90 from masque.file.gdsii import writefile from basic_shapes import GDS_OPTS @@ -12,8 +12,8 @@ def main() -> None: # Reuse the same patterns (pads, bends, vias) and tools as in pather.py library, M1_tool, M2_tool = prepare_tools() - # Create a RenderPather and place some initial pads (same as Pather tutorial) - rpather = RenderPather(library, tools=M2_tool) + # Create a deferred Pather and place some initial pads (same as Pather tutorial) + rpather = Pather(library, tools=M2_tool, auto_render=False) rpather.place('pad', offset=(18_000, 30_000), port_map={'wire_port': 'VCC'}) rpather.place('pad', offset=(18_000, 60_000), port_map={'wire_port': 'GND'}) @@ -156,7 +156,7 @@ def main() -> None: # # Rendering and Saving # - # Since we used RenderPather, we must call .render() to generate the geometry. + # Since we deferred auto-rendering, we must call .render() to generate the geometry. rpather.render() library['PortPather_Tutorial'] = rpather.pattern diff --git a/examples/tutorial/renderpather.py b/examples/tutorial/renderpather.py index 7b75f5d..4b43b19 100644 --- a/examples/tutorial/renderpather.py +++ b/examples/tutorial/renderpather.py @@ -1,7 +1,7 @@ """ -Manual wire routing tutorial: RenderPather an PathTool +Manual wire routing tutorial: deferred Pather and PathTool """ -from masque import RenderPather, Library +from masque import Pather, Library from masque.builder.tools import PathTool from masque.file.gdsii import writefile @@ -11,9 +11,9 @@ from pather import M1_WIDTH, V1_WIDTH, M2_WIDTH, map_layer, make_pad, make_via def main() -> None: # - # To illustrate the advantages of using `RenderPather`, we use `PathTool` instead + # To illustrate deferred routing with `Pather`, we use `PathTool` instead # of `AutoTool`. `PathTool` lacks some sophistication (e.g. no automatic transitions) - # but when used with `RenderPather`, it can consolidate multiple routing steps into + # but when used with `Pather(auto_render=False)`, it can consolidate multiple routing steps into # a single `Path` shape. # # We'll try to nearly replicate the layout from the `Pather` tutorial; see `pather.py` @@ -39,7 +39,7 @@ def main() -> None: # and what port type to present. M1_ptool = PathTool(layer='M1', width=M1_WIDTH, ptype='m1wire') M2_ptool = PathTool(layer='M2', width=M2_WIDTH, ptype='m2wire') - rpather = RenderPather(tools=M2_ptool, library=library) + rpather = Pather(tools=M2_ptool, library=library, auto_render=False) # As in the pather tutorial, we make some pads and labels... rpather.place('pad', offset=(18_000, 30_000), port_map={'wire_port': 'VCC'}) @@ -85,7 +85,7 @@ def main() -> None: # Render the path we defined rpather.render() - library['RenderPather_and_PathTool'] = rpather.pattern + library['Deferred_Pather_and_PathTool'] = rpather.pattern # Convert from text-based layers to numeric layers for GDS, and output the file diff --git a/masque/__init__.py b/masque/__init__.py index e435fac..8e13bb9 100644 --- a/masque/__init__.py +++ b/masque/__init__.py @@ -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, diff --git a/masque/builder/__init__.py b/masque/builder/__init__.py index 65958c1..a8f4cc0 100644 --- a/masque/builder/__init__.py +++ b/masque/builder/__init__.py @@ -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 ( diff --git a/masque/builder/logging.py b/masque/builder/logging.py index 78a566e..b4a113b 100644 --- a/masque/builder/logging.py +++ b/masque/builder/logging.py @@ -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) diff --git a/masque/builder/pather.py b/masque/builder/pather.py index e190203..a7bbedd 100644 --- a/masque/builder/pather.py +++ b/masque/builder/pather.py @@ -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, - ) diff --git a/masque/builder/tools.py b/masque/builder/tools.py index f0772a1..ddd4bba 100644 --- a/masque/builder/tools.py +++ b/masque/builder/tools.py @@ -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 diff --git a/masque/pattern.py b/masque/pattern.py index dfa45c7..e882795 100644 --- a/masque/pattern.py +++ b/masque/pattern.py @@ -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. diff --git a/masque/test/test_autotool_refactor.py b/masque/test/test_autotool_refactor.py index d93f935..d5f1c86 100644 --- a/masque/test/test_autotool_refactor.py +++ b/masque/test/test_autotool_refactor.py @@ -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 diff --git a/masque/test/test_builder.py b/masque/test/test_builder.py index 309dab6..9f73d2b 100644 --- a/masque/test/test_builder.py +++ b/masque/test/test_builder.py @@ -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 diff --git a/masque/test/test_pather_api.py b/masque/test/test_pather_api.py index 2e841ad..dd7dc8f 100644 --- a/masque/test/test_pather_api.py +++ b/masque/test/test_pather_api.py @@ -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) diff --git a/masque/test/test_renderpather.py b/masque/test/test_renderpather.py index 0da9588..9b5a8e3 100644 --- a/masque/test/test_renderpather.py +++ b/masque/test/test_renderpather.py @@ -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()