fix: avoid infinite recursion when accessing _copier_conf.answers_file
via Jinja context hook
#2114
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
I've fixed a regression introduced by #2023 which causes infinite recursion when accessing
_copier_conf.answers_file
via Jinja context hook withcopier-templates-extensions
.When rendering the answers file path in
Worker.answers_relpath
, which is accessible in the render context as_copier_conf.answers_file
, the render context also includes_copier_conf.answers_file
as a lazy dict value of_copier_conf
. That's no problem when simply rendering the answers file path exposed as_copier_conf.answers_file
because the answers file template never uses this variable itself. But when a context hook accesses_copier_conf.answers_file
(e.g. in github.com/scientific-python/cookie:helpers/extensions.py#L17), then one invocation of the context hook intercepts the render context for rendering the template for that same value, which results in an infinite recursion. To avoid it, I've extended theLazyDict
class to support setting entries and overwrote theanswers_file
entry with""
. This is a bit of a hack, but I don't see another way to avoid this problem. I'll also submit a PR tocopier-templates-extensions
with a new test case for this scenario once we've agreed on the path forward here, @pawamoy.Until v9.4.0, this problem never occurred because the render context of the answers file template consisted only of answers and didn't include additional variables such as
_copier_conf
. One would think that a context hook that accessed_copier_conf.answers_file
would have failed because_copier_conf
wasn't included in the render context of the answers file template, but no error occurred. That's because the context hook is invoked only when_copier_conf
exists. Thus, while a context hook accessing, e.g.,_copier_conf.*
was working with Copier until v9.4.0 – in the sense that no error occurred –, the behavior wasn't entirely correct, as not all rendering contexts were updated because_copier_conf
wasn't present in all of them until recent Copier versions.Now, to the best of my knowledge, all rendering contexts include
_copier_conf
, so the context hook is invoked for all rendering contexts including those prior to answering any questions. I believe that this is correct behavior and previous behavior was unintended. (WDYT, @pawamoy?) This means unconditional access of answers variables or other variables that require answers variables for rendering does not work. For example, github.com/scientific-python/cookie:helpers/extensions.py#L18 raises aKeyError
when accessing theurl
variable, as all rendering contexts prior to answering theurl
question don't contain it (@henryiii). In this specific example, I think the correct behavior is to inject the__ci
variable into the context only when theurl
variable exists. This is consistent with using a computed value incopier.yaml
:I'm aware that this may be considered a breaking change. To restore previous behavior where context hooks are invoked only when rendering files/directories/paths, I believe we could add another condition in
copier-templates-extensions
to check for the value of_copier_phase
, such that recent Copier versions that expose this variable don't cause a context hook invocation in other phases. However, I suggest to raise a deprecation warning and recommend to template authors to implement context updates with the different rendering phases in mind.WDYT, @pawamoy @henryiii?
Fixes #2113.