[OverlayLibrary] enable renaming all cells during add_source with rename_when='always'
This commit is contained in:
parent
3dea61b05e
commit
08bbb10827
2 changed files with 58 additions and 4 deletions
|
|
@ -17,7 +17,7 @@ Both the classic and Arrow-backed lazy GDS readers rely on these helpers.
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from typing import IO, Any, cast
|
from typing import IO, Any, Literal, cast
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from collections.abc import Callable, Iterator, Mapping, Sequence
|
from collections.abc import Callable, Iterator, Mapping, Sequence
|
||||||
import copy
|
import copy
|
||||||
|
|
@ -303,7 +303,23 @@ class OverlayLibrary(ILibrary):
|
||||||
source: Mapping[str, Pattern] | ILibraryView,
|
source: Mapping[str, Pattern] | ILibraryView,
|
||||||
*,
|
*,
|
||||||
rename_theirs: Callable[[ILibraryView, str], str] | None = None,
|
rename_theirs: Callable[[ILibraryView, str], str] | None = None,
|
||||||
|
rename_when: Literal['conflict', 'always'] = 'conflict',
|
||||||
) -> dict[str, str]:
|
) -> dict[str, str]:
|
||||||
|
"""
|
||||||
|
Add a source-backed library layer.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
rename_theirs: Function used to choose visible names for imported
|
||||||
|
source cells.
|
||||||
|
rename_when: If `'conflict'`, only conflicting names are renamed.
|
||||||
|
If `'always'`, every imported source name is passed through
|
||||||
|
`rename_theirs`.
|
||||||
|
"""
|
||||||
|
if rename_when not in ('conflict', 'always'):
|
||||||
|
raise ValueError(f'Unknown source rename mode: {rename_when!r}')
|
||||||
|
if rename_when == 'always' and rename_theirs is None:
|
||||||
|
raise TypeError('rename_theirs is required when rename_when="always"')
|
||||||
|
|
||||||
view = _coerce_library_view(source)
|
view = _coerce_library_view(source)
|
||||||
source_order = list(view.source_order())
|
source_order = list(view.source_order())
|
||||||
child_graph = view.child_graph(dangling='include')
|
child_graph = view.child_graph(dangling='include')
|
||||||
|
|
@ -314,12 +330,20 @@ class OverlayLibrary(ILibrary):
|
||||||
|
|
||||||
for name in source_order:
|
for name in source_order:
|
||||||
visible = name
|
visible = name
|
||||||
if visible in self._entries or visible in visible_to_source:
|
renamed = False
|
||||||
|
if rename_when == 'always':
|
||||||
|
visible = cast('Callable[[ILibraryView, str], str]', rename_theirs)(self, name)
|
||||||
|
renamed = True
|
||||||
|
elif visible in self._entries or visible in visible_to_source:
|
||||||
if rename_theirs is None:
|
if rename_theirs is None:
|
||||||
raise LibraryError(f'Conflicting name while adding source: {name!r}')
|
raise LibraryError(f'Conflicting name while adding source: {name!r}')
|
||||||
visible = rename_theirs(self, name)
|
visible = rename_theirs(self, name)
|
||||||
|
renamed = True
|
||||||
if visible in self._entries or visible in visible_to_source:
|
if visible in self._entries or visible in visible_to_source:
|
||||||
|
if not renamed:
|
||||||
|
raise LibraryError(f'Conflicting name while adding source: {name!r}')
|
||||||
raise LibraryError(f'Unresolved duplicate key encountered while adding source: {name!r} -> {visible!r}')
|
raise LibraryError(f'Unresolved duplicate key encountered while adding source: {name!r} -> {visible!r}')
|
||||||
|
if visible != name:
|
||||||
rename_map[name] = visible
|
rename_map[name] = visible
|
||||||
source_to_visible[name] = visible
|
source_to_visible[name] = visible
|
||||||
visible_to_source[visible] = name
|
visible_to_source[visible] = name
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
import numpy
|
import numpy
|
||||||
|
import pytest
|
||||||
from numpy.testing import assert_allclose
|
from numpy.testing import assert_allclose
|
||||||
|
|
||||||
from ..file import gdsii, gdsii_lazy
|
from ..file import gdsii, gdsii_lazy
|
||||||
|
|
@ -82,6 +83,35 @@ def test_gdsii_lazy_overlay_add_source_stays_lazy_for_processed_view(tmp_path: P
|
||||||
assert set(abstract.ports) == {'A'}
|
assert set(abstract.ports) == {'A'}
|
||||||
|
|
||||||
|
|
||||||
|
def test_gdsii_lazy_overlay_add_source_can_rename_every_source_cell() -> None:
|
||||||
|
src = _make_lazy_port_library()
|
||||||
|
overlay = gdsii_lazy.OverlayLibrary()
|
||||||
|
|
||||||
|
rename_map = overlay.add_source(
|
||||||
|
src,
|
||||||
|
rename_theirs=lambda _lib, name: f'mapped_{name}',
|
||||||
|
rename_when='always',
|
||||||
|
)
|
||||||
|
|
||||||
|
assert rename_map == {
|
||||||
|
'leaf': 'mapped_leaf',
|
||||||
|
'child': 'mapped_child',
|
||||||
|
'top': 'mapped_top',
|
||||||
|
}
|
||||||
|
assert tuple(overlay.keys()) == ('mapped_leaf', 'mapped_child', 'mapped_top')
|
||||||
|
assert 'mapped_leaf' in overlay['mapped_child'].refs
|
||||||
|
|
||||||
|
|
||||||
|
def test_gdsii_lazy_overlay_add_source_rename_when_validation() -> None:
|
||||||
|
src = _make_lazy_port_library()
|
||||||
|
|
||||||
|
with pytest.raises(TypeError, match='rename_theirs'):
|
||||||
|
gdsii_lazy.OverlayLibrary().add_source(src, rename_when='always')
|
||||||
|
|
||||||
|
with pytest.raises(ValueError, match='rename mode'):
|
||||||
|
gdsii_lazy.OverlayLibrary().add_source(src, rename_when='sometimes') # type: ignore[arg-type]
|
||||||
|
|
||||||
|
|
||||||
def test_gdsii_lazy_processed_write_roundtrips_without_explicit_units(tmp_path: Path) -> None:
|
def test_gdsii_lazy_processed_write_roundtrips_without_explicit_units(tmp_path: Path) -> None:
|
||||||
gds_file = tmp_path / 'lazy_roundtrip.gds'
|
gds_file = tmp_path / 'lazy_roundtrip.gds'
|
||||||
src = _make_lazy_port_library()
|
src = _make_lazy_port_library()
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue