multiple bugfixes for ordering

ordering
jan 4 weeks ago
parent 1b07a50e4a
commit 70a9c2a8ef

@ -1,12 +1,13 @@
"""
Helper functions for file reading and writing
"""
from typing import IO, Iterator
from typing import IO, Iterator, Mapping
import re
import pathlib
import logging
import tempfile
import shutil
from collections import defaultdict
from contextlib import contextmanager
from pprint import pformat
from itertools import chain
@ -24,6 +25,7 @@ def preflight(
allow_dangling_refs: bool | None = None,
allow_named_layers: bool = True,
prune_empty_patterns: bool = False,
wrap_repeated_shapes: bool = False,
) -> Library:
"""
Run a standard set of useful operations and checks, usually done immediately prior
@ -38,37 +40,45 @@ def preflight(
allow_named_layers: If `False`, raises a `PatternError` if any layer is referred to by
a string instead of a number (or tuple).
prune_empty_patterns: Runs `Library.prune_empty()`, recursively deleting any empty patterns.
wrap_repeated_shapes: Runs `Library.wrap_repeated_shapes()`, turning repeated shapes into
repeated refs containing non-repeated shapes.
Returns:
`lib` or an equivalent sorted library
"""
if sort:
lib = Library(dict(sorted(
(nn: pp.sort()) for nn, pp in lib.items()
(nn, pp.sort()) for nn, pp in lib.items()
)))
if not allow_dangling_refs:
refs = lib.referenced_patterns()
dangling = refs - set(lib.keys())
msg = 'Dangling refs in found: ' + pformat(dangling)
if allow_dangling_refs is None:
logger.warning(msg)
else:
raise LibraryError(msg)
if dangling:
msg = 'Dangling refs in found: ' + pformat(dangling)
if allow_dangling_refs is None:
logger.warning(msg)
else:
raise LibraryError(msg)
if not allow_named_layers:
named_layers = defaultdict(set)
named_layers: Mapping[str, set] = defaultdict(set)
for name, pat in lib.items():
for layer in chain(pat.shapes.keys(), pat.labels.keys()):
if isinstance(layer, str):
named_layers[name].add(layer)
raise PatternError('Non-numeric layers found:' + pformat(named_layers))
named_layers = dict(named_layers)
if named_layers:
raise PatternError('Non-numeric layers found:' + pformat(named_layers))
if prune_empty_patterns:
pruned = lib.prune_empty()
logger.info(f'Preflight pruned {len(pruned)} empty patterns')
logger.debug('Pruned: ' + pformat(pruned))
if wrap_repeated_shapes:
lib.wrap_repeated_shapes()
return lib

