[library / gdsii] cleanup using new library rework
This commit is contained in:
parent
ddb7742493
commit
7b589e4f44
14 changed files with 696 additions and 391 deletions
|
|
@ -378,12 +378,20 @@ class ILibraryView(Mapping[str, 'Pattern'], INameView, metaclass=ABCMeta):
|
|||
dangling_list = sorted(dangling)
|
||||
return LibraryError(f'Dangling refs found while {context}: ' + pformat(dangling_list))
|
||||
|
||||
def _raw_children(self, name: str) -> set[str]:
|
||||
"""Return direct, non-empty named references for one pattern."""
|
||||
return {
|
||||
child
|
||||
for child, refs in self[name].refs.items()
|
||||
if child is not None and refs
|
||||
}
|
||||
|
||||
def _raw_child_graph(self) -> tuple[dict[str, set[str]], set[str]]:
|
||||
existing = set(self.keys())
|
||||
graph: dict[str, set[str]] = {}
|
||||
dangling: set[str] = set()
|
||||
for name, pat in self.items():
|
||||
children = {child for child, refs in pat.refs.items() if child is not None and refs}
|
||||
for name in self:
|
||||
children = self._raw_children(name)
|
||||
graph[name] = children
|
||||
dangling |= children - existing
|
||||
return graph, dangling
|
||||
|
|
@ -626,11 +634,18 @@ class ILibraryView(Mapping[str, 'Pattern'], INameView, metaclass=ABCMeta):
|
|||
for parent in parent_graph.get(name, set()):
|
||||
if parent not in self: # parent_graph may be a for a superset of self
|
||||
continue
|
||||
for ref in self[parent].refs[name]:
|
||||
instances[parent].append(ref.as_transforms())
|
||||
instances[parent].extend(self._raw_ref_transforms(parent, name))
|
||||
|
||||
return instances
|
||||
|
||||
def _raw_ref_transforms(
|
||||
self,
|
||||
parent: str,
|
||||
target: str,
|
||||
) -> list[NDArray[numpy.float64]]:
|
||||
"""Return local transforms from one parent to one target."""
|
||||
return [ref.as_transforms() for ref in self[parent].refs.get(target, ())]
|
||||
|
||||
def find_refs_global(
|
||||
self,
|
||||
name: str,
|
||||
|
|
|
|||
|
|
@ -40,3 +40,12 @@ class IBorrowing(ABC):
|
|||
@abstractmethod
|
||||
def borrowed_sources(self) -> tuple[ILibraryView, ...]:
|
||||
"""Return the source views directly borrowed by this library."""
|
||||
|
||||
def source_cell(self, name: str) -> tuple[ILibraryView, str] | None: # noqa: ARG002
|
||||
"""
|
||||
Return a direct source cell with unchanged layout data, if available.
|
||||
|
||||
The source may use a different name, which is returned alongside it.
|
||||
Port metadata may differ because ports are not layout-file content.
|
||||
"""
|
||||
return None
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from pprint import pformat
|
||||
from typing import TYPE_CHECKING, Any, Self, cast
|
||||
from typing import TYPE_CHECKING, Self
|
||||
|
||||
from ..error import LibraryError
|
||||
from .base import ILibrary, ILibraryView
|
||||
|
|
@ -70,9 +70,6 @@ class _SubtreeLibraryView(ILibraryView, IMaterializable, IBorrowing):
|
|||
name: set(child_graph.get(name, set()))
|
||||
for name in self._order
|
||||
}
|
||||
if hasattr(source, 'library_info'):
|
||||
self.library_info = cast('dict[str, Any]', source.library_info)
|
||||
|
||||
def __getitem__(self, key: str) -> Pattern:
|
||||
if key not in self._names:
|
||||
raise KeyError(key)
|
||||
|
|
@ -90,6 +87,11 @@ class _SubtreeLibraryView(ILibraryView, IMaterializable, IBorrowing):
|
|||
def borrowed_sources(self) -> tuple[ILibraryView, ...]:
|
||||
return (self._source,)
|
||||
|
||||
def source_cell(self, name: str) -> tuple[ILibraryView, str] | None:
|
||||
if name not in self._names:
|
||||
return None
|
||||
return self._source, name
|
||||
|
||||
def source_order(self) -> tuple[str, ...]:
|
||||
return self._order
|
||||
|
||||
|
|
@ -134,21 +136,6 @@ class _SubtreeLibraryView(ILibraryView, IMaterializable, IBorrowing):
|
|||
refs = self._source.find_refs_local(name, parent_graph=parent_graph, dangling=dangling)
|
||||
return {parent: transforms for parent, transforms in refs.items() if parent in self._names}
|
||||
|
||||
def raw_struct_bytes(self, name: str) -> bytes:
|
||||
if name not in self._names:
|
||||
raise KeyError(name)
|
||||
reader = getattr(self._source, 'raw_struct_bytes', None)
|
||||
if not callable(reader):
|
||||
raise TypeError('raw_struct_bytes')
|
||||
return cast('bytes', reader(name))
|
||||
|
||||
def can_copy_raw_struct(self, name: str) -> bool:
|
||||
if name not in self._names:
|
||||
return False
|
||||
can_copy = getattr(self._source, 'can_copy_raw_struct', None)
|
||||
return bool(callable(can_copy) and can_copy(name))
|
||||
|
||||
|
||||
class Library(ILibrary):
|
||||
"""
|
||||
Default implementation for a writeable library.
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ from __future__ import annotations
|
|||
|
||||
from collections import defaultdict
|
||||
from dataclasses import dataclass
|
||||
from typing import TYPE_CHECKING, Any, Literal, Self, cast
|
||||
from typing import TYPE_CHECKING, Literal, Self, cast
|
||||
import copy
|
||||
|
||||
from ..error import LibraryError
|
||||
|
|
@ -53,9 +53,9 @@ class PortsLibraryView(ILibraryView, IMaterializable, IBorrowing):
|
|||
The view borrows its source: callers must keep the source open for the
|
||||
lifetime of the view and close the source themselves.
|
||||
|
||||
Graph queries, source ordering, and copy-through capabilities are delegated
|
||||
to the wrapped source whenever possible, while `__getitem__` and
|
||||
`materialize_many()` return port-imported patterns.
|
||||
Graph queries and source ordering are delegated to the wrapped source,
|
||||
while `source_cell()` exposes unchanged layout provenance and `__getitem__`
|
||||
and `materialize_many()` return port-imported patterns.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
|
|
@ -79,9 +79,6 @@ class PortsLibraryView(ILibraryView, IMaterializable, IBorrowing):
|
|||
self._replace = replace
|
||||
self._cache: dict[str, Pattern] = {}
|
||||
self._lookups_in_progress: list[str] = []
|
||||
if hasattr(source, 'library_info'):
|
||||
self.library_info = cast('dict[str, Any]', source.library_info)
|
||||
|
||||
def __getitem__(self, key: str) -> Pattern:
|
||||
return self.materialize(key, persist=True)
|
||||
|
||||
|
|
@ -139,6 +136,11 @@ class PortsLibraryView(ILibraryView, IMaterializable, IBorrowing):
|
|||
def borrowed_sources(self) -> tuple[ILibraryView, ...]:
|
||||
return (self._source,)
|
||||
|
||||
def source_cell(self, name: str) -> tuple[ILibraryView, str] | None:
|
||||
if name not in self._source or name in self._cache:
|
||||
return None
|
||||
return self._source, name
|
||||
|
||||
def child_graph(
|
||||
self,
|
||||
dangling: dangling_mode_t = 'error',
|
||||
|
|
@ -158,21 +160,6 @@ class PortsLibraryView(ILibraryView, IMaterializable, IBorrowing):
|
|||
return cast('dict[str, list[NDArray[numpy.float64]]]', finder(name, parent_graph=parent_graph, dangling=dangling))
|
||||
return super().find_refs_local(name, parent_graph=parent_graph, dangling=dangling)
|
||||
|
||||
def raw_struct_bytes(self, name: str) -> bytes:
|
||||
reader = getattr(self._source, 'raw_struct_bytes', None)
|
||||
if not callable(reader):
|
||||
raise TypeError('raw_struct_bytes')
|
||||
return cast('bytes', reader(name))
|
||||
|
||||
def can_copy_raw_struct(self, name: str) -> bool:
|
||||
if name in self._cache:
|
||||
return False
|
||||
can_copy = getattr(self._source, 'can_copy_raw_struct', None)
|
||||
if not callable(can_copy):
|
||||
return False
|
||||
return bool(can_copy(name))
|
||||
|
||||
|
||||
class OverlayLibrary(ILibrary, IMaterializable, IBorrowing):
|
||||
"""
|
||||
Mutable overlay over one or more source libraries.
|
||||
|
|
@ -434,23 +421,12 @@ class OverlayLibrary(ILibrary, IMaterializable, IBorrowing):
|
|||
def borrowed_sources(self) -> tuple[ILibraryView, ...]:
|
||||
return tuple(layer.library for layer in self._layers)
|
||||
|
||||
def can_copy_raw_struct(self, name: str) -> bool:
|
||||
entry = self._entries.get(name)
|
||||
if not isinstance(entry, _SourceEntry) or name != entry.source_name:
|
||||
return False
|
||||
layer = self._layers[entry.layer_index]
|
||||
can_copy = getattr(layer.library, 'can_copy_raw_struct', None)
|
||||
if not callable(can_copy) or not can_copy(entry.source_name):
|
||||
return False
|
||||
children = layer.child_graph.get(entry.source_name, set())
|
||||
return all(self._effective_target(layer, child) == child for child in children)
|
||||
|
||||
def raw_struct_bytes(self, name: str) -> bytes:
|
||||
def source_cell(self, name: str) -> tuple[ILibraryView, str] | None:
|
||||
entry = self._entries.get(name)
|
||||
if not isinstance(entry, _SourceEntry):
|
||||
raise TypeError('raw_struct_bytes')
|
||||
return None
|
||||
layer = self._layers[entry.layer_index]
|
||||
reader = getattr(layer.library, 'raw_struct_bytes', None)
|
||||
if not callable(reader):
|
||||
raise TypeError('raw_struct_bytes')
|
||||
return cast('bytes', reader(entry.source_name))
|
||||
children = layer.child_graph.get(entry.source_name, set())
|
||||
if any(self._effective_target(layer, child) != child for child in children):
|
||||
return None
|
||||
return layer.library, entry.source_name
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue