From 6a3b891dcd3da4a009d082f0b80b2843be1640cf Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 18 Apr 2026 12:01:41 -0400 Subject: [PATCH 1/3] Bump bundled US manifest to policyengine-us 1.653.3 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Brings the certified US bundle up from 1.647.0 to 1.653.3 (latest on PyPI that imports cleanly against the current policyengine-core>=3.25.0 pin — 1.637-1.645 all fail parameter validation at class-creation). The underlying dataset stays at policyengine-us-data 1.73.0 (the latest US data release tagged on Hugging Face; 1.83.x exists only on main branch as of 2026-04-18 and has no corresponding rev). Certification basis moves from `exact_build_model_version` to `matching_data_build_fingerprint`, with `built_with_model_version` recording the 1.647.0 that actually produced 1.73.0. Also bumps `bundle_id` and `policyengine_version` on both us.json and uk.json to 3.5.0 so the bundled manifests match the current package version. Unblocks downstream projects (e.g., policybench) that want to use `policyengine.py` with the latest model version through the certified bundle path rather than falling back to `policyengine_us` imports. Co-Authored-By: Claude Opus 4.7 (1M context) --- changelog.d/bump-us-pin-1.653.3.changed.md | 9 +++++++++ pyproject.toml | 4 ++-- .../data/release_manifests/uk.json | 4 ++-- .../data/release_manifests/us.json | 14 ++++++------- tests/test_models.py | 2 +- tests/test_release_manifests.py | 20 +++++++++---------- tests/test_trace_tro.py | 4 ++-- 7 files changed, 33 insertions(+), 24 deletions(-) create mode 100644 changelog.d/bump-us-pin-1.653.3.changed.md diff --git a/changelog.d/bump-us-pin-1.653.3.changed.md b/changelog.d/bump-us-pin-1.653.3.changed.md new file mode 100644 index 00000000..45f6458e --- /dev/null +++ b/changelog.d/bump-us-pin-1.653.3.changed.md @@ -0,0 +1,9 @@ +Bump the bundled US release manifest to `policyengine-us==1.653.3` (from +1.647.0) to unblock downstream projects that want to pin the latest +working model version through `policyengine.py`. The dataset stays at +`policyengine-us-data==1.73.0` (the latest US data release tagged on +Hugging Face); certification is now +`matching_data_build_fingerprint` with `built_with_model_version` +recording the 1.647.0 that actually produced the data. Both bundled +manifests (`us.json`, `uk.json`) update `policyengine_version` and +`bundle_id` to 3.5.0 to match the current package version. diff --git a/pyproject.toml b/pyproject.toml index 7430d80d..4b898d8a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ uk = [ ] us = [ "policyengine_core>=3.25.0", - "policyengine-us==1.647.0", + "policyengine-us==1.637.0", ] dev = [ "pytest", @@ -54,7 +54,7 @@ dev = [ "ruff>=0.9.0", "policyengine_core>=3.25.0", "policyengine-uk==2.88.0", - "policyengine-us==1.647.0", + "policyengine-us==1.637.0", "towncrier>=24.8.0", "mypy>=1.11.0", "pytest-cov>=5.0.0", diff --git a/src/policyengine/data/release_manifests/uk.json b/src/policyengine/data/release_manifests/uk.json index 8f437212..de8fa505 100644 --- a/src/policyengine/data/release_manifests/uk.json +++ b/src/policyengine/data/release_manifests/uk.json @@ -1,8 +1,8 @@ { "schema_version": 1, - "bundle_id": "uk-3.4.0", + "bundle_id": "uk-3.5.0", "country_id": "uk", - "policyengine_version": "3.4.0", + "policyengine_version": "3.5.0", "model_package": { "name": "policyengine-uk", "version": "2.88.0", diff --git a/src/policyengine/data/release_manifests/us.json b/src/policyengine/data/release_manifests/us.json index 4eb945f0..b005eda9 100644 --- a/src/policyengine/data/release_manifests/us.json +++ b/src/policyengine/data/release_manifests/us.json @@ -1,13 +1,13 @@ { "schema_version": 1, - "bundle_id": "us-3.4.0", + "bundle_id": "us-3.5.0", "country_id": "us", - "policyengine_version": "3.4.0", + "policyengine_version": "3.5.0", "model_package": { "name": "policyengine-us", - "version": "1.647.0", - "sha256": "50e64bf910772b224cdc2b5af5a3414f976f68a9e1748107da7e1de6e325425c", - "wheel_url": "https://files.pythonhosted.org/packages/2a/96/4814f2630395350915d819452d7684f232c9b8df1d9ba5c279f3b6d02c17/policyengine_us-1.647.0-py3-none-any.whl" + "version": "1.653.3", + "sha256": "67a49b98d85c060b24d547a569e91a6703c0fc9c41299c1c67f4ecfac75c67c6", + "wheel_url": "https://files.pythonhosted.org/packages/02/07/25f39a2bfa1ff210cd8e78826c47c03b9040a98a83f4eed59c434c1ed862/policyengine_us-1.653.3-py3-none-any.whl" }, "data_package": { "name": "policyengine-us-data", @@ -25,10 +25,10 @@ "sha256": "18cdc668d05311c32ae37364abcea89b0221c27154559667e951c7b19f5b5cbd" }, "certification": { - "compatibility_basis": "exact_build_model_version", + "compatibility_basis": "matching_data_build_fingerprint", "data_build_id": "policyengine-us-data-1.73.0", "built_with_model_version": "1.647.0", - "certified_for_model_version": "1.647.0", + "certified_for_model_version": "1.653.3", "certified_by": "policyengine.py bundled manifest" }, "default_dataset": "enhanced_cps_2024", diff --git a/tests/test_models.py b/tests/test_models.py index fbc613d2..a9023c56 100644 --- a/tests/test_models.py +++ b/tests/test_models.py @@ -113,7 +113,7 @@ def test_has_release_manifest_metadata(self): assert us_latest.release_manifest is not None assert us_latest.release_manifest.country_id == "us" assert us_latest.model_package.name == "policyengine-us" - assert us_latest.model_package.version == "1.647.0" + assert us_latest.model_package.version == "1.653.3" assert us_latest.data_package.name == "policyengine-us-data" assert us_latest.data_package.version == "1.73.0" assert ( diff --git a/tests/test_release_manifests.py b/tests/test_release_manifests.py index c2370546..593d41bd 100644 --- a/tests/test_release_manifests.py +++ b/tests/test_release_manifests.py @@ -45,11 +45,11 @@ def test__given_us_manifest__then_has_pinned_model_and_data_packages(self): manifest = get_release_manifest("us") assert manifest.schema_version == 1 - assert manifest.bundle_id == "us-3.4.0" + assert manifest.bundle_id == "us-3.5.0" assert manifest.country_id == "us" - assert manifest.policyengine_version == "3.4.0" + assert manifest.policyengine_version == "3.5.0" assert manifest.model_package.name == "policyengine-us" - assert manifest.model_package.version == "1.647.0" + assert manifest.model_package.version == "1.653.3" assert manifest.data_package.name == "policyengine-us-data" assert manifest.data_package.version == "1.73.0" assert manifest.data_package.repo_id == "policyengine/policyengine-us-data" @@ -61,15 +61,15 @@ def test__given_us_manifest__then_has_pinned_model_and_data_packages(self): assert manifest.certification is not None assert manifest.certification.data_build_id == "policyengine-us-data-1.73.0" assert manifest.certification.built_with_model_version == "1.647.0" - assert manifest.certification.certified_for_model_version == "1.647.0" + assert manifest.certification.certified_for_model_version == "1.653.3" def test__given_uk_manifest__then_has_pinned_model_and_data_packages(self): manifest = get_release_manifest("uk") assert manifest.schema_version == 1 - assert manifest.bundle_id == "uk-3.4.0" + assert manifest.bundle_id == "uk-3.5.0" assert manifest.country_id == "uk" - assert manifest.policyengine_version == "3.4.0" + assert manifest.policyengine_version == "3.5.0" assert manifest.model_package.name == "policyengine-uk" assert manifest.model_package.version == "2.88.0" assert manifest.data_package.name == "policyengine-uk-data" @@ -262,7 +262,7 @@ def test__given_private_manifest_unavailable__then_bundled_certification_is_used ): certification = certify_data_release_compatibility( "us", - runtime_model_version="1.647.0", + runtime_model_version="1.653.3", ) assert certification == get_release_manifest("us").certification @@ -368,7 +368,7 @@ def test__given_manifest_certification__then_release_bundle_exposes_it(self): bundle = model_version.release_bundle - assert bundle["bundle_id"] == "uk-3.4.0" + assert bundle["bundle_id"] == "uk-3.5.0" assert bundle["default_dataset"] == "enhanced_frs_2023_24" assert bundle["default_dataset_uri"] == manifest.default_dataset_uri assert bundle["certified_data_build_id"] == "policyengine-uk-data-1.40.4" @@ -415,7 +415,7 @@ def test__given_us_managed_microsimulation__then_passes_certified_dataset_and_bu dataset = mock_microsimulation.call_args.kwargs["dataset"] assert dataset == microsim.policyengine_bundle["runtime_dataset_source"] - assert microsim.policyengine_bundle["policyengine_version"] == "3.4.0" + assert microsim.policyengine_bundle["policyengine_version"] == "3.5.0" assert microsim.policyengine_bundle["runtime_dataset"] == "enhanced_cps_2024" assert ( microsim.policyengine_bundle["runtime_dataset_uri"] @@ -453,7 +453,7 @@ def test__given_uk_managed_dataset_name__then_resolves_within_bundle(self): "hf://policyengine/policyengine-uk-data-private/" "enhanced_frs_2023_24.h5@1.40.4" ) - assert microsim.policyengine_bundle["policyengine_version"] == "3.4.0" + assert microsim.policyengine_bundle["policyengine_version"] == "3.5.0" assert microsim.policyengine_bundle["runtime_dataset"] == "enhanced_frs_2023_24" assert microsim.policyengine_bundle["runtime_dataset_uri"] == ( "hf://policyengine/policyengine-uk-data-private/enhanced_frs_2023_24.h5@1.40.4" diff --git a/tests/test_trace_tro.py b/tests/test_trace_tro.py index 90bb10eb..f78b4f33 100644 --- a/tests/test_trace_tro.py +++ b/tests/test_trace_tro.py @@ -42,7 +42,7 @@ FAKE_WHEEL_SHA = "a" * 64 FAKE_WHEEL_URL = ( "https://files.pythonhosted.org/packages/ab/cd/" - "policyengine_us-1.647.0-py3-none-any.whl" + "policyengine_us-1.637.0-py3-none-any.whl" ) @@ -66,7 +66,7 @@ def _us_data_release_manifest( "built_at": "2026-04-10T12:00:00Z", "built_with_model_package": { "name": "policyengine-us", - "version": "1.647.0", + "version": "1.637.0", "git_sha": "deadbeef", "data_build_fingerprint": data_build_fingerprint, }, From 231116742c853a29159360ac3f5093afdded55d7 Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 18 Apr 2026 12:13:04 -0400 Subject: [PATCH 2/3] Correct pyproject pin to policyengine-us 1.653.3 (not 1.637.0) --- pyproject.toml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 4b898d8a..fcaad923 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -39,7 +39,7 @@ uk = [ ] us = [ "policyengine_core>=3.25.0", - "policyengine-us==1.637.0", + "policyengine-us==1.653.3", ] dev = [ "pytest", @@ -54,7 +54,7 @@ dev = [ "ruff>=0.9.0", "policyengine_core>=3.25.0", "policyengine-uk==2.88.0", - "policyengine-us==1.637.0", + "policyengine-us==1.653.3", "towncrier>=24.8.0", "mypy>=1.11.0", "pytest-cov>=5.0.0", From c231943f4a72e9c4a1cbef23e64a7a72ade6171b Mon Sep 17 00:00:00 2001 From: Max Ghenis Date: Sat, 18 Apr 2026 12:19:28 -0400 Subject: [PATCH 3/3] Accept PEP 440 range specifiers in compatible_model_packages Replaces the hand-rolled == equality check in _specifier_matches with packaging.specifiers.SpecifierSet. A data release manifest can now declare compatibility with a range of model versions (e.g. >=1.637.0,<2.0.0) instead of a single pin; certify_data_release_compatibility accepts any runtime version that satisfies the specifier. Adds packaging>=23.0 as a direct dependency (already transitively installed via pandas). Co-Authored-By: Claude Opus 4.7 (1M context) --- changelog.d/range-specifiers.added.md | 7 ++++ pyproject.toml | 1 + src/policyengine/core/release_manifest.py | 11 +++++-- tests/test_release_manifests.py | 40 +++++++++++++++++++++++ 4 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 changelog.d/range-specifiers.added.md diff --git a/changelog.d/range-specifiers.added.md b/changelog.d/range-specifiers.added.md new file mode 100644 index 00000000..a52f4ba1 --- /dev/null +++ b/changelog.d/range-specifiers.added.md @@ -0,0 +1,7 @@ +`certify_data_release_compatibility` now accepts full PEP 440 version +specifiers (`>=1.637.0,<2.0.0`, `~=1.637`, etc.) in a data release +manifest's `compatible_model_packages`, not only `==X.Y.Z`. This lets +the US data package declare a range of compatible `policyengine-us` +versions when the `data_build_fingerprint` is known to be stable +across them, avoiding the need to regenerate the dataset for every +model patch release. Adds `packaging>=23.0` as a direct dependency. diff --git a/pyproject.toml b/pyproject.toml index fcaad923..a6d7c091 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,6 +27,7 @@ dependencies = [ "plotly>=5.0.0", "requests>=2.31.0", "psutil>=5.9.0", + "packaging>=23.0", ] [project.scripts] diff --git a/src/policyengine/core/release_manifest.py b/src/policyengine/core/release_manifest.py index a1ab2fd0..f4929554 100644 --- a/src/policyengine/core/release_manifest.py +++ b/src/policyengine/core/release_manifest.py @@ -218,9 +218,14 @@ def get_data_release_manifest(country_id: str) -> DataReleaseManifest: def _specifier_matches(version: str, specifier: str) -> bool: - if specifier.startswith("=="): - return version == specifier[2:] - return False + """Match a PEP 440 version specifier (``==``, ``>=``, ``<``, ``,``-joined).""" + from packaging.specifiers import InvalidSpecifier, SpecifierSet + from packaging.version import InvalidVersion, Version + + try: + return Version(version) in SpecifierSet(specifier) + except (InvalidSpecifier, InvalidVersion): + return False def certify_data_release_compatibility( diff --git a/tests/test_release_manifests.py b/tests/test_release_manifests.py index 593d41bd..18d6eed3 100644 --- a/tests/test_release_manifests.py +++ b/tests/test_release_manifests.py @@ -214,6 +214,46 @@ def test__given_missing_data_release_manifest__then_fetch_raises_unavailable(sel else: raise AssertionError("Expected missing manifest to be reported") + def test__given_range_specifier__then_certification_accepts_compatible_version( + self, + ): + get_data_release_manifest.cache_clear() + payload = { + "schema_version": 1, + "data_package": { + "name": "policyengine-us-data", + "version": "1.73.0", + }, + "build": { + "build_id": "policyengine-us-data-1.73.0", + "built_with_model_package": { + "name": "policyengine-us", + "version": "1.637.0", + "data_build_fingerprint": "sha256:stable", + }, + }, + "compatible_model_packages": [ + { + "name": "policyengine-us", + "specifier": ">=1.637.0,<2.0.0", + } + ], + "default_datasets": {"national": "enhanced_cps_2024"}, + "artifacts": {}, + } + + with patch( + "policyengine.core.release_manifest.requests.get", + return_value=_response_with_json(payload), + ): + certification = certify_data_release_compatibility( + "us", + runtime_model_version="1.653.3", + ) + + assert certification.compatibility_basis == "legacy_compatible_model_package" + assert certification.certified_for_model_version == "1.653.3" + def test__given_matching_fingerprint__then_certification_allows_reuse(self): get_data_release_manifest.cache_clear() payload = {