Skip to content

Single-source the version from pyproject.toml - #16

Merged
garrison merged 1 commit into
mainfrom
version-single-source
Sep 2, 2026
Merged

Single-source the version from pyproject.toml#16
garrison merged 1 commit into
mainfrom
version-single-source

Conversation

@garrison

@garrison garrison commented Sep 2, 2026

Copy link
Copy Markdown
Member

This PR was generated by Claude Opus 5 under my guidance.


The version was declared twice — once in pyproject.toml and again as a literal __version__ in python/__init__.py. A release required editing both, and either edit alone would leave the two disagreeing with no error to signal it.

This reads the version from the installed distribution metadata instead, leaving the [project] table in pyproject.toml as the single declaration:

from importlib.metadata import version

__version__ = version("sbd-eigensolver")

Note the argument is the distribution name (sbd-eigensolver), not the import name (sbd).

Why this direction

The other way to de-duplicate is to have pyproject.toml declare dynamic = ["version"] and read attr = "sbd.__version__". That was not taken here. It depends on setuptools statically AST-parsing the assignment; if setuptools ever falls back to importing the package to resolve the attribute, it would import sbd before the extension modules are built, and this __init__ loads the _core_* backends at import time. Deriving the runtime attribute from the metadata avoids any build-time import of the package.

What this gives up

sbd.__version__ now requires the distribution metadata to be present. That holds for both pip install . and pip install -e .. It would break only for a source tree placed on sys.path without being installed — which is not a working configuration for this package regardless, since the compiled _core_* modules must be built into the package directory; importing in that state already fails with RuntimeError: No SBD backends available.

A try/except PackageNotFoundError fallback was deliberately omitted: it would convert a loud, accurate failure into a silently wrong version string for a case that cannot arise in a working install.

Verification

Checked in a throwaway virtualenv against a minimal package reproducing the same name mismatch and layout (packages = ["sbd"], package-dir = {sbd = "python"}):

  • pip install .sbd.__version__ == "1.6.1"
  • pip install -e .sbd.__version__ == "1.6.1"
  • bumping only pyproject.toml to 9.9.9 and reinstalling → sbd.__version__ == "9.9.9", confirming the value tracks the single declaration with no second edit

test/conftest.py already reads sbd.__version__ to build the pytest header, so the existing suite exercises this path on every run.

The version was declared twice, in pyproject.toml and as a literal
__version__ in python/__init__.py, so a release required editing both and
either edit alone would leave the two disagreeing.

Read it from the installed distribution metadata instead, leaving the
[project] table in pyproject.toml as the single declaration.

The alternative direction -- pyproject.toml declaring `dynamic = ["version"]`
and reading `attr = "sbd.__version__"` -- was not taken. It relies on
setuptools statically AST-parsing the assignment, and if setuptools ever
falls back to importing the package it would import it before the extension
modules are built, since this __init__ loads the _core_* backends at import
time.
@garrison
garrison marked this pull request as ready for review September 2, 2026 16:57
@garrison
garrison merged commit 9283f40 into main Sep 2, 2026
6 checks passed
@garrison
garrison deleted the version-single-source branch September 2, 2026 17:11
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