From 1b83034b7ef05dd6fe8ee4be7e86df3e9742d1a0 Mon Sep 17 00:00:00 2001 From: Jan Petykiewicz Date: Sat, 20 Jun 2026 00:15:42 -0700 Subject: [PATCH] [BuildLibrary / OverlayLibrary] further simplifications 2 --- masque/file/gdsii_lazy_core.py | 6 +-- masque/library.py | 86 ++++++++----------------------- masque/test/test_build_library.py | 23 +-------- 3 files changed, 26 insertions(+), 89 deletions(-) diff --git a/masque/file/gdsii_lazy_core.py b/masque/file/gdsii_lazy_core.py index 9cb1c85..88c4eed 100644 --- a/masque/file/gdsii_lazy_core.py +++ b/masque/file/gdsii_lazy_core.py @@ -32,7 +32,7 @@ from numpy.typing import NDArray from . import gdsii from .utils import tmpfile from ..error import LibraryError -from ..library import ILibrary, ILibraryView, LibraryView, _plan_source_names, dangling_mode_t +from ..library import ILibrary, ILibraryView, LibraryView, _plan_source_names, _source_rename_map, dangling_mode_t from ..pattern import Pattern, map_targets from ..utils import apply_transforms from ..utils.ports2data import data_to_ports @@ -319,7 +319,7 @@ class OverlayLibrary(ILibrary): source_order = list(view.source_order()) child_graph = view.child_graph(dangling='include') - source_to_visible, rename_map = _plan_source_names( + source_to_visible = _plan_source_names( self, source_order, self._entries, @@ -343,7 +343,7 @@ class OverlayLibrary(ILibrary): if visible_name not in self._order: self._order.append(visible_name) - return rename_map + return _source_rename_map(source_to_visible) def rename( self, diff --git a/masque/library.py b/masque/library.py index c21305d..8306f77 100644 --- a/masque/library.py +++ b/masque/library.py @@ -156,7 +156,7 @@ def _plan_source_names( *, rename_theirs: Callable[['ILibraryView', str], str] | None = None, rename_when: Literal['conflict', 'always'] = 'conflict', - ) -> tuple[dict[str, str], dict[str, str]]: + ) -> dict[str, str]: 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: @@ -164,7 +164,6 @@ def _plan_source_names( source_to_visible: dict[str, str] = {} visible_names: set[str] = set() - rename_map: dict[str, str] = {} for name in source_order: visible = name @@ -182,12 +181,18 @@ def _plan_source_names( 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}') - if visible != name: - rename_map[name] = visible source_to_visible[name] = visible visible_names.add(visible) - return source_to_visible, rename_map + return source_to_visible + + +def _source_rename_map(source_to_visible: Mapping[str, str]) -> dict[str, str]: + return { + source_name: visible_name + for source_name, visible_name in source_to_visible.items() + if source_name != visible_name + } class ILibraryView(Mapping[str, 'Pattern'], metaclass=ABCMeta): @@ -1675,12 +1680,11 @@ class BuildLibrary(ILibrary): move_references: bool = False, ) -> Self: """ - Rename an imported source-backed visible name during authoring. + Rename a helper cell during an active build session. - Only imported source-backed cells may be renamed on the builder itself. - Declared/generated cells must be registered under their intended final - names. `move_references=True` is intentionally unsupported here because - deferred recipes and declaration internals cannot be rewritten safely. + During authoring, declared cells must be registered under their + intended final names and imported source cells must be renamed through + `add_source(...)`. """ session = self._active_session() if session is not None: @@ -1697,41 +1701,10 @@ class BuildLibrary(ILibrary): ) if old_name not in self._names: raise LibraryError(f'"{old_name}" does not exist in the builder.') - if new_name in self._names: - raise LibraryError(f'"{new_name}" already exists in the builder.') - if move_references: - raise BuildError( - 'BuildLibrary.rename(..., move_references=True) is not supported for imported source cells. ' - 'Builder-level renames only change the visible imported name.' - ) - - source_index: int | None = None - source_name: str | None = None - for idx, (_source, source_to_visible) in enumerate(self._sources): - for candidate_source, candidate_visible in source_to_visible.items(): - if candidate_visible == old_name: - source_index = idx - source_name = candidate_source - break - if source_index is not None: - break - if source_index is None: - raise BuildError( - f'Cannot rename "{old_name}" during authoring because only imported source-backed ' - 'cells may be renamed on a BuildLibrary.' - ) - - source_library, source_to_visible = self._sources[source_index] - source_to_visible = dict(source_to_visible) - assert source_name is not None - - source_to_visible[source_name] = new_name - - self._sources[source_index] = (source_library, source_to_visible) - self._names.remove(old_name) - self._names.add(new_name) - self._order[self._order.index(old_name)] = new_name - return self + raise BuildError( + f'Cannot rename imported source cell "{old_name}" during authoring. ' + 'Choose visible source names with add_source(..., rename_theirs=..., rename_when=...).' + ) def abstract(self, name: str) -> Abstract: return self._require_active_session('abstract').abstract(name) @@ -1777,7 +1750,7 @@ class BuildLibrary(ILibrary): view = source if isinstance(source, ILibraryView) else LibraryView(source) source_order = tuple(view.source_order()) - source_to_visible, rename_map = _plan_source_names( + source_to_visible = _plan_source_names( self, source_order, self._names, @@ -1790,7 +1763,7 @@ class BuildLibrary(ILibrary): visible = source_to_visible[source_name] self._names.add(visible) self._order.append(visible) - return rename_map + return _source_rename_map(source_to_visible) def validate( self, @@ -2011,8 +1984,7 @@ class _BuildSessionLibrary(ILibrary): else: kind = 'helper' - self._record_provenance( - name = key, + self._provenance[key] = CellProvenance( requested_name = key, kind = kind, owner_declared_name = current if kind == 'helper' else key, @@ -2054,22 +2026,6 @@ class _BuildSessionLibrary(ILibrary): ) return rename_map - def _record_provenance( - self, - *, - name: str, - requested_name: str, - kind: Literal['declared', 'helper'], - owner_declared_name: str | None, - build_chain: tuple[str, ...], - ) -> None: - self._provenance[name] = CellProvenance( - requested_name = requested_name, - kind = kind, - owner_declared_name = owner_declared_name, - build_chain = build_chain, - ) - def _wrap_error(self, name: str, exc: Exception) -> BuildError: chain = tuple(self._declared_stack) msg = [f'Failed while building declared cell "{name}"'] diff --git a/masque/test/test_build_library.py b/masque/test/test_build_library.py index 3a623c7..eec2772 100644 --- a/masque/test/test_build_library.py +++ b/masque/test/test_build_library.py @@ -239,30 +239,11 @@ def test_build_library_rejects_add_source_during_build() -> None: builder.build() -def test_build_library_can_rename_imported_source_cells_during_authoring() -> None: - source = Library() - source["child"] = Pattern() - parent = Pattern() - parent.ref("child") - source["parent"] = parent - - builder = BuildLibrary() - builder.add_source(source) - builder.rename("child", "renamed_child") - - built, report = builder.build() - - assert "renamed_child" in built - assert "child" not in built - assert "renamed_child" in built["parent"].refs - assert report.provenance["renamed_child"].requested_name == "child" - - -def test_build_library_rejects_move_references_for_source_rename() -> None: +def test_build_library_rejects_renaming_imported_source_cells_during_authoring() -> None: builder = BuildLibrary() builder.add_source(Library({"src": Pattern()})) - with pytest.raises(BuildError, match="move_references=True"): + with pytest.raises(BuildError, match="add_source"): builder.rename("src", "renamed_src", move_references=True)