A build-it-yourself guide. The version string lives in two places today —
version = "0.2.0" in pyproject.toml and
__version__ = "0.2.0" in modulearn/__init__.py. Two sources of truth
drift; a release where they disagree is confusing and entirely avoidable.
modulearn --version matches the version of the
built wheel with no manual sync.ModuLearn already builds with hatchling (see
[build-system] in pyproject.toml), and hatchling can read the version
straight out of a Python attribute. So keep __version__ in
modulearn/__init__.py as the one source — runtime code and
modulearn --version already import it — and have pyproject.toml declare
the version dynamic, pointing back at that attribute.
modulearn/__init__.py → __version__.pyproject.toml reads it via [tool.hatch.version].__version__ importable
regardless (it's in __all__), and you can't import from pyproject.toml.
Making the Python file authoritative means zero runtime machinery — the build tool does the reading,
not your package.[project] tableDelete the hard-coded version = "0.2.0" line and declare it dynamic instead.
[project]
name = "modulearn"
# version = "0.2.0" <- remove this line
dynamic = ["version"]
...
Tell the hatchling version hook which attribute to read.
[tool.hatch.version]
path = "modulearn/__init__.py"
__version__ = "..." assignment by default, which is exactly what
__init__.py already has.Nothing to edit here — __version__ = "0.2.0" stays put. From now on this is the
only line you bump to cut a release.
Build a wheel and confirm its version is read from the Python attribute, and that the runtime reports the same string.
pip install -e ".[dev]" # ensure hatchling + build are present
python -m build 2>&1 | grep -i modulearn # wheel name shows the version
# e.g. Successfully built modulearn-0.2.0.tar.gz and modulearn-0.2.0-py3-none-any.whl
modulearn --version # expect: modulearn 0.2.0
python -c "import modulearn; print(modulearn.__version__)" # 0.2.0
__version__ to "0.2.1", rebuild, and confirm the wheel name follows —
then revert. If the wheel tracks the edit with no other change, the two sources are truly one.git add pyproject.toml
git commit -m "Single-source the version from modulearn/__init__.py"
git push
gh run list --branch main --limit 1 # expect: success
Add done:true, to the
{area:"hygiene", … title:"Single-source the version"} item in
docs/roadmap.html.
__version__, add a changelog entry, tag — and pyproject, the wheel, and
modulearn --version all follow automatically. No more "which file did I forget?"