diff --git a/AGENTS.md b/AGENTS.md index e510903..bed5fe1 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,6 +48,7 @@ This repository publishes the open-source server, console, integration catalog, - Keep functions focused on one ownership boundary. - Propagate unexpected errors to the CLI or request boundary. - Keep technical claims executable through tests or generated validation. +- Keep the mirrored Python package, distribution, and CLI version in `sdks/python/elydora/_version.py`; Setuptools metadata must read that literal dynamically. - Interpret Python SDK `max_retries` as retries after the initial attempt and reject negative or non-integer values. - Retry RFC-idempotent Python SDK requests automatically; retry non-idempotent requests only when the transport proves the request was never sent. - Honor valid `Retry-After` delay-seconds and HTTP-date values, and release retryable responses before sleeping. diff --git a/sdks/python/elydora/__init__.py b/sdks/python/elydora/__init__.py index c87e6ab..5b14e1d 100644 --- a/sdks/python/elydora/__init__.py +++ b/sdks/python/elydora/__init__.py @@ -3,6 +3,7 @@ from .client import ElydoraClient from .async_client import AsyncElydoraClient from .errors import ElydoraError +from ._version import __version__ from .crypto import ( compute_chain_hash, compute_payload_hash, @@ -48,9 +49,8 @@ from .types import ( IntegrationType, ) -__version__ = "1.0.0" - __all__ = [ + "__version__", "ElydoraClient", "AsyncElydoraClient", "ElydoraError", diff --git a/sdks/python/elydora/_version.py b/sdks/python/elydora/_version.py new file mode 100644 index 0000000..6b481aa --- /dev/null +++ b/sdks/python/elydora/_version.py @@ -0,0 +1,3 @@ +"""Canonical Elydora package version.""" + +__version__ = "1.2.1" diff --git a/sdks/python/elydora/cli.py b/sdks/python/elydora/cli.py index 8b1d194..f7befaa 100644 --- a/sdks/python/elydora/cli.py +++ b/sdks/python/elydora/cli.py @@ -14,6 +14,7 @@ import shutil import sys from typing import Dict, Type +from ._version import __version__ from .crypto import get_public_key_base64url from .plugins.base import AgentPlugin, InstallConfig from .plugins.registry import SUPPORTED_AGENTS, get_agent_names @@ -174,7 +175,7 @@ def build_parser() -> argparse.ArgumentParser: description="Elydora — tamper-evident audit trail for AI agents", ) parser.add_argument( - "--version", action="version", version="%(prog)s 1.0.0" + "--version", action="version", version=f"%(prog)s {__version__}" ) subparsers = parser.add_subparsers(dest="command", help="Available commands") diff --git a/sdks/python/pyproject.toml b/sdks/python/pyproject.toml index 04a2a28..cdeebad 100644 --- a/sdks/python/pyproject.toml +++ b/sdks/python/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "elydora" -version = "1.1.0" +dynamic = ["version"] description = "Python SDK for the Elydora tamper-evident audit platform" readme = "README.md" license = {text = "MIT"} @@ -41,3 +41,6 @@ dev = [ [tool.setuptools.packages.find] include = ["elydora*"] + +[tool.setuptools.dynamic] +version = {attr = "elydora._version.__version__"} diff --git a/sdks/python/tests/test_version_contract.py b/sdks/python/tests/test_version_contract.py new file mode 100644 index 0000000..4cca48c --- /dev/null +++ b/sdks/python/tests/test_version_contract.py @@ -0,0 +1,18 @@ +from importlib.metadata import version + +import pytest + +from elydora import __version__ +from elydora.cli import build_parser + + +def test_runtime_version_matches_distribution_metadata() -> None: + assert __version__ == version("elydora") + + +def test_cli_reports_the_canonical_version(capsys: pytest.CaptureFixture[str]) -> None: + with pytest.raises(SystemExit) as exc_info: + build_parser().parse_args(["--version"]) + + assert exc_info.value.code == 0 + assert capsys.readouterr().out == f"elydora {__version__}\n"