policyengine 4.4.2__tar.gz → 4.4.3__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. {policyengine-4.4.2 → policyengine-4.4.3}/CHANGELOG.md +8 -0
  2. {policyengine-4.4.2 → policyengine-4.4.3}/PKG-INFO +6 -6
  3. {policyengine-4.4.2 → policyengine-4.4.3}/examples/income_distribution_us.py +12 -17
  4. {policyengine-4.4.2 → policyengine-4.4.3}/examples/us_budgetary_impact.py +9 -1
  5. {policyengine-4.4.2 → policyengine-4.4.3}/pyproject.toml +6 -6
  6. {policyengine-4.4.2 → policyengine-4.4.3}/scripts/refresh_release_bundle.py +3 -0
  7. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/__init__.py +5 -2
  8. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/data/release_manifests/uk.json +2 -2
  9. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/data/release_manifests/uk.trace.tro.jsonld +7 -7
  10. policyengine-4.4.3/src/policyengine/data/release_manifests/us.json +54 -0
  11. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/data/release_manifests/us.trace.tro.jsonld +23 -22
  12. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/provenance/bundle.py +167 -3
  13. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/us/analysis.py +20 -14
  14. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine.egg-info/PKG-INFO +6 -6
  15. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine.egg-info/requires.txt +5 -5
  16. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/household_calculator_snapshots/us_model_surface.json +1 -1
  17. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/household_calculator_snapshots/us_single_adult_no_income.json +2 -2
  18. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_bundle_refresh.py +261 -5
  19. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_models.py +3 -3
  20. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_release_manifests.py +15 -15
  21. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_us_program_statistics.py +9 -1
  22. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_us_regions.py +3 -3
  23. {policyengine-4.4.2 → policyengine-4.4.3}/uv.lock +12 -12
  24. policyengine-4.4.2/src/policyengine/data/release_manifests/us.json +0 -53
  25. {policyengine-4.4.2 → policyengine-4.4.3}/.claude/policyengine-guide.md +0 -0
  26. {policyengine-4.4.2 → policyengine-4.4.3}/.claude/quick-reference.md +0 -0
  27. {policyengine-4.4.2 → policyengine-4.4.3}/.github/CONTRIBUTING.md +0 -0
  28. {policyengine-4.4.2 → policyengine-4.4.3}/.github/bump_version.py +0 -0
  29. {policyengine-4.4.2 → policyengine-4.4.3}/.github/changelog_template.md +0 -0
  30. {policyengine-4.4.2 → policyengine-4.4.3}/.github/check-changelog.sh +0 -0
  31. {policyengine-4.4.2 → policyengine-4.4.3}/.github/fetch_version.py +0 -0
  32. {policyengine-4.4.2 → policyengine-4.4.3}/.github/get-changelog-diff.sh +0 -0
  33. {policyengine-4.4.2 → policyengine-4.4.3}/.github/has-functional-changes.sh +0 -0
  34. {policyengine-4.4.2 → policyengine-4.4.3}/.github/is-version-number-acceptable.sh +0 -0
  35. {policyengine-4.4.2 → policyengine-4.4.3}/.github/publish-git-tag.sh +0 -0
  36. {policyengine-4.4.2 → policyengine-4.4.3}/.github/workflows/pr_code_changes.yaml +0 -0
  37. {policyengine-4.4.2 → policyengine-4.4.3}/.github/workflows/pr_docs_changes.yaml +0 -0
  38. {policyengine-4.4.2 → policyengine-4.4.3}/.github/workflows/push.yaml +0 -0
  39. {policyengine-4.4.2 → policyengine-4.4.3}/.gitignore +0 -0
  40. {policyengine-4.4.2 → policyengine-4.4.3}/.python-version +0 -0
  41. {policyengine-4.4.2 → policyengine-4.4.3}/LICENSE +0 -0
  42. {policyengine-4.4.2 → policyengine-4.4.3}/Makefile +0 -0
  43. {policyengine-4.4.2 → policyengine-4.4.3}/README.md +0 -0
  44. {policyengine-4.4.2 → policyengine-4.4.3}/changelog.d/.gitkeep +0 -0
  45. {policyengine-4.4.2 → policyengine-4.4.3}/docs/.gitignore +0 -0
  46. {policyengine-4.4.2 → policyengine-4.4.3}/docs/_generator/README.md +0 -0
  47. {policyengine-4.4.2 → policyengine-4.4.3}/docs/_generator/build_reference.py +0 -0
  48. {policyengine-4.4.2 → policyengine-4.4.3}/docs/_quarto.yml +0 -0
  49. {policyengine-4.4.2 → policyengine-4.4.3}/docs/countries.md +0 -0
  50. {policyengine-4.4.2 → policyengine-4.4.3}/docs/data-publishing-design.md +0 -0
  51. {policyengine-4.4.2 → policyengine-4.4.3}/docs/dev.md +0 -0
  52. {policyengine-4.4.2 → policyengine-4.4.3}/docs/examples.md +0 -0
  53. {policyengine-4.4.2 → policyengine-4.4.3}/docs/getting-started.md +0 -0
  54. {policyengine-4.4.2 → policyengine-4.4.3}/docs/households.md +0 -0
  55. {policyengine-4.4.2 → policyengine-4.4.3}/docs/impact-analysis.md +0 -0
  56. {policyengine-4.4.2 → policyengine-4.4.3}/docs/index.md +0 -0
  57. {policyengine-4.4.2 → policyengine-4.4.3}/docs/methodology/index.md +0 -0
  58. {policyengine-4.4.2 → policyengine-4.4.3}/docs/methodology/model-architecture.md +0 -0
  59. {policyengine-4.4.2 → policyengine-4.4.3}/docs/methodology/us-health-costs.md +0 -0
  60. {policyengine-4.4.2 → policyengine-4.4.3}/docs/microsim.md +0 -0
  61. {policyengine-4.4.2 → policyengine-4.4.3}/docs/outputs.md +0 -0
  62. {policyengine-4.4.2 → policyengine-4.4.3}/docs/programs/index.md +0 -0
  63. {policyengine-4.4.2 → policyengine-4.4.3}/docs/programs/us-chip.md +0 -0
  64. {policyengine-4.4.2 → policyengine-4.4.3}/docs/reference/index.md +0 -0
  65. {policyengine-4.4.2 → policyengine-4.4.3}/docs/reforms.md +0 -0
  66. {policyengine-4.4.2 → policyengine-4.4.3}/docs/regions.md +0 -0
  67. {policyengine-4.4.2 → policyengine-4.4.3}/docs/release-bundles.md +0 -0
  68. {policyengine-4.4.2 → policyengine-4.4.3}/docs/trace-case-study.md +0 -0
  69. {policyengine-4.4.2 → policyengine-4.4.3}/docs/visualisation.md +0 -0
  70. {policyengine-4.4.2 → policyengine-4.4.3}/examples/employment_income_variation_uk.py +0 -0
  71. {policyengine-4.4.2 → policyengine-4.4.3}/examples/employment_income_variation_us.py +0 -0
  72. {policyengine-4.4.2 → policyengine-4.4.3}/examples/household_impact_example.py +0 -0
  73. {policyengine-4.4.2 → policyengine-4.4.3}/examples/income_bands_uk.py +0 -0
  74. {policyengine-4.4.2 → policyengine-4.4.3}/examples/paper_repro_uk.py +0 -0
  75. {policyengine-4.4.2 → policyengine-4.4.3}/examples/policy_change_uk.py +0 -0
  76. {policyengine-4.4.2 → policyengine-4.4.3}/examples/speedtest_us_simulation.py +0 -0
  77. {policyengine-4.4.2 → policyengine-4.4.3}/scripts/check_data_staleness.py +0 -0
  78. {policyengine-4.4.2 → policyengine-4.4.3}/scripts/generate_trace_tros.py +0 -0
  79. {policyengine-4.4.2 → policyengine-4.4.3}/setup.cfg +0 -0
  80. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/cli.py +0 -0
  81. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/__init__.py +0 -0
  82. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/cache.py +0 -0
  83. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/dataset.py +0 -0
  84. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/dynamic.py +0 -0
  85. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/output.py +0 -0
  86. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/parameter.py +0 -0
  87. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/parameter_node.py +0 -0
  88. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/parameter_value.py +0 -0
  89. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/policy.py +0 -0
  90. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/region.py +0 -0
  91. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/scoping_strategy.py +0 -0
  92. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/simulation.py +0 -0
  93. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/tax_benefit_model.py +0 -0
  94. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/tax_benefit_model_version.py +0 -0
  95. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/core/variable.py +0 -0
  96. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/countries/__init__.py +0 -0
  97. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/countries/uk/__init__.py +0 -0
  98. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/countries/uk/regions.py +0 -0
  99. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/countries/us/__init__.py +0 -0
  100. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/countries/us/data/__init__.py +0 -0
  101. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/countries/us/data/districts.py +0 -0
  102. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/countries/us/data/places.py +0 -0
  103. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/countries/us/data/states.py +0 -0
  104. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/countries/us/regions.py +0 -0
  105. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/data/schemas/trace_tro.schema.json +0 -0
  106. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/graph/__init__.py +0 -0
  107. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/graph/extractor.py +0 -0
  108. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/graph/graph.py +0 -0
  109. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/outputs/__init__.py +0 -0
  110. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/outputs/aggregate.py +0 -0
  111. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/outputs/change_aggregate.py +0 -0
  112. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/outputs/congressional_district_impact.py +0 -0
  113. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/outputs/constituency_impact.py +0 -0
  114. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/outputs/decile_impact.py +0 -0
  115. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/outputs/inequality.py +0 -0
  116. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/outputs/intra_decile_impact.py +0 -0
  117. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/outputs/local_authority_impact.py +0 -0
  118. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/outputs/poverty.py +0 -0
  119. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/outputs/program_statistics.py +0 -0
  120. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/provenance/__init__.py +0 -0
  121. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/provenance/manifest.py +0 -0
  122. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/provenance/trace.py +0 -0
  123. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/results/__init__.py +0 -0
  124. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/results/schema.py +0 -0
  125. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/results/trace_tro.py +0 -0
  126. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/results/tracking.py +0 -0
  127. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/common/__init__.py +0 -0
  128. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/common/extra_variables.py +0 -0
  129. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/common/household.py +0 -0
  130. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/common/model_version.py +0 -0
  131. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/common/reform.py +0 -0
  132. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/common/result.py +0 -0
  133. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/uk/__init__.py +0 -0
  134. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/uk/analysis.py +0 -0
  135. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/uk/datasets.py +0 -0
  136. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/uk/household.py +0 -0
  137. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/uk/model.py +0 -0
  138. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/us/__init__.py +0 -0
  139. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/us/datasets.py +0 -0
  140. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/us/household.py +0 -0
  141. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/tax_benefit_models/us/model.py +0 -0
  142. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/utils/__init__.py +0 -0
  143. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/utils/dates.py +0 -0
  144. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/utils/design.py +0 -0
  145. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/utils/entity_utils.py +0 -0
  146. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/utils/errors.py +0 -0
  147. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/utils/household_validation.py +0 -0
  148. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/utils/parameter_labels.py +0 -0
  149. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/utils/parametric_reforms.py +0 -0
  150. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine/utils/plotting.py +0 -0
  151. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine.egg-info/SOURCES.txt +0 -0
  152. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine.egg-info/dependency_links.txt +0 -0
  153. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine.egg-info/entry_points.txt +0 -0
  154. {policyengine-4.4.2 → policyengine-4.4.3}/src/policyengine.egg-info/top_level.txt +0 -0
  155. {policyengine-4.4.2 → policyengine-4.4.3}/tests/__init__.py +0 -0
  156. {policyengine-4.4.2 → policyengine-4.4.3}/tests/conftest.py +0 -0
  157. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/__init__.py +0 -0
  158. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/filtering_fixtures.py +0 -0
  159. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/household_calculator_snapshots/uk_couple_two_kids.json +0 -0
  160. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/household_calculator_snapshots/uk_model_surface.json +0 -0
  161. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/household_calculator_snapshots/uk_single_adult_employment_income.json +0 -0
  162. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/household_calculator_snapshots/uk_single_adult_no_income.json +0 -0
  163. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/household_calculator_snapshots/uk_single_parent_one_child.json +0 -0
  164. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/household_calculator_snapshots/us_married_two_kids_high_income.json +0 -0
  165. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/household_calculator_snapshots/us_single_adult_employment_income.json +0 -0
  166. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/household_calculator_snapshots/us_single_parent_one_child.json +0 -0
  167. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/parameter_labels_fixtures.py +0 -0
  168. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/parametric_reforms_fixtures.py +0 -0
  169. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/poverty_by_demographics_fixtures.py +0 -0
  170. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/region_fixtures.py +0 -0
  171. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/us_reform_fixtures.py +0 -0
  172. {policyengine-4.4.2 → policyengine-4.4.3}/tests/fixtures/variable_label_fixtures.py +0 -0
  173. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_aggregate.py +0 -0
  174. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_bump_version.py +0 -0
  175. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_cache.py +0 -0
  176. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_change_aggregate.py +0 -0
  177. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_congressional_district_impact.py +0 -0
  178. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_constituency_impact.py +0 -0
  179. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_dict_reforms_on_simulation.py +0 -0
  180. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_entity_mapping.py +0 -0
  181. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_entity_utils.py +0 -0
  182. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_errors.py +0 -0
  183. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_extra_variables.py +0 -0
  184. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_filtering.py +0 -0
  185. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_graph/__init__.py +0 -0
  186. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_graph/conftest.py +0 -0
  187. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_graph/test_extractor.py +0 -0
  188. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_household_calculator_snapshot.py +0 -0
  189. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_household_impact.py +0 -0
  190. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_inequality.py +0 -0
  191. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_intra_decile_impact.py +0 -0
  192. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_local_authority_impact.py +0 -0
  193. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_manifest_version_mismatch.py +0 -0
  194. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_pandas3_compatibility.py +0 -0
  195. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_parameter_labels.py +0 -0
  196. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_parametric_reforms.py +0 -0
  197. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_poverty.py +0 -0
  198. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_poverty_by_demographics.py +0 -0
  199. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_poverty_run.py +0 -0
  200. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_preservation_mirror.py +0 -0
  201. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_region.py +0 -0
  202. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_results.py +0 -0
  203. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_scoping_strategy.py +0 -0
  204. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_small_follow_ups.py +0 -0
  205. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_trace_tro.py +0 -0
  206. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_uk_regions.py +0 -0
  207. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_us_microsim_structural_reforms.py +0 -0
  208. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_us_reform_application.py +0 -0
  209. {policyengine-4.4.2 → policyengine-4.4.3}/tests/test_variable_labels.py +0 -0
