policyengine 3.4.0__tar.gz → 3.4.2__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.0 → policyengine-3.4.2}/CHANGELOG.md +14 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/PKG-INFO +16 -5
- {policyengine-3.4.0 → policyengine-3.4.2}/README.md +11 -0
- policyengine-3.4.2/examples/paper_repro_uk.py +76 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/pyproject.toml +5 -5
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/__init__.py +7 -0
- policyengine-3.4.2/src/policyengine/core/release_manifest.py +178 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/simulation.py +14 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/tax_benefit_model_version.py +30 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/countries/uk/regions.py +2 -1
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/countries/us/regions.py +12 -3
- policyengine-3.4.2/src/policyengine/data/release_manifests/uk.json +27 -0
- policyengine-3.4.2/src/policyengine/data/release_manifests/us.json +30 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/outputs/decile_impact.py +30 -14
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/uk/__init__.py +1 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/uk/analysis.py +15 -16
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/uk/datasets.py +27 -17
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/uk/model.py +15 -1
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/uk/outputs.py +3 -8
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/us/__init__.py +1 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/us/analysis.py +2 -5
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/us/datasets.py +26 -16
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/us/model.py +13 -2
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/us/outputs.py +3 -8
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine.egg-info/PKG-INFO +16 -5
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine.egg-info/SOURCES.txt +5 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine.egg-info/requires.txt +4 -4
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_intra_decile_impact.py +131 -1
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_models.py +26 -0
- policyengine-3.4.2/tests/test_release_manifests.py +114 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_uk_regions.py +4 -2
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_us_regions.py +12 -4
- {policyengine-3.4.0 → policyengine-3.4.2}/uv.lock +279 -43
- {policyengine-3.4.0 → policyengine-3.4.2}/.claude/policyengine-guide.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.claude/quick-reference.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/CONTRIBUTING.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/bump_version.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/changelog_template.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/check-changelog.sh +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/fetch_version.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/get-changelog-diff.sh +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/has-functional-changes.sh +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/is-version-number-acceptable.sh +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/publish-git-tag.sh +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/workflows/pr_code_changes.yaml +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/workflows/pr_docs_changes.yaml +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.github/workflows/push.yaml +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.gitignore +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/.python-version +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/LICENSE +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/Makefile +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/changelog.d/.gitkeep +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/.gitignore +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/advanced-outputs.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/core-concepts.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/country-models-uk.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/country-models-us.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/dev.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/economic-impact-analysis.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/examples.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/index.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/myst.yml +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/regions-and-scoping.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/docs/visualisation.md +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/examples/employment_income_variation_uk.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/examples/employment_income_variation_us.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/examples/household_impact_example.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/examples/income_bands_uk.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/examples/income_distribution_us.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/examples/policy_change_uk.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/examples/speedtest_us_simulation.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/examples/us_budgetary_impact.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/setup.cfg +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/__init__.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/cache.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/dataset.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/dataset_version.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/dynamic.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/output.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/parameter.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/parameter_node.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/parameter_value.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/policy.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/region.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/scoping_strategy.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/tax_benefit_model.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/variable.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/countries/__init__.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/countries/uk/__init__.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/countries/us/__init__.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/countries/us/data/__init__.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/countries/us/data/districts.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/countries/us/data/places.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/countries/us/data/states.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/outputs/__init__.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/outputs/aggregate.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/outputs/change_aggregate.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/outputs/congressional_district_impact.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/outputs/constituency_impact.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/outputs/inequality.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/outputs/intra_decile_impact.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/outputs/local_authority_impact.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/outputs/poverty.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/uk.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/tax_benefit_models/us.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/utils/__init__.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/utils/dates.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/utils/entity_utils.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/utils/parameter_labels.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/utils/parametric_reforms.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/utils/plotting.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine.egg-info/dependency_links.txt +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine.egg-info/top_level.txt +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/__init__.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/conftest.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/fixtures/__init__.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/fixtures/filtering_fixtures.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/fixtures/parameter_labels_fixtures.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/fixtures/parametric_reforms_fixtures.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/fixtures/poverty_by_demographics_fixtures.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/fixtures/region_fixtures.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/fixtures/us_reform_fixtures.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/fixtures/variable_label_fixtures.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_aggregate.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_cache.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_change_aggregate.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_congressional_district_impact.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_constituency_impact.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_entity_mapping.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_entity_utils.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_filtering.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_household_impact.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_inequality.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_local_authority_impact.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_pandas3_compatibility.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_parameter_labels.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_parametric_reforms.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_poverty.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_poverty_by_demographics.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_poverty_run.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_region.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_scoping_strategy.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_us_reform_application.py +0 -0
- {policyengine-3.4.0 → policyengine-3.4.2}/tests/test_variable_labels.py +0 -0
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [3.4.2] - 2026-04-12
|
|
2
|
+
|
|
3
|
+
### Changed
|
|
4
|
+
|
|
5
|
+
- Align the bundled UK release manifest with the pinned `policyengine-uk` package version and updated data package revisions.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## [3.4.1] - 2026-04-09
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Fixed the UK paper reproduction workflow so the checked-in example runs on Python 3.14 and the associated analysis helpers handle that path cleanly.
|
|
13
|
+
|
|
14
|
+
|
|
1
15
|
## [3.4.0] - 2026-04-08
|
|
2
16
|
|
|
3
17
|
### Added
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: policyengine
|
|
3
|
-
Version: 3.4.
|
|
3
|
+
Version: 3.4.2
|
|
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
|
|
@@ -678,10 +678,10 @@ Requires-Dist: requests>=2.31.0
|
|
|
678
678
|
Requires-Dist: psutil>=5.9.0
|
|
679
679
|
Provides-Extra: uk
|
|
680
680
|
Requires-Dist: policyengine_core>=3.23.6; extra == "uk"
|
|
681
|
-
Requires-Dist: policyengine-uk
|
|
681
|
+
Requires-Dist: policyengine-uk==2.78.0; extra == "uk"
|
|
682
682
|
Provides-Extra: us
|
|
683
683
|
Requires-Dist: policyengine_core>=3.23.6; extra == "us"
|
|
684
|
-
Requires-Dist: policyengine-us
|
|
684
|
+
Requires-Dist: policyengine-us==1.602.0; extra == "us"
|
|
685
685
|
Provides-Extra: dev
|
|
686
686
|
Requires-Dist: pytest; extra == "dev"
|
|
687
687
|
Requires-Dist: furo; extra == "dev"
|
|
@@ -693,8 +693,8 @@ Requires-Dist: build; extra == "dev"
|
|
|
693
693
|
Requires-Dist: pytest-asyncio>=0.26.0; extra == "dev"
|
|
694
694
|
Requires-Dist: ruff>=0.9.0; extra == "dev"
|
|
695
695
|
Requires-Dist: policyengine_core>=3.23.6; extra == "dev"
|
|
696
|
-
Requires-Dist: policyengine-uk
|
|
697
|
-
Requires-Dist: policyengine-us
|
|
696
|
+
Requires-Dist: policyengine-uk==2.78.0; extra == "dev"
|
|
697
|
+
Requires-Dist: policyengine-us==1.602.0; extra == "dev"
|
|
698
698
|
Requires-Dist: towncrier>=24.8.0; extra == "dev"
|
|
699
699
|
Requires-Dist: mypy>=1.11.0; extra == "dev"
|
|
700
700
|
Requires-Dist: pytest-cov>=5.0.0; extra == "dev"
|
|
@@ -747,6 +747,7 @@ print(f"Total UC spending: £{agg.result / 1e9:.1f}bn")
|
|
|
747
747
|
- `examples/income_distribution_us.py`: Analyse benefit distribution by decile
|
|
748
748
|
- `examples/employment_income_variation_uk.py`: Model employment income phase-outs
|
|
749
749
|
- `examples/policy_change_uk.py`: Analyse policy reform impacts
|
|
750
|
+
- `examples/paper_repro_uk.py`: Reproduce the UK reform analysis used in the JOSS paper draft
|
|
750
751
|
|
|
751
752
|
## Installation
|
|
752
753
|
|
|
@@ -838,6 +839,16 @@ echo "Description of change" > changelog.d/my-change.added
|
|
|
838
839
|
|
|
839
840
|
On merge, the versioning workflow bumps the version, builds the changelog, and creates a GitHub Release.
|
|
840
841
|
|
|
842
|
+
## Paper reproduction
|
|
843
|
+
|
|
844
|
+
Use the pinned interpreter and the UK extra to run the checked-in paper repro:
|
|
845
|
+
|
|
846
|
+
```bash
|
|
847
|
+
uv run --python 3.14 --extra uk python examples/paper_repro_uk.py
|
|
848
|
+
```
|
|
849
|
+
|
|
850
|
+
On first run this will create `./data/enhanced_frs_2023_24_year_2026.h5`.
|
|
851
|
+
|
|
841
852
|
## Features
|
|
842
853
|
|
|
843
854
|
- **Multi-country support**: UK and US tax-benefit systems
|
|
@@ -45,6 +45,7 @@ print(f"Total UC spending: £{agg.result / 1e9:.1f}bn")
|
|
|
45
45
|
- `examples/income_distribution_us.py`: Analyse benefit distribution by decile
|
|
46
46
|
- `examples/employment_income_variation_uk.py`: Model employment income phase-outs
|
|
47
47
|
- `examples/policy_change_uk.py`: Analyse policy reform impacts
|
|
48
|
+
- `examples/paper_repro_uk.py`: Reproduce the UK reform analysis used in the JOSS paper draft
|
|
48
49
|
|
|
49
50
|
## Installation
|
|
50
51
|
|
|
@@ -136,6 +137,16 @@ echo "Description of change" > changelog.d/my-change.added
|
|
|
136
137
|
|
|
137
138
|
On merge, the versioning workflow bumps the version, builds the changelog, and creates a GitHub Release.
|
|
138
139
|
|
|
140
|
+
## Paper reproduction
|
|
141
|
+
|
|
142
|
+
Use the pinned interpreter and the UK extra to run the checked-in paper repro:
|
|
143
|
+
|
|
144
|
+
```bash
|
|
145
|
+
uv run --python 3.14 --extra uk python examples/paper_repro_uk.py
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
On first run this will create `./data/enhanced_frs_2023_24_year_2026.h5`.
|
|
149
|
+
|
|
139
150
|
## Features
|
|
140
151
|
|
|
141
152
|
- **Multi-country support**: UK and US tax-benefit systems
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"""Reproduce the UK policy-reform analysis used in the JOSS paper draft.
|
|
2
|
+
|
|
3
|
+
This script uses the same reform shown in `paper.md`, but adds the missing
|
|
4
|
+
dataset setup so it can run end-to-end from a fresh checkout.
|
|
5
|
+
|
|
6
|
+
Run:
|
|
7
|
+
uv run --python 3.14 --extra uk python examples/paper_repro_uk.py
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
from datetime import date
|
|
11
|
+
|
|
12
|
+
from policyengine.core import Parameter, ParameterValue, Policy, Simulation
|
|
13
|
+
from policyengine.tax_benefit_models.uk import (
|
|
14
|
+
economic_impact_analysis,
|
|
15
|
+
ensure_datasets,
|
|
16
|
+
uk_latest,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def load_dataset(year: int = 2026):
|
|
21
|
+
"""Load or create the enhanced UK dataset used for population analysis."""
|
|
22
|
+
datasets = ensure_datasets(
|
|
23
|
+
datasets=["hf://policyengine/policyengine-uk-data/enhanced_frs_2023_24.h5"],
|
|
24
|
+
years=[year],
|
|
25
|
+
)
|
|
26
|
+
return datasets[f"enhanced_frs_2023_24_{year}"]
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def create_reform(year: int = 2026) -> Policy:
|
|
30
|
+
"""Set the UK personal allowance to zero for one tax year."""
|
|
31
|
+
parameter = Parameter(
|
|
32
|
+
name="gov.hmrc.income_tax.allowances.personal_allowance.amount",
|
|
33
|
+
tax_benefit_model_version=uk_latest,
|
|
34
|
+
)
|
|
35
|
+
|
|
36
|
+
return Policy(
|
|
37
|
+
name="Zero personal allowance",
|
|
38
|
+
parameter_values=[
|
|
39
|
+
ParameterValue(
|
|
40
|
+
parameter=parameter,
|
|
41
|
+
start_date=date(year, 1, 1),
|
|
42
|
+
end_date=date(year, 12, 31),
|
|
43
|
+
value=0,
|
|
44
|
+
)
|
|
45
|
+
],
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def main():
|
|
50
|
+
dataset = load_dataset()
|
|
51
|
+
reform = create_reform()
|
|
52
|
+
|
|
53
|
+
baseline = Simulation(
|
|
54
|
+
dataset=dataset,
|
|
55
|
+
tax_benefit_model_version=uk_latest,
|
|
56
|
+
)
|
|
57
|
+
reformed = Simulation(
|
|
58
|
+
dataset=dataset,
|
|
59
|
+
tax_benefit_model_version=uk_latest,
|
|
60
|
+
policy=reform,
|
|
61
|
+
)
|
|
62
|
+
|
|
63
|
+
analysis = economic_impact_analysis(baseline, reformed)
|
|
64
|
+
|
|
65
|
+
first_decile = analysis.decile_impacts.outputs[0]
|
|
66
|
+
|
|
67
|
+
print(f"Dataset: {dataset.filepath}")
|
|
68
|
+
print(f"Households: {len(dataset.data.household):,}")
|
|
69
|
+
print(f"Baseline Gini: {analysis.baseline_inequality.gini:.4f}")
|
|
70
|
+
print(f"Reform Gini: {analysis.reform_inequality.gini:.4f}")
|
|
71
|
+
print(f"Decile 1 mean change: {first_decile.absolute_change:,.2f}")
|
|
72
|
+
print(f"Programmes analysed: {len(analysis.programme_statistics.outputs)}")
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
if __name__ == "__main__":
|
|
76
|
+
main()
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "policyengine"
|
|
7
|
-
version = "3.4.
|
|
7
|
+
version = "3.4.2"
|
|
8
8
|
description = "A package to conduct policy analysis using PolicyEngine tax-benefit models."
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = [
|
|
@@ -28,11 +28,11 @@ dependencies = [
|
|
|
28
28
|
[project.optional-dependencies]
|
|
29
29
|
uk = [
|
|
30
30
|
"policyengine_core>=3.23.6",
|
|
31
|
-
"policyengine-uk
|
|
31
|
+
"policyengine-uk==2.78.0",
|
|
32
32
|
]
|
|
33
33
|
us = [
|
|
34
34
|
"policyengine_core>=3.23.6",
|
|
35
|
-
"policyengine-us
|
|
35
|
+
"policyengine-us==1.602.0",
|
|
36
36
|
]
|
|
37
37
|
dev = [
|
|
38
38
|
"pytest",
|
|
@@ -45,8 +45,8 @@ dev = [
|
|
|
45
45
|
"pytest-asyncio>=0.26.0",
|
|
46
46
|
"ruff>=0.9.0",
|
|
47
47
|
"policyengine_core>=3.23.6",
|
|
48
|
-
"policyengine-uk
|
|
49
|
-
"policyengine-us
|
|
48
|
+
"policyengine-uk==2.78.0",
|
|
49
|
+
"policyengine-us==1.602.0",
|
|
50
50
|
"towncrier>=24.8.0",
|
|
51
51
|
"mypy>=1.11.0",
|
|
52
52
|
"pytest-cov>=5.0.0",
|
|
@@ -12,6 +12,13 @@ from .policy import Policy as Policy
|
|
|
12
12
|
from .region import Region as Region
|
|
13
13
|
from .region import RegionRegistry as RegionRegistry
|
|
14
14
|
from .region import RegionType as RegionType
|
|
15
|
+
from .release_manifest import CountryReleaseManifest as CountryReleaseManifest
|
|
16
|
+
from .release_manifest import DataPackageVersion as DataPackageVersion
|
|
17
|
+
from .release_manifest import DataReleaseArtifact as DataReleaseArtifact
|
|
18
|
+
from .release_manifest import DataReleaseManifest as DataReleaseManifest
|
|
19
|
+
from .release_manifest import PackageVersion as PackageVersion
|
|
20
|
+
from .release_manifest import get_data_release_manifest as get_data_release_manifest
|
|
21
|
+
from .release_manifest import get_release_manifest as get_release_manifest
|
|
15
22
|
from .scoping_strategy import RegionScopingStrategy as RegionScopingStrategy
|
|
16
23
|
from .scoping_strategy import RowFilterStrategy as RowFilterStrategy
|
|
17
24
|
from .scoping_strategy import ScopingStrategy as ScopingStrategy
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from functools import lru_cache
|
|
3
|
+
from importlib.resources import files
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import requests
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
8
|
+
|
|
9
|
+
HF_REQUEST_TIMEOUT_SECONDS = 30
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class PackageVersion(BaseModel):
|
|
13
|
+
name: str
|
|
14
|
+
version: str
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class DataPackageVersion(PackageVersion):
|
|
18
|
+
repo_id: str
|
|
19
|
+
repo_type: str = "model"
|
|
20
|
+
release_manifest_path: str = "release_manifest.json"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CompatibleModelPackage(BaseModel):
|
|
24
|
+
name: str
|
|
25
|
+
specifier: str
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
class ArtifactPathReference(BaseModel):
|
|
29
|
+
path: str
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
class ArtifactPathTemplate(BaseModel):
|
|
33
|
+
path_template: str
|
|
34
|
+
|
|
35
|
+
def resolve(self, **kwargs: str) -> str:
|
|
36
|
+
return self.path_template.format(**kwargs)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class DataReleaseArtifact(BaseModel):
|
|
40
|
+
kind: str
|
|
41
|
+
path: str
|
|
42
|
+
repo_id: str
|
|
43
|
+
revision: str
|
|
44
|
+
sha256: str | None = None
|
|
45
|
+
size_bytes: int | None = None
|
|
46
|
+
|
|
47
|
+
@property
|
|
48
|
+
def uri(self) -> str:
|
|
49
|
+
return build_hf_uri(
|
|
50
|
+
repo_id=self.repo_id,
|
|
51
|
+
path_in_repo=self.path,
|
|
52
|
+
revision=self.revision,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class DataReleaseManifest(BaseModel):
|
|
57
|
+
schema_version: int
|
|
58
|
+
data_package: PackageVersion
|
|
59
|
+
compatible_model_packages: list[CompatibleModelPackage] = Field(
|
|
60
|
+
default_factory=list
|
|
61
|
+
)
|
|
62
|
+
default_datasets: dict[str, str] = Field(default_factory=dict)
|
|
63
|
+
artifacts: dict[str, DataReleaseArtifact] = Field(default_factory=dict)
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class CountryReleaseManifest(BaseModel):
|
|
67
|
+
country_id: str
|
|
68
|
+
policyengine_version: str
|
|
69
|
+
model_package: PackageVersion
|
|
70
|
+
data_package: DataPackageVersion
|
|
71
|
+
default_dataset: str
|
|
72
|
+
datasets: dict[str, ArtifactPathReference] = Field(default_factory=dict)
|
|
73
|
+
region_datasets: dict[str, ArtifactPathTemplate] = Field(default_factory=dict)
|
|
74
|
+
|
|
75
|
+
@property
|
|
76
|
+
def default_dataset_uri(self) -> str:
|
|
77
|
+
return resolve_dataset_reference(self.country_id, self.default_dataset)
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def build_hf_uri(repo_id: str, path_in_repo: str, revision: str) -> str:
|
|
81
|
+
return f"hf://{repo_id}/{path_in_repo}@{revision}"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
@lru_cache
|
|
85
|
+
def get_release_manifest(country_id: str) -> CountryReleaseManifest:
|
|
86
|
+
manifest_path = files("policyengine").joinpath(
|
|
87
|
+
"data", "release_manifests", f"{country_id}.json"
|
|
88
|
+
)
|
|
89
|
+
if not manifest_path.is_file():
|
|
90
|
+
raise ValueError(f"No bundled release manifest for country '{country_id}'")
|
|
91
|
+
|
|
92
|
+
return CountryReleaseManifest.model_validate_json(manifest_path.read_text())
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
def _data_release_manifest_url(data_package: DataPackageVersion) -> str:
|
|
96
|
+
return (
|
|
97
|
+
"https://huggingface.co/"
|
|
98
|
+
f"{data_package.repo_id}/resolve/{data_package.version}/"
|
|
99
|
+
f"{data_package.release_manifest_path}"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
@lru_cache
|
|
104
|
+
def get_data_release_manifest(country_id: str) -> DataReleaseManifest:
|
|
105
|
+
country_manifest = get_release_manifest(country_id)
|
|
106
|
+
data_package = country_manifest.data_package
|
|
107
|
+
|
|
108
|
+
headers = {}
|
|
109
|
+
token = os.environ.get("HUGGING_FACE_TOKEN")
|
|
110
|
+
if token:
|
|
111
|
+
headers["Authorization"] = f"Bearer {token}"
|
|
112
|
+
|
|
113
|
+
response = requests.get(
|
|
114
|
+
_data_release_manifest_url(data_package),
|
|
115
|
+
headers=headers,
|
|
116
|
+
timeout=HF_REQUEST_TIMEOUT_SECONDS,
|
|
117
|
+
)
|
|
118
|
+
if response.status_code in (401, 403):
|
|
119
|
+
raise ValueError(
|
|
120
|
+
"Could not fetch the data release manifest from Hugging Face. "
|
|
121
|
+
"If this country uses a private data repo, set HUGGING_FACE_TOKEN."
|
|
122
|
+
)
|
|
123
|
+
response.raise_for_status()
|
|
124
|
+
return DataReleaseManifest.model_validate_json(response.text)
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
def resolve_dataset_reference(country_id: str, dataset: str) -> str:
|
|
128
|
+
if "://" in dataset:
|
|
129
|
+
return dataset
|
|
130
|
+
|
|
131
|
+
manifest = get_release_manifest(country_id)
|
|
132
|
+
path_reference = manifest.datasets.get(dataset)
|
|
133
|
+
if path_reference is not None:
|
|
134
|
+
return build_hf_uri(
|
|
135
|
+
repo_id=manifest.data_package.repo_id,
|
|
136
|
+
path_in_repo=path_reference.path,
|
|
137
|
+
revision=manifest.data_package.version,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
data_release_manifest = get_data_release_manifest(country_id)
|
|
141
|
+
artifact = data_release_manifest.artifacts.get(dataset)
|
|
142
|
+
if artifact is None:
|
|
143
|
+
raise ValueError(
|
|
144
|
+
f"Unknown dataset '{dataset}' for country '{country_id}'. "
|
|
145
|
+
f"Known datasets: {sorted(manifest.datasets)}"
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
return artifact.uri
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
def dataset_logical_name(dataset: str) -> str:
|
|
152
|
+
return Path(dataset.rsplit("@", 1)[0]).stem
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
def resolve_default_datasets(country_id: str) -> list[str]:
|
|
156
|
+
manifest = get_release_manifest(country_id)
|
|
157
|
+
return list(manifest.datasets.keys())
|
|
158
|
+
|
|
159
|
+
|
|
160
|
+
def resolve_region_dataset_path(
|
|
161
|
+
country_id: str,
|
|
162
|
+
region_type: str,
|
|
163
|
+
**kwargs: str,
|
|
164
|
+
) -> str | None:
|
|
165
|
+
manifest = get_release_manifest(country_id)
|
|
166
|
+
template = manifest.region_datasets.get(region_type)
|
|
167
|
+
if template is None:
|
|
168
|
+
return None
|
|
169
|
+
|
|
170
|
+
resolved_path = template.resolve(**kwargs)
|
|
171
|
+
if "://" in resolved_path:
|
|
172
|
+
return resolved_path
|
|
173
|
+
|
|
174
|
+
return build_hf_uri(
|
|
175
|
+
repo_id=manifest.data_package.repo_id,
|
|
176
|
+
path_in_repo=resolved_path,
|
|
177
|
+
revision=manifest.data_package.version,
|
|
178
|
+
)
|
|
@@ -94,3 +94,17 @@ class Simulation(BaseModel):
|
|
|
94
94
|
def load(self):
|
|
95
95
|
"""Load the simulation's output dataset."""
|
|
96
96
|
self.tax_benefit_model_version.load(self)
|
|
97
|
+
|
|
98
|
+
@property
|
|
99
|
+
def release_bundle(self) -> dict[str, str | None]:
|
|
100
|
+
bundle = (
|
|
101
|
+
self.tax_benefit_model_version.release_bundle
|
|
102
|
+
if self.tax_benefit_model_version is not None
|
|
103
|
+
else {}
|
|
104
|
+
)
|
|
105
|
+
return {
|
|
106
|
+
**bundle,
|
|
107
|
+
"dataset_filepath": self.dataset.filepath
|
|
108
|
+
if self.dataset is not None
|
|
109
|
+
else None,
|
|
110
|
+
}
|
{policyengine-3.4.0 → policyengine-3.4.2}/src/policyengine/core/tax_benefit_model_version.py
RENAMED
|
@@ -4,6 +4,7 @@ from uuid import uuid4
|
|
|
4
4
|
|
|
5
5
|
from pydantic import BaseModel, Field
|
|
6
6
|
|
|
7
|
+
from .release_manifest import CountryReleaseManifest, PackageVersion
|
|
7
8
|
from .tax_benefit_model import TaxBenefitModel
|
|
8
9
|
|
|
9
10
|
if TYPE_CHECKING:
|
|
@@ -32,6 +33,13 @@ class TaxBenefitModelVersion(BaseModel):
|
|
|
32
33
|
region_registry: "RegionRegistry | None" = Field(
|
|
33
34
|
default=None, description="Registry of supported geographic regions"
|
|
34
35
|
)
|
|
36
|
+
release_manifest: CountryReleaseManifest | None = Field(
|
|
37
|
+
default=None,
|
|
38
|
+
exclude=True,
|
|
39
|
+
)
|
|
40
|
+
model_package: PackageVersion | None = Field(default=None)
|
|
41
|
+
data_package: PackageVersion | None = Field(default=None)
|
|
42
|
+
default_dataset_uri: str | None = Field(default=None)
|
|
35
43
|
|
|
36
44
|
@property
|
|
37
45
|
def parameter_values(self) -> list["ParameterValue"]:
|
|
@@ -116,6 +124,28 @@ class TaxBenefitModelVersion(BaseModel):
|
|
|
116
124
|
return None
|
|
117
125
|
return self.region_registry.get(code)
|
|
118
126
|
|
|
127
|
+
@property
|
|
128
|
+
def release_bundle(self) -> dict[str, str | None]:
|
|
129
|
+
return {
|
|
130
|
+
"country_id": self.release_manifest.country_id
|
|
131
|
+
if self.release_manifest is not None
|
|
132
|
+
else None,
|
|
133
|
+
"policyengine_version": self.release_manifest.policyengine_version
|
|
134
|
+
if self.release_manifest is not None
|
|
135
|
+
else None,
|
|
136
|
+
"model_package": self.model_package.name
|
|
137
|
+
if self.model_package is not None
|
|
138
|
+
else None,
|
|
139
|
+
"model_version": self.version,
|
|
140
|
+
"data_package": self.data_package.name
|
|
141
|
+
if self.data_package is not None
|
|
142
|
+
else None,
|
|
143
|
+
"data_version": self.data_package.version
|
|
144
|
+
if self.data_package is not None
|
|
145
|
+
else None,
|
|
146
|
+
"default_dataset_uri": self.default_dataset_uri,
|
|
147
|
+
}
|
|
148
|
+
|
|
119
149
|
def __repr__(self) -> str:
|
|
120
150
|
# Give the id and version, and the number of variables, parameters, parameter nodes, parameter values
|
|
121
151
|
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)}>"
|
|
@@ -15,6 +15,7 @@ import logging
|
|
|
15
15
|
from typing import TYPE_CHECKING
|
|
16
16
|
|
|
17
17
|
from policyengine.core.region import Region, RegionRegistry
|
|
18
|
+
from policyengine.core.release_manifest import resolve_region_dataset_path
|
|
18
19
|
from policyengine.core.scoping_strategy import (
|
|
19
20
|
RowFilterStrategy,
|
|
20
21
|
WeightReplacementStrategy,
|
|
@@ -127,7 +128,7 @@ def build_uk_region_registry(
|
|
|
127
128
|
code="uk",
|
|
128
129
|
label="United Kingdom",
|
|
129
130
|
region_type="national",
|
|
130
|
-
dataset_path=
|
|
131
|
+
dataset_path=resolve_region_dataset_path("uk", "national"),
|
|
131
132
|
)
|
|
132
133
|
)
|
|
133
134
|
|
|
@@ -8,6 +8,7 @@ in the data/ subdirectory:
|
|
|
8
8
|
"""
|
|
9
9
|
|
|
10
10
|
from policyengine.core.region import Region, RegionRegistry
|
|
11
|
+
from policyengine.core.release_manifest import resolve_region_dataset_path
|
|
11
12
|
from policyengine.core.scoping_strategy import RowFilterStrategy
|
|
12
13
|
|
|
13
14
|
from .data import AT_LARGE_STATES, DISTRICT_COUNTS, US_PLACES, US_STATES
|
|
@@ -40,7 +41,7 @@ def build_us_region_registry() -> RegionRegistry:
|
|
|
40
41
|
code="us",
|
|
41
42
|
label="United States",
|
|
42
43
|
region_type="national",
|
|
43
|
-
dataset_path=
|
|
44
|
+
dataset_path=resolve_region_dataset_path("us", "national"),
|
|
44
45
|
)
|
|
45
46
|
)
|
|
46
47
|
|
|
@@ -52,7 +53,11 @@ def build_us_region_registry() -> RegionRegistry:
|
|
|
52
53
|
label=name,
|
|
53
54
|
region_type="state",
|
|
54
55
|
parent_code="us",
|
|
55
|
-
dataset_path=
|
|
56
|
+
dataset_path=resolve_region_dataset_path(
|
|
57
|
+
"us",
|
|
58
|
+
"state",
|
|
59
|
+
state_code=abbrev,
|
|
60
|
+
),
|
|
56
61
|
state_code=abbrev,
|
|
57
62
|
state_name=name,
|
|
58
63
|
)
|
|
@@ -76,7 +81,11 @@ def build_us_region_registry() -> RegionRegistry:
|
|
|
76
81
|
label=label,
|
|
77
82
|
region_type="congressional_district",
|
|
78
83
|
parent_code=f"state/{state_abbrev.lower()}",
|
|
79
|
-
dataset_path=
|
|
84
|
+
dataset_path=resolve_region_dataset_path(
|
|
85
|
+
"us",
|
|
86
|
+
"congressional_district",
|
|
87
|
+
district_code=district_code,
|
|
88
|
+
),
|
|
80
89
|
state_code=state_abbrev,
|
|
81
90
|
state_name=state_name,
|
|
82
91
|
)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"country_id": "uk",
|
|
3
|
+
"policyengine_version": "3.4.1",
|
|
4
|
+
"model_package": {
|
|
5
|
+
"name": "policyengine-uk",
|
|
6
|
+
"version": "2.78.0"
|
|
7
|
+
},
|
|
8
|
+
"data_package": {
|
|
9
|
+
"name": "policyengine-uk-data",
|
|
10
|
+
"version": "1.40.3",
|
|
11
|
+
"repo_id": "policyengine/policyengine-uk-data-private"
|
|
12
|
+
},
|
|
13
|
+
"default_dataset": "enhanced_frs_2023_24",
|
|
14
|
+
"datasets": {
|
|
15
|
+
"frs_2023_24": {
|
|
16
|
+
"path": "frs_2023_24.h5"
|
|
17
|
+
},
|
|
18
|
+
"enhanced_frs_2023_24": {
|
|
19
|
+
"path": "enhanced_frs_2023_24.h5"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"region_datasets": {
|
|
23
|
+
"national": {
|
|
24
|
+
"path_template": "enhanced_frs_2023_24.h5"
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
{
|
|
2
|
+
"country_id": "us",
|
|
3
|
+
"policyengine_version": "3.4.1",
|
|
4
|
+
"model_package": {
|
|
5
|
+
"name": "policyengine-us",
|
|
6
|
+
"version": "1.602.0"
|
|
7
|
+
},
|
|
8
|
+
"data_package": {
|
|
9
|
+
"name": "policyengine-us-data",
|
|
10
|
+
"version": "1.77.0",
|
|
11
|
+
"repo_id": "policyengine/policyengine-us-data"
|
|
12
|
+
},
|
|
13
|
+
"default_dataset": "enhanced_cps_2024",
|
|
14
|
+
"datasets": {
|
|
15
|
+
"enhanced_cps_2024": {
|
|
16
|
+
"path": "enhanced_cps_2024.h5"
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
"region_datasets": {
|
|
20
|
+
"national": {
|
|
21
|
+
"path_template": "enhanced_cps_2024.h5"
|
|
22
|
+
},
|
|
23
|
+
"state": {
|
|
24
|
+
"path_template": "states/{state_code}.h5"
|
|
25
|
+
},
|
|
26
|
+
"congressional_district": {
|
|
27
|
+
"path_template": "districts/{district_code}.h5"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
}
|
|
@@ -97,32 +97,48 @@ class DecileImpact(Output):
|
|
|
97
97
|
|
|
98
98
|
|
|
99
99
|
def calculate_decile_impacts(
|
|
100
|
-
dataset: Dataset,
|
|
101
|
-
tax_benefit_model_version: TaxBenefitModelVersion,
|
|
100
|
+
dataset: Dataset | None = None,
|
|
101
|
+
tax_benefit_model_version: TaxBenefitModelVersion | None = None,
|
|
102
102
|
baseline_policy: Policy | None = None,
|
|
103
103
|
reform_policy: Policy | None = None,
|
|
104
104
|
dynamic: Dynamic | None = None,
|
|
105
105
|
income_variable: str = "equiv_hbai_household_net_income",
|
|
106
106
|
entity: str | None = None,
|
|
107
107
|
quantiles: int = 10,
|
|
108
|
+
baseline_simulation: Simulation | None = None,
|
|
109
|
+
reform_simulation: Simulation | None = None,
|
|
108
110
|
) -> OutputCollection[DecileImpact]:
|
|
109
111
|
"""Calculate decile-by-decile impact of a reform.
|
|
110
112
|
|
|
111
113
|
Returns:
|
|
112
114
|
OutputCollection containing list of DecileImpact objects and DataFrame
|
|
113
115
|
"""
|
|
114
|
-
baseline_simulation
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
116
|
+
if (baseline_simulation is None) != (reform_simulation is None):
|
|
117
|
+
raise ValueError(
|
|
118
|
+
"baseline_simulation and reform_simulation must be provided together"
|
|
119
|
+
)
|
|
120
|
+
|
|
121
|
+
if baseline_simulation is None:
|
|
122
|
+
if dataset is None or tax_benefit_model_version is None:
|
|
123
|
+
raise ValueError(
|
|
124
|
+
"dataset and tax_benefit_model_version are required when simulations are not provided"
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
baseline_simulation = Simulation(
|
|
128
|
+
dataset=dataset,
|
|
129
|
+
tax_benefit_model_version=tax_benefit_model_version,
|
|
130
|
+
policy=baseline_policy,
|
|
131
|
+
dynamic=dynamic,
|
|
132
|
+
)
|
|
133
|
+
reform_simulation = Simulation(
|
|
134
|
+
dataset=dataset,
|
|
135
|
+
tax_benefit_model_version=tax_benefit_model_version,
|
|
136
|
+
policy=reform_policy,
|
|
137
|
+
dynamic=dynamic,
|
|
138
|
+
)
|
|
139
|
+
|
|
140
|
+
baseline_simulation.ensure()
|
|
141
|
+
reform_simulation.ensure()
|
|
126
142
|
|
|
127
143
|
results = []
|
|
128
144
|
for decile in range(1, quantiles + 1):
|