mirror of
https://github.com/Screenly/Anthias.git
synced 2026-06-10 09:08:09 -04:00
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:
@@ -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
|
||||
|
||||
@@ -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 ''
|
||||
|
||||
|
||||
Reference in New Issue
Block a user