@@ -1,3 +1,11 @@
1
+ ## [4.4.3] - 2026-05-11
2
+
3
+ ### Changed
4
+
5
+ - Derive US program-statistics entity from variable metadata instead of duplicating it in the program list.
6
+ - Update the bundled US release to policyengine-us 1.690.7 and refresh data provenance metadata.
7
+
8
+
1
9
  ## [4.4.2] - 2026-05-09
2
10
 
3
11
  ### Fixed
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: policyengine
3
- Version: 4.4.2
3
+ Version: 4.4.3
4
4
  Summary: A package to conduct policy analysis using PolicyEngine tax-benefit models.
5
5
  Author-email: PolicyEngine <hello@policyengine.org>
6
6
  License: GNU AFFERO GENERAL PUBLIC LICENSE
@@ -686,11 +686,11 @@ Requires-Dist: plotly>=5.0.0; extra == "plotting"
686
686
  Provides-Extra: graph
687
687
  Requires-Dist: networkx>=3.0; extra == "graph"
688
688
  Provides-Extra: uk
689
- Requires-Dist: policyengine_core>=3.26.0; extra == "uk"
689
+ Requires-Dist: policyengine_core>=3.26.1; extra == "uk"
690
690
  Requires-Dist: policyengine-uk==2.88.14; extra == "uk"
