Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 20 additions & 1 deletion .github/workflows/pr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,25 @@ jobs:
echo "Types: added, changed, fixed, removed, breaking"
exit 1
fi
BundleMetadataContract:
name: Validate bundle metadata contract
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Set up Python
uses: actions/setup-python@v6
with:
python-version: "3.14"
- name: Install uv
uses: astral-sh/setup-uv@v8.1.0
- name: Install core
run: uv pip install --system .
- name: Install bundle validation tooling
# Pin the test-only bundle contract dependency until policyengine-bundles
# has published releases suitable for ordinary dependency specifiers.
run: uv pip install --system "policyengine-bundles @ git+https://github.com/PolicyEngine/policyengine-bundles@8ae9f56fefcf89f69b8a7e3bc49928509c6207be"
- name: Validate runtime metadata contract
run: python -m pytest tests/core/test_build_metadata.py
Test:
strategy:
matrix:
Expand Down Expand Up @@ -100,4 +119,4 @@ jobs:
run: python -m pytest -m smoke --reruns 2 --reruns-delay 5 -v -s
env:
RUN_SMOKE_TESTS: "0"
POLICYENGINE_GITHUB_MICRODATA_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
POLICYENGINE_GITHUB_MICRODATA_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
1 change: 1 addition & 0 deletions changelog.d/add-runtime-metadata.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added dependency-free runtime metadata for bundle validation.
1 change: 1 addition & 0 deletions policyengine_core/__init__.py
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
from policyengine_core.build_metadata import get_runtime_metadata
from policyengine_core.simulations import Microsimulation, Simulation
from policyengine_core.taxbenefitsystems import TaxBenefitSystem
67 changes: 67 additions & 0 deletions policyengine_core/build_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
from __future__ import annotations

import importlib.metadata
import json
from typing import Any, Dict, Optional


PACKAGE_NAME = "policyengine-core"

__all__ = ["get_runtime_metadata"]


def get_runtime_metadata() -> Dict[str, Any]:
"""Return JSON-compatible metadata describing this core runtime.

The payload intentionally avoids importing the bundle orchestrator. It is
shaped to be validated by policyengine-bundles when that package is
available in release or integration-test workflows.
"""

distribution = importlib.metadata.distribution(PACKAGE_NAME)
metadata: Dict[str, Any] = {
"name": PACKAGE_NAME,
"version": distribution.version,
}

git_sha = _get_direct_url_git_sha(distribution)
if git_sha is not None:
metadata["git_sha"] = git_sha

return metadata


def _get_direct_url_git_sha(
distribution: importlib.metadata.Distribution,
) -> Optional[str]:
direct_url = _read_direct_url(distribution)
if direct_url is None:
return None

vcs_info = direct_url.get("vcs_info")
if not isinstance(vcs_info, dict):
return None

commit_id = vcs_info.get("commit_id")
if isinstance(commit_id, str) and commit_id:
return commit_id

return None


def _read_direct_url(
distribution: importlib.metadata.Distribution,
) -> Optional[Dict[str, Any]]:
direct_url_text = distribution.read_text("direct_url.json")
if direct_url_text is None:
return None

try:
direct_url = json.loads(direct_url_text)
except json.JSONDecodeError:
return None

if isinstance(direct_url, dict):
return direct_url

return None
60 changes: 60 additions & 0 deletions tests/core/test_build_metadata.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from __future__ import annotations

import importlib.metadata
import json

import pytest

from policyengine_core import get_runtime_metadata
from policyengine_core import build_metadata


def test_runtime_metadata_has_core_identity():
metadata = get_runtime_metadata()

assert metadata["name"] == "policyengine-core"
assert metadata["version"] == importlib.metadata.version("policyengine-core")


def test_runtime_metadata_is_json_compatible():
json.dumps(get_runtime_metadata())


def test_runtime_metadata_does_not_include_local_source_path():
assert "source_path" not in get_runtime_metadata()


def test_runtime_metadata_uses_pep_610_vcs_commit(monkeypatch):
class Distribution:
version = "1.2.3"

def read_text(self, name):
if name == "direct_url.json":
return json.dumps(
{
"vcs_info": {
"vcs": "git",
"commit_id": "abc123",
}
}
)

return None

monkeypatch.setattr(
build_metadata.importlib.metadata,
"distribution",
lambda name: Distribution(),
)

assert get_runtime_metadata() == {
"name": "policyengine-core",
"version": "1.2.3",
"git_sha": "abc123",
}


def test_runtime_metadata_uses_bundle_contract_when_available():
validation = pytest.importorskip("policyengine_bundles")

validation.load_component_metadata(get_runtime_metadata())