From 5fbbaa0648668e932ee90df10f200e5692386c5c Mon Sep 17 00:00:00 2001 From: jan Date: Wed, 19 Nov 2025 23:08:17 -0800 Subject: [PATCH 1/5] [Library.flatten] add dangling_ok param --- masque/builder/tools.py | 8 ++++---- masque/library.py | 10 +++++++++- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/masque/builder/tools.py b/masque/builder/tools.py index 1db156b..6a58b70 100644 --- a/masque/builder/tools.py +++ b/masque/builder/tools.py @@ -378,7 +378,7 @@ class SimpleTool(Tool, metaclass=ABCMeta): else: straight_tree = straight_pat_or_tree top = straight_tree.top() - straight_tree.flatten(top) + straight_tree.flatten(top, dangling_ok=True) pat.plug(straight_tree[top], pmap, append=True) if data.ccw is not None: bend, bport_in, bport_out = self.bend @@ -653,7 +653,7 @@ class AutoTool(Tool, metaclass=ABCMeta): else: straight_tree = straight_pat_or_tree top = straight_tree.top() - straight_tree.flatten(top) + straight_tree.flatten(top, dangling_ok=True) pat.plug(straight_tree[top], pmap, append=True) if data.b_transition: pat.plug(data.b_transition.abstract, {port_names[1]: data.b_transition.our_port_name}) @@ -801,7 +801,7 @@ class AutoTool(Tool, metaclass=ABCMeta): else: straight_tree = straight_pat_or_tree top = straight_tree.top() - straight_tree.flatten(top) + straight_tree.flatten(top, dangling_ok=True) pat.plug(straight_tree[top], pmap, append=True) if data.b_transition: pat.plug(data.b_transition.abstract, {port_names[1]: data.b_transition.our_port_name}) @@ -813,7 +813,7 @@ class AutoTool(Tool, metaclass=ABCMeta): else: sbend_tree = sbend_pat_or_tree top = sbend_tree.top() - sbend_tree.flatten(top) + sbend_tree.flatten(top, dangling_ok=True) pat.plug(sbend_tree[top], pmap, append=True, mirrored=data.jog_remaining < 0) if data.out_transition: pat.plug(data.out_transition.abstract, {port_names[1]: data.out_transition.our_port_name}) diff --git a/masque/library.py b/masque/library.py index b52da74..9e7c133 100644 --- a/masque/library.py +++ b/masque/library.py @@ -264,6 +264,7 @@ class ILibraryView(Mapping[str, 'Pattern'], metaclass=ABCMeta): self, tops: str | Sequence[str], flatten_ports: bool = False, + dangling_ok: bool = False, ) -> dict[str, 'Pattern']: """ Returns copies of all `tops` patterns with all refs @@ -276,6 +277,9 @@ class ILibraryView(Mapping[str, 'Pattern'], metaclass=ABCMeta): tops: The pattern(s) to flattern. flatten_ports: If `True`, keep ports from any referenced patterns; otherwise discard them. + dangling_ok: If `True`, no error will be thrown if any + ref points to a name which is not present in the library. + Default False. Returns: {name: flat_pattern} mapping for all flattened patterns. @@ -292,6 +296,8 @@ class ILibraryView(Mapping[str, 'Pattern'], metaclass=ABCMeta): for target in pat.refs: if target is None: continue + if dangling_ok and target not in self: + continue if target not in flattened: flatten_single(target) @@ -307,7 +313,9 @@ class ILibraryView(Mapping[str, 'Pattern'], metaclass=ABCMeta): p.ports.clear() pat.append(p) - pat.refs.clear() + for target in set(pat.refs.keys()) & set(self.keys()): + del pat.refs[target] + flattened[name] = pat for top in tops: From 1eba387b6aae0879ea0867374ee80bf5e49f1977 Mon Sep 17 00:00:00 2001 From: jan Date: Wed, 19 Nov 2025 23:14:02 -0800 Subject: [PATCH 2/5] [AutoTool / SimpleTool] allow choice between rotating or mirroring bends --- masque/builder/tools.py | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/masque/builder/tools.py b/masque/builder/tools.py index 6a58b70..9c27a41 100644 --- a/masque/builder/tools.py +++ b/masque/builder/tools.py @@ -302,6 +302,9 @@ class SimpleTool(Tool, metaclass=ABCMeta): default_out_ptype: str """ Default value for out_ptype """ + mirror_bend: bool = True + """ Whether a clockwise bend should be mirrored (vs rotated) to get a ccw bend """ + @dataclass(frozen=True, slots=True) class LData: """ Data for planL """ @@ -382,7 +385,9 @@ class SimpleTool(Tool, metaclass=ABCMeta): pat.plug(straight_tree[top], pmap, append=True) if data.ccw is not None: bend, bport_in, bport_out = self.bend - pat.plug(bend, {port_names[1]: bport_in}, mirrored=bool(data.ccw)) + mirrored = self.mirror_bend and bool(data.ccw) + inport = bport_in if (self.mirror_bend or not data.ccw) else bport_out + pat.plug(bend, {port_names[1]: inport}, mirrored=mirrored) return tree def path( @@ -463,7 +468,8 @@ class AutoTool(Tool, metaclass=ABCMeta): abstract: Abstract in_port_name: str out_port_name: str - clockwise: bool = True + clockwise: bool = True # Is in-to-out clockwise? + mirror: bool = True # Should we mirror to get the other rotation? @property def in_port(self) -> Port: @@ -658,8 +664,11 @@ class AutoTool(Tool, metaclass=ABCMeta): if data.b_transition: pat.plug(data.b_transition.abstract, {port_names[1]: data.b_transition.our_port_name}) if data.ccw is not None: - assert data.bend is not None - pat.plug(data.bend.abstract, {port_names[1]: data.bend.in_port_name}, mirrored=bool(data.ccw) == data.bend.clockwise) + bend = data.bend + assert bend is not None + mirrored = bend.mirror and (bool(data.ccw) == bend.clockwise) + inport = bend.in_port_name if (bend.mirror or bool(data.ccw) != bend.clockwise) else bend.out_port_name + pat.plug(bend.abstract, {port_names[1]: inport}, mirrored=mirrored) if data.out_transition: pat.plug(data.out_transition.abstract, {port_names[1]: data.out_transition.our_port_name}) return tree From 04905153d3fd2d058b3e3b56a692085a9d139ac1 Mon Sep 17 00:00:00 2001 From: jan Date: Wed, 19 Nov 2025 23:14:36 -0800 Subject: [PATCH 3/5] [PortPather] add some more port-related convenience functions --- masque/builder/pather_mixin.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/masque/builder/pather_mixin.py b/masque/builder/pather_mixin.py index f2b8229..79053db 100644 --- a/masque/builder/pather_mixin.py +++ b/masque/builder/pather_mixin.py @@ -537,6 +537,10 @@ class PortPather: self.pather[self.port].set_ptype(ptype) return self + def translate(self, *args, **kwargs) -> Self: + self.pather[self.port].translate(*args, **kwargs) + return self + def mirror(self, *args, **kwargs) -> Self: self.pather[self.port].mirror(*args, **kwargs) return self @@ -556,3 +560,13 @@ class PortPather: def rename_from(self, old_name: str) -> Self: self.pather.rename_ports({old_name: self.port}) return self + + def into_copy(self, new_name: str) -> Self: + self.pather.ports[new_name] = self.pather[self.port].copy() + self.port = new_name + return self + + def save_copy(self, new_name: str) -> Self: + self.pather.ports[new_name] = self.pather[self.port].copy() + return self + From 5e65dfafa10c45ec4d1b1c004b2ab23df8bc213d Mon Sep 17 00:00:00 2001 From: jan Date: Wed, 19 Nov 2025 23:14:54 -0800 Subject: [PATCH 4/5] cleanup --- masque/builder/pather_mixin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/masque/builder/pather_mixin.py b/masque/builder/pather_mixin.py index 79053db..bcf9d5e 100644 --- a/masque/builder/pather_mixin.py +++ b/masque/builder/pather_mixin.py @@ -1,4 +1,4 @@ -from typing import Self, TYPE_CHECKING +from typing import Self from collections.abc import Sequence, Iterator, Iterable import logging from contextlib import contextmanager From e75a76e5a8d7032f117ddb6b45829daa514c7b81 Mon Sep 17 00:00:00 2001 From: jan Date: Wed, 19 Nov 2025 23:15:22 -0800 Subject: [PATCH 5/5] [RenderPather.plug] fix ok_connections param --- masque/builder/renderpather.py | 1 + 1 file changed, 1 insertion(+) diff --git a/masque/builder/renderpather.py b/masque/builder/renderpather.py index 1665ed0..747a098 100644 --- a/masque/builder/renderpather.py +++ b/masque/builder/renderpather.py @@ -279,6 +279,7 @@ class RenderPather(PatherMixin): thru = thru, set_rotation = set_rotation, append = append, + ok_connections = ok_connections, ) return self