[BuildLibrary / OverlayLibrary] further simplifications 2

This commit is contained in:
Jan Petykiewicz 2026-06-20 00:15:42 -07:00
commit 1b83034b7e
3 changed files with 26 additions and 89 deletions

View file

@ -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,

View file

@ -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}"']

View file

@ -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)