[library / gdsii] add materialize_detached and do some more cleanup

This commit is contained in:
Jan Petykiewicz 2026-07-14 22:18:17 -07:00
commit 93dd3503ca
11 changed files with 930 additions and 23 deletions

View file

@ -497,6 +497,36 @@ def test_gdsii_lazy_cached_source_cell_disables_only_its_raw_copy(
assert set(roundtrip['leaf'].labels) == {(10, 0), (30, 0)}
def test_gdsii_lazy_detached_processing_copies_only_cached_patterns(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
gds_file = tmp_path / 'classic_detached_source.gds'
gdsii.writefile(_make_lazy_port_library(), gds_file, meters_per_unit=1e-9)
raw, _ = gdsii_lazy.readfile(gds_file)
mapped = LayerMappedView(raw, lambda layer: layer)
original_deepcopy = Pattern.deepcopy
copied: list[Pattern] = []
def count_deepcopy(pattern: Pattern) -> Pattern:
copied.append(pattern)
return original_deepcopy(pattern)
monkeypatch.setattr(Pattern, 'deepcopy', count_deepcopy)
fresh = mapped.materialize_detached('top')
assert not copied
assert not raw._cache
assert not mapped._cache
cached = raw['top']
copied.clear()
detached = mapped.materialize_detached('top')
assert copied == [cached]
assert detached is not cached
assert detached is not fresh
def test_gdsii_lazy_materialized_cell_disables_only_its_raw_copy(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,

View file

@ -193,6 +193,32 @@ def test_gdsii_lazy_arrow_ref_queries_match_eager_reader(tmp_path: Path) -> None
assert _global_refs_key(lazy.find_refs_global(name)) == _global_refs_key(eager.find_refs_global(name))
def test_gdsii_lazy_arrow_detached_batch_preserves_native_batching(
tmp_path: Path,
monkeypatch: pytest.MonkeyPatch,
) -> None:
gds_file = tmp_path / 'lazy_arrow_detached_batch.gds'
gdsii.writefile(_make_small_library(), gds_file, meters_per_unit=1e-9)
raw, _ = gdsii_lazy_arrow.readfile(gds_file)
mapped = LayerMappedView(raw, lambda layer: layer)
original_read = gdsii_arrow._read_selected_cells_to_arrow
call_count = 0
def count_read(*args, **kwargs) -> object:
nonlocal call_count
call_count += 1
return original_read(*args, **kwargs)
monkeypatch.setattr(gdsii_arrow, '_read_selected_cells_to_arrow', count_read)
detached = mapped.materialize_many_detached(('leaf', 'mid', 'leaf'))
assert tuple(detached) == ('leaf', 'mid')
assert call_count == 1
assert not raw._cache
assert not mapped._cache
def test_gdsii_lazy_arrow_invalid_input_raises_klamath_error(tmp_path: Path) -> None:
gds_file = tmp_path / 'invalid.gds'
gds_file.write_bytes(b'not-a-gds')

View file

@ -825,6 +825,74 @@ def test_library_materialization_and_borrowing_capabilities() -> None:
assert not isinstance(plain_view, IMaterializable | IBorrowing)
def test_detached_materialization_default_is_owned_and_deduplicated() -> None:
shared_a = Pattern()
shared_b = Pattern()
lazy = LazyLibrary()
lazy['a'] = lambda: shared_a
lazy['b'] = lambda: shared_b
detached = lazy.materialize_many_detached(('b', 'a', 'b'))
assert tuple(detached) == ('b', 'a')
assert detached['a'] is not shared_a
assert detached['b'] is not shared_b
detached['a'].polygon('L', vertices=[[0, 0], [1, 0], [0, 1]])
assert not shared_a.shapes
assert not lazy.cache
def test_nested_detached_views_copy_plain_source_once(monkeypatch: pytest.MonkeyPatch) -> None:
source_pattern = Pattern()
source_pattern.polygon('A', vertices=[[0, 0], [1, 0], [0, 1]])
source = Library({'top': source_pattern})
ports = PortLoadView(source, ports={'top': {'P': Port((1, 2), 0)}})
mapped = LayerMappedView(ports, lambda _layer: 'B')
overlay = OverlayLibrary()
overlay.add_source(mapped)
original_deepcopy = Pattern.deepcopy
copied: list[Pattern] = []
def count_deepcopy(pattern: Pattern) -> Pattern:
copied.append(pattern)
return original_deepcopy(pattern)
monkeypatch.setattr(Pattern, 'deepcopy', count_deepcopy)
detached = overlay.materialize_detached('top')
assert copied == [source_pattern]
assert set(detached.shapes) == {'B'}
assert set(detached.ports) == {'P'}
assert not source_pattern.ports
assert not ports._cache
assert not mapped._cache
assert overlay.source_cell('top') == (mapped, 'top')
def test_nested_detached_views_copy_cached_pattern_once(monkeypatch: pytest.MonkeyPatch) -> None:
source_pattern = Pattern()
source = Library({'top': source_pattern})
ports = PortLoadView(source, ports={'top': {'P': Port((1, 2), 0)}})
cached = ports['top']
mapped = LayerMappedView(ports, lambda layer: layer)
original_deepcopy = Pattern.deepcopy
copied: list[Pattern] = []
def count_deepcopy(pattern: Pattern) -> Pattern:
copied.append(pattern)
return original_deepcopy(pattern)
monkeypatch.setattr(Pattern, 'deepcopy', count_deepcopy)
detached = mapped.materialize_detached('top')
assert copied == [cached]
assert detached is not cached
detached.ports.clear()
assert set(cached.ports) == {'P'}
def test_borrowed_source_cell_tracks_persistent_materialization() -> None:
source = Library({"top": Pattern()})
source.library_info = {"name": "not-forwarded"} # type: ignore[attr-defined]