691
691
  Provides-Extra: us
692
- Requires-Dist: policyengine_core>=3.26.0; extra == "us"
693
- Requires-Dist: policyengine-us==1.687.0; extra == "us"
692
+ Requires-Dist: policyengine_core>=3.26.1; extra == "us"
693
+ Requires-Dist: policyengine-us==1.690.7; extra == "us"
694
694
  Provides-Extra: dev
695
695
  Requires-Dist: pytest; extra == "dev"
696
696
  Requires-Dist: furo; extra == "dev"
@@ -702,9 +702,9 @@ Requires-Dist: build; extra == "dev"
702
702
  Requires-Dist: plotly>=5.0.0; extra == "dev"
703
703
  Requires-Dist: pytest-asyncio>=0.26.0; extra == "dev"
704
704
  Requires-Dist: ruff>=0.9.0; extra == "dev"
705
- Requires-Dist: policyengine_core>=3.26.0; extra == "dev"
705
+ Requires-Dist: policyengine_core>=3.26.1; extra == "dev"
706
706
  Requires-Dist: policyengine-uk==2.88.14; extra == "dev"
707
- Requires-Dist: policyengine-us==1.687.0; extra == "dev"
707
+ Requires-Dist: policyengine-us==1.690.7; extra == "dev"
708
708
  Requires-Dist: towncrier>=24.8.0; extra == "dev"
709
709
  Requires-Dist: mypy>=1.11.0; extra == "dev"
710
710
  Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
