Describe the problem
Copier 9.15.2 renders a non-root {{ _copier_conf.answers_file }}.jinja template to the destination root as .copier-answers.yml.
Copier 9.15.1 rendered the same answers-file template into the same nested destination directory where the template file lived. This changes the generated output path for existing templates that include .copier-answers.yml.jinja below the template root.
Template
This minimal template can be created locally with:
rm -rf /tmp/copier-answers-repro
mkdir -p /tmp/copier-answers-repro/template/nested/{{ project_name }}
cd /tmp/copier-answers-repro
cat > template/copier.yml <<'YAML'
project_name:
type: str
default: example-project
YAML
cat > 'template/nested/{{ project_name }}/.copier-answers.yml.jinja' <<'JINJA'
_commit: ''
_src_path: template
project_name: {{ project_name }}
JINJA
cat > 'template/nested/{{ project_name }}/README.md.jinja' <<'JINJA'
# {{ project_name }}
JINJA
To Reproduce
- Create the template above.
- Run Copier
9.15.1:
rm -rf /tmp/copier-answers-repro/output-9151
mkdir -p /tmp/copier-answers-repro/output-9151
cd /tmp/copier-answers-repro/output-9151
git init -q
uvx --from "copier==9.15.1" copier copy --trust --defaults --force \
--data project_name=example-project \
../template .
- Check where the answers file was created:
test -f nested/example-project/.copier-answers.yml && echo "nested answers exists"
test ! -f .copier-answers.yml && echo "root answers absent"
Observed with 9.15.1:
nested answers exists
root answers absent
- Run Copier
9.15.2:
rm -rf /tmp/copier-answers-repro/output-9152
mkdir -p /tmp/copier-answers-repro/output-9152
cd /tmp/copier-answers-repro/output-9152
git init -q
uvx --from "copier==9.15.2" copier copy --trust --defaults --force \
--data project_name=example-project \
../template .
- Check where the answers file was created:
test ! -f nested/example-project/.copier-answers.yml && echo "nested answers missing"
test -f .copier-answers.yml && echo "root answers exists"
Observed with 9.15.2:
nested answers missing
root answers exists
Logs
Expected behavior
The answers file should be rendered consistently with the previous Copier behavior, or the new behavior should require an explicit opt-in.
For the template above, I expected:
nested/example-project/.copier-answers.yml
I did not expect:
Screenshots/screencasts/logs
No response
Operating system
Linux
Operating system distribution and version
linux 6.12.91-1-MANJARO
Copier version
copier 9.15.2
Python version
Python 3.14.5
Installation method
uvx+pypi
Additional context
This appears related to the 9.15.2 answers-file path changes. The same template behaves differently across Copier versions:
- Copier
9.15.1 renders the nested .copier-answers.yml.jinja file into the nested destination directory.
- Copier
9.15.2 renders .copier-answers.yml at the destination root instead.
The exact behavioral change
Removed _adjust_rendered_part(), which used to turn a full rendered answers path into just the filename so the file could land in the template’s subdirectory:
[Commit d76195a — deletion of _adjust_rendered_part](d76195a#diff-8b8e8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8The breaking change is in copier-org/copier#2186, specifically commit d76195a in copier/_main.py.
The exact behavioral change
Removed _adjust_rendered_part(), which used to strip a full rendered answers path down to just the filename so nested templates could place the file under a subdirectory:
commit d76195a — deletion of _adjust_rendered_part
The diff hunk is around lines 1040–1057 in that commit view.
Replaced with an early yield of self.answers_relpath (default .copier-answers.yml at repo root) whenever the rendered path matches the answers file:
if str(self.answers_relpath) == rendered_part:
yield self.answers_relpath, new_context
continue
and:
if str(self.answers_relpath) == rendered_part:
yield (self.answers_relpath, extra_context)
return
Describe the problem
Copier
9.15.2renders a non-root{{ _copier_conf.answers_file }}.jinjatemplate to the destination root as.copier-answers.yml.Copier
9.15.1rendered the same answers-file template into the same nested destination directory where the template file lived. This changes the generated output path for existing templates that include.copier-answers.yml.jinjabelow the template root.Template
This minimal template can be created locally with:
rm -rf /tmp/copier-answers-repro mkdir -p /tmp/copier-answers-repro/template/nested/{{ project_name }} cd /tmp/copier-answers-repro cat > template/copier.yml <<'YAML' project_name: type: str default: example-project YAML cat > 'template/nested/{{ project_name }}/.copier-answers.yml.jinja' <<'JINJA' _commit: '' _src_path: template project_name: {{ project_name }} JINJA cat > 'template/nested/{{ project_name }}/README.md.jinja' <<'JINJA' # {{ project_name }} JINJATo Reproduce
9.15.1:Observed with
9.15.1:9.15.2:Observed with
9.15.2:Logs
Expected behavior
The answers file should be rendered consistently with the previous Copier behavior, or the new behavior should require an explicit opt-in.
For the template above, I expected:
I did not expect:
Screenshots/screencasts/logs
No response
Operating system
Linux
Operating system distribution and version
linux 6.12.91-1-MANJARO
Copier version
copier 9.15.2
Python version
Python 3.14.5
Installation method
uvx+pypi
Additional context
This appears related to the
9.15.2answers-file path changes. The same template behaves differently across Copier versions:9.15.1renders the nested.copier-answers.yml.jinjafile into the nested destination directory.9.15.2renders.copier-answers.ymlat the destination root instead.The exact behavioral change
Removed _adjust_rendered_part(), which used to turn a full rendered answers path into just the filename so the file could land in the template’s subdirectory:
[Commit d76195a — deletion of _adjust_rendered_part](d76195a#diff-8b8e8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8f8The breaking change is in copier-org/copier#2186, specifically commit d76195a in copier/_main.py.
The exact behavioral change
Removed _adjust_rendered_part(), which used to strip a full rendered answers path down to just the filename so nested templates could place the file under a subdirectory:
commit d76195a — deletion of _adjust_rendered_part
The diff hunk is around lines 1040–1057 in that commit view.
Replaced with an early yield of self.answers_relpath (default .copier-answers.yml at repo root) whenever the rendered path matches the answers file:
if str(self.answers_relpath) == rendered_part:
yield self.answers_relpath, new_context
continue
and:
if str(self.answers_relpath) == rendered_part:
yield (self.answers_relpath, extra_context)
return