Skip to content

Derive the version from the git tag instead of a checked-in file - #50

Merged
hdrake merged 2 commits into
MOM6-community:masterfrom
hdrake:dynamic-version
Jul 29, 2026
Merged

hdrake merged 2 commits into
MOM6-community:masterfrom
hdrake:dynamic-version

Conversation

@hdrake

@hdrake hdrake commented Jul 28, 2026 •

Copy link
Copy Markdown
Member

Ports the scheme from hdrake/xeos#10 to sectionate: the version is derived from the git tag by hatch-vcs instead of being read from a literal in sectionate/version.py.

Why

sectionate/version.py held __version__ = "0.3.3", which had to be bumped in its own commit before every release. Nothing tied that commit to the tag the release was actually cut from, so the two could disagree — and when they did, the symptom was a 400 File already exists from PyPI at the very end of the release. That is exactly how the xeos v0.2.1 release failed: the tag was placed one commit before the bump, the workflow built the previous version, and PyPI rejected it.

With the tag as the source of truth, tagging is the bump. There is no second commit to remember and no way for the tag and the artifact to disagree.

What changed

  • pyproject.toml — hatch-vcs added to build-system.requires; [tool.hatch.version] switches from path = "sectionate/version.py" to source = "vcs"; local_scheme = "no-local-version" so untagged builds are X.Y.Z.devN rather than PEP 440 local versions that indexes refuse; a build hook writes the resolved version to sectionate/_version.py.
  • sectionate/version.py — now a shim that imports from the generated _version.py, with a 0.0.0+unknown fallback for a checkout that has never been built or installed. sectionate.__version__ is unchanged for anything installed from a release.
  • .gitignore — ignores the generated sectionate/_version.py.
  • .github/workflows/publish-to-pypi.yml — fetch-depth: 0 (a shallow clone has no tag, so the build would silently produce a .devN artifact), plus a step asserting the built version matches the release tag. checkout/setup-python bumped off the long-EOL v2.
  • .github/workflows/ci.yml — fetch-depth: 0 on the checkout, since the job installs the package.
  • .readthedocs.yaml — post_checkout unshallows and fetches tags. docs/source/conf.py titles the pages with the installed version, so without this they would read .devN.
  • conda/meta.yaml — hatch-vcs added to host. The recipe builds with --no-build-isolation, so the backend's requirements must be installed there; I confirmed locally that without it the wheel build fails in hatchling.builders.plugin.interface.get_build_hooks. The same addition is needed on conda-forge/sectionate-feedstock before the next release builds.
  • README.md — a Releasing section documenting the tag-is-the-version procedure and the two invariants it implies.

Verified locally

  • Clean tag → exact version: building at a throwaway v9.9.9 produces sectionate-9.9.9.tar.gz / .whl, no suffix, with the generated sectionate/_version.py inside the sdist.
  • Untagged master builds as 0.3.4.devN (last tag v0.3.3 + distance) — i.e. the same next-version line the checked-in literal was heading for.

Note on untagged checkouts

A checkout without tags — a shallow clone, or a fork that never fetched them — now resolves a .devN version rather than the release line. Two places that matters here:

  • CI and Read the Docs, handled above.
  • pip install git+https://github.com/<fork>/sectionate.git@<branch> will report 0.1.devN if that fork has no tags, which can fall below a downstream sectionate >= 0.3.3 floor. Pushing the release tags to the fork (git push <fork> --tags) fixes it; downstreams that install a dev branch this way should install it last with --force-reinstall --no-deps, as they already do for xgcm (which has used tag-derived versions for some time).

CI is red for an unrelated, pre-existing reason

The four build jobs fail at collection, before any test runs, on
ValueError: Argument 'boundary' has been renamed to 'padding' from
xgcm/grid.py — an xgcm 1.0 API break that sectionate/tests/test_section_class.py
and test_section_cornercases.py hit at import time. master has not run CI since
March 2026; it would fail the same way today. Nothing in this PR touches Python
outside version.py.

What this PR is responsible for did pass in those same runs: pip install -e .
resolved the version from the tag, and conda list reports
sectionate 0.3.4.dev16 — the tag v0.3.3 plus distance, which is exactly right.

🤖 Generated with Claude Code

`sectionate/version.py` held a literal that had to be bumped in its own commit
before every release, and nothing tied that commit to the tag the release was
actually cut from. The two could disagree, and when they did the symptom was a
400 from PyPI at the very end of the release.

hatch-vcs derives the version from the tag at build time and writes it to a
generated `sectionate/_version.py`, so tagging *is* the bump. `version.py`
becomes a shim over the generated file, with a `0.0.0+unknown` fallback for a
checkout that has never been built.

The tag has to be visible for that to work, so the CI and publish checkouts use
`fetch-depth: 0` and Read the Docs unshallows in `post_checkout`; without it the
build quietly produces a `.devN` artifact. The publish workflow also asserts
that the version it built matches the tag it was fired from, which is the check
that would have caught the failure mode described above.

conda/meta.yaml gains `hatch-vcs` in `host`: the recipe builds with
`--no-build-isolation`, so the backend's own requirements must be installed
there or the wheel build fails.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>

@hdrake hdrake left a comment

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me.

hdrake

This comment was marked as duplicate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@hdrake
hdrake merged commit e673487 into MOM6-community:master Jul 29, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant