fix(template): stabilize copier update and unbreak the first commit - #345
Merged
Conversation
…ions Floors track the version the template is actually exercised against, not the oldest release that still happens to work: ruff 0.16.1, ty 0.0.66, prek 0.4.12. Also carries copier 9.17.1 (security fixes) through uv.lock. The ruff ci-group assertion now compares against required-version as a lower bound instead of matching a literal string, so the ci floor can track the tested release without the test having to be edited in lockstep. prek 0.4.11 added the [priorities] alias tables; with the floor at 0.4.12 the generated-config note about them being blocked no longer applies.
… across updates
`copier update` regenerates pyproject.toml in full from the template and splices
back only marked regions. `project.version` and `tool.semantic_release.tag_format`
are owned by neither the template nor the user but by python-semantic-release,
which rewrites them in the project between updates, so a fresh render resets them
to the seed `0.0.0` / `{version}`.
Markers cannot fix this: a project updating *from* a marker-less version has no
snapshot to splice, so its first update -- the one that matters -- would still
reset them. sync_marked_sections.py now snapshots both by key path from the
existing file and writes them back into the fresh render.
The table-end scan requires a whole-line bracketed header. A bare `^[` would
truncate [tool.semantic_release] at the column-0 shell guards inside the
multi-line build_command, which sit before tag_format -- preservation would have
silently no-opped on the real template while passing synthetic tests.
Refs DOT-620
uv 0.12.0 made `uv init` write a [build-system] block by default; on 0.12.1 it emits `uv_build>=0.12.1,<0.13.0`. The template's window was `>=0.12,<0.13`, so raise the floor to match uv verbatim. The upper bound stays, and the docs now say why it is not ours to drop: uv_build follows uv's versioning policy and uv's own build-backend docs ask for an upper bound so packages keep building as new versions land. Also documents why a stale window is never a breakage -- uv uses its bundled backend copy only when it satisfies `requires`, and otherwise resolves uv_build from PyPI into an isolated build env, so the project still builds, just without the bundled fast path. No template machinery selects the backend; [build-system] is PEP 517's, and uv has converged on the src/ layout the template already generated.
The first commit in a freshly scaffolded project fails. The pytest-testmon pre-commit hook dies before running anything: INTERNALERROR> coverage.exceptions.CoverageWarning: Dynamic contexts aren't supported with core=sysmon; context data may be incomplete Nothing in the template changed to cause this; four existing choices finally lined up: 1. coverage selects the sys.monitoring core by default on CPython 3.14+ (SYSMON_DEFAULT = CPYTHON and PYVERSION >= (3, 14)). This template requires 3.14, so every generated project gets it. 2. That core cannot do dynamic contexts. coverage does fall back on its own -- but only when dynamic_context is set in config, which it reads once, up front. 3. testmon never sets it in config; it calls switch_context() imperatively per test, long after coverage has committed to sysmon. All coverage can do is warn. 4. filterwarnings = ["error"] promotes that warning to an exception raised inside a pluggy hook, so pytest aborts with INTERNALERROR and exit 3. Fixed by forcing COVERAGE_CORE=ctrace on the testmon hook only. Silencing the warning was rejected: testmon uses those per-test contexts to decide which tests a change affects, so incomplete context data would keep the hook green while quietly selecting the wrong tests. Scoped through prek's per-hook env rather than [tool.coverage.run] core, so the pytest-cov hook and poe test-cov keep sysmon, the faster core on 3.14. env also works on Windows, which the CI matrix covers -- an 'env VAR=value' prefix on entry would not, since prek execs the entry without a shell. Adds a fast assertion on the rendered hook; the existing integration test covers the same ground end-to-end but is marked slow.
Member
Author
|
This change is part of the following stack: Change managed by git-spice. |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.
Summary
Four commits that make
copier updatesafe to run on a released project, plus thedependency bump they were tested against.
dcf0f7fb40cc5aproject.versionandtool.semantic_release.tag_formatacross updates.1fc4bbcuv_buildpin; raise the floor to 0.12.1.a68a425Why
b40cc5ais the one worth reading closely.sync_marked_sections.pyregeneratespyproject.tomlin full from the template and splices back only marked regions.project.versionandtag_formatare owned by neither the template nor the user butby python-semantic-release, which rewrites them in the project between updates — so a
fresh render resets them to the seed
0.0.0/{version}.Markers cannot fix this. A project updating from a marker-less version has no
snapshot to splice, so its first update — the one that matters — would still reset
them. Preservation is therefore by key path, which needs no downstream action.
One subtlety in the implementation: the table-end scan requires a whole-line bracketed
header. A bare
^\[truncates[tool.semantic_release]at the column-0 shell guardsinside the multi-line
build_command, which sit beforetag_format— preservationwould have silently no-opped on the real template while passing synthetic tests. There
is a regression test for exactly that shape.
a68a425fixes a live breakage. The firstgit commitin any freshly scaffoldedproject currently fails. coverage selects the
sys.monitoringcore by default onCPython 3.14+, that core cannot do dynamic contexts,
pytest-testmonuses them, andfilterwarnings = ["error"]promotes coverage's warning into anINTERNALERROR.Fixed by scoping
COVERAGE_CORE=ctraceto the testmon hook via prek's per-hookenv,so
pytest-covkeeps the faster core. Silencing the warning was rejected: testmon usesthose contexts to pick which tests to run, so incomplete data would keep the hook green
while selecting the wrong tests.
1fc4bbcchanges nothing structural. uv 0.12 madeuv initemit[build-system]with
uv_buildby default, converging on what this template already generated. Theupper bound stays because it is uv's recommendation, not ours.
Test plan
pytest tests/test_template_lint.py— 39 passed (all boolean answer combinations render valid TOML/YAML)pytest tests/test_template.py::TestIntegration::test_first_commit_succeeds_with_prek_hooks— passes; this is the test that was failing beforea68a425tag_formatsurvive an update; the table scan survives thebuild_commandshell guards; an absent scalar keeps the fresh seed; the renderedpyproject.tomlis both readable and rewritable by the preservation codeCOVERAGE_CORE=ctracevia prek'senvkey rather than anentryprefix (the CI matrix includes Windows, where anenv VAR=valueprefix would not work)0.18.0andv{version}survive an update whileline-lengthstill tracks the templateRefs DOT-620
Greptile Summary
This change updates generated-project dependency floors, raises the uv build-backend requirement, preserves semantic-release-managed version metadata during Copier updates, and configures the testmon hook to use coverage’s C tracer core on Python 3.14+.
A real Copier update from the pre-change template to this revision was exercised with a released
project.versionand a customtool.semantic_release.tag_format. Both values remained intact after the update, while template-owned configuration—including the updateduv_buildrequirement—was refreshed. Focused tests also passed for scalar preservation, rendered configuration shape, and the multiline semantic-release build-command case.No defects were found.
Confidence Score: 5/5
Safe to merge based on the exercised Copier update flow and focused regression coverage.
No defects remain after validating that release-managed metadata survives a real update while fresh template-owned configuration is applied.
Files Needing Attention: None.
What T-Rex did
Reviews (1): Last reviewed commit: "fix(template): stop coverage sysmon core..." | Re-trigger Greptile