Skip to content

Commit d551851

Browse files
authored
Harden UK release manifest retries (#384)
1 parent 7b1ce55 commit d551851

2 files changed

Lines changed: 109 additions & 3 deletions

File tree

policyengine_uk_data/tests/test_release_manifest.py

Lines changed: 91 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
import hashlib
22
from io import BytesIO
3+
from importlib import metadata
34
from pathlib import Path
45
from unittest.mock import MagicMock, patch
56

7+
import pytest
68
from huggingface_hub import CommitOperationAdd
9+
from huggingface_hub.errors import EntryNotFoundError
710

8-
from policyengine_uk_data.utils.data_upload import upload_files_to_hf
11+
from policyengine_uk_data.utils.data_upload import (
12+
_get_model_package_version,
13+
load_release_manifest_from_hf,
14+
upload_files_to_hf,
15+
)
916
from policyengine_uk_data.utils.release_manifest import (
1017
RELEASE_MANIFEST_SCHEMA_VERSION,
1118
build_release_manifest,
@@ -81,6 +88,89 @@ def test_build_release_manifest_tracks_uk_release_artifacts(tmp_path):
8188
assert manifest["artifacts"]["local_authority_weights"]["kind"] == "weights"
8289

8390

91+
def test_build_release_manifest_refreshes_compatible_model_packages_for_draft_retry(
92+
tmp_path,
93+
):
94+
dataset_path = _write_file(
95+
tmp_path / "enhanced_frs_2023_24.h5",
96+
b"enhanced-frs",
97+
)
98+
99+
manifest = build_release_manifest(
100+
files_with_repo_paths=[(dataset_path, "enhanced_frs_2023_24.h5")],
101+
version="1.40.4",
102+
repo_id="policyengine/policyengine-uk-data-private",
103+
model_package_version="9.99.9",
104+
existing_manifest={
105+
"schema_version": RELEASE_MANIFEST_SCHEMA_VERSION,
106+
"data_package": {
107+
"name": "policyengine-uk-data",
108+
"version": "1.40.4",
109+
},
110+
"compatible_model_packages": [
111+
{
112+
"name": "policyengine-uk",
113+
"specifier": "==1.0.0",
114+
}
115+
],
116+
"default_datasets": {},
117+
"created_at": "2026-04-10T12:00:00Z",
118+
"artifacts": {},
119+
},
120+
)
121+
122+
assert manifest["compatible_model_packages"] == [
123+
{"name": "policyengine-uk", "specifier": "==9.99.9"}
124+
]
125+
126+
127+
def test_load_release_manifest_from_hf_raises_non_missing_download_errors():
128+
with patch(
129+
"policyengine_uk_data.utils.data_upload.hf_hub_download",
130+
side_effect=RuntimeError("boom"),
131+
):
132+
with pytest.raises(RuntimeError, match="boom"):
133+
load_release_manifest_from_hf(version="1.40.4")
134+
135+
136+
def test_load_release_manifest_from_hf_continues_on_missing_entry(tmp_path):
137+
manifest_path = tmp_path / "release_manifest.json"
138+
manifest_path.write_text('{"data_package": {"version": "1.40.4"}}')
139+
140+
with patch(
141+
"policyengine_uk_data.utils.data_upload.hf_hub_download",
142+
side_effect=[
143+
EntryNotFoundError("missing"),
144+
str(manifest_path),
145+
],
146+
):
147+
manifest = load_release_manifest_from_hf(version="1.40.4")
148+
149+
assert manifest["data_package"]["version"] == "1.40.4"
150+
151+
152+
def test_get_model_package_version_prefers_imported_checkout(tmp_path):
153+
package_root = tmp_path / "policyengine_uk"
154+
package_root.mkdir()
155+
(package_root / "__init__.py").write_text("")
156+
pyproject_path = tmp_path / "pyproject.toml"
157+
pyproject_path.write_text(
158+
'[project]\nname = "policyengine-uk"\nversion = "2.78.0"\n'
159+
)
160+
fake_spec = MagicMock(origin=str(package_root / "__init__.py"))
161+
162+
with (
163+
patch(
164+
"policyengine_uk_data.utils.data_upload.find_spec", return_value=fake_spec
165+
),
166+
patch(
167+
"policyengine_uk_data.utils.data_upload.metadata.version",
168+
side_effect=metadata.PackageNotFoundError,
169+
),
170+
):
171+
assert _get_model_package_version() == "2.78.0"
172+
173+
84174
def test_upload_files_to_hf_adds_uk_release_manifest_operations(tmp_path):
85175
dataset_path = _write_file(
86176
tmp_path / "enhanced_frs_2023_24.h5",

policyengine_uk_data/utils/data_upload.py

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,16 @@
11
from io import BytesIO
22
from typing import Dict, List, Optional, Tuple
33
from huggingface_hub import HfApi, CommitOperationAdd, hf_hub_download
4-
from huggingface_hub.errors import RevisionNotFoundError
4+
from huggingface_hub.errors import EntryNotFoundError, RevisionNotFoundError
55
from google.cloud import storage
66
from pathlib import Path
77
from importlib import metadata
8+
from importlib.util import find_spec
89
import google.auth
910
import json
1011
import logging
1112
import os
13+
import tomllib
1214

1315
from policyengine_uk_data.utils.release_manifest import (
1416
build_release_manifest,
@@ -21,6 +23,20 @@
2123
def _get_model_package_version(
2224
package_name: str = "policyengine-uk",
2325
) -> Optional[str]:
26+
module_name = package_name.replace("-", "_")
27+
spec = find_spec(module_name)
28+
module_origin = getattr(spec, "origin", None) if spec is not None else None
29+
if module_origin is not None:
30+
package_root = Path(module_origin).resolve().parent
31+
for parent in [package_root, *package_root.parents]:
32+
pyproject_path = parent / "pyproject.toml"
33+
if not pyproject_path.exists():
34+
continue
35+
with open(pyproject_path, "rb") as f:
36+
pyproject = tomllib.load(f)
37+
project = pyproject.get("project", {})
38+
if project.get("name") == package_name and project.get("version"):
39+
return project["version"]
2440
try:
2541
return metadata.version(package_name)
2642
except metadata.PackageNotFoundError:
@@ -87,7 +103,7 @@ def load_release_manifest_from_hf(
87103
)
88104
except RevisionNotFoundError:
89105
raise
90-
except Exception:
106+
except EntryNotFoundError:
91107
continue
92108

93109
with open(manifest_path) as f:

0 commit comments

Comments
 (0)