[BuildLibrary / OverlayLibrary] further simplifications
This commit is contained in:
parent
c420ac8085
commit
1723212424
3 changed files with 105 additions and 133 deletions
|
|
@ -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, dangling_mode_t
|
from ..library import ILibrary, ILibraryView, LibraryView, _plan_source_names, 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
|
||||||
|
|
@ -315,38 +315,18 @@ class OverlayLibrary(ILibrary):
|
||||||
If `'always'`, every imported source name is passed through
|
If `'always'`, every imported source name is passed through
|
||||||
`rename_theirs`.
|
`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')
|
||||||
|
|
||||||
source_to_visible: dict[str, str] = {}
|
source_to_visible, rename_map = _plan_source_names(
|
||||||
visible_to_source: dict[str, str] = {}
|
self,
|
||||||
rename_map: dict[str, str] = {}
|
source_order,
|
||||||
|
self._entries,
|
||||||
for name in source_order:
|
rename_theirs = rename_theirs,
|
||||||
visible = name
|
rename_when = rename_when,
|
||||||
renamed = False
|
)
|
||||||
if rename_when == 'always':
|
visible_to_source = {visible: source_name for source_name, visible in source_to_visible.items()}
|
||||||
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:
|
|
||||||
raise LibraryError(f'Conflicting name while adding source: {name!r}')
|
|
||||||
visible = rename_theirs(self, name)
|
|
||||||
renamed = True
|
|
||||||
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}')
|
|
||||||
if visible != name:
|
|
||||||
rename_map[name] = visible
|
|
||||||
source_to_visible[name] = visible
|
|
||||||
visible_to_source[visible] = name
|
|
||||||
|
|
||||||
layer = _SourceLayer(
|
layer = _SourceLayer(
|
||||||
library=view,
|
library=view,
|
||||||
|
|
|
||||||
|
|
@ -15,10 +15,11 @@ Classes include:
|
||||||
library. Generated with `ILibraryView.abstract_view()`.
|
library. Generated with `ILibraryView.abstract_view()`.
|
||||||
"""
|
"""
|
||||||
from typing import Self, TYPE_CHECKING, Any, cast, TypeAlias, Protocol, Literal
|
from typing import Self, TYPE_CHECKING, Any, cast, TypeAlias, Protocol, Literal
|
||||||
from collections.abc import Iterator, Mapping, MutableMapping, Sequence, Callable
|
from collections.abc import Container, Iterator, Mapping, MutableMapping, Sequence, Callable
|
||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
import copy
|
import copy
|
||||||
|
from functools import wraps
|
||||||
from pprint import pformat
|
from pprint import pformat
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
from abc import ABCMeta, abstractmethod
|
from abc import ABCMeta, abstractmethod
|
||||||
|
|
@ -87,15 +88,11 @@ class CellProvenance:
|
||||||
any. Imported source cells leave this as `None`.
|
any. Imported source cells leave this as `None`.
|
||||||
build_chain: Declared-cell dependency chain that was active when the
|
build_chain: Declared-cell dependency chain that was active when the
|
||||||
cell was emitted.
|
cell was emitted.
|
||||||
renamed_from: Original requested name when the final name differs.
|
|
||||||
source_name: Original on-source name for imported cells.
|
|
||||||
"""
|
"""
|
||||||
requested_name: str
|
requested_name: str
|
||||||
kind: Literal['declared', 'helper', 'source']
|
kind: Literal['declared', 'helper', 'source']
|
||||||
owner_declared_name: str | None
|
owner_declared_name: str | None
|
||||||
build_chain: tuple[str, ...]
|
build_chain: tuple[str, ...]
|
||||||
renamed_from: str | None = None
|
|
||||||
source_name: str | None = None
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
@dataclass(frozen=True)
|
||||||
|
|
@ -152,6 +149,47 @@ def _rename_patterns(lib: 'ILibraryView', name: str) -> str:
|
||||||
return lib.get_name(SINGLE_USE_PREFIX + stem)
|
return lib.get_name(SINGLE_USE_PREFIX + stem)
|
||||||
|
|
||||||
|
|
||||||
|
def _plan_source_names(
|
||||||
|
target: 'ILibraryView',
|
||||||
|
source_order: Sequence[str],
|
||||||
|
existing_names: Container[str],
|
||||||
|
*,
|
||||||
|
rename_theirs: Callable[['ILibraryView', str], str] | None = None,
|
||||||
|
rename_when: Literal['conflict', 'always'] = 'conflict',
|
||||||
|
) -> tuple[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:
|
||||||
|
raise TypeError('rename_theirs is required when rename_when="always"')
|
||||||
|
|
||||||
|
source_to_visible: dict[str, str] = {}
|
||||||
|
visible_names: set[str] = set()
|
||||||
|
rename_map: dict[str, str] = {}
|
||||||
|
|
||||||
|
for name in source_order:
|
||||||
|
visible = name
|
||||||
|
renamed = False
|
||||||
|
if rename_when == 'always':
|
||||||
|
assert rename_theirs is not None
|
||||||
|
visible = rename_theirs(target, name)
|
||||||
|
renamed = True
|
||||||
|
elif visible in existing_names or visible in visible_names:
|
||||||
|
if rename_theirs is None:
|
||||||
|
raise LibraryError(f'Conflicting name while adding source: {name!r}')
|
||||||
|
visible = rename_theirs(target, name)
|
||||||
|
renamed = True
|
||||||
|
if visible in existing_names or visible in visible_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
|
||||||
|
|
||||||
|
|
||||||
class ILibraryView(Mapping[str, 'Pattern'], metaclass=ABCMeta):
|
class ILibraryView(Mapping[str, 'Pattern'], metaclass=ABCMeta):
|
||||||
"""
|
"""
|
||||||
Interface for a read-only library.
|
Interface for a read-only library.
|
||||||
|
|
@ -1453,23 +1491,6 @@ class Library(ILibrary):
|
||||||
return tree, pat
|
return tree, pat
|
||||||
|
|
||||||
|
|
||||||
class _CellFactory:
|
|
||||||
"""
|
|
||||||
Adapter that turns a plain pattern factory into a deferred recipe factory.
|
|
||||||
|
|
||||||
Calling the wrapper captures arguments and returns a `_BuildRecipe`
|
|
||||||
instead of executing the function immediately.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def __init__(self, func: Callable[..., 'Pattern']) -> None:
|
|
||||||
self.func = func
|
|
||||||
self.__name__ = getattr(func, '__name__', type(self).__name__)
|
|
||||||
self.__doc__ = getattr(func, '__doc__')
|
|
||||||
|
|
||||||
def __call__(self, *args: Any, **kwargs: Any) -> '_BuildRecipe':
|
|
||||||
return _BuildRecipe(func=self.func, args=args, kwargs=kwargs)
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class _BuildRecipe:
|
class _BuildRecipe:
|
||||||
""" Captured deferred call to a pattern factory. """
|
""" Captured deferred call to a pattern factory. """
|
||||||
|
|
@ -1483,25 +1504,17 @@ class _BuildRecipe:
|
||||||
return self
|
return self
|
||||||
|
|
||||||
|
|
||||||
@dataclass(frozen=True)
|
def cell(func: Callable[..., 'Pattern']) -> Callable[..., _BuildRecipe]:
|
||||||
class _SourceDeclaration:
|
|
||||||
"""
|
|
||||||
Imported source-backed names registered with a `BuildLibrary`.
|
|
||||||
|
|
||||||
The declaration stores visible-name remapping. Underlying source cells stay
|
|
||||||
lazy until a build session materializes or copies them through.
|
|
||||||
"""
|
|
||||||
library: ILibraryView
|
|
||||||
source_to_visible: Mapping[str, str]
|
|
||||||
|
|
||||||
|
|
||||||
def cell(func: Callable[..., 'Pattern']) -> _CellFactory:
|
|
||||||
"""
|
"""
|
||||||
Wrap a plain pattern factory so calls return deferred build recipes.
|
Wrap a plain pattern factory so calls return deferred build recipes.
|
||||||
|
|
||||||
Use as either `cell(fn)(...)` or `@cell`.
|
Use as either `cell(fn)(...)` or `@cell`.
|
||||||
"""
|
"""
|
||||||
return _CellFactory(func)
|
@wraps(func)
|
||||||
|
def wrapper(*args: Any, **kwargs: Any) -> _BuildRecipe:
|
||||||
|
return _BuildRecipe(func=func, args=args, kwargs=kwargs)
|
||||||
|
|
||||||
|
return wrapper
|
||||||
|
|
||||||
|
|
||||||
class BuildCellsView:
|
class BuildCellsView:
|
||||||
|
|
@ -1555,7 +1568,7 @@ class BuildLibrary(ILibrary):
|
||||||
self.cells = BuildCellsView(self)
|
self.cells = BuildCellsView(self)
|
||||||
self._frozen = False
|
self._frozen = False
|
||||||
self._declarations: dict[str, 'Pattern | _BuildRecipe'] = {}
|
self._declarations: dict[str, 'Pattern | _BuildRecipe'] = {}
|
||||||
self._sources: list[_SourceDeclaration] = []
|
self._sources: list[tuple[ILibraryView, dict[str, str]]] = []
|
||||||
self._names: set[str] = set()
|
self._names: set[str] = set()
|
||||||
self._order: list[str] = []
|
self._order: list[str] = []
|
||||||
|
|
||||||
|
|
@ -1694,8 +1707,8 @@ class BuildLibrary(ILibrary):
|
||||||
|
|
||||||
source_index: int | None = None
|
source_index: int | None = None
|
||||||
source_name: str | None = None
|
source_name: str | None = None
|
||||||
for idx, spec in enumerate(self._sources):
|
for idx, (_source, source_to_visible) in enumerate(self._sources):
|
||||||
for candidate_source, candidate_visible in spec.source_to_visible.items():
|
for candidate_source, candidate_visible in source_to_visible.items():
|
||||||
if candidate_visible == old_name:
|
if candidate_visible == old_name:
|
||||||
source_index = idx
|
source_index = idx
|
||||||
source_name = candidate_source
|
source_name = candidate_source
|
||||||
|
|
@ -1708,16 +1721,13 @@ class BuildLibrary(ILibrary):
|
||||||
'cells may be renamed on a BuildLibrary.'
|
'cells may be renamed on a BuildLibrary.'
|
||||||
)
|
)
|
||||||
|
|
||||||
spec = self._sources[source_index]
|
source_library, source_to_visible = self._sources[source_index]
|
||||||
source_to_visible = dict(spec.source_to_visible)
|
source_to_visible = dict(source_to_visible)
|
||||||
assert source_name is not None
|
assert source_name is not None
|
||||||
|
|
||||||
source_to_visible[source_name] = new_name
|
source_to_visible[source_name] = new_name
|
||||||
|
|
||||||
self._sources[source_index] = replace(
|
self._sources[source_index] = (source_library, source_to_visible)
|
||||||
spec,
|
|
||||||
source_to_visible = source_to_visible,
|
|
||||||
)
|
|
||||||
self._names.remove(old_name)
|
self._names.remove(old_name)
|
||||||
self._names.add(new_name)
|
self._names.add(new_name)
|
||||||
self._order[self._order.index(old_name)] = new_name
|
self._order[self._order.index(old_name)] = new_name
|
||||||
|
|
@ -1761,48 +1771,23 @@ class BuildLibrary(ILibrary):
|
||||||
Mapping of `{source_name: visible_name}` for imported names that
|
Mapping of `{source_name: visible_name}` for imported names that
|
||||||
were renamed while being added.
|
were renamed while being added.
|
||||||
"""
|
"""
|
||||||
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"')
|
|
||||||
if self._active_session() is not None:
|
if self._active_session() is not None:
|
||||||
raise BuildError('BuildLibrary.add_source() is only available while authoring, not during validate() or build().')
|
raise BuildError('BuildLibrary.add_source() is only available while authoring, not during validate() or build().')
|
||||||
self._assert_editable()
|
self._assert_editable()
|
||||||
|
|
||||||
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(
|
||||||
|
self,
|
||||||
|
source_order,
|
||||||
|
self._names,
|
||||||
|
rename_theirs = rename_theirs,
|
||||||
|
rename_when = rename_when,
|
||||||
|
)
|
||||||
|
|
||||||
source_to_visible: dict[str, str] = {}
|
self._sources.append((view, dict(source_to_visible)))
|
||||||
visible_names: set[str] = set()
|
for source_name in source_order:
|
||||||
rename_map: dict[str, str] = {}
|
visible = source_to_visible[source_name]
|
||||||
new_names: list[str] = []
|
|
||||||
|
|
||||||
for name in source_order:
|
|
||||||
visible = name
|
|
||||||
renamed = False
|
|
||||||
if rename_when == 'always':
|
|
||||||
visible = cast('Callable[[ILibraryView, str], str]', rename_theirs)(self, name)
|
|
||||||
renamed = True
|
|
||||||
elif visible in self._names or visible in visible_names:
|
|
||||||
if rename_theirs is None:
|
|
||||||
raise LibraryError(f'Conflicting name while adding source: {name!r}')
|
|
||||||
visible = rename_theirs(self, name)
|
|
||||||
renamed = True
|
|
||||||
if visible in self._names or visible in visible_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)
|
|
||||||
new_names.append(visible)
|
|
||||||
|
|
||||||
self._sources.append(_SourceDeclaration(
|
|
||||||
library = view,
|
|
||||||
source_to_visible = dict(source_to_visible),
|
|
||||||
))
|
|
||||||
for visible in new_names:
|
|
||||||
self._names.add(visible)
|
self._names.add(visible)
|
||||||
self._order.append(visible)
|
self._order.append(visible)
|
||||||
return rename_map
|
return rename_map
|
||||||
|
|
@ -1902,9 +1887,9 @@ class _BuildSessionLibrary(ILibrary):
|
||||||
self._install_sources()
|
self._install_sources()
|
||||||
|
|
||||||
def _install_sources(self) -> None:
|
def _install_sources(self) -> None:
|
||||||
for spec in self._builder._sources:
|
for source_library, source_to_visible in self._builder._sources:
|
||||||
source_order = spec.library.source_order()
|
source_order = source_library.source_order()
|
||||||
expected_names = set(spec.source_to_visible)
|
expected_names = set(source_to_visible)
|
||||||
actual_names = set(source_order)
|
actual_names = set(source_order)
|
||||||
if actual_names != expected_names:
|
if actual_names != expected_names:
|
||||||
added_names = sorted(actual_names - expected_names)
|
added_names = sorted(actual_names - expected_names)
|
||||||
|
|
@ -1920,24 +1905,22 @@ class _BuildSessionLibrary(ILibrary):
|
||||||
'Do not structurally mutate source libraries between add_source() and build()/validate().'
|
'Do not structurally mutate source libraries between add_source() and build()/validate().'
|
||||||
)
|
)
|
||||||
|
|
||||||
def rename_source(_lib: ILibraryView, name: str, *, mapping: Mapping[str, str] = spec.source_to_visible) -> str:
|
def rename_source(_lib: ILibraryView, name: str, *, mapping: Mapping[str, str] = source_to_visible) -> str:
|
||||||
return mapping[name]
|
return mapping[name]
|
||||||
|
|
||||||
self._overlay.add_source(
|
self._overlay.add_source(
|
||||||
spec.library,
|
source_library,
|
||||||
rename_theirs = rename_source,
|
rename_theirs = rename_source,
|
||||||
rename_when = 'always',
|
rename_when = 'always',
|
||||||
)
|
)
|
||||||
|
|
||||||
for source_name in source_order:
|
for source_name in source_order:
|
||||||
visible_name = spec.source_to_visible[source_name]
|
visible_name = source_to_visible[source_name]
|
||||||
self._provenance[visible_name] = CellProvenance(
|
self._provenance[visible_name] = CellProvenance(
|
||||||
requested_name = source_name,
|
requested_name = source_name,
|
||||||
kind = 'source',
|
kind = 'source',
|
||||||
owner_declared_name = None,
|
owner_declared_name = None,
|
||||||
build_chain = (),
|
build_chain = (),
|
||||||
renamed_from = source_name if visible_name != source_name else None,
|
|
||||||
source_name = source_name,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def __iter__(self) -> Iterator[str]:
|
def __iter__(self) -> Iterator[str]:
|
||||||
|
|
@ -1947,7 +1930,7 @@ class _BuildSessionLibrary(ILibrary):
|
||||||
return len(self._names)
|
return len(self._names)
|
||||||
|
|
||||||
def __contains__(self, key: object) -> bool:
|
def __contains__(self, key: object) -> bool:
|
||||||
return key in self._names or key in self._overlay
|
return key in self._names
|
||||||
|
|
||||||
def _touch_name(self, key: str) -> None:
|
def _touch_name(self, key: str) -> None:
|
||||||
if key not in self._names:
|
if key not in self._names:
|
||||||
|
|
@ -1998,11 +1981,7 @@ class _BuildSessionLibrary(ILibrary):
|
||||||
self._order[idx] = new_name
|
self._order[idx] = new_name
|
||||||
|
|
||||||
provenance = self._provenance.pop(old_name)
|
provenance = self._provenance.pop(old_name)
|
||||||
requested_name = provenance.requested_name
|
self._provenance[new_name] = provenance
|
||||||
self._provenance[new_name] = replace(
|
|
||||||
provenance,
|
|
||||||
renamed_from = requested_name if new_name != requested_name else None,
|
|
||||||
)
|
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def __getitem__(self, key: str) -> 'Pattern':
|
def __getitem__(self, key: str) -> 'Pattern':
|
||||||
|
|
@ -2038,7 +2017,6 @@ class _BuildSessionLibrary(ILibrary):
|
||||||
kind = kind,
|
kind = kind,
|
||||||
owner_declared_name = current if kind == 'helper' else key,
|
owner_declared_name = current if kind == 'helper' else key,
|
||||||
build_chain = tuple(self._declared_stack),
|
build_chain = tuple(self._declared_stack),
|
||||||
renamed_from = None,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def __delitem__(self, key: str) -> None:
|
def __delitem__(self, key: str) -> None:
|
||||||
|
|
@ -2072,7 +2050,6 @@ class _BuildSessionLibrary(ILibrary):
|
||||||
self._provenance[new_name] = replace(
|
self._provenance[new_name] = replace(
|
||||||
self._provenance[new_name],
|
self._provenance[new_name],
|
||||||
requested_name = old_name,
|
requested_name = old_name,
|
||||||
renamed_from = old_name,
|
|
||||||
owner_declared_name = current if current is not None else self._provenance[new_name].owner_declared_name,
|
owner_declared_name = current if current is not None else self._provenance[new_name].owner_declared_name,
|
||||||
)
|
)
|
||||||
return rename_map
|
return rename_map
|
||||||
|
|
@ -2085,14 +2062,12 @@ class _BuildSessionLibrary(ILibrary):
|
||||||
kind: Literal['declared', 'helper'],
|
kind: Literal['declared', 'helper'],
|
||||||
owner_declared_name: str | None,
|
owner_declared_name: str | None,
|
||||||
build_chain: tuple[str, ...],
|
build_chain: tuple[str, ...],
|
||||||
renamed_from: str | None,
|
|
||||||
) -> None:
|
) -> None:
|
||||||
self._provenance[name] = CellProvenance(
|
self._provenance[name] = CellProvenance(
|
||||||
requested_name = requested_name,
|
requested_name = requested_name,
|
||||||
kind = kind,
|
kind = kind,
|
||||||
owner_declared_name = owner_declared_name,
|
owner_declared_name = owner_declared_name,
|
||||||
build_chain = build_chain,
|
build_chain = build_chain,
|
||||||
renamed_from = renamed_from,
|
|
||||||
)
|
)
|
||||||
|
|
||||||
def _wrap_error(self, name: str, exc: Exception) -> BuildError:
|
def _wrap_error(self, name: str, exc: Exception) -> BuildError:
|
||||||
|
|
|
||||||
|
|
@ -50,13 +50,13 @@ def test_build_library_tracks_helper_provenance_and_tree_merge_renames() -> None
|
||||||
_built, report = builder.build()
|
_built, report = builder.build()
|
||||||
|
|
||||||
helpers = [
|
helpers = [
|
||||||
prov for prov in report.provenance.values()
|
(name, prov) for name, prov in report.provenance.items()
|
||||||
if prov.owner_declared_name == "top" and prov.kind == "helper"
|
if prov.owner_declared_name == "top" and prov.kind == "helper"
|
||||||
]
|
]
|
||||||
|
|
||||||
assert "top" in _owned_by(report, "top")
|
assert "top" in _owned_by(report, "top")
|
||||||
assert len(helpers) == 2
|
assert len(helpers) == 2
|
||||||
assert any(prov.renamed_from == "_helper" for prov in helpers)
|
assert any(name != prov.requested_name for name, prov in helpers)
|
||||||
|
|
||||||
|
|
||||||
def test_build_library_requires_build_session_for_reads_and_freezes_after_build() -> None:
|
def test_build_library_requires_build_session_for_reads_and_freezes_after_build() -> None:
|
||||||
|
|
@ -152,6 +152,25 @@ def test_build_library_allows_helper_writes_via_pather() -> None:
|
||||||
assert helper_prov.owner_declared_name == "top"
|
assert helper_prov.owner_declared_name == "top"
|
||||||
|
|
||||||
|
|
||||||
|
def test_build_library_contains_tracks_active_session_names() -> None:
|
||||||
|
builder = BuildLibrary()
|
||||||
|
builder["leaf"] = Pattern()
|
||||||
|
builder.add_source(Library({"src": Pattern()}))
|
||||||
|
|
||||||
|
def make_top(lib: BuildLibrary) -> Pattern:
|
||||||
|
assert "leaf" in lib
|
||||||
|
assert "src" in lib
|
||||||
|
assert "_helper" not in lib
|
||||||
|
lib["_helper"] = Pattern()
|
||||||
|
assert "_helper" in lib
|
||||||
|
return Pattern()
|
||||||
|
|
||||||
|
builder.cells.top = cell(make_top)(builder)
|
||||||
|
built, _report = builder.build()
|
||||||
|
|
||||||
|
assert "_helper" in built
|
||||||
|
|
||||||
|
|
||||||
def test_build_library_preserves_source_cells_and_records_source_provenance() -> None:
|
def test_build_library_preserves_source_cells_and_records_source_provenance() -> None:
|
||||||
source = Library({"src": Pattern()})
|
source = Library({"src": Pattern()})
|
||||||
builder = BuildLibrary()
|
builder = BuildLibrary()
|
||||||
|
|
@ -184,7 +203,7 @@ def test_build_library_add_source_can_rename_every_source_cell() -> None:
|
||||||
"parent": "mapped_parent",
|
"parent": "mapped_parent",
|
||||||
}
|
}
|
||||||
assert "mapped_child" in built["mapped_parent"].refs
|
assert "mapped_child" in built["mapped_parent"].refs
|
||||||
assert report.provenance["mapped_child"].source_name == "child"
|
assert report.provenance["mapped_child"].requested_name == "child"
|
||||||
|
|
||||||
|
|
||||||
def test_build_library_rejects_source_cells_added_after_add_source() -> None:
|
def test_build_library_rejects_source_cells_added_after_add_source() -> None:
|
||||||
|
|
@ -236,7 +255,7 @@ def test_build_library_can_rename_imported_source_cells_during_authoring() -> No
|
||||||
assert "renamed_child" in built
|
assert "renamed_child" in built
|
||||||
assert "child" not in built
|
assert "child" not in built
|
||||||
assert "renamed_child" in built["parent"].refs
|
assert "renamed_child" in built["parent"].refs
|
||||||
assert report.provenance["renamed_child"].source_name == "child"
|
assert report.provenance["renamed_child"].requested_name == "child"
|
||||||
|
|
||||||
|
|
||||||
def test_build_library_rejects_move_references_for_source_rename() -> None:
|
def test_build_library_rejects_move_references_for_source_rename() -> None:
|
||||||
|
|
@ -276,7 +295,6 @@ def test_build_library_helper_rename_updates_provenance_owner() -> None:
|
||||||
prov = report.provenance["final_helper"]
|
prov = report.provenance["final_helper"]
|
||||||
assert prov.kind == "helper"
|
assert prov.kind == "helper"
|
||||||
assert prov.requested_name == "_helper"
|
assert prov.requested_name == "_helper"
|
||||||
assert prov.renamed_from == "_helper"
|
|
||||||
|
|
||||||
|
|
||||||
def test_build_library_helper_delete_removes_provenance_and_ownership() -> None:
|
def test_build_library_helper_delete_removes_provenance_and_ownership() -> None:
|
||||||
|
|
@ -314,7 +332,6 @@ def test_build_library_helper_rename_after_auto_rename_preserves_requested_name(
|
||||||
assert "final_helper" in built
|
assert "final_helper" in built
|
||||||
prov = report.provenance["final_helper"]
|
prov = report.provenance["final_helper"]
|
||||||
assert prov.requested_name == "_helper"
|
assert prov.requested_name == "_helper"
|
||||||
assert prov.renamed_from == "_helper"
|
|
||||||
|
|
||||||
|
|
||||||
def test_build_library_rejects_renaming_declared_or_source_cells_during_build() -> None:
|
def test_build_library_rejects_renaming_declared_or_source_cells_during_build() -> None:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue