policyengine 3.4.3__tar.gz → 3.4.4__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.
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/workflows/push.yaml +1 -3
- {policyengine-3.4.3 → policyengine-3.4.4}/CHANGELOG.md +7 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/Makefile +9 -3
- {policyengine-3.4.3 → policyengine-3.4.4}/PKG-INFO +3 -2
- {policyengine-3.4.3 → policyengine-3.4.4}/README.md +2 -1
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/dev.md +2 -1
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/release-bundles.md +49 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/pyproject.toml +1 -1
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/__init__.py +7 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/tax_benefit_model_version.py +23 -1
- policyengine-3.4.4/src/policyengine/core/trace_tro.py +259 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine.egg-info/PKG-INFO +3 -2
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine.egg-info/SOURCES.txt +1 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_release_manifests.py +185 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.claude/policyengine-guide.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.claude/quick-reference.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/CONTRIBUTING.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/bump_version.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/changelog_template.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/check-changelog.sh +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/fetch_version.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/get-changelog-diff.sh +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/has-functional-changes.sh +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/is-version-number-acceptable.sh +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/publish-git-tag.sh +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/workflows/pr_code_changes.yaml +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.github/workflows/pr_docs_changes.yaml +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.gitignore +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/.python-version +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/LICENSE +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/changelog.d/.gitkeep +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/.gitignore +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/advanced-outputs.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/core-concepts.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/country-models-uk.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/country-models-us.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/economic-impact-analysis.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/examples.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/index.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/myst.yml +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/regions-and-scoping.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/docs/visualisation.md +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/examples/employment_income_variation_uk.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/examples/employment_income_variation_us.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/examples/household_impact_example.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/examples/income_bands_uk.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/examples/income_distribution_us.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/examples/paper_repro_uk.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/examples/policy_change_uk.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/examples/speedtest_us_simulation.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/examples/us_budgetary_impact.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/setup.cfg +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/__init__.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/cache.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/dataset.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/dataset_version.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/dynamic.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/output.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/parameter.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/parameter_node.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/parameter_value.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/policy.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/region.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/release_manifest.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/scoping_strategy.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/simulation.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/tax_benefit_model.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/variable.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/countries/__init__.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/countries/uk/__init__.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/countries/uk/regions.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/countries/us/__init__.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/countries/us/data/__init__.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/countries/us/data/districts.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/countries/us/data/places.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/countries/us/data/states.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/countries/us/regions.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/data/release_manifests/uk.json +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/data/release_manifests/us.json +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/outputs/__init__.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/outputs/aggregate.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/outputs/change_aggregate.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/outputs/congressional_district_impact.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/outputs/constituency_impact.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/outputs/decile_impact.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/outputs/inequality.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/outputs/intra_decile_impact.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/outputs/local_authority_impact.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/outputs/poverty.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/uk/__init__.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/uk/analysis.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/uk/datasets.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/uk/model.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/uk/outputs.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/uk.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/us/__init__.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/us/analysis.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/us/datasets.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/us/model.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/us/outputs.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/tax_benefit_models/us.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/utils/__init__.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/utils/dates.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/utils/entity_utils.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/utils/parameter_labels.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/utils/parametric_reforms.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/utils/plotting.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine.egg-info/dependency_links.txt +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine.egg-info/requires.txt +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine.egg-info/top_level.txt +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/__init__.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/conftest.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/fixtures/__init__.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/fixtures/filtering_fixtures.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/fixtures/parameter_labels_fixtures.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/fixtures/parametric_reforms_fixtures.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/fixtures/poverty_by_demographics_fixtures.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/fixtures/region_fixtures.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/fixtures/us_reform_fixtures.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/fixtures/variable_label_fixtures.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_aggregate.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_bump_version.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_cache.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_change_aggregate.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_congressional_district_impact.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_constituency_impact.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_entity_mapping.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_entity_utils.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_filtering.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_household_impact.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_inequality.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_intra_decile_impact.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_local_authority_impact.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_models.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_pandas3_compatibility.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_parameter_labels.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_parametric_reforms.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_poverty.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_poverty_by_demographics.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_poverty_run.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_region.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_scoping_strategy.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_uk_regions.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_us_reform_application.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_us_regions.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/tests/test_variable_labels.py +0 -0
- {policyengine-3.4.3 → policyengine-3.4.4}/uv.lock +0 -0
|
@@ -81,10 +81,8 @@ jobs:
|
|
|
81
81
|
- uses: actions/setup-node@v4
|
|
82
82
|
with:
|
|
83
83
|
node-version: 18.x
|
|
84
|
-
- name: Install MyST
|
|
85
|
-
run: npm install -g mystmd
|
|
86
84
|
- name: Build HTML Assets
|
|
87
|
-
run:
|
|
85
|
+
run: make docs
|
|
88
86
|
- name: Upload artifact
|
|
89
87
|
uses: actions/upload-pages-artifact@v3
|
|
90
88
|
with:
|
|
@@ -1,9 +1,15 @@
|
|
|
1
|
-
.PHONY: docs
|
|
1
|
+
.PHONY: docs docs-serve
|
|
2
|
+
|
|
3
|
+
MYSTMD_VERSION ?= 1.8.3
|
|
4
|
+
MYST_CMD = npx --yes mystmd@$(MYSTMD_VERSION)
|
|
2
5
|
|
|
3
6
|
all: build-package
|
|
4
7
|
|
|
5
8
|
docs:
|
|
6
|
-
cd docs &&
|
|
9
|
+
cd docs && $(MYST_CMD) build --html
|
|
10
|
+
|
|
11
|
+
docs-serve:
|
|
12
|
+
cd docs && $(MYST_CMD) start
|
|
7
13
|
|
|
8
14
|
install:
|
|
9
15
|
uv pip install -e .[dev]
|
|
@@ -27,4 +33,4 @@ build-package:
|
|
|
27
33
|
python -m build
|
|
28
34
|
|
|
29
35
|
test:
|
|
30
|
-
pytest tests --cov=policyengine --cov-report=term-missing
|
|
36
|
+
pytest tests --cov=policyengine --cov-report=term-missing
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: policyengine
|
|
3
|
-
Version: 3.4.
|
|
3
|
+
Version: 3.4.4
|
|
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
|
|
@@ -788,7 +788,8 @@ uv pip install -e .[dev] # install with dev dependencies (pytest, ruff, m
|
|
|
788
788
|
```bash
|
|
789
789
|
make format # ruff format
|
|
790
790
|
make test # pytest with coverage
|
|
791
|
-
make docs # build Jupyter Book
|
|
791
|
+
make docs # build static MyST/Jupyter Book 2 HTML docs
|
|
792
|
+
make docs-serve # preview the docs locally
|
|
792
793
|
make clean # remove caches, build artifacts, .h5 files
|
|
793
794
|
```
|
|
794
795
|
|
|
@@ -86,7 +86,8 @@ uv pip install -e .[dev] # install with dev dependencies (pytest, ruff, m
|
|
|
86
86
|
```bash
|
|
87
87
|
make format # ruff format
|
|
88
88
|
make test # pytest with coverage
|
|
89
|
-
make docs # build Jupyter Book
|
|
89
|
+
make docs # build static MyST/Jupyter Book 2 HTML docs
|
|
90
|
+
make docs-serve # preview the docs locally
|
|
90
91
|
make clean # remove caches, build artifacts, .h5 files
|
|
91
92
|
```
|
|
92
93
|
|
|
@@ -23,7 +23,8 @@ dependencies used in CI (pytest, ruff, mypy, towncrier).
|
|
|
23
23
|
```bash
|
|
24
24
|
make format # ruff format
|
|
25
25
|
make test # pytest with coverage
|
|
26
|
-
make docs #
|
|
26
|
+
make docs # build static MyST/Jupyter Book 2 HTML docs
|
|
27
|
+
make docs-serve # preview the docs locally
|
|
27
28
|
make clean # remove caches, build artifacts, .h5 files
|
|
28
29
|
```
|
|
29
30
|
|
|
@@ -186,6 +186,55 @@ Notes:
|
|
|
186
186
|
- apps and APIs should surface this bundle, not only country package versions
|
|
187
187
|
- a bundle may reuse a previously staged data artifact if compatibility is explicitly certified
|
|
188
188
|
|
|
189
|
+
## TRACE export
|
|
190
|
+
|
|
191
|
+
The internal build manifest and certified runtime bundle remain the operational source of
|
|
192
|
+
truth.
|
|
193
|
+
|
|
194
|
+
TRACE sits on top of those manifests as a standards-based export layer.
|
|
195
|
+
|
|
196
|
+
### What gets exported
|
|
197
|
+
|
|
198
|
+
Country `*-data` repos should emit a `trace.tro.jsonld` file for each published data
|
|
199
|
+
release. That TRO should cover:
|
|
200
|
+
|
|
201
|
+
- the release manifest itself
|
|
202
|
+
- each published artifact hash listed in the release manifest
|
|
203
|
+
- the build-time model provenance recorded in the release manifest
|
|
204
|
+
|
|
205
|
+
`policyengine.py` should emit a separate certified-bundle TRO. That TRO should cover:
|
|
206
|
+
|
|
207
|
+
- the bundled country release manifest shipped in `policyengine.py`
|
|
208
|
+
- the country data release manifest resolved for the certified data package version
|
|
209
|
+
- the certified dataset artifact hash
|
|
210
|
+
- the certification basis used to allow runtime reuse
|
|
211
|
+
|
|
212
|
+
### What TRACE does not replace
|
|
213
|
+
|
|
214
|
+
TRACE is not the source of truth for compatibility policy.
|
|
215
|
+
|
|
216
|
+
In particular, TRACE does not decide:
|
|
217
|
+
|
|
218
|
+
- whether a new model version can safely reuse an existing data artifact
|
|
219
|
+
- how `data_build_fingerprint` is computed
|
|
220
|
+
- which staged artifact becomes a supported runtime default
|
|
221
|
+
|
|
222
|
+
Those decisions still belong to the country data build manifest and the
|
|
223
|
+
`policyengine.py` certified runtime bundle.
|
|
224
|
+
|
|
225
|
+
### Why we still want it
|
|
226
|
+
|
|
227
|
+
TRACE adds three things our internal manifests do not provide by themselves:
|
|
228
|
+
|
|
229
|
+
- a standard declaration format for provenance exchange
|
|
230
|
+
- a composition fingerprint over the exact artifacts in scope
|
|
231
|
+
- a better external surface for papers, audits, and reproducibility reviews
|
|
232
|
+
|
|
233
|
+
That is why the recommended design is:
|
|
234
|
+
|
|
235
|
+
- internal manifests for build/certification control
|
|
236
|
+
- generated TRACE TROs for standards-based export
|
|
237
|
+
|
|
189
238
|
## Compatibility rule
|
|
190
239
|
|
|
191
240
|
The architecture should avoid forcing a new data build for every harmless country model release.
|
|
@@ -36,6 +36,13 @@ from .tax_benefit_model import TaxBenefitModel as TaxBenefitModel
|
|
|
36
36
|
from .tax_benefit_model_version import (
|
|
37
37
|
TaxBenefitModelVersion as TaxBenefitModelVersion,
|
|
38
38
|
)
|
|
39
|
+
from .trace_tro import (
|
|
40
|
+
build_trace_tro_from_release_bundle as build_trace_tro_from_release_bundle,
|
|
41
|
+
)
|
|
42
|
+
from .trace_tro import (
|
|
43
|
+
compute_trace_composition_fingerprint as compute_trace_composition_fingerprint,
|
|
44
|
+
)
|
|
45
|
+
from .trace_tro import serialize_trace_tro as serialize_trace_tro
|
|
39
46
|
from .variable import Variable as Variable
|
|
40
47
|
|
|
41
48
|
# Rebuild models to resolve forward references
|
{policyengine-3.4.3 → policyengine-3.4.4}/src/policyengine/core/tax_benefit_model_version.py
RENAMED
|
@@ -4,8 +4,14 @@ from uuid import uuid4
|
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel, Field
|
|
6
6
|
|
|
7
|
-
from .release_manifest import
|
|
7
|
+
from .release_manifest import (
|
|
8
|
+
CountryReleaseManifest,
|
|
9
|
+
DataCertification,
|
|
10
|
+
PackageVersion,
|
|
11
|
+
get_data_release_manifest,
|
|
12
|
+
)
|
|
8
13
|
from .tax_benefit_model import TaxBenefitModel
|
|
14
|
+
from .trace_tro import build_trace_tro_from_release_bundle
|
|
9
15
|
|
|
10
16
|
if TYPE_CHECKING:
|
|
11
17
|
from .parameter import Parameter
|
|
@@ -201,6 +207,22 @@ class TaxBenefitModelVersion(BaseModel):
|
|
|
201
207
|
),
|
|
202
208
|
}
|
|
203
209
|
|
|
210
|
+
@property
|
|
211
|
+
def trace_tro(self) -> dict:
|
|
212
|
+
if self.release_manifest is None:
|
|
213
|
+
raise ValueError(
|
|
214
|
+
"TRACE TRO export requires a bundled country release manifest."
|
|
215
|
+
)
|
|
216
|
+
|
|
217
|
+
data_release_manifest = get_data_release_manifest(
|
|
218
|
+
self.release_manifest.country_id
|
|
219
|
+
)
|
|
220
|
+
return build_trace_tro_from_release_bundle(
|
|
221
|
+
self.release_manifest,
|
|
222
|
+
data_release_manifest,
|
|
223
|
+
certification=self.data_certification,
|
|
224
|
+
)
|
|
225
|
+
|
|
204
226
|
def __repr__(self) -> str:
|
|
205
227
|
# Give the id and version, and the number of variables, parameters, parameter nodes, parameter values
|
|
206
228
|
return f"<TaxBenefitModelVersion id={self.id} variables={len(self.variables)} parameters={len(self.parameters)} parameter_nodes={len(self.parameter_nodes)} parameter_values={len(self.parameter_values)}>"
|
|
@@ -0,0 +1,259 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import hashlib
|
|
4
|
+
import json
|
|
5
|
+
from collections.abc import Iterable, Mapping
|
|
6
|
+
|
|
7
|
+
from .release_manifest import (
|
|
8
|
+
CountryReleaseManifest,
|
|
9
|
+
DataCertification,
|
|
10
|
+
DataReleaseManifest,
|
|
11
|
+
)
|
|
12
|
+
|
|
13
|
+
TRACE_TROV_VERSION = "0.1"
|
|
14
|
+
TRACE_CONTEXT = [
|
|
15
|
+
{
|
|
16
|
+
"rdf": "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
|
17
|
+
"rdfs": "http://www.w3.org/2000/01/rdf-schema#",
|
|
18
|
+
"trov": "https://w3id.org/trace/trov/0.1#",
|
|
19
|
+
"schema": "https://schema.org/",
|
|
20
|
+
}
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def _hash_object(value: str) -> dict[str, str]:
|
|
25
|
+
return {
|
|
26
|
+
"trov:hashAlgorithm": "sha256",
|
|
27
|
+
"trov:hashValue": value,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def _artifact_mime_type(path_or_uri: str) -> str | None:
|
|
32
|
+
suffix = path_or_uri.rsplit(".", 1)[-1].lower() if "." in path_or_uri else ""
|
|
33
|
+
return {
|
|
34
|
+
"h5": "application/x-hdf5",
|
|
35
|
+
"json": "application/json",
|
|
36
|
+
"jsonld": "application/ld+json",
|
|
37
|
+
}.get(suffix)
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _canonical_json_bytes(value: Mapping) -> bytes:
|
|
41
|
+
return (json.dumps(value, indent=2, sort_keys=True) + "\n").encode("utf-8")
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def compute_trace_composition_fingerprint(
|
|
45
|
+
artifact_hashes: Iterable[str],
|
|
46
|
+
) -> str:
|
|
47
|
+
digest = hashlib.sha256()
|
|
48
|
+
digest.update("".join(sorted(artifact_hashes)).encode("utf-8"))
|
|
49
|
+
return digest.hexdigest()
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def build_trace_tro_from_release_bundle(
|
|
53
|
+
country_manifest: CountryReleaseManifest,
|
|
54
|
+
data_release_manifest: DataReleaseManifest,
|
|
55
|
+
*,
|
|
56
|
+
certification: DataCertification | None = None,
|
|
57
|
+
bundle_manifest_path: str | None = None,
|
|
58
|
+
data_release_manifest_path: str | None = None,
|
|
59
|
+
) -> dict:
|
|
60
|
+
certified_artifact = country_manifest.certified_data_artifact
|
|
61
|
+
if certified_artifact is None:
|
|
62
|
+
raise ValueError(
|
|
63
|
+
"Country release manifest does not define a certified artifact."
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
dataset_artifact = data_release_manifest.artifacts.get(certified_artifact.dataset)
|
|
67
|
+
if dataset_artifact is None:
|
|
68
|
+
raise ValueError(
|
|
69
|
+
"Data release manifest does not include the certified dataset "
|
|
70
|
+
f"'{certified_artifact.dataset}'."
|
|
71
|
+
)
|
|
72
|
+
if dataset_artifact.sha256 is None:
|
|
73
|
+
raise ValueError(
|
|
74
|
+
"Data release manifest does not include a SHA256 for the certified dataset "
|
|
75
|
+
f"'{certified_artifact.dataset}'."
|
|
76
|
+
)
|
|
77
|
+
|
|
78
|
+
effective_certification = certification or country_manifest.certification
|
|
79
|
+
bundle_manifest_location = (
|
|
80
|
+
bundle_manifest_path
|
|
81
|
+
or f"data/release_manifests/{country_manifest.country_id}.json"
|
|
82
|
+
)
|
|
83
|
+
data_manifest_location = data_release_manifest_path or (
|
|
84
|
+
"https://huggingface.co/"
|
|
85
|
+
f"{country_manifest.data_package.repo_id}/resolve/"
|
|
86
|
+
f"{country_manifest.data_package.version}/"
|
|
87
|
+
f"{country_manifest.data_package.release_manifest_path}"
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
bundle_manifest_payload = country_manifest.model_dump(mode="json")
|
|
91
|
+
data_release_payload = data_release_manifest.model_dump(mode="json")
|
|
92
|
+
bundle_manifest_hash = hashlib.sha256(
|
|
93
|
+
_canonical_json_bytes(bundle_manifest_payload)
|
|
94
|
+
).hexdigest()
|
|
95
|
+
data_release_manifest_hash = hashlib.sha256(
|
|
96
|
+
_canonical_json_bytes(data_release_payload)
|
|
97
|
+
).hexdigest()
|
|
98
|
+
|
|
99
|
+
artifact_specs = [
|
|
100
|
+
{
|
|
101
|
+
"hash": bundle_manifest_hash,
|
|
102
|
+
"location": bundle_manifest_location,
|
|
103
|
+
"mime_type": "application/json",
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
"hash": data_release_manifest_hash,
|
|
107
|
+
"location": data_manifest_location,
|
|
108
|
+
"mime_type": "application/json",
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
"hash": dataset_artifact.sha256,
|
|
112
|
+
"location": certified_artifact.uri,
|
|
113
|
+
"mime_type": _artifact_mime_type(certified_artifact.uri),
|
|
114
|
+
},
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
composition_artifacts = []
|
|
118
|
+
arrangement_locations = []
|
|
119
|
+
artifact_hashes = []
|
|
120
|
+
|
|
121
|
+
for index, artifact in enumerate(artifact_specs):
|
|
122
|
+
artifact_id = f"composition/1/artifact/{index}"
|
|
123
|
+
artifact_hashes.append(artifact["hash"])
|
|
124
|
+
artifact_entry = {
|
|
125
|
+
"@id": artifact_id,
|
|
126
|
+
"@type": "trov:ResearchArtifact",
|
|
127
|
+
"trov:hash": _hash_object(artifact["hash"]),
|
|
128
|
+
}
|
|
129
|
+
if artifact["mime_type"] is not None:
|
|
130
|
+
artifact_entry["trov:mimeType"] = artifact["mime_type"]
|
|
131
|
+
composition_artifacts.append(artifact_entry)
|
|
132
|
+
arrangement_locations.append(
|
|
133
|
+
{
|
|
134
|
+
"@id": f"arrangement/0/location/{index}",
|
|
135
|
+
"@type": "trov:ArtifactLocation",
|
|
136
|
+
"trov:artifact": {"@id": artifact_id},
|
|
137
|
+
"trov:path": artifact["location"],
|
|
138
|
+
}
|
|
139
|
+
)
|
|
140
|
+
|
|
141
|
+
certification_description = ""
|
|
142
|
+
if effective_certification is not None:
|
|
143
|
+
certification_description = (
|
|
144
|
+
f" Certified for runtime model version "
|
|
145
|
+
f"{effective_certification.certified_for_model_version} via "
|
|
146
|
+
f"{effective_certification.compatibility_basis}."
|
|
147
|
+
)
|
|
148
|
+
if effective_certification.built_with_model_version is not None:
|
|
149
|
+
certification_description += (
|
|
150
|
+
f" Built with {country_manifest.model_package.name} "
|
|
151
|
+
f"{effective_certification.built_with_model_version}."
|
|
152
|
+
)
|
|
153
|
+
if effective_certification.data_build_fingerprint is not None:
|
|
154
|
+
certification_description += (
|
|
155
|
+
f" Data-build fingerprint: "
|
|
156
|
+
f"{effective_certification.data_build_fingerprint}."
|
|
157
|
+
)
|
|
158
|
+
|
|
159
|
+
created_at = country_manifest.published_at or (
|
|
160
|
+
data_release_manifest.build.built_at
|
|
161
|
+
if data_release_manifest.build is not None
|
|
162
|
+
else None
|
|
163
|
+
)
|
|
164
|
+
build_id = (
|
|
165
|
+
effective_certification.data_build_id
|
|
166
|
+
if effective_certification is not None
|
|
167
|
+
else (
|
|
168
|
+
certified_artifact.build_id
|
|
169
|
+
or f"{country_manifest.data_package.name}-{country_manifest.data_package.version}"
|
|
170
|
+
)
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
"@context": TRACE_CONTEXT,
|
|
175
|
+
"@graph": [
|
|
176
|
+
{
|
|
177
|
+
"@id": "tro",
|
|
178
|
+
"@type": ["trov:TransparentResearchObject", "schema:CreativeWork"],
|
|
179
|
+
"trov:vocabularyVersion": TRACE_TROV_VERSION,
|
|
180
|
+
"schema:creator": country_manifest.policyengine_version,
|
|
181
|
+
"schema:name": (
|
|
182
|
+
f"policyengine {country_manifest.country_id} certified bundle TRO"
|
|
183
|
+
),
|
|
184
|
+
"schema:description": (
|
|
185
|
+
f"TRACE TRO for certified runtime bundle "
|
|
186
|
+
f"{country_manifest.bundle_id or country_manifest.country_id} "
|
|
187
|
+
f"covering the bundled country release manifest, the country data "
|
|
188
|
+
f"release manifest, and the certified dataset artifact."
|
|
189
|
+
f"{certification_description}"
|
|
190
|
+
),
|
|
191
|
+
"schema:dateCreated": created_at,
|
|
192
|
+
"trov:wasAssembledBy": {
|
|
193
|
+
"@id": "trs",
|
|
194
|
+
"@type": ["trov:TrustedResearchSystem", "schema:Organization"],
|
|
195
|
+
"schema:name": "PolicyEngine certified release bundle pipeline",
|
|
196
|
+
"schema:description": (
|
|
197
|
+
"PolicyEngine certification workflow for runtime bundles that "
|
|
198
|
+
"pin a country model version, a country data release, and a "
|
|
199
|
+
"specific dataset artifact."
|
|
200
|
+
),
|
|
201
|
+
},
|
|
202
|
+
"trov:createdWith": {
|
|
203
|
+
"@type": "schema:SoftwareApplication",
|
|
204
|
+
"schema:name": "policyengine",
|
|
205
|
+
"schema:softwareVersion": country_manifest.policyengine_version,
|
|
206
|
+
},
|
|
207
|
+
"trov:hasComposition": {
|
|
208
|
+
"@id": "composition/1",
|
|
209
|
+
"@type": "trov:ArtifactComposition",
|
|
210
|
+
"trov:hasFingerprint": {
|
|
211
|
+
"@id": "fingerprint",
|
|
212
|
+
"@type": "trov:CompositionFingerprint",
|
|
213
|
+
"trov:hash": _hash_object(
|
|
214
|
+
compute_trace_composition_fingerprint(artifact_hashes)
|
|
215
|
+
),
|
|
216
|
+
},
|
|
217
|
+
"trov:hasArtifact": composition_artifacts,
|
|
218
|
+
},
|
|
219
|
+
"trov:hasArrangement": [
|
|
220
|
+
{
|
|
221
|
+
"@id": "arrangement/0",
|
|
222
|
+
"@type": "trov:ArtifactArrangement",
|
|
223
|
+
"rdfs:comment": (
|
|
224
|
+
f"Certified arrangement for bundle "
|
|
225
|
+
f"{country_manifest.bundle_id or country_manifest.country_id}."
|
|
226
|
+
),
|
|
227
|
+
"trov:hasArtifactLocation": arrangement_locations,
|
|
228
|
+
}
|
|
229
|
+
],
|
|
230
|
+
"trov:hasPerformance": [
|
|
231
|
+
{
|
|
232
|
+
"@id": "trp/0",
|
|
233
|
+
"@type": "trov:TrustedResearchPerformance",
|
|
234
|
+
"rdfs:comment": (
|
|
235
|
+
f"Certification of build {build_id} for "
|
|
236
|
+
f"{country_manifest.model_package.name} "
|
|
237
|
+
f"{country_manifest.model_package.version}."
|
|
238
|
+
),
|
|
239
|
+
"trov:wasConductedBy": {"@id": "trs"},
|
|
240
|
+
"trov:startedAtTime": (
|
|
241
|
+
data_release_manifest.build.built_at
|
|
242
|
+
if data_release_manifest.build is not None
|
|
243
|
+
else created_at
|
|
244
|
+
),
|
|
245
|
+
"trov:endedAtTime": created_at,
|
|
246
|
+
"trov:contributedToArrangement": {
|
|
247
|
+
"@id": "trp/0/binding/0",
|
|
248
|
+
"@type": "trov:ArrangementBinding",
|
|
249
|
+
"trov:arrangement": {"@id": "arrangement/0"},
|
|
250
|
+
},
|
|
251
|
+
}
|
|
252
|
+
],
|
|
253
|
+
}
|
|
254
|
+
],
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
def serialize_trace_tro(tro: Mapping) -> bytes:
|
|
259
|
+
return (json.dumps(tro, indent=2, sort_keys=True) + "\n").encode("utf-8")
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: policyengine
|
|
3
|
-
Version: 3.4.
|
|
3
|
+
Version: 3.4.4
|
|
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
|
|
@@ -788,7 +788,8 @@ uv pip install -e .[dev] # install with dev dependencies (pytest, ruff, m
|
|
|
788
788
|
```bash
|
|
789
789
|
make format # ruff format
|
|
790
790
|
make test # pytest with coverage
|
|
791
|
-
make docs # build Jupyter Book
|
|
791
|
+
make docs # build static MyST/Jupyter Book 2 HTML docs
|
|
792
|
+
make docs-serve # preview the docs locally
|
|
792
793
|
make clean # remove caches, build artifacts, .h5 files
|
|
793
794
|
```
|
|
794
795
|
|
|
@@ -65,6 +65,7 @@ src/policyengine/core/scoping_strategy.py
|
|
|
65
65
|
src/policyengine/core/simulation.py
|
|
66
66
|
src/policyengine/core/tax_benefit_model.py
|
|
67
67
|
src/policyengine/core/tax_benefit_model_version.py
|
|
68
|
+
src/policyengine/core/trace_tro.py
|
|
68
69
|
src/policyengine/core/variable.py
|
|
69
70
|
src/policyengine/countries/__init__.py
|
|
70
71
|
src/policyengine/countries/uk/__init__.py
|