policyengine 6.2.2__tar.gz → 6.2.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.
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/workflows/draft-pdf.yml +4 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/workflows/pr_code_changes.yaml +8 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/workflows/pr_docs_changes.yaml +1 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/workflows/push.yaml +3 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/AGENTS.md +13 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/CHANGELOG.md +11 -0
- {policyengine-6.2.2/src/policyengine.egg-info → policyengine-6.2.3}/PKG-INFO +1 -1
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/engineering/skills/repository-guidance.md +29 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/regions.md +32 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/pyproject.toml +1 -1
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/scoping_strategy.py +4 -2
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/countries/uk/regions.py +21 -5
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/data/bundle/manifest.json +10 -10
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/data/bundle/uk.trace.tro.jsonld +5 -5
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/data/bundle/us.trace.tro.jsonld +5 -5
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/utils/entity_utils.py +15 -6
- {policyengine-6.2.2 → policyengine-6.2.3/src/policyengine.egg-info}/PKG-INFO +1 -1
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_scoping_strategy.py +57 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_uk_regions.py +167 -8
- {policyengine-6.2.2 → policyengine-6.2.3}/uv.lock +1 -1
- {policyengine-6.2.2 → policyengine-6.2.3}/.claude/policyengine-guide.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.claude/quick-reference.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/CONTRIBUTING.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/bump_version.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/capture-version.sh +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/changelog_template.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/check-changelog.sh +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/copilot-instructions.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/dispatch-policyengine-release.sh +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/fetch_version.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/get-changelog-diff.sh +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/has-functional-changes.sh +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/is-version-number-acceptable.sh +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/publish-git-tag.sh +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.github/wait-for-pypi.sh +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.gitignore +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/.python-version +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/CITATION.cff +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/CLAUDE.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/CODE_OF_CONDUCT.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/CONTRIBUTING.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/LICENSE +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/Makefile +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/README.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/architecture.png +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/architecture.svg +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/changelog.d/.gitkeep +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/.gitignore +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/_generator/README.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/_generator/build_reference.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/_quarto.yml +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/bundles.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/countries.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/data-publishing-design.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/decile-impact-spec.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/dev.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/engineering/runbooks/build-m-us-populace-certification.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/engineering/runbooks/canonical-spm-development.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/engineering/skills/README.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/engineering/skills/data-certification.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/engineering/skills/github-prs.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/examples.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/getting-started.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/households.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/impact-analysis.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/index.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/methodology/index.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/methodology/model-architecture.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/methodology/us-health-costs.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/microsim.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/outputs.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/programs/index.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/programs/us-chip.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/reference/index.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/reforms.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/release-bundles.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/run-records.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/trace-case-study.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/docs/visualisation.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/examples/belgium_axiom_pilot.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/examples/employment_income_variation_uk.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/examples/employment_income_variation_us.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/examples/household_impact_example.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/examples/income_bands_uk.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/examples/income_distribution_us.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/examples/paper_repro_uk.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/examples/policy_change_uk.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/examples/speedtest_us_simulation.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/examples/us_budgetary_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/paper-preview.html +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/paper.bib +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/paper.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/scripts/bundle.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/scripts/certify_data_release.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/scripts/check_data_staleness.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/scripts/check_native_spm_loading.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/scripts/check_release_credentials.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/scripts/export_bundle_release_assets.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/scripts/generate_bundle_artifacts.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/scripts/generate_trace_tros.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/scripts/prepare_package_bundle_update.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/scripts/release_lock.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/scripts/spm_bundle.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/setup.cfg +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/bundle.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/cli.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/cache.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/dataset.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/dynamic.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/output.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/parameter.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/parameter_node.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/parameter_value.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/policy.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/region.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/run_record.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/simulation.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/spm.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/tax_benefit_model.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/tax_benefit_model_version.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/core/variable.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/countries/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/countries/uk/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/countries/us/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/countries/us/data/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/countries/us/data/districts.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/countries/us/data/places.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/countries/us/data/states.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/countries/us/regions.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/data/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/data/schemas/trace_tro.schema.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/data/uk_geography_assets.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/derivations/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/derivations/narrate.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/derivations/trace.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/graph/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/graph/extractor.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/graph/graph.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/aggregate.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/change_aggregate.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/cliff_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/congressional_district_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/constituency_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/decile_analysis.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/decile_grouping.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/decile_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/extra_variables.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/inequality.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/intra_decile_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/labor_supply_response.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/local_authority_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/poverty.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/program_statistics.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/uk_geography_assets.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/outputs/uk_geography_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/provenance/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/provenance/bundle_validation.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/provenance/certification.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/provenance/dataset_materialization.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/provenance/manifest.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/provenance/pyproject_pins.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/provenance/spm_configuration.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/provenance/trace.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/provenance/verify.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/provenance/zenodo.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/results/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/results/schema.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/results/trace_tro.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/results/tracking.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/be/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/be/datasets.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/be/model.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/common/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/common/axes.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/common/extra_variables.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/common/household.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/common/model_version.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/common/reform.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/common/result.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/uk/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/uk/analysis.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/uk/datasets.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/uk/household.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/uk/model.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/us/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/us/analysis.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/us/datasets.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/us/household.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/us/legacy_inputs.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/us/model.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/tax_benefit_models/us/spm.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/utils/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/utils/dates.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/utils/design.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/utils/errors.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/utils/hashing.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/utils/household_validation.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/utils/parameter_labels.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/utils/parametric_reforms.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine/utils/plotting.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine.egg-info/SOURCES.txt +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine.egg-info/dependency_links.txt +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine.egg-info/entry_points.txt +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine.egg-info/requires.txt +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/src/policyengine.egg-info/top_level.txt +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/conftest.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/filtering_fixtures.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/household_calculator_snapshots/uk_couple_two_kids.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/household_calculator_snapshots/uk_model_surface.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/household_calculator_snapshots/uk_single_adult_employment_income.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/household_calculator_snapshots/uk_single_adult_no_income.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/household_calculator_snapshots/uk_single_parent_one_child.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/household_calculator_snapshots/us_married_two_kids_high_income.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/household_calculator_snapshots/us_model_surface.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/household_calculator_snapshots/us_single_adult_employment_income.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/household_calculator_snapshots/us_single_adult_no_income.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/household_calculator_snapshots/us_single_parent_one_child.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/parameter_labels_fixtures.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/parametric_reforms_fixtures.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/poverty_by_demographics_fixtures.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/region_fixtures.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/release_tros/README.md +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/release_tros/country-models.lock.toml +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/release_tros/manifest.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/release_tros/us-release_manifest.json +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/release_tros/us.trace.tro.jsonld +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/spm_development.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/us_reform_fixtures.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/fixtures/variable_label_fixtures.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_aggregate.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_be_axiom_pilot.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_budgetary_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_bump_version.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_bundle.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_bundle_metadata.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_cache.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_certify_data_release.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_change_aggregate.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_cliff_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_cliff_impact_analysis.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_congressional_district_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_constituency_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_dataset_materialization.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_dataset_persistence.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_dataset_runtime.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_dataset_source.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_decile_grouping.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_derivations.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_dict_reforms_on_simulation.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_entity_mapping.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_entity_utils.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_entity_utils_characterization.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_errors.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_extra_variables.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_filtering.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_generate_trace_tros.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_graph/__init__.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_graph/conftest.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_graph/test_extractor.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_household_calculator_snapshot.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_household_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_inequality.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_intra_decile_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_labor_supply_response.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_local_authority_impact.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_manifest_version_mismatch.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_models.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_pandas3_compatibility.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_parameter_labels.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_parameter_nodes.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_parameter_values.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_parametric_reforms.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_poverty.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_poverty_by_demographics.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_poverty_run.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_preservation_mirror.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_program_statistics.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_pyproject_pins.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_region.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_region_group_strategy.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_release_credentials.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_release_lock.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_release_manifests.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_release_tro_generation.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_results.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_run_record.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_small_follow_ups.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_spm_bundle_bootstrap.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_spm_bundle_tooling.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_spm_decile.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_spm_development_authentication.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_spm_household.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_spm_model.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_spm_selection.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_spm_selection_schema.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_trace_tro.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_trace_tro_verify.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_uk_analysis.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_uk_geography_assets.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_uk_program_statistics.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_us_legacy_inputs.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_us_legacy_inputs_integration.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_us_long_term_datasets.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_us_microsim_structural_reforms.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_us_native_alignment.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_us_native_hdf_weights.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_us_program_statistics.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_us_reform_application.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_us_regions.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_variable_labels.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_variable_metadata.py +0 -0
- {policyengine-6.2.2 → policyengine-6.2.3}/tests/test_zenodo_mirror.py +0 -0
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
on:
|
|
2
|
+
# Feature branches get the pull_request run below; building the draft again
|
|
3
|
+
# on every branch push duplicated it.
|
|
2
4
|
push:
|
|
5
|
+
branches: [main]
|
|
3
6
|
paths:
|
|
4
7
|
- paper.md
|
|
5
8
|
- paper.bib
|
|
@@ -18,6 +21,7 @@ jobs:
|
|
|
18
21
|
paper:
|
|
19
22
|
runs-on: ubuntu-latest
|
|
20
23
|
name: Draft PDF
|
|
24
|
+
timeout-minutes: 15
|
|
21
25
|
steps:
|
|
22
26
|
- uses: actions/checkout@v4
|
|
23
27
|
- uses: openjournals/openjournals-draft-action@master
|
|
@@ -22,6 +22,7 @@ jobs:
|
|
|
22
22
|
check-changelog:
|
|
23
23
|
name: Check changelog fragment
|
|
24
24
|
runs-on: ubuntu-latest
|
|
25
|
+
timeout-minutes: 10
|
|
25
26
|
steps:
|
|
26
27
|
- uses: actions/checkout@v6
|
|
27
28
|
with:
|
|
@@ -32,6 +33,7 @@ jobs:
|
|
|
32
33
|
run: .github/check-changelog.sh
|
|
33
34
|
Lint:
|
|
34
35
|
runs-on: ubuntu-latest
|
|
36
|
+
timeout-minutes: 10
|
|
35
37
|
steps:
|
|
36
38
|
- uses: actions/checkout@v6
|
|
37
39
|
- name: Install ruff
|
|
@@ -44,6 +46,7 @@ jobs:
|
|
|
44
46
|
run: ruff check .
|
|
45
47
|
Mypy:
|
|
46
48
|
runs-on: ubuntu-latest
|
|
49
|
+
timeout-minutes: 20
|
|
47
50
|
steps:
|
|
48
51
|
- uses: actions/checkout@v6
|
|
49
52
|
- name: Install uv
|
|
@@ -61,6 +64,7 @@ jobs:
|
|
|
61
64
|
Python-Compat:
|
|
62
65
|
name: Install + smoke-import (py${{ matrix.python-version }})
|
|
63
66
|
runs-on: ubuntu-latest
|
|
67
|
+
timeout-minutes: 15
|
|
64
68
|
strategy:
|
|
65
69
|
fail-fast: false
|
|
66
70
|
matrix:
|
|
@@ -85,6 +89,7 @@ jobs:
|
|
|
85
89
|
# Private manifest credentials are available only to trusted repository PRs.
|
|
86
90
|
if: github.event_name != 'pull_request' || github.event.pull_request.head.repo.full_name == github.repository
|
|
87
91
|
runs-on: ubuntu-latest
|
|
92
|
+
timeout-minutes: 30
|
|
88
93
|
env:
|
|
89
94
|
POLICYENGINE_SKIP_COUNTRY_IMPORTS: "1"
|
|
90
95
|
steps:
|
|
@@ -136,6 +141,9 @@ jobs:
|
|
|
136
141
|
run: policyengine bundle verify --country us --country uk --packages-only --json
|
|
137
142
|
Test:
|
|
138
143
|
runs-on: ubuntu-latest
|
|
144
|
+
# Slowest observed 2026-10-06..08: 28 minutes. Fail a hung job instead of
|
|
145
|
+
# holding a shared org runner for the 6-hour default.
|
|
146
|
+
timeout-minutes: 60
|
|
139
147
|
strategy:
|
|
140
148
|
fail-fast: false
|
|
141
149
|
matrix:
|
|
@@ -28,6 +28,7 @@ jobs:
|
|
|
28
28
|
Lint:
|
|
29
29
|
if: github.event.head_commit.message != 'Update package version'
|
|
30
30
|
runs-on: ubuntu-latest
|
|
31
|
+
timeout-minutes: 10
|
|
31
32
|
steps:
|
|
32
33
|
- uses: actions/checkout@v6
|
|
33
34
|
- name: Install ruff
|
|
@@ -40,6 +41,8 @@ jobs:
|
|
|
40
41
|
Test:
|
|
41
42
|
if: github.event.head_commit.message != 'Update package version'
|
|
42
43
|
runs-on: ubuntu-latest
|
|
44
|
+
# Slowest observed 2026-10-06..08: 26 minutes.
|
|
45
|
+
timeout-minutes: 60
|
|
43
46
|
strategy:
|
|
44
47
|
fail-fast: false
|
|
45
48
|
matrix:
|
|
@@ -33,3 +33,16 @@ round-trip is a documented property of the public surface.
|
|
|
33
33
|
|
|
34
34
|
Do not cache arbitrary Python objects in public result structures. The
|
|
35
35
|
`core.Simulation` output must stay serialisable.
|
|
36
|
+
|
|
37
|
+
## UK country filtering
|
|
38
|
+
|
|
39
|
+
Select Scotland, Wales, and Northern Ireland through the stored household
|
|
40
|
+
`region` column: `SCOTLAND`, `WALES`, and `NORTHERN_IRELAND`, respectively.
|
|
41
|
+
Never require a `country` column when filtering raw UK household inputs;
|
|
42
|
+
`country` is derived by the UK model after loading the data. The public selector
|
|
43
|
+
`country/scotland` describes the requested area, not an input column name.
|
|
44
|
+
|
|
45
|
+
England must select the nine English `region` values, not `ENGLAND` and not
|
|
46
|
+
the complement of the other countries. Preserve these rules in new filters,
|
|
47
|
+
refactors, and tests. Read the UK country filtering section in
|
|
48
|
+
`docs/engineering/skills/repository-guidance.md` before changing this behavior.
|
|
@@ -1,3 +1,14 @@
|
|
|
1
|
+
## [6.2.3] - 2026-10-09
|
|
2
|
+
|
|
3
|
+
### Changed
|
|
4
|
+
|
|
5
|
+
- Give every lint, test, docs and paper CI job a timeout, so a hung job frees its shared GitHub Actions runner instead of holding it for six hours.
|
|
6
|
+
|
|
7
|
+
### Fixed
|
|
8
|
+
|
|
9
|
+
- Filter UK country simulations using stored household regions, selecting all nine English regions for England and preserving entity relationships and weights without requiring a derived country column.
|
|
10
|
+
|
|
11
|
+
|
|
1
12
|
## [6.2.2] - 2026-10-07
|
|
2
13
|
|
|
3
14
|
### Changed
|
|
@@ -52,6 +52,35 @@ representative-data runs unless the change specifically needs that coverage.
|
|
|
52
52
|
When a test needs country package data, make the dependency explicit and skip
|
|
53
53
|
cleanly if credentials or local artifacts are unavailable.
|
|
54
54
|
|
|
55
|
+
## UK country filtering
|
|
56
|
+
|
|
57
|
+
Raw UK household data stores `region`. The UK model derives `country` from
|
|
58
|
+
that input during calculation. Filtering precedes calculation, so agents and
|
|
59
|
+
developers must use `region` for country selection even though the registry's
|
|
60
|
+
public identifiers start with `country/`.
|
|
61
|
+
|
|
62
|
+
| Public selector | Required input filter |
|
|
63
|
+
| --- | --- |
|
|
64
|
+
| `country/scotland` | `region == "SCOTLAND"` |
|
|
65
|
+
| `country/wales` | `region == "WALES"` |
|
|
66
|
+
| `country/northern_ireland` | `region == "NORTHERN_IRELAND"` |
|
|
67
|
+
| `country/england` | `region` is one of the nine English values below |
|
|
68
|
+
|
|
69
|
+
The English values are `NORTH_EAST`, `NORTH_WEST`, `YORKSHIRE`, `EAST_MIDLANDS`,
|
|
70
|
+
`WEST_MIDLANDS`, `EAST_OF_ENGLAND`, `LONDON`, `SOUTH_EAST`, and `SOUTH_WEST`.
|
|
71
|
+
There is no stored `ENGLAND` region value. Use explicit membership so unknown
|
|
72
|
+
or missing regions do not become English households.
|
|
73
|
+
|
|
74
|
+
Keep all four country entries as `RowFilterStrategy` so the simulation API can
|
|
75
|
+
combine them with `RegionGroupStrategy`. Do not add a dataset `country` column
|
|
76
|
+
or run a preliminary model calculation to work around an incorrect filter.
|
|
77
|
+
Preserve household membership, related people/benefit units, and weights.
|
|
78
|
+
|
|
79
|
+
Regression tests must exercise Scotland, Wales, Northern Ireland, and England
|
|
80
|
+
against household inputs with `region` and **no `country` column**, including
|
|
81
|
+
the string and byte representations accepted by the dataset loader. See
|
|
82
|
+
`tests/test_uk_regions.py` and the public explanation in `docs/regions.md`.
|
|
83
|
+
|
|
55
84
|
## Anti-Patterns
|
|
56
85
|
|
|
57
86
|
- Do not bypass the wrapper layer without a clear reason.
|
|
@@ -54,6 +54,38 @@ for row in impacts.district_results:
|
|
|
54
54
|
at-large districts use `00`). Congressional district regions load the same
|
|
55
55
|
ACS-local file and scope its rows by `congressional_district_geoid`.
|
|
56
56
|
|
|
57
|
+
## UK countries
|
|
58
|
+
|
|
59
|
+
UK country simulations filter the national dataset's stored household `region`
|
|
60
|
+
column. The UK model derives `country` from `region`; the input dataset does not
|
|
61
|
+
need a separate `country` column.
|
|
62
|
+
|
|
63
|
+
| Country selector | Stored household input selection |
|
|
64
|
+
| --- | --- |
|
|
65
|
+
| `country/scotland` | `region == "SCOTLAND"` |
|
|
66
|
+
| `country/wales` | `region == "WALES"` |
|
|
67
|
+
| `country/northern_ireland` | `region == "NORTHERN_IRELAND"` |
|
|
68
|
+
|
|
69
|
+
The `country/` prefix identifies a public geographic selector; it does not name
|
|
70
|
+
a dataset column. Always filter these countries through `region` before running
|
|
71
|
+
the simulation.
|
|
72
|
+
|
|
73
|
+
Each country uses `RowFilterStrategy`. England matches a list of nine ITL1 regions:
|
|
74
|
+
`NORTH_EAST`, `NORTH_WEST`, `YORKSHIRE`, `EAST_MIDLANDS`, `WEST_MIDLANDS`,
|
|
75
|
+
`EAST_OF_ENGLAND`, `LONDON`, `SOUTH_EAST`, and `SOUTH_WEST`. Scotland, Wales and
|
|
76
|
+
Northern Ireland each match their corresponding stored value: `SCOTLAND`,
|
|
77
|
+
`WALES`, or `NORTHERN_IRELAND`. Unknown regions are excluded
|
|
78
|
+
from all four countries. These filters preserve the selected households'
|
|
79
|
+
people, benefit units and weights.
|
|
80
|
+
|
|
81
|
+
```python
|
|
82
|
+
scotland = pe.uk.model.get_region("country/scotland")
|
|
83
|
+
england = pe.uk.model.get_region("country/england")
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Pass the registry entry's `scoping_strategy` to `Simulation` when using a
|
|
87
|
+
national UK dataset.
|
|
88
|
+
|
|
57
89
|
## UK parliamentary constituencies
|
|
58
90
|
|
|
59
91
|
Constituency-level impacts group household output rows by the longwise
|
|
@@ -24,6 +24,7 @@ from microdf import MicroDataFrame
|
|
|
24
24
|
from pydantic import BaseModel, Discriminator, Field
|
|
25
25
|
|
|
26
26
|
from policyengine.utils.entity_utils import (
|
|
27
|
+
HouseholdFilterValue,
|
|
27
28
|
filter_dataset_by_household_ids,
|
|
28
29
|
filter_dataset_by_household_variable,
|
|
29
30
|
matching_household_ids,
|
|
@@ -69,12 +70,13 @@ class RowFilterStrategy(RegionScopingStrategy):
|
|
|
69
70
|
"""Scoping strategy that filters dataset rows by a household variable.
|
|
70
71
|
|
|
71
72
|
Used for regions where we want to keep only households matching a
|
|
72
|
-
specific variable value (e.g.,
|
|
73
|
+
specific variable value or any value in a list (e.g., the nine English
|
|
74
|
+
regions). Additional filters must also match.
|
|
73
75
|
"""
|
|
74
76
|
|
|
75
77
|
strategy_type: Literal["row_filter"] = "row_filter"
|
|
76
78
|
variable_name: str
|
|
77
|
-
variable_value:
|
|
79
|
+
variable_value: HouseholdFilterValue
|
|
78
80
|
additional_filters: dict[str, Union[str, int, float]] = Field(default_factory=dict)
|
|
79
81
|
|
|
80
82
|
def apply(
|
|
@@ -39,6 +39,21 @@ UK_COUNTRIES = {
|
|
|
39
39
|
"northern_ireland": "Northern Ireland",
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
# Stored names from policyengine_uk's Region enum. England spans nine ITL1
|
|
43
|
+
# regions; each other UK country is itself one ITL1 region.
|
|
44
|
+
# https://www.ons.gov.uk/methodology/geography/ukgeographies/eurostat
|
|
45
|
+
ENGLISH_REGIONS = (
|
|
46
|
+
"NORTH_EAST",
|
|
47
|
+
"NORTH_WEST",
|
|
48
|
+
"YORKSHIRE",
|
|
49
|
+
"EAST_MIDLANDS",
|
|
50
|
+
"WEST_MIDLANDS",
|
|
51
|
+
"EAST_OF_ENGLAND",
|
|
52
|
+
"LONDON",
|
|
53
|
+
"SOUTH_EAST",
|
|
54
|
+
"SOUTH_WEST",
|
|
55
|
+
)
|
|
56
|
+
|
|
42
57
|
|
|
43
58
|
def _load_constituencies_from_csv() -> list[dict]:
|
|
44
59
|
"""Load UK constituency data from CSV.
|
|
@@ -135,18 +150,19 @@ def build_uk_region_registry(
|
|
|
135
150
|
)
|
|
136
151
|
)
|
|
137
152
|
|
|
138
|
-
# 2.
|
|
153
|
+
# 2. Countries scope the stored region input; country is a derived variable.
|
|
139
154
|
for code, name in UK_COUNTRIES.items():
|
|
155
|
+
scoping_strategy = RowFilterStrategy(
|
|
156
|
+
variable_name="region",
|
|
157
|
+
variable_value=list(ENGLISH_REGIONS) if code == "england" else code.upper(),
|
|
158
|
+
)
|
|
140
159
|
regions.append(
|
|
141
160
|
Region(
|
|
142
161
|
code=f"country/{code}",
|
|
143
162
|
label=name,
|
|
144
163
|
region_type="country",
|
|
145
164
|
parent_code="uk",
|
|
146
|
-
scoping_strategy=
|
|
147
|
-
variable_name="country",
|
|
148
|
-
variable_value=code.upper(),
|
|
149
|
-
),
|
|
165
|
+
scoping_strategy=scoping_strategy,
|
|
150
166
|
)
|
|
151
167
|
)
|
|
152
168
|
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
|
-
"bundle_version": "6.2.
|
|
2
|
+
"bundle_version": "6.2.3",
|
|
3
3
|
"citation": {
|
|
4
4
|
"publisher": "PolicyEngine",
|
|
5
|
-
"title": "PolicyEngine bundle 6.2.
|
|
5
|
+
"title": "PolicyEngine bundle 6.2.3",
|
|
6
6
|
"type": "software-bundle",
|
|
7
|
-
"version": "6.2.
|
|
7
|
+
"version": "6.2.3"
|
|
8
8
|
},
|
|
9
9
|
"countries": {
|
|
10
10
|
"uk": {
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
"data_releases": {
|
|
18
18
|
"uk": {
|
|
19
19
|
"build_id": "policyengine-uk-data-1.56.16",
|
|
20
|
-
"bundle_id": "uk-6.2.
|
|
20
|
+
"bundle_id": "uk-6.2.3",
|
|
21
21
|
"certification": {
|
|
22
22
|
"built_with_model_git_sha": "12a1e028afeef08d8b2d74ee03fd9de3a78b2dd3",
|
|
23
23
|
"built_with_model_version": "2.89.2",
|
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"version": "2.102.3",
|
|
100
100
|
"wheel_url": "https://files.pythonhosted.org/packages/37/e6/e8d9069d498f1510a1380f24a78e957902d01f00b10248c146d6710d5b37/policyengine_uk-2.102.3-py3-none-any.whl"
|
|
101
101
|
},
|
|
102
|
-
"policyengine_version": "6.2.
|
|
102
|
+
"policyengine_version": "6.2.3",
|
|
103
103
|
"region_datasets": {
|
|
104
104
|
"national": {
|
|
105
105
|
"path_template": "enhanced_frs_2024_25.h5"
|
|
@@ -112,7 +112,7 @@
|
|
|
112
112
|
},
|
|
113
113
|
"us": {
|
|
114
114
|
"build_id": "populace-us-2024-spm-20260915",
|
|
115
|
-
"bundle_id": "us-6.2.
|
|
115
|
+
"bundle_id": "us-6.2.3",
|
|
116
116
|
"certification": {
|
|
117
117
|
"built_with_model_version": "2.2.1",
|
|
118
118
|
"certified_by": "policyengine.py bundle certification",
|
|
@@ -217,7 +217,7 @@
|
|
|
217
217
|
"version": "2.2.1",
|
|
218
218
|
"wheel_url": "https://files.pythonhosted.org/packages/5e/09/86ac3968d2a18e28fce3ba1186fc21728e9f299b96a806d6f204f1e0aaed/policyengine_us-2.2.1-py3-none-any.whl"
|
|
219
219
|
},
|
|
220
|
-
"policyengine_version": "6.2.
|
|
220
|
+
"policyengine_version": "6.2.3",
|
|
221
221
|
"region_datasets": {
|
|
222
222
|
"congressional_district": {
|
|
223
223
|
"path_template": "populace_us_2024_acs_local.h5"
|
|
@@ -295,10 +295,10 @@
|
|
|
295
295
|
"packages": {
|
|
296
296
|
"policyengine": {
|
|
297
297
|
"import_name": "policyengine",
|
|
298
|
-
"install_requirement": "policyengine==6.2.
|
|
298
|
+
"install_requirement": "policyengine==6.2.3",
|
|
299
299
|
"name": "policyengine",
|
|
300
300
|
"role": "bundle_carrier",
|
|
301
|
-
"version": "6.2.
|
|
301
|
+
"version": "6.2.3"
|
|
302
302
|
},
|
|
303
303
|
"policyengine-core": {
|
|
304
304
|
"import_name": "policyengine_core",
|
|
@@ -334,6 +334,6 @@
|
|
|
334
334
|
"wheel_url": "https://files.pythonhosted.org/packages/19/a0/c484f69a0ebf88a9b9fd0ac28176f8df66550f46714f1b0c5ec0b360824e/spm_calculator-1.0.0-py3-none-any.whl"
|
|
335
335
|
}
|
|
336
336
|
},
|
|
337
|
-
"policyengine_version": "6.2.
|
|
337
|
+
"policyengine_version": "6.2.3",
|
|
338
338
|
"schema_version": 2
|
|
339
339
|
}
|
|
@@ -18,18 +18,18 @@
|
|
|
18
18
|
"schema:url": "https://policyengine.org"
|
|
19
19
|
},
|
|
20
20
|
"schema:dateCreated": "2026-08-18T14:20:32.100961Z",
|
|
21
|
-
"schema:description": "TRACE TRO for certified runtime bundle uk-6.2.
|
|
21
|
+
"schema:description": "TRACE TRO for certified runtime bundle uk-6.2.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": "6.2.
|
|
26
|
+
"schema:softwareVersion": "6.2.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-6.2.
|
|
32
|
+
"rdfs:comment": "Certified arrangement for bundle uk-6.2.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": "
|
|
78
|
+
"trov:sha256": "4f4d1c5802ff917e555ce9f5520150fa4e7e1584853782afc38c03818101c9c6"
|
|
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": "
|
|
105
|
+
"trov:sha256": "23c38fee2f5fe5e6dd89137ba46b18b0add70f1a906cccbd28025f13c9061f64"
|
|
106
106
|
}
|
|
107
107
|
},
|
|
108
108
|
"trov:hasPerformance": {
|
|
@@ -17,18 +17,18 @@
|
|
|
17
17
|
"schema:name": "PolicyEngine",
|
|
18
18
|
"schema:url": "https://policyengine.org"
|
|
19
19
|
},
|
|
20
|
-
"schema:description": "TRACE TRO for certified runtime bundle us-6.2.
|
|
20
|
+
"schema:description": "TRACE TRO for certified runtime bundle us-6.2.3 covering the bundle manifest, the certified dataset artifact, the country model wheel, and the country data release manifest when it is available.",
|
|
21
21
|
"schema:name": "policyengine us certified bundle TRO",
|
|
22
22
|
"trov:createdWith": {
|
|
23
23
|
"@type": "schema:SoftwareApplication",
|
|
24
24
|
"schema:name": "policyengine",
|
|
25
|
-
"schema:softwareVersion": "6.2.
|
|
25
|
+
"schema:softwareVersion": "6.2.3"
|
|
26
26
|
},
|
|
27
27
|
"trov:hasArrangement": [
|
|
28
28
|
{
|
|
29
29
|
"@id": "arrangement/1",
|
|
30
30
|
"@type": "trov:ArtifactArrangement",
|
|
31
|
-
"rdfs:comment": "Certified arrangement for bundle us-6.2.
|
|
31
|
+
"rdfs:comment": "Certified arrangement for bundle us-6.2.3.",
|
|
32
32
|
"trov:hasArtifactLocation": [
|
|
33
33
|
{
|
|
34
34
|
"@id": "arrangement/1/location/bundle_manifest",
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
"@type": "trov:ResearchArtifact",
|
|
75
75
|
"schema:name": "policyengine.py bundle manifest for us",
|
|
76
76
|
"trov:mimeType": "application/json",
|
|
77
|
-
"trov:sha256": "
|
|
77
|
+
"trov:sha256": "4f4d1c5802ff917e555ce9f5520150fa4e7e1584853782afc38c03818101c9c6"
|
|
78
78
|
},
|
|
79
79
|
{
|
|
80
80
|
"@id": "composition/1/artifact/data_release_manifest",
|
|
@@ -101,7 +101,7 @@
|
|
|
101
101
|
"trov:hasFingerprint": {
|
|
102
102
|
"@id": "composition/1/fingerprint",
|
|
103
103
|
"@type": "trov:CompositionFingerprint",
|
|
104
|
-
"trov:sha256": "
|
|
104
|
+
"trov:sha256": "f601acd275cdd7a90632c491593474090dac2c4478f372fe65472e23352e1194"
|
|
105
105
|
}
|
|
106
106
|
},
|
|
107
107
|
"trov:hasPerformance": {
|
|
@@ -8,6 +8,8 @@ from microdf import MicroDataFrame
|
|
|
8
8
|
|
|
9
9
|
logger = logging.getLogger(__name__)
|
|
10
10
|
|
|
11
|
+
HouseholdFilterValue = Union[str, int, float, list[Union[str, int, float]]]
|
|
12
|
+
|
|
11
13
|
|
|
12
14
|
def _resolve_id_column(person_data: pd.DataFrame, entity_name: str) -> str:
|
|
13
15
|
"""Resolve the ID column name for a group entity in person data.
|
|
@@ -55,10 +57,10 @@ def build_entity_relationships(
|
|
|
55
57
|
def _household_mask(
|
|
56
58
|
household_data: pd.DataFrame,
|
|
57
59
|
variable_name: str,
|
|
58
|
-
variable_value:
|
|
60
|
+
variable_value: HouseholdFilterValue,
|
|
59
61
|
additional_filters: Optional[dict[str, Union[str, int, float]]] = None,
|
|
60
62
|
):
|
|
61
|
-
"""Boolean mask
|
|
63
|
+
"""Boolean mask matching one value or any value in a list.
|
|
62
64
|
|
|
63
65
|
Local intermediate only — never crosses a function boundary — so no
|
|
64
66
|
positional-alignment invariant leaks out (callers key on household_id).
|
|
@@ -85,7 +87,7 @@ def _household_mask(
|
|
|
85
87
|
def matching_household_ids(
|
|
86
88
|
entity_data: dict[str, MicroDataFrame],
|
|
87
89
|
variable_name: str,
|
|
88
|
-
variable_value:
|
|
90
|
+
variable_value: HouseholdFilterValue,
|
|
89
91
|
additional_filters: Optional[dict[str, Union[str, int, float]]] = None,
|
|
90
92
|
) -> set:
|
|
91
93
|
"""Return the set of ``household_id`` values matching a household filter.
|
|
@@ -163,7 +165,7 @@ def filter_dataset_by_household_variable(
|
|
|
163
165
|
entity_data: dict[str, MicroDataFrame],
|
|
164
166
|
group_entities: list[str],
|
|
165
167
|
variable_name: str,
|
|
166
|
-
variable_value:
|
|
168
|
+
variable_value: HouseholdFilterValue,
|
|
167
169
|
additional_filters: Optional[dict[str, Union[str, int, float]]] = None,
|
|
168
170
|
) -> dict[str, MicroDataFrame]:
|
|
169
171
|
"""Filter dataset entities to only include households matching variables.
|
|
@@ -177,7 +179,8 @@ def filter_dataset_by_household_variable(
|
|
|
177
179
|
(from YearData.entity_data).
|
|
178
180
|
group_entities: List of group entity names for this country.
|
|
179
181
|
variable_name: The household-level variable to filter on.
|
|
180
|
-
variable_value:
|
|
182
|
+
variable_value: One value or a list of allowed values. String values
|
|
183
|
+
match both str and bytes encoding.
|
|
181
184
|
additional_filters: Optional household-level filters that must also
|
|
182
185
|
match, keyed by variable name.
|
|
183
186
|
|
|
@@ -201,7 +204,13 @@ def filter_dataset_by_household_variable(
|
|
|
201
204
|
)
|
|
202
205
|
|
|
203
206
|
|
|
204
|
-
def _values_match(values, expected:
|
|
207
|
+
def _values_match(values, expected: HouseholdFilterValue):
|
|
208
|
+
if isinstance(expected, list):
|
|
209
|
+
allowed = [
|
|
210
|
+
*expected,
|
|
211
|
+
*(value.encode() for value in expected if isinstance(value, str)),
|
|
212
|
+
]
|
|
213
|
+
return pd.Series(values).isin(allowed).to_numpy(copy=True)
|
|
205
214
|
if isinstance(expected, str):
|
|
206
215
|
return (values == expected) | (values == expected.encode())
|
|
207
216
|
return values == expected
|
|
@@ -15,6 +15,63 @@ from policyengine.core.scoping_strategy import (
|
|
|
15
15
|
from policyengine.core.simulation import Simulation
|
|
16
16
|
|
|
17
17
|
|
|
18
|
+
@pytest.mark.parametrize(
|
|
19
|
+
"values,selected,expected",
|
|
20
|
+
[
|
|
21
|
+
(["LONDON", b"NORTH_WEST", "SCOTLAND"], ["LONDON", "NORTH_WEST"], [0, 1]),
|
|
22
|
+
([6, 34, 36], [6, 36], [0, 2]),
|
|
23
|
+
([6, "6", b"6"], [6], [0]),
|
|
24
|
+
([6, "6", b"6"], ["6"], [1, 2]),
|
|
25
|
+
(["LONDON", "SCOTLAND", "WALES"], [], []),
|
|
26
|
+
],
|
|
27
|
+
)
|
|
28
|
+
def test_row_filter_matches_any_list_value(values, selected, expected):
|
|
29
|
+
household = MicroDataFrame(
|
|
30
|
+
pd.DataFrame(
|
|
31
|
+
{
|
|
32
|
+
"household_id": [0, 1, 2],
|
|
33
|
+
"household_weight": [10.0, 20.0, 30.0],
|
|
34
|
+
"geography": values,
|
|
35
|
+
}
|
|
36
|
+
),
|
|
37
|
+
weights="household_weight",
|
|
38
|
+
)
|
|
39
|
+
person = MicroDataFrame(
|
|
40
|
+
pd.DataFrame({"person_id": [0, 1, 2], "person_household_id": [0, 1, 2]})
|
|
41
|
+
)
|
|
42
|
+
strategy = RowFilterStrategy(variable_name="geography", variable_value=selected)
|
|
43
|
+
data = {"household": household, "person": person}
|
|
44
|
+
|
|
45
|
+
if not expected:
|
|
46
|
+
with pytest.raises(ValueError, match="No households found"):
|
|
47
|
+
strategy.apply(data, ["household"], 2026)
|
|
48
|
+
else:
|
|
49
|
+
result = strategy.apply(data, ["household"], 2026)
|
|
50
|
+
assert result["household"]["household_id"].tolist() == expected
|
|
51
|
+
assert result["person"]["person_id"].tolist() == expected
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def test_row_filter_list_values_respect_additional_filters(us_entity_data):
|
|
55
|
+
strategy = RowFilterStrategy(
|
|
56
|
+
variable_name="state_fips",
|
|
57
|
+
variable_value=[6, 34],
|
|
58
|
+
additional_filters={"congressional_district_geoid": 601},
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
result = strategy.apply(
|
|
62
|
+
us_entity_data,
|
|
63
|
+
["household", "tax_unit", "spm_unit", "family", "marital_unit"],
|
|
64
|
+
2026,
|
|
65
|
+
)
|
|
66
|
+
|
|
67
|
+
assert result["household"]["household_id"].tolist() == [1]
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def test_row_filter_scalar_cache_key_is_unchanged():
|
|
71
|
+
strategy = RowFilterStrategy(variable_name="region", variable_value="SCOTLAND")
|
|
72
|
+
assert strategy.cache_key == "row_filter:region=SCOTLAND"
|
|
73
|
+
|
|
74
|
+
|
|
18
75
|
class TestRowFilterStrategy:
|
|
19
76
|
"""Tests for RowFilterStrategy."""
|
|
20
77
|
|