redo library class naming

This commit is contained in:
jan 2023-04-07 18:08:42 -07:00
parent c7505a12b0
commit 9c9d3c3928
13 changed files with 78 additions and 78 deletions

View File

@ -7,7 +7,7 @@ from skimage.measure import find_contours
from matplotlib import pyplot from matplotlib import pyplot
import numpy import numpy
from masque import Pattern, Library, Polygon from masque import Pattern, Polygon
from masque.file.gdsii import writefile from masque.file.gdsii import writefile
# #

View File

@ -5,14 +5,14 @@ import numpy
from numpy import pi from numpy import pi
import masque import masque
from masque import Pattern, Ref, Arc, WrapLibrary from masque import Pattern, Ref, Arc, Library
from masque.repetition import Grid from masque.repetition import Grid
from masque.file import gdsii, dxf, oasis from masque.file import gdsii, dxf, oasis
def main(): def main():
lib = WrapLibrary() lib = Library()
cell_name = 'ellip_grating' cell_name = 'ellip_grating'
pat = masque.Pattern() pat = masque.Pattern()
@ -115,7 +115,7 @@ def main():
print(f'Read back and rewrite to {dxf2}') print(f'Read back and rewrite to {dxf2}')
dxf_lib, _info = dxf.readfile(dxf1) dxf_lib, _info = dxf.readfile(dxf1)
print(WrapLibrary(dxf_lib)) print(Library(dxf_lib))
dxf.writefile(dxf_lib, 'Model', dxf2) dxf.writefile(dxf_lib, 'Model', dxf2)
layer_map = {'base': (0,0), 'mylabel': (1,2)} layer_map = {'base': (0,0), 'mylabel': (1,2)}

View File

@ -6,7 +6,7 @@ from numpy import pi
from masque import ( from masque import (
layer_t, Pattern, Ref, Label, Builder, Port, Polygon, layer_t, Pattern, Ref, Label, Builder, Port, Polygon,
WrapLibrary, Library, Library, ILibraryView,
) )
from masque.utils import ports2data from masque.utils import ports2data
from masque.file.gdsii import writefile, check_valid_names from masque.file.gdsii import writefile, check_valid_names
@ -247,7 +247,7 @@ def main(interactive: bool = True) -> None:
devices['l3cav'] = perturbed_l3(lattice_constant=a, hole='smile', hole_lib=shape_lib, xy_size=(4, 10)) # uses smile :) devices['l3cav'] = perturbed_l3(lattice_constant=a, hole='smile', hole_lib=shape_lib, xy_size=(4, 10)) # uses smile :)
# Turn our dict of devices into a Library -- useful for getting abstracts # Turn our dict of devices into a Library -- useful for getting abstracts
lib = WrapLibrary(devices) lib = Library(devices)
abv = lib.abstract_view() # lets us use abv[cell] instead of lib.abstract(cell) abv = lib.abstract_view() # lets us use abv[cell] instead of lib.abstract(cell)
# #

View File

@ -4,7 +4,7 @@ from pprint import pformat
import numpy import numpy
from numpy import pi from numpy import pi
from masque import Pattern, Builder, WrapLibrary, LazyLibrary, Library from masque import Pattern, Builder, LazyLibrary
from masque.file.gdsii import writefile, load_libraryfile from masque.file.gdsii import writefile, load_libraryfile
import pcgen import pcgen

View File

@ -35,8 +35,8 @@ from .ref import Ref
from .pattern import Pattern from .pattern import Pattern
from .library import ( from .library import (
Library, MutableLibrary, ILibraryView, ILibrary,
WrapROLibrary, WrapLibrary, LazyLibrary, LibraryView, Library, LazyLibrary,
AbstractView, AbstractView,
Tree, Tree,
) )

View File

@ -11,7 +11,7 @@ from .utils import rotation_matrix_2d, normalize_mirror
#if TYPE_CHECKING: #if TYPE_CHECKING:
# from .builder import Builder, Tool # from .builder import Builder, Tool
# from .library import MutableLibrary # from .library import ILibrary
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -44,7 +44,7 @@ class Abstract(PortList):
# def build( # def build(
# self, # self,
# library: 'MutableLibrary', # library: 'ILibrary',
# tools: 'None | Tool | MutableMapping[str | None, Tool]' = None, # tools: 'None | Tool | MutableMapping[str | None, Tool]' = None,
# ) -> 'Builder': # ) -> 'Builder':
# """ # """