@@ -10,7 +10,6 @@ Run: python examples/income_distribution_us.py
10
10
  """
11
11
 
12
12
  import time
13
- from pathlib import Path
14
13
 
15
14
  import plotly.graph_objects as go
16
15
  from plotly.subplots import make_subplots
@@ -19,29 +18,25 @@ from policyengine.core import Simulation
19
18
  from policyengine.outputs.aggregate import Aggregate, AggregateType
20
19
  from policyengine.tax_benefit_models.us import (
21
20
  PolicyEngineUSDataset,
21
+ ensure_datasets,
22
22
  us_latest,
23
23
  )
24
24
  from policyengine.utils.plotting import COLORS, format_fig
25
25
 
26
26
 
27
27
  def load_representative_data(year: int = 2024) -> PolicyEngineUSDataset:
28
- """Load representative household microdata for a given year."""
29
- dataset_path = Path(__file__).parent / "data" / f"enhanced_cps_2024_year_{year}.h5"
30
-
31
- if not dataset_path.exists():
32
- raise FileNotFoundError(
33
- f"Dataset not found at {dataset_path}. "
34
- "Run create_datasets() from policyengine.tax_benefit_models.us first."
35
- )
36
-
37
- dataset = PolicyEngineUSDataset(
38
- name=f"Enhanced CPS {year}",
39
- description=f"Representative household microdata for {year}",
40
- filepath=str(dataset_path),
41
- year=year,
28
+ """Load representative household microdata for a given year.
29
+
30
+ Downloads the enhanced CPS dataset from HuggingFace on first run and
31
+ caches it locally under ./data, matching the pattern used by the
32
+ other examples (e.g. us_budgetary_impact.py).
33
+ """
34
+ datasets = ensure_datasets(
35
+ datasets=["hf://policyengine/policyengine-us-data/enhanced_cps_2024.h5"],
36
+ years=[year],
37
+ data_folder="./data",
42
38
  )
43
- dataset.load()
44
- return dataset
39
+ return datasets[f"enhanced_cps_2024_{year}"]
45
40
 
46
41
 
47
42
  def run_simulation(dataset: PolicyEngineUSDataset) -> Simulation:
@@ -8,6 +8,14 @@ Demonstrates the canonical policyengine.py workflow:
8
8
  5. Use ChangeAggregate for targeted single-metric queries
9
9
 
10
10
  Run: python examples/us_budgetary_impact.py
11
+
12
+ System requirements: this example holds two full enhanced-CPS US
13
+ simulations in memory simultaneously to compute reform-vs-baseline
14
+ deltas. On a 2026 dataset (~101k people / 41k households) peak memory
15
+ has been observed at ~7.5 GiB RSS / ~80 GiB virtual, and end-to-end
16
+ runtime is ~20 minutes on a developer laptop. Run with at least 16 GiB
17
+ of free RAM and expect to close other memory-heavy applications. See
18
+ https://github.com/PolicyEngine/policyengine.py/issues/328 for tracking.
11
19
  """
12
20
 
13
21
  import datetime
@@ -35,7 +43,7 @@ def main():
35
43
  data_folder="./data",
36
44
  )
37
45
  dataset = datasets[f"enhanced_cps_2024_{year}"]
38
- print(f" Loaded: {dataset}")
46
+ print(f" Loaded: {dataset.name} ({len(dataset.data.person):,} people)")
39
47
 
40
48
  # ── Step 2: Define a reform ──
41
49
  # Example: double the standard deduction for single filers
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "policyengine"
7
- version = "4.4.2"
7
+ version = "4.4.3"
8
8
  description = "A package to conduct policy analysis using PolicyEngine tax-benefit models."
9
9
  readme = "README.md"
