From 4e23b5774a19283d94458a99fcf1943ff79e56a0 Mon Sep 17 00:00:00 2001 From: Josh <162485031+wiyth00@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:51:05 -0400 Subject: [PATCH] chore: derive __version__ from installed package metadata __version__ now comes from importlib.metadata.version("chained-eclipse") with a "0+unknown" fallback for uninstalled source trees. MODEL_VERSION remains a deliberately separate model version, bumped when outputs change for fixed inputs. tests/test_versions.py pins CITATION.cff to the package version. --- chained_eclipse/__init__.py | 22 ++++++++++++++++-- tests/test_versions.py | 46 +++++++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 tests/test_versions.py diff --git a/chained_eclipse/__init__.py b/chained_eclipse/__init__.py index 9684cec..5944444 100644 --- a/chained_eclipse/__init__.py +++ b/chained_eclipse/__init__.py @@ -1,6 +1,24 @@ -"""Chained solar-eclipse search package.""" +"""Chained solar-eclipse search package. + +Two distinct version identifiers live here on purpose: + +- ``__version__`` is the *package* version, derived from the installed + distribution metadata (single-sourced from ``pyproject.toml``). It moves + with releases. +- ``MODEL_VERSION`` is the *model* version, defined in ``constants``. It is + bumped when computed outputs change for fixed inputs (see the CHANGELOG + policy) and is therefore allowed to differ from ``__version__``. +""" + +from __future__ import annotations + +from importlib.metadata import PackageNotFoundError, version from .constants import MODEL_VERSION -__all__ = ["MODEL_VERSION"] +try: + __version__ = version("chained-eclipse") +except PackageNotFoundError: # source tree without an installed distribution + __version__ = "0+unknown" +__all__ = ["MODEL_VERSION", "__version__"] diff --git a/tests/test_versions.py b/tests/test_versions.py new file mode 100644 index 0000000..613accd --- /dev/null +++ b/tests/test_versions.py @@ -0,0 +1,46 @@ +"""Version single-sourcing checks. + +``pyproject.toml`` is the only place the package version is written by hand. +``__version__`` must mirror the installed distribution, and ``CITATION.cff`` +must be bumped in lockstep with releases. ``MODEL_VERSION`` is deliberately +independent (it tracks output-changing model revisions, not packaging), so it +is only checked for shape, never for equality with the package version. +""" + +from __future__ import annotations + +from importlib.metadata import PackageNotFoundError, version +from pathlib import Path + +import pytest +import yaml + +import chained_eclipse + +CITATION_FILE = Path(__file__).resolve().parents[1] / "CITATION.cff" + + +def _installed_version() -> str: + try: + return version("chained-eclipse") + except PackageNotFoundError: # pragma: no cover - CI always installs + pytest.skip("chained-eclipse is not installed") + + +def test_dunder_version_matches_installed_distribution() -> None: + assert chained_eclipse.__version__ == _installed_version() + + +def test_citation_cff_version_matches_installed_distribution() -> None: + citation = yaml.safe_load(CITATION_FILE.read_text(encoding="utf-8")) + assert str(citation["version"]) == _installed_version(), ( + "CITATION.cff `version:` must be bumped in the same commit that changes " + "the package version in pyproject.toml" + ) + + +def test_model_version_is_present_and_separate() -> None: + assert isinstance(chained_eclipse.MODEL_VERSION, str) + assert chained_eclipse.MODEL_VERSION + # No equality assertion with __version__: the model version is allowed to + # differ from the package version by design.