View File

@ -8,7 +8,7 @@ from numpy.typing import ArrayLike
from ..pattern import Pattern from ..pattern import Pattern
from ..ref import Ref from ..ref import Ref
from ..library import MutableLibrary from ..library import ILibrary
from ..error import PortError, BuildError from ..error import PortError, BuildError
from ..ports import PortList, Port from ..ports import PortList, Port
from ..abstract import Abstract from ..abstract import Abstract
@ -79,7 +79,7 @@ class Builder(PortList):
pattern: Pattern pattern: Pattern
""" Layout of this device """ """ Layout of this device """
library: MutableLibrary | None library: ILibrary | None
""" """
Library from which existing patterns should be referenced, and to which Library from which existing patterns should be referenced, and to which
new ones should be added new ones should be added
@ -98,7 +98,7 @@ class Builder(PortList):
def __init__( def __init__(
self, self,
library: MutableLibrary | None = None, library: ILibrary | None = None,
*, *,
pattern: Pattern | None = None, pattern: Pattern | None = None,
ports: str | Mapping[str, Port] | None = None, ports: str | Mapping[str, Port] | None = None,
@ -140,7 +140,7 @@ class Builder(PortList):
cls, cls,
source: PortList | Mapping[str, Port] | str, source: PortList | Mapping[str, Port] | str,
*, *,
library: MutableLibrary | None = None, library: ILibrary | None = None,
in_prefix: str = 'in_', in_prefix: str = 'in_',
out_prefix: str = '', out_prefix: str = '',
port_map: dict[str, str] | Sequence[str] | None = None, port_map: dict[str, str] | Sequence[str] | None = None,
@ -194,7 +194,7 @@ class Builder(PortList):
names. names.
""" """
if library is None: if library is None:
if hasattr(source, 'library') and isinstance(source.library, MutableLibrary): if hasattr(source, 'library') and isinstance(source.library, ILibrary):
library = source.library library = source.library
if isinstance(source, str): if isinstance(source, str):
@ -541,7 +541,7 @@ class Pather(Builder):
""" """
__slots__ = ('tools',) __slots__ = ('tools',)
library: MutableLibrary library: ILibrary
""" """
Library from which existing patterns should be referenced, and to which Library from which existing patterns should be referenced, and to which
new ones should be added new ones should be added
@ -555,7 +555,7 @@ class Pather(Builder):
def __init__( def __init__(
self, self,
library: MutableLibrary, library: ILibrary,
*, *,
pattern: Pattern | None = None, pattern: Pattern | None = None,
ports: str | Mapping[str, Port] | None = None, ports: str | Mapping[str, Port] | None = None,
@ -599,7 +599,7 @@ class Pather(Builder):
@classmethod @classmethod
def mk( def mk(
cls, cls,
library: MutableLibrary, library: ILibrary,
name: str, name: str,
*, *,
ports: str | Mapping[str, Port] | None = None, ports: str | Mapping[str, Port] | None = None,
@ -614,7 +614,7 @@ class Pather(Builder):
cls, cls,
builder: Builder, builder: Builder,
*, *,
library: MutableLibrary | None = None, library: ILibrary | None = None,
tools: Tool | MutableMapping[str | None, Tool] | None = None, tools: Tool | MutableMapping[str | None, Tool] | None = None,
) -> 'Pather': ) -> 'Pather':
"""TODO from_builder docs""" """TODO from_builder docs"""
@ -629,7 +629,7 @@ class Pather(Builder):
cls, cls,
source: PortList | Mapping[str, Port] | str, source: PortList | Mapping[str, Port] | str,
*, *,
library: MutableLibrary | None = None, library: ILibrary | None = None,
tools: Tool | MutableMapping[str | None, Tool] | None = None, tools: Tool | MutableMapping[str | None, Tool] | None = None,
in_prefix: str = 'in_', in_prefix: str = 'in_',
out_prefix: str = '', out_prefix: str = '',
@ -640,7 +640,7 @@ class Pather(Builder):
TODO doc pather.interface TODO doc pather.interface
""" """
if library is None: if library is None:
if hasattr(source, 'library') and isinstance(source.library, MutableLibrary): if hasattr(source, 'library') and isinstance(source.library, ILibrary):
library = source.library library = source.library
else: else:
raise BuildError('No library provided (and not present in `source.library`') raise BuildError('No library provided (and not present in `source.library`')

View File

@ -105,8 +105,8 @@ class FlatBuilder(PortList):
Args: Args:
source: A collection of ports (e.g. Pattern, Builder, or dict) source: A collection of ports (e.g. Pattern, Builder, or dict)
from which to create the interface. from which to create the interface.
library: Used for buildin functions; if not passed and the source library: Used for buildin functions; if not passed and the source TODO
library: Library from which existing patterns should be referenced, library: Library from which existing patterns should be referenced, TODO
and to which new ones should be added. If not provided, and to which new ones should be added. If not provided,
the source's library will be used (if available). the source's library will be used (if available).
tools: Tool objects are used to dynamically generate new single-use tools: Tool objects are used to dynamically generate new single-use

View File

@ -18,7 +18,7 @@ from ezdxf.enums import TextEntityAlignment
from .utils import is_gzipped, tmpfile from .utils import is_gzipped, tmpfile
from .. import Pattern, Ref, PatternError, Label from .. import Pattern, Ref, PatternError, Label
from ..library import Library, WrapROLibrary, WrapLibrary from ..library import ILibraryView, LibraryView, Library
from ..shapes import Shape, Polygon, Path from ..shapes import Shape, Polygon, Path
from ..repetition import Grid from ..repetition import Grid
from ..utils import rotation_matrix_2d, layer_t from ..utils import rotation_matrix_2d, layer_t
@ -75,9 +75,9 @@ def write(
#TODO consider supporting DXF arcs? #TODO consider supporting DXF arcs?
if not isinstance(library, Library): if not isinstance(library, Library):
if isinstance(library, dict): if isinstance(library, dict):
library = WrapROLibrary(library) library = LibraryView(library)
else: else:
library = WrapROLibrary(dict(library)) library = LibraryView(dict(library))
pattern = library[top_name] pattern = library[top_name]
subtree = library.subtree(top_name) subtree = library.subtree(top_name)
@ -148,7 +148,7 @@ def readfile(
filename: str | pathlib.Path, filename: str | pathlib.Path,
*args, *args,
**kwargs, **kwargs,
) -> tuple[WrapLibrary, dict[str, Any]]: ) -> tuple[Library, dict[str, Any]]:
""" """
Wrapper for `dxf.read()` that takes a filename or path instead of a stream. Wrapper for `dxf.read()` that takes a filename or path instead of a stream.
@ -172,7 +172,7 @@ def readfile(
def read( def read(
stream: TextIO, stream: TextIO,
) -> tuple[WrapLibrary, dict[str, Any]]: ) -> tuple[Library, dict[str, Any]]:
""" """
Read a dxf file and translate it into a dict of `Pattern` objects. DXF `Block`s are Read a dxf file and translate it into a dict of `Pattern` objects. DXF `Block`s are
translated into `Pattern` objects; `LWPolyline`s are translated into polygons, and `Insert`s translated into `Pattern` objects; `LWPolyline`s are translated into polygons, and `Insert`s
@ -190,7 +190,7 @@ def read(
msp = lib.modelspace() msp = lib.modelspace()
top_name, top_pat = _read_block(msp) top_name, top_pat = _read_block(msp)
mlib = WrapLibrary({top_name: top_pat}) mlib = Library({top_name: top_pat})
for bb in lib.blocks: for bb in lib.blocks:
if bb.name == '*Model_Space': if bb.name == '*Model_Space':
continue continue

View File

@ -38,7 +38,7 @@ from .. import Pattern, Ref, PatternError, LibraryError, Label, Shape
from ..shapes import Polygon, Path from ..shapes import Polygon, Path
from ..repetition import Grid from ..repetition import Grid
from ..utils import layer_t, normalize_mirror, annotations_t from ..utils import layer_t, normalize_mirror, annotations_t
from ..library import LazyLibrary, WrapLibrary, MutableLibrary, Library from ..library import LazyLibrary, Library, ILibrary, ILibraryView
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -97,11 +97,11 @@ def write(
library_name: Library name written into the GDSII file. library_name: Library name written into the GDSII file.
Default 'masque-klamath'. Default 'masque-klamath'.
""" """
if not isinstance(library, MutableLibrary): if not isinstance(library, ILibrary):
if isinstance(library, dict): if isinstance(library, dict):
library = WrapLibrary(library) library = Library(library)
else: else:
library = WrapLibrary(dict(library)) library = Library(dict(library))
# Create library # Create library
header = klamath.library.FileHeader( header = klamath.library.FileHeader(
@ -160,7 +160,7 @@ def readfile(
filename: str | pathlib.Path, filename: str | pathlib.Path,
*args, *args,
**kwargs, **kwargs,
) -> tuple[WrapLibrary, dict[str, Any]]: ) -> tuple[Library, dict[str, Any]]:
""" """
Wrapper for `read()` that takes a filename or path instead of a stream. Wrapper for `read()` that takes a filename or path instead of a stream.
@ -185,7 +185,7 @@ def readfile(
def read( def read(
stream: IO[bytes], stream: IO[bytes],
raw_mode: bool = True, raw_mode: bool = True,
) -> tuple[WrapLibrary, dict[str, Any]]: ) -> tuple[Library, dict[str, Any]]:
""" """
# TODO check GDSII file for cycles! # TODO check GDSII file for cycles!
Read a gdsii file and translate it into a dict of Pattern objects. GDSII structures are Read a gdsii file and translate it into a dict of Pattern objects. GDSII structures are
@ -208,7 +208,7 @@ def read(
""" """
library_info = _read_header(stream) library_info = _read_header(stream)
mlib = WrapLibrary() mlib = Library()
found_struct = records.BGNSTR.skip_past(stream) found_struct = records.BGNSTR.skip_past(stream)
while found_struct: while found_struct:
name = records.STRNAME.skip_and_read(stream) name = records.STRNAME.skip_and_read(stream)
@ -511,7 +511,7 @@ def load_library(
stream: IO[bytes], stream: IO[bytes],
*, *,
full_load: bool = False, full_load: bool = False,
postprocess: Callable[[Library, str, Pattern], Pattern] | None = None postprocess: Callable[[ILibraryView, str, Pattern], Pattern] | None = None
) -> tuple[LazyLibrary, dict[str, Any]]: ) -> tuple[LazyLibrary, dict[str, Any]]:
""" """
Scan a GDSII stream to determine what structures are present, and create Scan a GDSII stream to determine what structures are present, and create
@ -571,7 +571,7 @@ def load_libraryfile(
*, *,
use_mmap: bool = True, use_mmap: bool = True,
full_load: bool = False, full_load: bool = False,
postprocess: Callable[[Library, str, Pattern], Pattern] | None = None postprocess: Callable[[ILibraryView, str, Pattern], Pattern] | None = None
) -> tuple[LazyLibrary, dict[str, Any]]: ) -> tuple[LazyLibrary, dict[str, Any]]:
""" """
Wrapper for `load_library()` that takes a filename or path instead of a stream. Wrapper for `load_library()` that takes a filename or path instead of a stream.

View File

@ -29,7 +29,7 @@ from fatamorgana.basic import PathExtensionScheme, AString, NString, PropStringR
from .utils import is_gzipped, tmpfile from .utils import is_gzipped, tmpfile
from .. import Pattern, Ref, PatternError, LibraryError, Label, Shape from .. import Pattern, Ref, PatternError, LibraryError, Label, Shape
from ..library import WrapLibrary, MutableLibrary from ..library import Library, ILibrary
from ..shapes import Polygon, Path, Circle from ..shapes import Polygon, Path, Circle
from ..repetition import Grid, Arbitrary, Repetition from ..repetition import Grid, Arbitrary, Repetition
from ..utils import layer_t, normalize_mirror, annotations_t from ..utils import layer_t, normalize_mirror, annotations_t
@ -98,11 +98,11 @@ def build(
Returns: Returns:
`fatamorgana.OasisLayout` `fatamorgana.OasisLayout`
""" """
if not isinstance(library, MutableLibrary): if not isinstance(library, ILibrary):
if isinstance(library, dict): if isinstance(library, dict):
library = WrapLibrary(library) library = Library(library)
else: else:
library = WrapLibrary(dict(library)) library = Library(dict(library))
if layer_map is None: if layer_map is None:
layer_map = {} layer_map = {}
@ -205,7 +205,7 @@ def readfile(
filename: str | pathlib.Path, filename: str | pathlib.Path,
*args, *args,
**kwargs, **kwargs,
) -> tuple[WrapLibrary, dict[str, Any]]: ) -> tuple[Library, dict[str, Any]]:
""" """
Wrapper for `oasis.read()` that takes a filename or path instead of a stream. Wrapper for `oasis.read()` that takes a filename or path instead of a stream.
@ -229,7 +229,7 @@ def readfile(
def read( def read(
stream: IO[bytes], stream: IO[bytes],
) -> tuple[WrapLibrary, dict[str, Any]]: ) -> tuple[Library, dict[str, Any]]:
""" """
Read a OASIS file and translate it into a dict of Pattern objects. OASIS cells are Read a OASIS file and translate it into a dict of Pattern objects. OASIS cells are
translated into Pattern objects; Polygons are translated into polygons, and Placements translated into Pattern objects; Polygons are translated into polygons, and Placements
@ -260,7 +260,7 @@ def read(
layer_map[str(layer_name.nstring)] = layer_name layer_map[str(layer_name.nstring)] = layer_name
library_info['layer_map'] = layer_map library_info['layer_map'] = layer_map
mlib = WrapLibrary() mlib = Library()
for cell in lib.cells: for cell in lib.cells:
if isinstance(cell.name, int): if isinstance(cell.name, int):
cell_name = lib.cellnames[cell.name].nstring.string cell_name = lib.cellnames[cell.name].nstring.string

View File

@ -35,7 +35,7 @@ logger = logging.getLogger(__name__)
visitor_function_t = Callable[..., 'Pattern'] visitor_function_t = Callable[..., 'Pattern']
def _rename_patterns(lib: 'Library', name: str) -> str: def _rename_patterns(lib: 'ILibraryView', name: str) -> str:
# TODO document rename function # TODO document rename function
if not name.startswith('_'): if not name.startswith('_'):
return name return name
@ -44,7 +44,7 @@ def _rename_patterns(lib: 'Library', name: str) -> str:
return lib.get_name(stem) return lib.get_name(stem)
class Library(Mapping[str, 'Pattern'], metaclass=ABCMeta): class ILibraryView(Mapping[str, 'Pattern'], metaclass=ABCMeta):
# inherited abstract functions # inherited abstract functions
#def __getitem__(self, key: str) -> 'Pattern': #def __getitem__(self, key: str) -> 'Pattern':
#def __iter__(self) -> Iterator[str]: #def __iter__(self) -> Iterator[str]:
@ -68,7 +68,7 @@ class Library(Mapping[str, 'Pattern'], metaclass=ABCMeta):
return Abstract(name=name, ports=self[name].ports) return Abstract(name=name, ports=self[name].ports)
def __repr__(self) -> str: def __repr__(self) -> str:
return '<Library with keys\n' + pformat(list(self.keys())) + '>' return '<ILibraryView with keys\n' + pformat(list(self.keys())) + '>'
def dangling_refs( def dangling_refs(
self, self,
@ -138,9 +138,9 @@ class Library(Mapping[str, 'Pattern'], metaclass=ABCMeta):
def subtree( def subtree(
self, self,
tops: str | Sequence[str], tops: str | Sequence[str],
) -> 'Library': ) -> 'ILibraryView':
""" """
Return a new `Library`, containing only the specified patterns and the patterns they Return a new `ILibraryView`, containing only the specified patterns and the patterns they
reference (recursively). reference (recursively).
Dangling references do not cause an error. Dangling references do not cause an error.
@ -148,7 +148,7 @@ class Library(Mapping[str, 'Pattern'], metaclass=ABCMeta):
tops: Name(s) of patterns to keep tops: Name(s) of patterns to keep
Returns: Returns:
A `WrapROLibrary` containing only `tops` and the patterns they reference. A `LibraryView` containing only `tops` and the patterns they reference.
""" """
if isinstance(tops, str): if isinstance(tops, str):
tops = (tops,) tops = (tops,)
@ -157,7 +157,7 @@ class Library(Mapping[str, 'Pattern'], metaclass=ABCMeta):
keep |= set(tops) keep |= set(tops)
filtered = {kk: vv for kk, vv in self.items() if kk in keep} filtered = {kk: vv for kk, vv in self.items() if kk in keep}
new = WrapROLibrary(filtered) new = LibraryView(filtered)
return new return new
def polygonize( def polygonize(
@ -415,19 +415,19 @@ class Library(Mapping[str, 'Pattern'], metaclass=ABCMeta):
if pattern is not original_pattern: if pattern is not original_pattern:
name = hierarchy[-1] # TODO what is name=None? name = hierarchy[-1] # TODO what is name=None?
if not isinstance(self, MutableLibrary): if not isinstance(self, ILibrary):
raise LibraryError('visit_* functions returned a new `Pattern` object' raise LibraryError('visit_* functions returned a new `Pattern` object'
' but the library is immutable') ' but the library is immutable')
if name is None: if name is None:
raise LibraryError('visit_* functions returned a new `Pattern` object' raise LibraryError('visit_* functions returned a new `Pattern` object'
' but no top-level name was provided in `hierarchy`') ' but no top-level name was provided in `hierarchy`')
cast(MutableLibrary, self)[name] = pattern cast(ILibrary, self)[name] = pattern
return self return self
class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta): class ILibrary(ILibraryView, MutableMapping[str, 'Pattern'], metaclass=ABCMeta):
# inherited abstract functions # inherited abstract functions
#def __getitem__(self, key: str) -> 'Pattern': #def __getitem__(self, key: str) -> 'Pattern':
#def __iter__(self) -> Iterator[str]: #def __iter__(self) -> Iterator[str]:
@ -510,7 +510,7 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
def add( def add(
self, self,
other: Mapping[str, 'Pattern'], other: Mapping[str, 'Pattern'],
rename_theirs: Callable[['Library', str], str] = _rename_patterns, rename_theirs: Callable[['ILibraryView', str], str] = _rename_patterns,
) -> dict[str, str]: ) -> dict[str, str]:
""" """
Add keys from another library into this one. Add keys from another library into this one.
@ -534,7 +534,7 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
self._merge(key, other, key) self._merge(key, other, key)
return {} return {}
temp = WrapLibrary(copy.deepcopy(dict(other))) # TODO maybe add a `mutate` arg? Might want to keep the same patterns temp = Library(copy.deepcopy(dict(other))) # TODO maybe add a `mutate` arg? Might want to keep the same patterns
rename_map = {} rename_map = {}
for old_name in temp: for old_name in temp:
if old_name in self: if old_name in self:
@ -559,13 +559,13 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
self, self,
tree: 'Tree', tree: 'Tree',
name: str | None = None, name: str | None = None,
rename_theirs: Callable[['Library', str], str] = _rename_patterns, rename_theirs: Callable[['ILibraryView', str], str] = _rename_patterns,
) -> str: ) -> str:
""" """
Add a `Tree` object into the current library. Add a `Tree` object into the current library.
Args: Args:
tree: The `Tree` object (a `Library` with a specified `top` Pattern) tree: The `Tree` object (an `ILibraryView` with a specified `top` Pattern)
which will be added into the current library. which will be added into the current library.
name: New name for the top-level pattern. If not given, `tree.top` is used. name: New name for the top-level pattern. If not given, `tree.top` is used.
rename_theirs: Called as rename_theirs(self, name) for each duplicate name rename_theirs: Called as rename_theirs(self, name) for each duplicate name
@ -593,8 +593,8 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
if len(other) == 1: if len(other) == 1:
name = next(iter(other)) name = next(iter(other))
else: else:
if not isinstance(other, Library): if not isinstance(other, ILibraryView):
other = WrapROLibrary(other) other = LibraryView(other)
tops = other.tops() tops = other.tops()
if len(tops) > 1: if len(tops) > 1:
@ -764,7 +764,7 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
tops: str | Sequence[str], tops: str | Sequence[str],
) -> Self: ) -> Self:
""" """
Return a new `Library`, containing only the specified patterns and the patterns they Return a new `ILibraryView`, containing only the specified patterns and the patterns they
reference (recursively). reference (recursively).
Dangling references do not cause an error. Dangling references do not cause an error.
@ -772,7 +772,7 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
tops: Name(s) of patterns to keep tops: Name(s) of patterns to keep
Returns: Returns:
A `Library` containing only `tops` and the patterns they reference. An object of the same type as `self` containing only `tops` and the patterns they reference.
""" """
if isinstance(tops, str): if isinstance(tops, str):
tops = (tops,) tops = (tops,)
@ -815,7 +815,7 @@ class MutableLibrary(Library, MutableMapping[str, 'Pattern'], metaclass=ABCMeta)
return self return self
class WrapROLibrary(Library): class LibraryView(ILibraryView):
mapping: Mapping[str, 'Pattern'] mapping: Mapping[str, 'Pattern']
def __init__( def __init__(
@ -837,10 +837,10 @@ class WrapROLibrary(Library):
return key in self.mapping return key in self.mapping
def __repr__(self) -> str: def __repr__(self) -> str:
return f'<WrapROLibrary ({type(self.mapping)}) with keys\n' + pformat(list(self.keys())) + '>' return f'<LibraryView ({type(self.mapping)}) with keys\n' + pformat(list(self.keys())) + '>'
class WrapLibrary(MutableLibrary): class Library(ILibrary):
mapping: MutableMapping[str, 'Pattern'] mapping: MutableMapping[str, 'Pattern']
def __init__( def __init__(
@ -885,10 +885,10 @@ class WrapLibrary(MutableLibrary):
self[key_self] = other[key_other] self[key_self] = other[key_other]
def __repr__(self) -> str: def __repr__(self) -> str:
return f'<WrapLibrary ({type(self.mapping)}) with keys\n' + pformat(list(self.keys())) + '>' return f'<Library ({type(self.mapping)}) with keys\n' + pformat(list(self.keys())) + '>'
class LazyLibrary(MutableLibrary): class LazyLibrary(ILibrary):
""" """
This class is usually used to create a library of Patterns by mapping names to This class is usually used to create a library of Patterns by mapping names to
functions which generate or load the relevant `Pattern` object as-needed. functions which generate or load the relevant `Pattern` object as-needed.
@ -1027,9 +1027,9 @@ class LazyLibrary(MutableLibrary):
class AbstractView(Mapping[str, Abstract]): class AbstractView(Mapping[str, Abstract]):
library: Library library: ILibraryView
def __init__(self, library: Library) -> None: def __init__(self, library: ILibraryView) -> None:
self.library = library self.library = library
def __getitem__(self, key: str) -> Abstract: def __getitem__(self, key: str) -> Abstract:
@ -1042,9 +1042,9 @@ class AbstractView(Mapping[str, Abstract]):
return self.library.__len__() return self.library.__len__()
class Tree(MutableLibrary): class Tree(ILibrary):
top: str top: str
library: MutableLibrary library: ILibrary
@property @property
def pattern(self) -> 'Pattern': def pattern(self) -> 'Pattern':
@ -1053,10 +1053,10 @@ class Tree(MutableLibrary):
def __init__( def __init__(
self, self,
top: str, top: str,
library: MutableLibrary | None = None library: ILibrary | None = None
) -> None: ) -> None:
self.top = top self.top = top
self.library = library if library is not None else WrapLibrary() self.library = library if library is not None else Library()
@classmethod @classmethod
def mk(cls, top: str) -> tuple['Tree', 'Pattern']: def mk(cls, top: str) -> tuple['Tree', 'Pattern']:

View File

@ -16,7 +16,7 @@ from ..label import Label
from ..utils import layer_t from ..utils import layer_t
from ..ports import Port from ..ports import Port
from ..error import PatternError from ..error import PatternError
from ..library import Library, WrapROLibrary from ..library import ILibraryView, LibraryView
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
@ -88,8 +88,8 @@ def data_to_ports(
logger.warning(f'Pattern {name if name else pattern} already had ports, skipping data_to_ports') logger.warning(f'Pattern {name if name else pattern} already had ports, skipping data_to_ports')
return pattern return pattern
if not isinstance(library, Library): if not isinstance(library, ILibraryView):
library = WrapROLibrary(library) library = LibraryView(library)
data_to_ports_flat(layers, pattern, name) data_to_ports_flat(layers, pattern, name)
if (skip_subcells and pattern.ports) or max_depth == 0: if (skip_subcells and pattern.ports) or max_depth == 0: