|
1 | 1 | """Packaging metadata tests. |
2 | 2 |
|
3 | | -Ensures the package version is single-sourced from installed metadata |
4 | | -(see issue #78). |
| 3 | +Ensures the package version is single-sourced via ``hatch-vcs`` and not |
| 4 | +hand-maintained in multiple places (see issue #78). |
5 | 5 | """ |
6 | 6 |
|
7 | 7 | from __future__ import annotations |
8 | 8 |
|
| 9 | +import re |
9 | 10 | from importlib.metadata import version as pkg_version |
| 11 | +from pathlib import Path |
10 | 12 |
|
11 | 13 | import haclient |
12 | 14 |
|
13 | 15 |
|
14 | | -def test_version_matches_package_metadata() -> None: |
15 | | - """``haclient.__version__`` must match installed package metadata. |
| 16 | +def test_version_is_single_sourced_from_vcs() -> None: |
| 17 | + """``haclient.__version__`` must come from the generated ``_version.py``. |
16 | 18 |
|
17 | | - This guards against the previous drift where ``pyproject.toml`` and |
18 | | - ``haclient/__init__.py`` declared different versions. |
| 19 | + With ``hatch-vcs`` the version is derived from git tags at build time and |
| 20 | + written into ``src/haclient/_version.py``. ``pyproject.toml`` must not |
| 21 | + declare a static ``[project].version`` and ``__init__.py`` must not embed |
| 22 | + a literal version string. |
19 | 23 | """ |
20 | | - assert haclient.__version__ == pkg_version("haclient") |
| 24 | + pyproject = Path(__file__).resolve().parent.parent / "pyproject.toml" |
| 25 | + contents = pyproject.read_text(encoding="utf-8") |
| 26 | + assert 'dynamic = ["version"]' in contents |
| 27 | + # No static ``version = "x.y.z"`` line under [project]. |
| 28 | + assert '\nversion = "' not in contents |
| 29 | + |
| 30 | + init_file = Path(haclient.__file__) |
| 31 | + init_text = init_file.read_text(encoding="utf-8") |
| 32 | + # No hand-maintained release version literal (e.g. ``__version__ = "1.2.3"``). |
| 33 | + assert not re.search(r'__version__\s*=\s*"\d+\.\d+\.\d+"', init_text) |
21 | 34 |
|
22 | 35 |
|
23 | 36 | def test_version_is_non_empty_string() -> None: |
24 | | - """``__version__`` must be a non-empty string.""" |
| 37 | + """``__version__`` must be a non-empty PEP 440-ish string.""" |
25 | 38 | assert isinstance(haclient.__version__, str) |
26 | 39 | assert haclient.__version__ |
| 40 | + # Must at least start with a digit (PEP 440 release segment). |
| 41 | + assert haclient.__version__[0].isdigit() |
| 42 | + |
| 43 | + |
| 44 | +def test_installed_metadata_is_available() -> None: |
| 45 | + """The package must expose a version via ``importlib.metadata``. |
| 46 | +
|
| 47 | + This does not require equality with ``__version__`` because an editable |
| 48 | + install records the version at install time while ``_version.py`` is |
| 49 | + regenerated on every build; the two can legitimately differ between |
| 50 | + rebuilds. We only assert that metadata is present and non-empty. |
| 51 | + """ |
| 52 | + meta_version = pkg_version("haclient") |
| 53 | + assert isinstance(meta_version, str) |
| 54 | + assert meta_version |
0 commit comments