Skip to content
This repository was archived by the owner on Jun 19, 2026. It is now read-only.

Commit d46ad21

Browse files
authored
Merge pull request #424 from PolicyEngine/release-bundle-single-country-fallback
Support compatible UK model specifiers
2 parents 61d9bc1 + 014cb0e commit d46ad21

4 files changed

Lines changed: 60 additions & 9 deletions

File tree

changelog.d/423.added.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add release-manifest support for declaring additional compatible UK model versions.

policyengine_uk_data/tests/test_release_manifest.py

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,37 @@ def test_build_release_manifest_tracks_uk_release_artifacts(tmp_path):
186186
}
187187

188188

189+
def test_build_release_manifest_adds_additional_compatible_specifiers(tmp_path):
190+
dataset_path = _write_file(
191+
tmp_path / "enhanced_frs_2023_24.h5",
192+
b"enhanced-frs",
193+
)
194+
195+
manifest = build_release_manifest(
196+
files_with_repo_paths=[(dataset_path, "enhanced_frs_2023_24.h5")],
197+
version="1.40.4",
198+
repo_id=PRIVATE_REPO,
199+
model_package_version="2.74.0",
200+
model_package_git_sha="deadbeef",
201+
model_package_data_build_fingerprint="sha256:fingerprint",
202+
core_package_metadata=EXPECTED_CORE_PACKAGE,
203+
data_package_git_sha="cafebabe",
204+
additional_compatible_specifiers=("==2.89.0", ">=2.90.0,<3"),
205+
created_at="2026-04-10T12:00:00Z",
206+
)
207+
208+
assert manifest["compatible_model_packages"] == [
209+
{"name": "policyengine-uk", "specifier": "==2.74.0"},
210+
{"name": "policyengine-uk", "specifier": "==2.89.0"},
211+
{"name": "policyengine-uk", "specifier": ">=2.90.0,<3"},
212+
]
213+
validate_release_manifest(
214+
manifest,
215+
version="1.40.4",
216+
repo_id=PRIVATE_REPO,
217+
)
218+
219+
189220
def test_build_release_manifest_defaults_to_current_frs_release(tmp_path):
190221
enhanced_path = _write_file(
191222
tmp_path / CURRENT_FRS_RELEASE.enhanced_dataset_file,
@@ -590,6 +621,7 @@ def test_upload_files_to_hf_adds_uk_release_manifest_operations(tmp_path):
590621
upload_files_to_hf(
591622
files=[dataset_path],
592623
version="1.40.4",
624+
additional_compatible_specifiers=("==2.89.0",),
593625
)
594626

595627
operations = mock_api.create_commit.call_args.kwargs["operations"]
@@ -612,6 +644,10 @@ def test_upload_files_to_hf_adds_uk_release_manifest_operations(tmp_path):
612644
payload = release_ops[0].path_or_fileobj.getvalue()
613645
manifest = json.loads(payload.decode("utf-8"))
614646
_assert_single_uk_data_release_version(manifest)
647+
assert manifest["compatible_model_packages"] == [
648+
{"name": "policyengine-uk", "specifier": "==2.74.0"},
649+
{"name": "policyengine-uk", "specifier": "==2.89.0"},
650+
]
615651
assert manifest["compatible_core_packages"] == EXPECTED_COMPATIBLE_CORE_PACKAGES
616652
assert manifest["build"]["built_with_core_package"] == EXPECTED_CORE_PACKAGE
617653
assert manifest["build"]["metadata"] == {

policyengine_uk_data/utils/data_upload.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from io import BytesIO
2-
from typing import Any, Dict, List, Mapping, Optional, Tuple
2+
from typing import Any, Dict, List, Mapping, Optional, Sequence, Tuple
33
from huggingface_hub import HfApi, CommitOperationAdd, hf_hub_download
44
from huggingface_hub.errors import EntryNotFoundError, RevisionNotFoundError
55
from google.cloud import storage
@@ -296,6 +296,7 @@ def create_release_manifest_commit_operations(
296296
core_package_metadata: Optional[Mapping[str, Any]] = None,
297297
data_package_git_sha: Optional[str] = None,
298298
existing_manifest: Optional[Dict] = None,
299+
additional_compatible_specifiers: Optional[Sequence[str]] = None,
299300
) -> Tuple[Dict, List[CommitOperationAdd]]:
300301
manifest = build_release_manifest(
301302
files_with_repo_paths=files_with_repo_paths,
@@ -309,6 +310,7 @@ def create_release_manifest_commit_operations(
309310
core_package_metadata=core_package_metadata,
310311
data_package_git_sha=data_package_git_sha,
311312
existing_manifest=existing_manifest,
313+
additional_compatible_specifiers=additional_compatible_specifiers,
312314
)
313315
validate_release_manifest(
314316
manifest,
@@ -337,6 +339,7 @@ def upload_data_files(
337339
hf_repo_name: str = PUBLIC_REPO,
338340
hf_repo_type: str = "model",
339341
version: str = None,
342+
additional_compatible_specifiers: Optional[Sequence[str]] = None,
340343
):
341344
if version is None:
342345
version = metadata.version("policyengine-uk-data")
@@ -346,6 +349,7 @@ def upload_data_files(
346349
version=version,
347350
hf_repo_name=hf_repo_name,
348351
hf_repo_type=hf_repo_type,
352+
additional_compatible_specifiers=additional_compatible_specifiers,
349353
)
350354

351355
upload_files_to_gcs(
@@ -360,6 +364,7 @@ def upload_files_to_hf(
360364
version: str,
361365
hf_repo_name: str = PRIVATE_REPO,
362366
hf_repo_type: str = "model",
367+
additional_compatible_specifiers: Optional[Sequence[str]] = None,
363368
):
364369
"""
365370
Upload files to Hugging Face repository and tag the commit with the version.
@@ -414,6 +419,7 @@ def upload_files_to_hf(
414419
core_package_metadata=core_package_metadata,
415420
data_package_git_sha=_get_data_package_git_sha(),
416421
existing_manifest=existing_manifest,
422+
additional_compatible_specifiers=additional_compatible_specifiers,
417423
)
418424
if finalized_manifest is not None:
419425
if candidate_manifest == finalized_manifest:

policyengine_uk_data/utils/release_manifest.py

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -129,15 +129,19 @@ def _model_package_compatibility(
129129
*,
130130
model_package_name: str,
131131
model_package_version: str | None,
132+
additional_compatible_specifiers: Sequence[str] | None = None,
132133
) -> list[Dict[str, str]]:
133-
if not model_package_version:
134-
return []
135-
return [
136-
{
137-
"name": model_package_name,
138-
"specifier": f"=={model_package_version}",
139-
}
140-
]
134+
compatible_packages = []
135+
if model_package_version:
136+
compatible_packages.append(
137+
{
138+
"name": model_package_name,
139+
"specifier": f"=={model_package_version}",
140+
}
141+
)
142+
for specifier in additional_compatible_specifiers or ():
143+
compatible_packages.append({"name": model_package_name, "specifier": specifier})
144+
return compatible_packages
141145

142146

143147
def _core_package_compatibility(
@@ -506,11 +510,13 @@ def _update_compatibility(
506510
model_package_name: str,
507511
model_package_version: str | None,
508512
core_package_metadata: Mapping[str, Any] | None,
513+
additional_compatible_specifiers: Sequence[str] | None = None,
509514
) -> None:
510515
manifest.setdefault("compatible_model_packages", [])
511516
model_package_compatibility = _model_package_compatibility(
512517
model_package_name=model_package_name,
513518
model_package_version=model_package_version,
519+
additional_compatible_specifiers=additional_compatible_specifiers,
514520
)
515521
if model_package_compatibility:
516522
manifest["compatible_model_packages"] = model_package_compatibility
@@ -607,6 +613,7 @@ def build_release_manifest(
607613
existing_manifest: Mapping | None = None,
608614
default_datasets: Optional[Mapping[str, str]] = None,
609615
created_at: str | None = None,
616+
additional_compatible_specifiers: Sequence[str] | None = None,
610617
) -> Dict:
611618
manifest = _normalize_existing_manifest(
612619
existing_manifest,
@@ -644,6 +651,7 @@ def build_release_manifest(
644651
model_package_name=model_package_name,
645652
model_package_version=model_package_version,
646653
core_package_metadata=core_package_metadata,
654+
additional_compatible_specifiers=additional_compatible_specifiers,
647655
)
648656
_update_artifacts(
649657
manifest,

0 commit comments

Comments
 (0)