10
10
  authors = [
@@ -41,12 +41,12 @@ graph = [
41
41
  "networkx>=3.0",
42
42
  ]
43
43
  uk = [
44
- "policyengine_core>=3.26.0",
44
+ "policyengine_core>=3.26.1",
45
45
  "policyengine-uk==2.88.14",
46
46
  ]
47
47
  us = [
48
- "policyengine_core>=3.26.0",
49
- "policyengine-us==1.687.0",
48
+ "policyengine_core>=3.26.1",
49
+ "policyengine-us==1.690.7",
50
50
  ]
51
51
  dev = [
52
52
  "pytest",
@@ -59,9 +59,9 @@ dev = [
59
59
  "plotly>=5.0.0",
60
60
  "pytest-asyncio>=0.26.0",
61
61
  "ruff>=0.9.0",
62
- "policyengine_core>=3.26.0",
62
+ "policyengine_core>=3.26.1",
63
63
  "policyengine-uk==2.88.14",
64
- "policyengine-us==1.687.0",
64
+ "policyengine-us==1.690.7",
65
65
  "towncrier>=24.8.0",
66
66
  "mypy>=1.11.0",
67
67
  "pytest-cov>=5.0.0",
@@ -26,8 +26,11 @@ After running:
26
26
  from __future__ import annotations
27
27
 
28
28
  import argparse
29
+ import os
29
30
  import sys
30
31
 
32
+ os.environ.setdefault("POLICYENGINE_SKIP_COUNTRY_IMPORTS", "1")
33
+
31
34
  from policyengine.provenance.bundle import (
32
35
  refresh_release_bundle,
33
36
  regenerate_trace_tro,
@@ -28,17 +28,20 @@ Each country module exposes ``calculate_household``, ``model``
28
28
  (the pinned ``TaxBenefitModelVersion``), and the microsim helpers.
29
29
  """
30
30
 
31
+ import os
31
32
  from importlib.util import find_spec
32
33
 
33
34
  from policyengine import outputs as outputs
34
35
  from policyengine.core import Simulation as Simulation
35
36
 
36
- if find_spec("policyengine_us") is not None:
37
+ _SKIP_COUNTRY_IMPORTS = os.environ.get("POLICYENGINE_SKIP_COUNTRY_IMPORTS") == "1"
38
+
39
+ if not _SKIP_COUNTRY_IMPORTS and find_spec("policyengine_us") is not None:
37
40
  from policyengine.tax_benefit_models import us as us
38
41
  else: # pragma: no cover
39
42
  us = None # type: ignore[assignment]
40
43
 
41
- if find_spec("policyengine_uk") is not None:
44
+ if not _SKIP_COUNTRY_IMPORTS and find_spec("policyengine_uk") is not None:
42
45
  from policyengine.tax_benefit_models import uk as uk
43
46
  else: # pragma: no cover
44
47
  uk = None # type: ignore[assignment]
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "schema_version": 1,
3
- "bundle_id": "uk-4.4.2",
3
+ "bundle_id": "uk-4.4.3",
4
4
  "country_id": "uk",
5
- "policyengine_version": "4.4.2",
5
+ "policyengine_version": "4.4.3",
6
6
  "model_package": {
7
7
  "name": "policyengine-uk",
8
8
  "version": "2.88.14",
@@ -18,18 +18,18 @@
18
18
  "schema:url": "https://policyengine.org"
19
19
  },
20
20
  "schema:dateCreated": "2026-05-09T07:14:50.156352Z",
21
- "schema:description": "TRACE TRO for certified runtime bundle uk-4.4.2 covering the bundle manifest, the certified dataset artifact, the country model wheel, and the country data release manifest when it is available.",
21
+ "schema:description": "TRACE TRO for certified runtime bundle uk-4.4.3 covering the bundle manifest, the certified dataset artifact, the country model wheel, and the country data release manifest when it is available.",
22
22
  "schema:name": "policyengine uk certified bundle TRO",
23
23
  "trov:createdWith": {
24
24
  "@type": "schema:SoftwareApplication",
25
25
  "schema:name": "policyengine",
26
- "schema:softwareVersion": "4.4.2"
26
+ "schema:softwareVersion": "4.4.3"
27
27
  },
28
28
  "trov:hasArrangement": [
29
29
  {
30
30
  "@id": "arrangement/1",
31
31
  "@type": "trov:ArtifactArrangement",
32
- "rdfs:comment": "Certified arrangement for bundle uk-4.4.2.",
32
+ "rdfs:comment": "Certified arrangement for bundle uk-4.4.3.",
33
33
  "trov:hasArtifactLocation": [
34
34
  {
35
35
  "@id": "arrangement/1/location/bundle_manifest",
@@ -75,7 +75,7 @@
75
75
  "@type": "trov:ResearchArtifact",
76
76
  "schema:name": "policyengine.py bundle manifest for uk",
77
77
  "trov:mimeType": "application/json",
78
- "trov:sha256": "68c397241d27ca5ed2b479a53e6316710eb174d02d0d4c148937dc530ad260a4"
78
+ "trov:sha256": "77947ecc210cad81ab4ec04aedae8a9997930d3d3cc9c7f2092c9d62aa84e105"
79
79
  },
80
80
  {
81
81
  "@id": "composition/1/artifact/data_release_manifest",
@@ -102,7 +102,7 @@
102
102
  "trov:hasFingerprint": {
103
103
  "@id": "composition/1/fingerprint",
104
104
  "@type": "trov:CompositionFingerprint",
105
- "trov:sha256": "f33a4fe9983eef2ffb8a329d97eba8ae4800f311720b91683e5d7acc4679e1a8"
105
+ "trov:sha256": "3643c10fef547c3b0a3885ae277c699bc70b1da872f2cbe8b211b269d292e8e7"
106
106
  }
107
107
  },
108
108
  "trov:hasPerformance": {
@@ -112,8 +112,8 @@
112
112
  "pe:certifiedBy": "policyengine.py bundled manifest",
113
113
  "pe:certifiedForModelVersion": "2.88.14",
114
114
  "pe:ciGitRef": "refs/heads/main",
115
- "pe:ciGitSha": "eb7334698e9116cc06a5c6232ac4b4a91e2aef9a",
116
- "pe:ciRunUrl": "https://github.com/PolicyEngine/policyengine.py/actions/runs/25598363562",
115
+ "pe:ciGitSha": "1718b493e4749faf62f0ffdff480205abdd20011",
116
+ "pe:ciRunUrl": "https://github.com/PolicyEngine/policyengine.py/actions/runs/25692889721",
117
117
  "pe:compatibilityBasis": "matching_data_build_fingerprint",
118
118
  "pe:dataBuildFingerprint": "sha256:dff5c5bb976ce254fa965ecfce6a0d84859fe1629a714ae28a79b3075522a0ae",
119
119
  "pe:dataBuildId": "policyengine-uk-data-1.55.5",
@@ -0,0 +1,54 @@
1
+ {
2
+ "schema_version": 1,
3
+ "bundle_id": "us-4.4.3",
4
+ "country_id": "us",
5
+ "policyengine_version": "4.4.3",
6
+ "model_package": {
7
+ "name": "policyengine-us",
8
+ "version": "1.690.7",
9
+ "sha256": "5a7a541efabac98fa069d6845902cf5924c81db67383234b55dcd2b8bfcfc3ca",
10
+ "wheel_url": "https://files.pythonhosted.org/packages/2a/02/52109bae5f4767237b43bd72ce0bc4edf7925650a788053b2bc168caa5ae/policyengine_us-1.690.7-py3-none-any.whl"
11
+ },
12
+ "data_package": {
13
+ "name": "policyengine-us-data",
14
+ "version": "1.110.12",
15
+ "repo_id": "policyengine/policyengine-us-data",
16
+ "release_manifest_path": "releases/1.110.12/release_manifest.json",
17
+ "release_manifest_revision": "3aac4505ec10d31efc1b3799a1e6458a15853ecc"
18
+ },
19
+ "certified_data_artifact": {
20
+ "data_package": {
21
+ "name": "policyengine-us-data",
22
+ "version": "1.110.12"
23
+ },
24
+ "build_id": "policyengine-us-data-1.110.12",
25
+ "dataset": "enhanced_cps_2024",
26
+ "uri": "hf://policyengine/policyengine-us-data/enhanced_cps_2024.h5@1.110.12",
27
+ "sha256": "58a6639f7511b8d804701417e2647f0c3a77f51a3d90441037eaf004b1f00761"
28
+ },
29
+ "certification": {
30
+ "compatibility_basis": "exact_build_model_version",
31
+ "data_build_id": "policyengine-us-data-1.110.12",
32
+ "built_with_model_version": "1.690.7",
33
+ "certified_for_model_version": "1.690.7",
34
+ "certified_by": "policyengine.py bundled manifest",
35
+ "data_build_fingerprint": "sha256:9961ed1c5d00943a360724da560eee425eb9f99f91896f053dca74724c46e96e"
36
+ },
37
+ "default_dataset": "enhanced_cps_2024",
38
+ "datasets": {
39
+ "enhanced_cps_2024": {
40
+ "path": "enhanced_cps_2024.h5"
41
+ }
42
+ },
43
+ "region_datasets": {
44
+ "national": {
45
+ "path_template": "enhanced_cps_2024.h5"
46
+ },
47
+ "state": {
48
+ "path_template": "states/{state_code}.h5"
49
+ },
50
+ "congressional_district": {
51
+ "path_template": "districts/{district_code}.h5"
52
+ }
53
+ }
54
+ }
@@ -17,19 +17,19 @@
17
17
  "schema:name": "PolicyEngine",
18
18
  "schema:url": "https://policyengine.org"
19
19
  },
20
- "schema:dateCreated": "2026-05-09T09:38:11.356906Z",
21
- "schema:description": "TRACE TRO for certified runtime bundle us-4.4.2 covering the bundle manifest, the certified dataset artifact, the country model wheel, and the country data release manifest when it is available.",
20
+ "schema:dateCreated": "2026-05-11T18:53:05.508006Z",
21
+ "schema:description": "TRACE TRO for certified runtime bundle us-4.4.3 covering the bundle manifest, the certified dataset artifact, the country model wheel, and the country data release manifest when it is available.",
22
22
  "schema:name": "policyengine us certified bundle TRO",
23
23
  "trov:createdWith": {
24
24
  "@type": "schema:SoftwareApplication",
25
25
  "schema:name": "policyengine",
26
- "schema:softwareVersion": "4.4.2"
26
+ "schema:softwareVersion": "4.4.3"
27
27
  },
28
28
  "trov:hasArrangement": [
29
29
  {
30
30
  "@id": "arrangement/1",
31
31
  "@type": "trov:ArtifactArrangement",
32
- "rdfs:comment": "Certified arrangement for bundle us-4.4.2.",
32
+ "rdfs:comment": "Certified arrangement for bundle us-4.4.3.",
33
33
  "trov:hasArtifactLocation": [
34
34
  {
35
35
  "@id": "arrangement/1/location/bundle_manifest",
@@ -45,7 +45,7 @@
45
45
  "trov:hasArtifact": {
46
46
  "@id": "composition/1/artifact/data_release_manifest"
47
47
  },
48
- "trov:hasLocation": "https://huggingface.co/policyengine/policyengine-us-data/resolve/9cb665df0a546f9c3d79b496f8eb2dd55859d38d/releases/1.78.2/release_manifest.json"
48
+ "trov:hasLocation": "https://huggingface.co/policyengine/policyengine-us-data/resolve/3aac4505ec10d31efc1b3799a1e6458a15853ecc/releases/1.110.12/release_manifest.json"
49
49
  },
50
50
  {
51
51
  "@id": "arrangement/1/location/dataset",
@@ -53,7 +53,7 @@
53
53
  "trov:hasArtifact": {
54
54
  "@id": "composition/1/artifact/dataset"
55
55
  },
56
- "trov:hasLocation": "https://huggingface.co/policyengine/policyengine-us-data/resolve/1.78.2/enhanced_cps_2024.h5"
56
+ "trov:hasLocation": "https://huggingface.co/policyengine/policyengine-us-data/resolve/1.110.12/enhanced_cps_2024.h5"
57
57
  },
58
58
  {
59
59
  "@id": "arrangement/1/location/model_wheel",
@@ -61,7 +61,7 @@
61
61
  "trov:hasArtifact": {
62
62
  "@id": "composition/1/artifact/model_wheel"
63
63
  },
64
- "trov:hasLocation": "https://files.pythonhosted.org/packages/c3/36/5633f5a3996c915494154ec3852011b1a239ea06d9f08cb6287ab709618c/policyengine_us-1.687.0-py3-none-any.whl"
64
+ "trov:hasLocation": "https://files.pythonhosted.org/packages/2a/02/52109bae5f4767237b43bd72ce0bc4edf7925650a788053b2bc168caa5ae/policyengine_us-1.690.7-py3-none-any.whl"
65
65
  }
66
66
  ]
67
67
  }
@@ -75,53 +75,54 @@
75
75
  "@type": "trov:ResearchArtifact",
76
76
  "schema:name": "policyengine.py bundle manifest for us",
77
77
  "trov:mimeType": "application/json",
78
- "trov:sha256": "ee037378f3e655360894dc9fe66f1d0c335321ff48789e3ebb0ff38805933d72"
78
+ "trov:sha256": "41e196a6263b8168d403058029c52ebab795e17024ac9ebef11ff876e36959e2"
79
79
  },
80
80
  {
81
81
  "@id": "composition/1/artifact/data_release_manifest",
82
82
  "@type": "trov:ResearchArtifact",
83
- "schema:name": "policyengine-us-data release manifest 1.78.2",
83
+ "schema:name": "policyengine-us-data release manifest 1.110.12",
84
84
  "trov:mimeType": "application/json",
85
- "trov:sha256": "83aafd9fa3d33a444c0277aa4b31b2041a8785910bee30660773ab96e1b1c8b9"
85
+ "trov:sha256": "17cfd2fbb31064834ed82c0fd7d8ae5c272fe7f24b1e48b226a4acf97ff4c5dd"
86
86
  },
87
87
  {
88
88
  "@id": "composition/1/artifact/dataset",
89
89
  "@type": "trov:ResearchArtifact",
90
90
  "schema:name": "enhanced_cps_2024",
91
91
  "trov:mimeType": "application/x-hdf5",
92
- "trov:sha256": "4e92b340c3ea3e200ed5d55edf752ee1a13baf787442956fb67d25242fed13b5"
92
+ "trov:sha256": "58a6639f7511b8d804701417e2647f0c3a77f51a3d90441037eaf004b1f00761"
93
93
  },
94
94
  {
95
95
  "@id": "composition/1/artifact/model_wheel",
96
96
  "@type": "trov:ResearchArtifact",
97
- "schema:name": "policyengine-us==1.687.0 wheel",
97
+ "schema:name": "policyengine-us==1.690.7 wheel",
98
98
  "trov:mimeType": "application/zip",
99
- "trov:sha256": "cac7da3aa9ba4bf57009eee75d798217bbef7e1c5ca17646d472fad715ab634f"
99
+ "trov:sha256": "5a7a541efabac98fa069d6845902cf5924c81db67383234b55dcd2b8bfcfc3ca"
100
100
  }
101
101
  ],
102
102
  "trov:hasFingerprint": {
103
103
  "@id": "composition/1/fingerprint",
104
104
  "@type": "trov:CompositionFingerprint",
105
- "trov:sha256": "a26e89fc2cd91ee54bc7526aa4c1a32c5b8ad35caefa1e7f2572e2fb8bb303a0"
105
+ "trov:sha256": "b84e895b3f19ffee5ec299b94ae2155448a12af2b3dc61d00f3d17003ecdf14a"
106
106
  }
107
107
  },
108
108
  "trov:hasPerformance": {
109
109
  "@id": "trp/1",
110
110
  "@type": "trov:TransparentResearchPerformance",
111
- "pe:builtWithModelVersion": "1.647.0",
111
+ "pe:builtWithModelVersion": "1.690.7",
112
112
  "pe:certifiedBy": "policyengine.py bundled manifest",
113
- "pe:certifiedForModelVersion": "1.687.0",
113
+ "pe:certifiedForModelVersion": "1.690.7",
114
114
  "pe:ciGitRef": "refs/heads/main",
115
- "pe:ciGitSha": "eb7334698e9116cc06a5c6232ac4b4a91e2aef9a",
116
- "pe:ciRunUrl": "https://github.com/PolicyEngine/policyengine.py/actions/runs/25598363562",
117
- "pe:compatibilityBasis": "matching_data_build_fingerprint",
118
- "pe:dataBuildId": "policyengine-us-data-1.78.2",
115
+ "pe:ciGitSha": "1718b493e4749faf62f0ffdff480205abdd20011",
116
+ "pe:ciRunUrl": "https://github.com/PolicyEngine/policyengine.py/actions/runs/25692889721",
117
+ "pe:compatibilityBasis": "exact_build_model_version",
118
+ "pe:dataBuildFingerprint": "sha256:9961ed1c5d00943a360724da560eee425eb9f99f91896f053dca74724c46e96e",
119
+ "pe:dataBuildId": "policyengine-us-data-1.110.12",
119
120
  "pe:emittedIn": "github-actions",
120
- "rdfs:comment": "Certification of build policyengine-us-data-1.78.2 for policyengine-us 1.687.0.",
121
+ "rdfs:comment": "Certification of build policyengine-us-data-1.110.12 for policyengine-us 1.690.7.",
121
122
  "trov:accessedArrangement": {
122
123
  "@id": "arrangement/1"
123
124
  },
124
- "trov:startedAtTime": "2026-05-09T09:38:11.356906Z",
125
+ "trov:startedAtTime": "2026-05-11T18:53:05.508006Z",
125
126
  "trov:wasConductedBy": {
126
127
  "@id": "trs"
127
128
  }
@@ -174,6 +174,66 @@ def _hf_dataset_sha256(repo_id: str, path: str, revision: str) -> str:
174
174
  return hasher.hexdigest()
175
175
 
176
176
 
177
+ @dataclass(frozen=True)
178
+ class _DataReleaseManifestFetch:
179
+ payload: dict
180
+ repo_commit: Optional[str]
181
+
182
+
183
+ def _fetch_data_release_manifest(
184
+ repo_id: str,
185
+ release_manifest_path: str,
186
+ revision: str,
187
+ ) -> Optional[_DataReleaseManifestFetch]:
188
+ """Fetch a data release manifest from HF if one is available.
189
+
190
+ Older data releases may not have a machine-readable release manifest at the
191
+ inferred path. In that case the bundle refresh falls back to hashing the
192
+ dataset artifact directly.
193
+
194
+ Data releases are stored under versioned paths, but the HF repository does
195
+ not necessarily create a matching git tag for each data version. Try the
196
+ version revision first for repositories that do publish tags, then fall
197
+ back to ``main`` and persist the immutable ``x-repo-commit`` header.
198
+ """
199
+ headers = {"User-Agent": "policyengine.py"}
200
+ token = os.environ.get("HUGGING_FACE_TOKEN") or os.environ.get("HF_TOKEN")
201
+ if token:
202
+ headers["Authorization"] = f"Bearer {token}"
203
+
204
+ revisions = [revision]
205
+ if revision != "main":
206
+ revisions.append("main")
207
+
208
+ for candidate in revisions:
209
+ url = (
210
+ f"https://huggingface.co/{repo_id}/resolve/"
211
+ f"{candidate}/{release_manifest_path}"
212
+ )
213
+ try:
214
+ with urlopen(Request(url, headers=headers)) as f:
215
+ payload = json.load(f)
216
+ repo_commit = getattr(f, "headers", {}).get("x-repo-commit")
217
+ return _DataReleaseManifestFetch(
218
+ payload=payload,
219
+ repo_commit=repo_commit,
220
+ )
221
+ except (OSError, ValueError):
222
+ continue
223
+ return None
224
+
225
+
226
+ def _updated_release_manifest_path(
227
+ current_path: str,
228
+ old_data: str,
229
+ new_data: str,
230
+ ) -> str:
231
+ """Preserve country-specific release-manifest layout while bumping versions."""
232
+ if old_data in current_path:
233
+ return current_path.replace(old_data, new_data)
234
+ return current_path
235
+
236
+
177
237
  # ---------------------------------------------------------------------------
178
238
  # Refresh result
179
239
  # ---------------------------------------------------------------------------
@@ -276,19 +336,90 @@ def refresh_release_bundle(
276
336
  )
277
337
  repo_id, dataset_path, _old_revision = repo_id_match.groups()
278
338
 
339
+ data_package_json = manifest_json["data_package"]
340
+ release_manifest_json = None
341
+ new_release_manifest_revision = None
342
+ new_release_manifest_path = data_package_json.get("release_manifest_path")
343
+ if new_data != old_data and new_release_manifest_path is not None:
344
+ new_release_manifest_path = _updated_release_manifest_path(
345
+ current_path=new_release_manifest_path,
346
+ old_data=old_data,
347
+ new_data=new_data,
348
+ )
349
+ release_manifest_fetch = _fetch_data_release_manifest(
350
+ repo_id=repo_id,
351
+ release_manifest_path=new_release_manifest_path,
352
+ revision=new_data,
353
+ )
354
+ if release_manifest_fetch is None:
355
+ raise ValueError(
356
+ "Could not fetch data release manifest "
357
+ f"{new_release_manifest_path!r} from {repo_id}@{new_data}. "
358
+ "Refusing to refresh a release-manifest-backed bundle with "
359
+ "partial certification metadata."
360
+ )
361
+ if release_manifest_fetch.repo_commit is None:
362
+ raise ValueError(
363
+ "Could not resolve an immutable HF commit for data release "
364
+ f"manifest {new_release_manifest_path!r} from {repo_id}@{new_data}."
365
+ )
366
+ release_manifest_json = release_manifest_fetch.payload
367
+ release_manifest_data_version = release_manifest_json.get(
368
+ "data_package", {}
369
+ ).get("version")
370
+ if release_manifest_data_version != new_data:
371
+ raise ValueError(
372
+ "Data release manifest "
373
+ f"{new_release_manifest_path!r} from {repo_id} declares "
374
+ f"version {release_manifest_data_version!r}, expected {new_data!r}."
375
+ )
376
+ new_release_manifest_revision = release_manifest_fetch.repo_commit
377
+
378
+ certified_dataset = (
379
+ current.certified_data_artifact.dataset
380
+ if current.certified_data_artifact is not None
381
+ else current.default_dataset
382
+ )
383
+ data_artifact_json = {}
384
+ if release_manifest_json is not None:
385
+ data_artifact_json = release_manifest_json.get("artifacts", {}).get(
386
+ certified_dataset,
387
+ {},
388
+ )
389
+ if not data_artifact_json:
390
+ raise ValueError(
391
+ "Data release manifest "
392
+ f"{new_release_manifest_path!r} from {repo_id}@{new_data} "
393
+ f"does not include certified dataset {certified_dataset!r}."
394
+ )
395
+ dataset_repo_id = data_artifact_json.get("repo_id", repo_id)
396
+ dataset_path = data_artifact_json.get("path", dataset_path)
397
+ dataset_revision = data_artifact_json.get("revision", new_data)
398
+
279
399
  # Only hit HF if the data version actually changed.
280
400
  if new_data != old_data:
281
- new_dataset_sha256 = _hf_dataset_sha256(repo_id, dataset_path, new_data)
401
+ new_dataset_sha256 = data_artifact_json.get("sha256") or _hf_dataset_sha256(
402
+ dataset_repo_id,
403
+ dataset_path,
404
+ dataset_revision,
405
+ )
282
406
  else:
283
407
  new_dataset_sha256 = old_dataset_sha256
284
- new_uri = f"hf://{repo_id}/{dataset_path}@{new_data}"
408
+ new_uri = f"hf://{dataset_repo_id}/{dataset_path}@{dataset_revision}"
285
409
  policyengine_version = _pyproject_version(pyproject_path)
286
410
 
287
411
  # Mutate the manifest JSON in place (keep unknown fields untouched).
288
412
  manifest_json["model_package"]["version"] = new_model
289
413
  manifest_json["model_package"]["sha256"] = new_wheel_sha256
290
414
  manifest_json["model_package"]["wheel_url"] = new_wheel_url
291
- manifest_json["data_package"]["version"] = new_data
415
+ data_package_json["version"] = new_data
416
+ if new_data != old_data:
417
+ if new_release_manifest_path is not None:
418
+ data_package_json["release_manifest_path"] = new_release_manifest_path
419
+ if new_release_manifest_revision is not None:
420
+ data_package_json["release_manifest_revision"] = (
421
+ new_release_manifest_revision
422
+ )
292
423
  manifest_json["certified_data_artifact"]["data_package"]["version"] = new_data
293
424
  manifest_json["certified_data_artifact"]["build_id"] = (
294
425
  f"{current.data_package.name}-{new_data}"
@@ -299,10 +430,43 @@ def refresh_release_bundle(
299
430
  f"{current.data_package.name}-{new_data}"
300
431
  )
301
432
  manifest_json["certification"]["certified_for_model_version"] = new_model
433
+ if release_manifest_json is not None:
434
+ build = release_manifest_json.get("build") or {}
435
+ built_with_model = build.get("built_with_model_package") or {}
436
+ data_build_id = (
437
+ build.get("build_id") or f"{current.data_package.name}-{new_data}"
438
+ )
439
+ manifest_json["certified_data_artifact"]["build_id"] = data_build_id
440
+ certification_json = manifest_json["certification"]
441
+ certification_json["data_build_id"] = data_build_id
442
+ certification_json["certified_for_model_version"] = new_model
443
+ built_with_model_version = built_with_model.get("version")
444
+ if built_with_model_version is not None:
445
+ certification_json["built_with_model_version"] = built_with_model_version
446
+ if built_with_model.get("git_sha") is not None:
447
+ certification_json["built_with_model_git_sha"] = built_with_model["git_sha"]
448
+ else:
449
+ certification_json.pop("built_with_model_git_sha", None)
450
+ data_build_fingerprint = built_with_model.get("data_build_fingerprint")
451
+ if data_build_fingerprint is not None:
452
+ certification_json["data_build_fingerprint"] = data_build_fingerprint
453
+ else:
454
+ certification_json.pop("data_build_fingerprint", None)
455
+ if built_with_model_version == new_model:
456
+ certification_json["compatibility_basis"] = "exact_build_model_version"
457
+ elif data_build_fingerprint is not None:
458
+ certification_json["compatibility_basis"] = (
459
+ "matching_data_build_fingerprint"
460
+ )
461
+ else:
462
+ certification_json["compatibility_basis"] = (
463
+ "legacy_compatible_model_package"
464
+ )
302
465
 
303
466
  manifest_path.write_text(
304
467
  json.dumps(manifest_json, indent=2, sort_keys=False) + "\n"
305
468
  )
469
+ get_release_manifest.cache_clear()
306
470
  sync_release_manifest_policyengine_version(
307
471
  policyengine_version=policyengine_version,
308
472
  manifest_dir=manifest_dir,