Skip to content

Latest copier now has recursion error #2113

Open
@henryiii

Description

@henryiii

Describe the problem

I'm now getting a recursion error in scientific-python/cookie after the latest release:

  File "/Users/runner/work/cookie/cookie/.nox/compare_copier/lib/python3.9/site-packages/jinja2/environment.py", line 1388, in new_context
    return new_context(
  File "/Users/runner/work/cookie/cookie/.nox/compare_copier/lib/python3.9/site-packages/jinja2/runtime.py", line 117, in new_context
    return environment.context_class(
  File "/Users/runner/work/cookie/cookie/.nox/compare_copier/lib/python3.9/site-packages/copier_templates_extensions/_internal/context.py", line 48, in __init__
    if "_copier_conf" in parent and (context := extension_self.hook(parent)) is not None:  # type: ignore[attr-defined]
  File "/Users/runner/work/cookie/cookie/.nox/compare_copier/tmp/copier._vcs.clone.ujdu7qtg/helpers/extensions.py", line 17, in hook
  File "/Users/runner/work/cookie/cookie/.nox/compare_copier/lib/python3.9/site-packages/copier/_types.py", line 89, in __getitem__
    self._done[key] = self._pending[key]()
  File "/Users/runner/work/cookie/cookie/.nox/compare_copier/lib/python3.9/site-packages/copier/_main.py", line 400, in <lambda>
    "answers_file": lambda: self.answers_relpath,
  File "/Users/runner/work/cookie/cookie/.nox/compare_copier/lib/python3.9/site-packages/copier/_main.py", line 629, in answers_relpath
    return Path(template.render(self._render_context()))
  File "/Users/runner/work/cookie/cookie/.nox/compare_copier/lib/python3.9/site-packages/jinja2/environment.py", line 1290, in render
    ctx = self.new_context(dict(*args, **kwargs))
<repeats till Recursion error>

If I run it manually instead of in CI, where I'm pre-loading the answers, instead I get a KeyError:

uvx --with copier-templates-extensions copier copy gh:scientific-python/cookie package --trust --vcs-ref=HEAD                                                                              Mon Apr 28 10:38:15 2025
Installed 22 packages in 73ms
Traceback (most recent call last):
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/bin/copier", line 12, in <module>
    sys.exit(CopierApp.run())
             ~~~~~~~~~~~~~^^
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/plumbum/cli/application.py", line 640, in run
    inst, retcode = subapp.run(argv, exit=False)
                    ~~~~~~~~~~^^^^^^^^^^^^^^^^^^
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/plumbum/cli/application.py", line 635, in run
    retcode = inst.main(*tailargs)
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier/_cli.py", line 282, in main
    return _handle_exceptions(inner)
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier/_cli.py", line 71, in _handle_exceptions
    method()
    ~~~~~~^^
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier/_cli.py", line 273, in inner
    with self._worker(
         ~~~~~~~~~~~~^
        template_src,
        ^^^^^^^^^^^^^
    ...<3 lines>...
        overwrite=self.force or self.overwrite,
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    ) as worker:
    ^
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier/_main.py", line 267, in __exit__
    raise value
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier/_cli.py", line 280, in inner
    worker.run_copy()
    ~~~~~~~~~~~~~~~^^
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier/_main.py", line 94, in _wrapper
    return func(*args, **kwargs)
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier/_main.py", line 1015, in run_copy
    self._ask()
    ~~~~~~~~~^^
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier/_main.py", line 601, in _ask
    [question.get_questionary_structure()],
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier/_user_data.py", line 390, in get_questionary_structure
    "message": self.get_message(),
               ~~~~~~~~~~~~~~~~^^
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier/_user_data.py", line 365, in get_message
    if rendered_help := self.render_value(self.help):
                        ~~~~~~~~~~~~~~~~~^^^^^^^^^^^
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier/_user_data.py", line 472, in render_value
    return template.render({**self.context, **(extra_answers or {})})
           ~~~~~~~~~~~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/jinja2/environment.py", line 1290, in render
    ctx = self.new_context(dict(*args, **kwargs))
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/jinja2/environment.py", line 1388, in new_context
    return new_context(
        self.environment, self.name, self.blocks, vars, shared, self.globals, locals
    )
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/jinja2/runtime.py", line 117, in new_context
    return environment.context_class(
           ~~~~~~~~~~~~~~~~~~~~~~~~~^
        environment, parent, template_name, blocks, globals=globals
        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    )
    ^
  File "/Users/henryschreiner/.cache/uv/archive-v0/w1rn4hvLzuCz3j6fY0JZu/lib/python3.13/site-packages/copier_templates_extensions/_internal/context.py", line 48, in __init__
    if "_copier_conf" in parent and (context := extension_self.hook(parent)) is not None:  # type: ignore[attr-defined]
                                                ~~~~~~~~~~~~~~~~~~~^^^^^^^^
  File "/private/var/folders/_8/xtbws09n017fbzdx9dmgnyyr0000gn/T/copier._vcs.clone.4_gst8jp/helpers/extensions.py", line 10, in hook
KeyError: 'project_name'

Template

https://github.com/scientific-python/cookie

To Reproduce

To see the KeyError:

uvx --with copier-templates-extensions copier copy gh:scientific-python/cookie package --trust --vcs-ref=HEAD

Or to see the RecursionError:

uvx --with copier-templates-extensions copier copy gh:scientific-python/cookie package --trust --vcs-ref=HEAD --defaults --data=project_name=cookie-hatch --data=org=org --data=backend=hatch '--data=full_name=My Name' --data=email=me@email.com --data=license=BSD --data=vcs=False

Using copier==9.7.0 also fails. But copier==9.6.0 works correctly.

Logs

https://github.com/scientific-python/cookie/actions/runs/14664378902/job/41155672563?pr=582

Expected behavior

Not to break? :)

Screenshots/screencasts/logs

No response

Operating system

macOS

Operating system distribution and version

All CI OS's and local top

Copier version

7.9.1 and 7.9.0

Python version

All

Installation method

pipx+pypi

Additional context

Why is uv not listed above? ;) Over 20% of all package installations from PyPI are now through uv (as of a week ago).

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugtriageTrying to make sure if this is valid or not

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions