fix(version): pyproject.toml fallback for environments without an installed wheel

importlib.metadata.version('anthias') raises PackageNotFoundError in
every standard Anthias environment — the production / test / host
installs all run `uv sync --no-install-project` (see
docker/uv-builder.j2, docker/Dockerfile.{server,test,viewer},
bin/install.sh). That flag installs the project's deps but not the
project itself, so the previous helper returned an empty string and
the System Info version label silently dropped to "(03490087,
vanilla-django)" with no CalVer head — defeating the whole point of
the new label.

get_anthias_release() now resolves in two steps:

  1. importlib.metadata.version (works for editable installs / wheels)
  2. Direct tomllib read of the repo-root pyproject.toml (works for
     --no-install-project deployments)

Result is cached on the function attribute so per-request System Info
renders and the v2 info API don't re-open the file.

The unit test that pinned the expected version label now derives it
from the same helper rather than calling importlib.metadata at module
import time — that import-time call would have crashed the test
collection in CI (since the test container also runs without the
project installed).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Viktor Petersson
2026-05-04 11:44:50 +00:00
parent 0349008728
commit 4697cfd58f
2 changed files with 56 additions and 13 deletions

View File

@@ -2,7 +2,6 @@
Tests for Info API endpoints (v1 and v2).
"""
from importlib.metadata import version as _pkg_version
from typing import Any
from unittest import mock
@@ -11,10 +10,14 @@ from django.urls import reverse
from rest_framework import status
from rest_framework.test import APIClient
# Pulled from pyproject.toml's [project].version via the installed
# package metadata so the test moves in lockstep with the release
# bumper without anyone having to update both places.
_ANTHIAS_RELEASE = _pkg_version('anthias')
from anthias_server.lib.diagnostics import get_anthias_release
# Pulled from pyproject.toml's [project].version via the diagnostics
# helper so the test moves in lockstep with the release bumper, and
# also works in environments built with `uv sync --no-install-project`
# (production, host install) where importlib.metadata wouldn't find
# the package — the helper falls back to a tomllib read.
_ANTHIAS_RELEASE = get_anthias_release()
@pytest.fixture

View File

@@ -92,17 +92,57 @@ _RELEASE_BRANCHES = frozenset({'master', 'main'})
def get_anthias_release() -> str:
"""Read the project version from the installed package metadata
(sourced from pyproject.toml's [project].version, currently
CalVer ``YYYY.M.MICRO``). Falls back to the empty string when the
package isn't installed under this interpreter — e.g. running
ad-hoc scripts straight off the source tree without `uv sync`."""
"""Read the project version, sourced from pyproject.toml's
[project].version (currently CalVer ``YYYY.M.MICRO``).
Resolution order:
1. ``importlib.metadata.version('anthias')`` — works for
editable installs (``pip install -e .``) and any path where
the project ships as a wheel.
2. Fallback: parse ``pyproject.toml`` directly with ``tomllib``.
Required because every production / test / host environment
runs ``uv sync --no-install-project`` (see
docker/uv-builder.j2, docker/Dockerfile.{server,test,viewer},
bin/install.sh) — that flag installs the project's deps but
NOT the project itself, so importlib.metadata has no record
of an ``anthias`` distribution to read.
Cached after first successful read so the System Info HTML render
(called per request) and the v2 info API don't re-open the file.
Returns the empty string only when both sources fail.
"""
cached: str | None = getattr(get_anthias_release, '_cached', None)
if cached is not None:
return cached
value: str
try:
from importlib.metadata import PackageNotFoundError, version
return version('anthias')
except PackageNotFoundError:
return ''
try:
value = version('anthias')
except PackageNotFoundError:
value = _read_version_from_pyproject()
except Exception:
value = ''
setattr(get_anthias_release, '_cached', value)
return value
def _read_version_from_pyproject() -> str:
"""Last-ditch source for the project version when the package
isn't installed in the active venv. Walks up from this file to
find the repo-root pyproject.toml — `__file__` lives at
``src/anthias_server/lib/diagnostics.py``, so parents[3] is the
checkout root in both editable installs and the
``uv sync --no-install-project`` Docker layout."""
try:
import tomllib
from pathlib import Path
pyproject = Path(__file__).resolve().parents[3] / 'pyproject.toml'
with pyproject.open('rb') as f:
data = tomllib.load(f)
return str(data.get('project', {}).get('version', ''))
except Exception:
return ''