@ -247,6 +247,9 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
return False
def __eq__(self, other: Any) -> bool:
if type(self) is not type(other):
return False
self_nonempty_targets = [target for target, reflist in self.refs.items() if reflist]
other_nonempty_targets = [target for target, reflist in self.refs.items() if reflist]
self_tgtkeys = tuple(sorted((target is None, target) for target in self_nonempty_targets))
@ -305,16 +308,16 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
Returns:
self
"""
self.refs = dict(sorted(
self.refs = defaultdict(list, sorted(
(tgt, sorted(rrs)) for tgt, rrs in self.refs.items()
))
self.labels = dict(sorted(
(layer, sorted(lls)) for layer, lls in self.labels.items(),
key=lambda kk, vv: layer2key(ll),
self.labels = defaultdict(list, sorted(
((layer, sorted(lls)) for layer, lls in self.labels.items()),
key=lambda tt: layer2key(tt[0]),
))
self.shapes = dict(sorted(
(layer, sorted(sss)) for layer, sss in self.shapes.items(),
key=lambda kk, vv: layer2key(ll),
self.shapes = defaultdict(list, sorted(
((layer, sorted(sss)) for layer, sss in self.shapes.items()),
key=lambda tt: layer2key(tt[0]),
))
self.ports = dict(sorted(self.ports.items()))
@ -1217,7 +1220,7 @@ class Pattern(PortList, AnnotatableImpl, Mirrorable):
ports specified by `map_out`.
Examples:
=========
======list, ===
- `my_pat.plug(subdevice, {'A': 'C', 'B': 'B'}, map_out={'D': 'myport'})`
instantiates `subdevice` into `my_pat`, plugging ports 'A' and 'B'
of `my_pat` into ports 'C' and 'B' of `subdevice`. The connected ports

@ -135,7 +135,7 @@ class Port(PositionableImpl, Rotatable, PivotableImpl, Copyable, Mirrorable):
def __eq__(self, other: Any) -> bool:
return (
type(self) == type(other)
type(self) is type(other)
and self.ptype == other.ptype
and numpy.array_equal(self.offset, other.offset)
and self.rotation == other.rotation

@ -280,7 +280,7 @@ class Grid(Repetition):
return (f'<Grid {self.a_count}x{self.b_count} ({self.a_vector}{bv})>')
def __eq__(self, other: Any) -> bool:
if type(other) != type(self):
if type(other) is not type(self):
return False
if self.a_count != other.a_count or self.b_count != other.b_count:
return False
@ -295,7 +295,7 @@ class Grid(Repetition):
return True
def __le__(self, other: Repetition) -> bool:
if type(self) != type(other):
if type(self) is not type(other):
return repr(type(self)) < repr(type(other))
other = cast(Grid, other)
if self.a_count != other.a_count:
@ -353,12 +353,12 @@ class Arbitrary(Repetition):
return (f'<Arbitrary {len(self.displacements)}pts >')
def __eq__(self, other: Any) -> bool:
if not type(other) != type(self):
if not type(other) is not type(self):
return False
return numpy.array_equal(self.displacements, other.displacements)
def __le__(self, other: Repetition) -> bool:
if type(self) != type(other):
if type(self) is not type(other):
return repr(type(self)) < repr(type(other))
other = cast(Arbitrary, other)
if self.displacements.size != other.displacements.size:

@ -191,7 +191,7 @@ class Arc(Shape):
def __eq__(self, other: Any) -> bool:
return (
type(self) != type(other)
type(self) is type(other)
and numpy.array_equal(self.offset, other.offset)
and numpy.array_equal(self.radii, other.radii)
and numpy.array_equal(self.angles, other.angles)
@ -202,8 +202,10 @@ class Arc(Shape):
)
def __lt__(self, other: Shape) -> bool:
if type(self) != type(other):
return repr(type(self)) < repr(type(other))
if type(self) is not type(other):
if repr(type(self)) != repr(type(other)):
return repr(type(self)) < repr(type(other))
return id(type(self)) < id(type(other))
other = cast(Arc, other)
if self.width != other.width:
return self.width < other.width

@ -72,7 +72,7 @@ class Circle(Shape):
def __eq__(self, other: Any) -> bool:
return (
type(self) != type(other)
type(self) is type(other)
and numpy.array_equal(self.offset, other.offset)
and self.radius == other.radius
and self.repetition == other.repetition
@ -80,8 +80,10 @@ class Circle(Shape):
)
def __lt__(self, other: Shape) -> bool:
if type(self) != type(other):
return repr(type(self)) < repr(type(other))
if type(self) is not type(other):
if repr(type(self)) != repr(type(other)):
return repr(type(self)) < repr(type(other))
return id(type(self)) < id(type(other))
other = cast(Circle, other)
if not self.radius == other.radius:
return self.radius < other.radius

@ -121,7 +121,7 @@ class Ellipse(Shape):
def __eq__(self, other: Any) -> bool:
return (
type(self) != type(other)
type(self) is type(other)
and numpy.array_equal(self.offset, other.offset)
and numpy.array_equal(self.radii, other.radii)
and self.rotation == other.rotation
@ -130,8 +130,10 @@ class Ellipse(Shape):
)
def __lt__(self, other: Shape) -> bool:
if type(self) != type(other):
return repr(type(self)) < repr(type(other))
if type(self) is not type(other):
if repr(type(self)) != repr(type(other)):
return repr(type(self)) < repr(type(other))
return id(type(self)) < id(type(other))
other = cast(Ellipse, other)
if not numpy.array_equal(self.radii, other.radii):
return tuple(self.radii) < tuple(other.radii)

@ -209,7 +209,7 @@ class Path(Shape):
def __eq__(self, other: Any) -> bool:
return (
type(self) != type(other)
type(self) is type(other)
and numpy.array_equal(self.offset, other.offset)
and numpy.array_equal(self.vertices, other.vertices)
and self.width == other.width
@ -220,8 +220,10 @@ class Path(Shape):
)
def __lt__(self, other: Shape) -> bool:
if type(self) != type(other):
return repr(type(self)) < repr(type(other))
if type(self) is not type(other):
if repr(type(self)) != repr(type(other)):
return repr(type(self)) < repr(type(other))
return id(type(self)) < id(type(other))
other = cast(Path, other)
if self.width != other.width:
return self.width < other.width

@ -117,7 +117,7 @@ class Polygon(Shape):
def __eq__(self, other: Any) -> bool:
return (
type(self) != type(other)
type(self) is type(other)
and numpy.array_equal(self.offset, other.offset)
and numpy.array_equal(self.vertices, other.vertices)
and self.repetition == other.repetition
@ -125,8 +125,10 @@ class Polygon(Shape):
)
def __lt__(self, other: Shape) -> bool:
if type(self) != type(other):
return repr(type(self)) < repr(type(other))
if type(self) is not type(other):
if repr(type(self)) != repr(type(other)):
return repr(type(self)) < repr(type(other))
return id(type(self)) < id(type(other))
other = cast(Polygon, other)
if not numpy.array_equal(self.vertices, other.vertices):
return tuple(tuple(xy) for xy in self.vertices) < tuple(tuple(xy) for xy in other.vertices)

@ -100,7 +100,7 @@ class Text(RotatableImpl, Shape):
def __eq__(self, other: Any) -> bool:
return (
type(self) != type(other)
type(self) is type(other)
and numpy.array_equal(self.offset, other.offset)
and self.string == other.string
and self.height == other.height
@ -111,8 +111,10 @@ class Text(RotatableImpl, Shape):
)
def __lt__(self, other: Shape) -> bool:
if type(self) != type(other):
return repr(type(self)) < repr(type(other))
if type(self) is not type(other):
if repr(type(self)) != repr(type(other)):
return repr(type(self)) < repr(type(other))
return id(type(self)) < id(type(other))
other = cast(Text, other)
if not self.height == other.height:
return self.height < other.height

Loading…
Cancel
Save