[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 . import gdsii
from .utils import tmpfile from .utils import tmpfile
from ..error import LibraryError 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 ..pattern import Pattern, map_targets
from ..utils import apply_transforms from ..utils import apply_transforms
from ..utils.ports2data import data_to_ports from ..utils.ports2data import data_to_ports
@ -319,7 +319,7 @@ class OverlayLibrary(ILibrary):
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')
source_to_visible, rename_map = _plan_source_names( source_to_visible = _plan_source_names(
self, self,
source_order, source_order,
self._entries, self._entries,
@ -343,7 +343,7 @@ class OverlayLibrary(ILibrary):
if visible_name not in self._order: if visible_name not in self._order:
self._order.append(visible_name) self._order.append(visible_name)
return rename_map return _source_rename_map(source_to_visible)
def rename( def rename(
self, self,

View file

@ -156,7 +156,7 @@ def _plan_source_names(
*, *,
rename_theirs: Callable[['ILibraryView', str], str] | None = None, rename_theirs: Callable[['ILibraryView', str], str] | None = None,
rename_when: Literal['conflict', 'always'] = 'conflict', rename_when: Literal['conflict', 'always'] = 'conflict',
) -> tuple[dict[str, str], dict[str, str]]: ) -> dict[str, str]:
if rename_when not in ('conflict', 'always'): if rename_when not in ('conflict', 'always'):
raise ValueError(f'Unknown source rename mode: {rename_when!r}') raise ValueError(f'Unknown source rename mode: {rename_when!r}')
if rename_when == 'always' and rename_theirs is None: if rename_when == 'always' and rename_theirs is None:
@ -164,7 +164,6 @@ def _plan_source_names(
source_to_visible: dict[str, str] = {} source_to_visible: dict[str, str] = {}
visible_names: set[str] = set() visible_names: set[str] = set()
rename_map: dict[str, str] = {}
for name in source_order: for name in source_order:
visible = name visible = name
@ -182,12 +181,18 @@ def _plan_source_names(
if not renamed: if not renamed:
raise LibraryError(f'Conflicting name while adding source: {name!r}') 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
source_to_visible[name] = visible source_to_visible[name] = visible
visible_names.add(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): class ILibraryView(Mapping[str, 'Pattern'], metaclass=ABCMeta):
@ -1675,12 +1680,11 @@ class BuildLibrary(ILibrary):
move_references: bool = False, move_references: bool = False,
) -> Self: ) -> 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. During authoring, declared cells must be registered under their
Declared/generated cells must be registered under their intended final intended final names and imported source cells must be renamed through
names. `move_references=True` is intentionally unsupported here because `add_source(...)`.
deferred recipes and declaration internals cannot be rewritten safely.
""" """
session = self._active_session() session = self._active_session()
if session is not None: if session is not None:
@ -1697,42 +1701,11 @@ class BuildLibrary(ILibrary):
) )
if old_name not in self._names: if old_name not in self._names:
raise LibraryError(f'"{old_name}" does not exist in the builder.') 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( raise BuildError(
'BuildLibrary.rename(..., move_references=True) is not supported for imported source cells. ' f'Cannot rename imported source cell "{old_name}" during authoring. '
'Builder-level renames only change the visible imported name.' 'Choose visible source names with add_source(..., rename_theirs=..., rename_when=...).'
) )
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
def abstract(self, name: str) -> Abstract: def abstract(self, name: str) -> Abstract:
return self._require_active_session('abstract').abstract(name) return self._require_active_session('abstract').abstract(name)
@ -1777,7 +1750,7 @@ class BuildLibrary(ILibrary):
view = source if isinstance(source, ILibraryView) else LibraryView(source) view = source if isinstance(source, ILibraryView) else LibraryView(source)
source_order = tuple(view.source_order()) source_order = tuple(view.source_order())
source_to_visible, rename_map = _plan_source_names( source_to_visible = _plan_source_names(
self, self,
source_order, source_order,
self._names, self._names,
@ -1790,7 +1763,7 @@ class BuildLibrary(ILibrary):
visible = source_to_visible[source_name] visible = source_to_visible[source_name]
self._names.add(visible) self._names.add(visible)
self._order.append(visible) self._order.append(visible)
return rename_map return _source_rename_map(source_to_visible)
def validate( def validate(
self, self,
@ -2011,8 +1984,7 @@ class _BuildSessionLibrary(ILibrary):
else: else:
kind = 'helper' kind = 'helper'
self._record_provenance( self._provenance[key] = CellProvenance(
name = key,
requested_name = key, requested_name = key,
kind = kind, kind = kind,
owner_declared_name = current if kind == 'helper' else key, owner_declared_name = current if kind == 'helper' else key,
@ -2054,22 +2026,6 @@ class _BuildSessionLibrary(ILibrary):
) )
return rename_map 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: def _wrap_error(self, name: str, exc: Exception) -> BuildError:
chain = tuple(self._declared_stack) chain = tuple(self._declared_stack)
msg = [f'Failed while building declared cell "{name}"'] 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() builder.build()
def test_build_library_can_rename_imported_source_cells_during_authoring() -> None: def test_build_library_rejects_renaming_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:
builder = BuildLibrary() builder = BuildLibrary()
builder.add_source(Library({"src": Pattern()})) 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) builder.rename("src", "renamed_src", move_references=True)