diff --git a/changelog.d/migrate-trov-namespace-canonical.changed.md b/changelog.d/migrate-trov-namespace-canonical.changed.md new file mode 100644 index 00000000..9b614cf4 --- /dev/null +++ b/changelog.d/migrate-trov-namespace-canonical.changed.md @@ -0,0 +1 @@ +Migrated TRACE TRO emission from the prerelease TROv namespace `https://w3id.org/trace/2023/05/trov#` to the canonical `https://w3id.org/trace/trov/0.1#`. This aligns policyengine.py with policyengine-us-data (which already uses the canonical namespace per us-data PR #746), so both sides can share SHACL validators and TROs emitted by either side validate against the same vocabulary. Fixes #313. diff --git a/docs/release-bundles.md b/docs/release-bundles.md index a28e0d1d..b3e71f9c 100644 --- a/docs/release-bundles.md +++ b/docs/release-bundles.md @@ -205,7 +205,7 @@ composition pins four artifacts by sha256: when present, otherwise fetched from the PyPI JSON API at emit time) TROs use the public TROv vocabulary at -`https://w3id.org/trace/2023/05/trov#`. Every artifact location in the TRO +`https://w3id.org/trace/trov/0.1#`. Every artifact location in the TRO is a dereferenceable HTTPS URI or a local path relative to the shipped wheel. Certification metadata is carried as structured `pe:*` fields on the `trov:TransparentResearchPerformance` node so downstream tooling can diff --git a/pyproject.toml b/pyproject.toml index 5cb70ca7..3546f431 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,6 +24,7 @@ dependencies = [ "pydantic>=2.0.0", "pandas>=2.0.0", "microdf_python>=1.2.1", + "jsonschema>=4.0.0", "requests>=2.31.0", "psutil>=5.9.0", "packaging>=23.0", @@ -55,7 +56,6 @@ dev = [ "yaml-changelog>=0.1.7", "itables", "build", - "jsonschema>=4.0.0", "plotly>=5.0.0", "pytest-asyncio>=0.26.0", "ruff>=0.9.0", diff --git a/src/policyengine/data/schemas/trace_tro.schema.json b/src/policyengine/data/schemas/trace_tro.schema.json index b8a12a34..a6fe1905 100644 --- a/src/policyengine/data/schemas/trace_tro.schema.json +++ b/src/policyengine/data/schemas/trace_tro.schema.json @@ -15,7 +15,7 @@ "properties": { "trov": { "type": "string", - "const": "https://w3id.org/trace/2023/05/trov#" + "const": "https://w3id.org/trace/trov/0.1#" }, "schema": { "type": "string", diff --git a/src/policyengine/provenance/trace.py b/src/policyengine/provenance/trace.py index 83ac0b5b..2a48b38a 100644 --- a/src/policyengine/provenance/trace.py +++ b/src/policyengine/provenance/trace.py @@ -1,7 +1,7 @@ """TRACE Transparent Research Object (TRO) export. Emits JSON-LD that conforms to the TRACE TROv vocabulary -(https://w3id.org/trace/2023/05/trov#) for a PolicyEngine certified +(https://w3id.org/trace/trov/0.1#) for a PolicyEngine certified runtime bundle or a PolicyEngine simulation result. The bundle TRO pins the country model wheel, the country data release manifest, the certified dataset, and the bundle manifest itself by sha256. The @@ -33,7 +33,7 @@ https_release_manifest_uri, ) -TRACE_TROV_NAMESPACE = "https://w3id.org/trace/2023/05/trov#" +TRACE_TROV_NAMESPACE = "https://w3id.org/trace/trov/0.1#" POLICYENGINE_TRACE_NAMESPACE = "https://policyengine.org/trace/0.1#" TRACE_CONTEXT: list[dict[str, str]] = [ diff --git a/tests/test_graph/test_extractor.py b/tests/test_graph/test_extractor.py index 91e2a840..b555ff98 100644 --- a/tests/test_graph/test_extractor.py +++ b/tests/test_graph/test_extractor.py @@ -102,7 +102,6 @@ class TestDirectEntityReference: """Pattern 1: ``entity("", period)`` produces an edge.""" def test_single_direct_reference(self, tmp_path: Path) -> None: - root = tmp_path / "variables" _write_variable( root, @@ -153,7 +152,6 @@ class TestAddHelperReference: """Pattern 2: ``add(entity, period, [...])`` emits one edge per list item.""" def test_add_helper_list(self, tmp_path: Path) -> None: - root = tmp_path / "variables" _write_variable( root, @@ -175,7 +173,6 @@ class TestImpactAnalysis: """``impact(var)`` returns variables that depend on ``var`` transitively.""" def test_transitive_upstream(self, tmp_path: Path) -> None: - root = tmp_path / "variables" _write_variable(root, "wages", "return 0") _write_variable( @@ -228,7 +225,6 @@ class TestMultipleFormulas: """Year-specific ``formula_YYYY`` methods contribute edges too.""" def test_year_specific_formula_contributes_edges(self, tmp_path: Path) -> None: - root = tmp_path / "variables" (root / "ctc.py").parent.mkdir(parents=True, exist_ok=True) (root / "ctc.py").write_text( @@ -260,7 +256,6 @@ class TestPath: """``path(src, dst)`` returns a dependency chain if one exists.""" def test_path_two_hops(self, tmp_path: Path) -> None: - root = tmp_path / "variables" _write_variable(root, "wages", "return 0") _write_variable(root, "gross_income", 'return tax_unit("wages", period)') @@ -278,7 +273,6 @@ def test_path_two_hops(self, tmp_path: Path) -> None: ] def test_path_returns_none_if_unreachable(self, tmp_path: Path) -> None: - root = tmp_path / "variables" _write_variable(root, "island_a", "return 0") _write_variable(root, "island_b", "return 0") @@ -295,7 +289,6 @@ class TestRequiresVariableSubclass: """ def test_non_variable_classes_are_ignored(self, tmp_path: Path) -> None: - root = tmp_path / "variables" root.mkdir(parents=True, exist_ok=True) # Looks like a variable body but the class is not a Variable. diff --git a/tests/test_trace_tro.py b/tests/test_trace_tro.py index 9f32817f..fd673afd 100644 --- a/tests/test_trace_tro.py +++ b/tests/test_trace_tro.py @@ -118,7 +118,7 @@ class TestBundleTRO: def test__given_context__then_uses_public_trov_namespace(self, us_bundle_tro): context = us_bundle_tro["@context"][0] assert context["trov"] == TRACE_TROV_NAMESPACE - assert context["trov"] == "https://w3id.org/trace/2023/05/trov#" + assert context["trov"] == "https://w3id.org/trace/trov/0.1#" def test__given_root_type__then_is_single_transparent_research_object( self, us_bundle_tro diff --git a/uv.lock b/uv.lock index bbbd4300..65678a22 100644 --- a/uv.lock +++ b/uv.lock @@ -2417,12 +2417,12 @@ wheels = [ [[package]] name = "policyengine" -version = "3.4.5" +version = "4.3.0" source = { editable = "." } dependencies = [ { name = "microdf-python" }, + { name = "packaging" }, { name = "pandas" }, - { name = "plotly" }, { name = "psutil" }, { name = "pydantic" }, { name = "requests" }, @@ -2438,6 +2438,7 @@ dev = [ { name = "jupyter-book" }, { name = "mypy", version = "1.19.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, { name = "mypy", version = "1.20.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" }, + { name = "plotly" }, { name = "policyengine-core" }, { name = "policyengine-uk" }, { name = "policyengine-us" }, @@ -2448,6 +2449,14 @@ dev = [ { name = "towncrier" }, { name = "yaml-changelog" }, ] +graph = [ + { name = "networkx", version = "3.2.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" }, + { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.10.*'" }, + { name = "networkx", version = "3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, +] +plotting = [ + { name = "plotly" }, +] uk = [ { name = "policyengine-core" }, { name = "policyengine-uk" }, @@ -2467,15 +2476,18 @@ requires-dist = [ { name = "jupyter-book", marker = "extra == 'dev'" }, { name = "microdf-python", specifier = ">=1.2.1" }, { name = "mypy", marker = "extra == 'dev'", specifier = ">=1.11.0" }, + { name = "networkx", marker = "extra == 'graph'", specifier = ">=3.0" }, + { name = "packaging", specifier = ">=23.0" }, { name = "pandas", specifier = ">=2.0.0" }, - { name = "plotly", specifier = ">=5.0.0" }, + { name = "plotly", marker = "extra == 'dev'", specifier = ">=5.0.0" }, + { name = "plotly", marker = "extra == 'plotting'", specifier = ">=5.0.0" }, { name = "policyengine-core", marker = "extra == 'dev'", specifier = ">=3.25.0" }, { name = "policyengine-core", marker = "extra == 'uk'", specifier = ">=3.25.0" }, { name = "policyengine-core", marker = "extra == 'us'", specifier = ">=3.25.0" }, { name = "policyengine-uk", marker = "extra == 'dev'", specifier = "==2.88.0" }, { name = "policyengine-uk", marker = "extra == 'uk'", specifier = "==2.88.0" }, - { name = "policyengine-us", marker = "extra == 'dev'", specifier = "==1.647.0" }, - { name = "policyengine-us", marker = "extra == 'us'", specifier = "==1.647.0" }, + { name = "policyengine-us", marker = "extra == 'dev'", specifier = "==1.653.3" }, + { name = "policyengine-us", marker = "extra == 'us'", specifier = "==1.653.3" }, { name = "psutil", specifier = ">=5.9.0" }, { name = "pydantic", specifier = ">=2.0.0" }, { name = "pytest", marker = "extra == 'dev'" }, @@ -2486,7 +2498,7 @@ requires-dist = [ { name = "towncrier", marker = "extra == 'dev'", specifier = ">=24.8.0" }, { name = "yaml-changelog", marker = "extra == 'dev'", specifier = ">=0.1.7" }, ] -provides-extras = ["uk", "us", "dev"] +provides-extras = ["plotting", "graph", "uk", "us", "dev"] [[package]] name = "policyengine-core" @@ -2538,7 +2550,7 @@ wheels = [ [[package]] name = "policyengine-us" -version = "1.647.0" +version = "1.653.3" source = { registry = "https://pypi.org/simple" } dependencies = [ { name = "microdf-python" }, @@ -2550,9 +2562,9 @@ dependencies = [ { name = "tables", version = "3.11.1", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, { name = "tqdm" }, ] -sdist = { url = "https://files.pythonhosted.org/packages/60/85/bef86a7edb48fe7f3d7005ef03f955690c9f3bc6c1fa69598ae70b7e04e8/policyengine_us-1.647.0.tar.gz", hash = "sha256:118afa1b4dc7b0d23e04b5cf0dbacfd6c518c069ff506c4b264d919c1a964cce", size = 9067156, upload-time = "2026-04-17T21:00:38.12Z" } +sdist = { url = "https://files.pythonhosted.org/packages/a2/60/5b736fa238559857fbf29168933c809eaada9abf006d26910b7958f5748e/policyengine_us-1.653.3.tar.gz", hash = "sha256:8a5c33997b7aefa2061d0dafce837b130e8ebdb0b9f83ae8c236f80cbf1805d6", size = 9180339, upload-time = "2026-04-18T12:06:45.764Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/2a/96/4814f2630395350915d819452d7684f232c9b8df1d9ba5c279f3b6d02c17/policyengine_us-1.647.0-py3-none-any.whl", hash = "sha256:50e64bf910772b224cdc2b5af5a3414f976f68a9e1748107da7e1de6e325425c", size = 9156799, upload-time = "2026-04-17T21:00:33.492Z" }, + { url = "https://files.pythonhosted.org/packages/02/07/25f39a2bfa1ff210cd8e78826c47c03b9040a98a83f4eed59c434c1ed862/policyengine_us-1.653.3-py3-none-any.whl", hash = "sha256:67a49b98d85c060b24d547a569e91a6703c0fc9c41299c1c67f4ecfac75c67c6", size = 9445650, upload-time = "2026-04-18T12:06:43.163Z" }, ] [[package]]