fix: avoid infinite recursion when accessing _copier_conf.answers_file via Jinja context hook

This commit is contained in:
Sigurd Spieckermann 2025-04-29 13:19:40 +02:00
parent be767f6913
commit 33722d7c63
2 changed files with 16 additions and 3 deletions

View File

@ -626,7 +626,12 @@ class Worker:
"""
path = self.answers_file or self.template.answers_relpath
template = self.jinja_env.from_string(str(path))
return Path(template.render(self._render_context()))
# HACK: Override `_copier_conf.answers_file` in the render context to
# avoid infinite recursion when accessing it in a Jinja context hook via
# `copier-templates-extensions`.
context = self._render_context()
context["_copier_conf"]["answers_file"] = ""
return Path(template.render(**context))
@cached_property
def all_exclusions(self) -> Sequence[str]:

View File

@ -77,11 +77,11 @@ _V = TypeVar("_V")
# HACK https://github.com/copier-org/copier/pull/1880#discussion_r1887491497
class LazyDict(Mapping[_K, _V]):
class LazyDict(MutableMapping[_K, _V]):
"""A dict where values are functions that get evaluated only once when requested."""
def __init__(self, mapping: Mapping[_K, Callable[[], _V]] | None = None):
self._pending = mapping or {}
self._pending = dict(mapping or {})
self._done: dict[_K, _V] = {}
def __getitem__(self, key: _K) -> _V:
@ -89,6 +89,14 @@ class LazyDict(Mapping[_K, _V]):
self._done[key] = self._pending[key]()
return self._done[key]
def __setitem__(self, key: _K, value: _V) -> None:
self._pending[key] = lambda: value
self._done.pop(key, None)
def __delitem__(self, key: _K) -> None:
del self._pending[key]
del self._done[key]
def __iter__(self) -> Iterator[_K]:
return iter(self._pending)