policyengine-core 3.32.7__tar.gz → 3.32.9__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_core-3.32.7 → policyengine_core-3.32.9}/CHANGELOG.md +14 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/PKG-INFO +1 -1
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/simulation.py +51 -7
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/hugging_face.py +20 -4
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/variable.py +1 -1
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/pyproject.toml +1 -1
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tools/test_hugging_face.py +147 -0
- policyengine_core-3.32.9/tests/core/variables/test_variable_uprating.py +244 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/ISSUE_TEMPLATE.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/bump_version.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/changelog_template.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/get-changelog-diff.sh +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/has-functional-changes.sh +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/is-version-number-acceptable.sh +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/publish-git-tag.sh +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/requirements/legacy-country-smoke.txt +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/workflows/pr.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/workflows/push.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.gitignore +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.python-version +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/AGENTS.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/CLAUDE.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/CONTRIBUTING.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/LICENSE +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/MANIFEST.in +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/Makefile +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/README.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/_build/logs/myst.build.json +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/changelog.d/.gitkeep +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/_config.yml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/_static/style.css +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/_toc.yml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/add_plotly_to_book.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/contributing/intro.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/engineering/skills/README.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/engineering/skills/documentation_review.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/engineering/skills/github-prs.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/engineering/skills/testing.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/intro.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/logo.png +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/commons.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/country_template.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/data.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/data_storage.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/entities.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/enums.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/errors.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/experimental.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/extension_template.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/holders.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/parameters.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/periods.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/populations.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/projectors.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/reforms.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/scripts.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/simulations.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/taxbenefitsystems.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/taxscales.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/tools.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/tracers.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/types.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/variables.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/warnings.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/usage/country.ipynb +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/usage/datasets.ipynb +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/usage/parameters.md +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/usage/reforms.ipynb +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/usage/simulation.ipynb +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/mypy.ini +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/build_metadata.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/charts/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/charts/api.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/charts/bar.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/charts/formatting.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/commons/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/commons/formulas.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/commons/misc.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/commons/rates.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/constants.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/data/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/data/datasets/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/data/datasets/country_template_dataset.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/entities.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/modelled_policies.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/benefits/basic_income.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/benefits/housing_allowance.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/benefits/index.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/benefits/parenting_allowance/amount.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/benefits/parenting_allowance/income_threshold.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/general/age_of_majority.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/general/age_of_retirement.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/taxes/housing_tax.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/taxes/income_tax_rate.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/taxes/social_security_contribution.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/add_dynamic_variable.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/add_new_tax.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/flat_social_security_contribution.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/modify_social_security_taxation.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/removal_basic_income.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/situation_examples/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/situation_examples/couple.json +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/situation_examples/housing.json +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/situation_examples/single.json +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/age.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/basic_income.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/disposable_income.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/housing_allowance.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/housing_tax.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/income_tax.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/reforms/add_dynamic_variable.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/reforms/add_new_tax.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/reforms/modify_social_security_taxation.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/situations/income_tax.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/situations/parenting_allowance.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/social_security_contribution.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/test_microsimulation.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/benefits.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/demographics.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/housing.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/ids.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/income.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/stats.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/taxes.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data/dataset.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_storage/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_storage/in_memory_storage.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_storage/on_disk_storage.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_structures/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_structures/parameter_metadata.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_structures/parameter_node_metadata.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_structures/reference.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_structures/unit.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/entities/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/entities/entity.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/entities/group_entity.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/entities/helpers.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/entities/role.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/enums/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/enums/config.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/enums/enum.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/enums/enum_array.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/cycle_error.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/empty_argument_error.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/nan_creation_error.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/non_deterministic_formula_error.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/parameter_not_found_error.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/parameter_parsing_error.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/period_mismatch_error.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/situation_parsing_error.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/spiral_error.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/variable_name_conflict_error.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/variable_not_found_error.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/experimental/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/experimental/memory_config.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/local_benefit.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/parameters/local_town/child_allowance/amount.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/parameters/local_town/child_allowance/index.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/parameters/local_town/index.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/tests/local_benefit.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/holders/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/holders/helpers.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/holders/holder.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/model_api.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/at_instant_like.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/config.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/helpers.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/get_parameter.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/homogenize_parameters.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/interpolate_parameters.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/propagate_parameter_metadata.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/uprate_parameters.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter_at_instant.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter_node.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter_node_at_instant.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter_scale_bracket.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/vectorial_parameter_node_at_instant.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/periods/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/periods/config.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/periods/helpers.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/periods/instant_.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/periods/period_.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/populations/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/populations/config.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/populations/group_population.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/populations/population.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/entity_to_person_projector.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/first_person_to_entity_projector.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/helpers.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/projector.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/unique_role_to_entity_projector.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/reforms/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/reforms/reform.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/assets/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/assets/index.html +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/policyengine_command.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/run_data.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/run_test.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/simulation_generator.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/helpers.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/individual_sim.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/microsimulation.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/simulation_builder.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/simulation_macro_cache.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxbenefitsystems/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxbenefitsystems/tax_benefit_system.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/abstract_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/abstract_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/amount_tax_scale_like.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/helpers.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/linear_average_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/marginal_amount_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/marginal_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/rate_tax_scale_like.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/single_amount_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/tax_scale_like.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/google_cloud.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/simulation_dumper.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/test_from_situation.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/test_runner.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/win_file_manager.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/computation_log.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/flat_trace.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/full_tracer.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/performance_log.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/simple_tracer.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/trace_node.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/tracing_parameter_node_at_instant.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/variable_graph.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/types/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/types/data_types/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/types/data_types/arrays.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/config.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/defined_for.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/formula_randomness.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/helpers.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/typing.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/warnings/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/warnings/libyaml_warning.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/warnings/memory_config_warning.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/warnings/parameter_key_warning.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/warnings/tempfile_warning.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/pytest.ini +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/conftest.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/test_between_function.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/test_formulas.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/test_is_in_function.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/test_random_seed.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/test_rates.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/data/test_dataset.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/enums/test_enum.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/model_api/test_index_.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/array_type.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/duplicate_key.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/filesystem_hierarchy/empty_index_file/index.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/filesystem_hierarchy/node1/param.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/indentation.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/missing_value.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/parameter_for_unit_propagation.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/test_parameter_clone.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/test_parameter_validation.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/test_propagate_units.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/test_unknown_keys.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/unexpected_key_in_parameter.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/unexpected_key_in_scale.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/unexpected_key_in_value_at_instant.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/unexpected_key_in_value_history.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/unknown_key_beside_values.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/uprating_under_metadata.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_date.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_scale.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_type_in_bracket.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_type_in_brackets.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_type_in_parameter.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_type_in_scale.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_type_in_value_history.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_value.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/yaml_hierarchy/node1.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/operations/test_interpolation.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/operations/test_nesting.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/operations/test_propagation.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/operations/test_scale_threshold_uprating.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/operations/test_uprating.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/test_numpy2_structured_arrays.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters_fancy_indexing/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters_fancy_indexing/bareme.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters_fancy_indexing/local_tax.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters_fancy_indexing/rate.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters_fancy_indexing/test_fancy_indexing.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/simulations/test_formula_randomness_concurrency.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_abstract_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_abstract_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_linear_average_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_marginal_amount_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_marginal_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_rate_tax_scale_like.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_single_amount_tax_scale.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_tax_scales_commons.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_apply_reform_invalidates_cache.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_apply_reform_preserves_user_inputs.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_assert_near_precision.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_axes.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_bincount_minlength.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_branch_scoped_delete_arrays.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_build_metadata.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_calculate_output.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_countries.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_cycles.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_dataset_getattr.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_dataset_unknown_column_warning.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_dump_restore.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_entities.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_eternity_subperiods.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_extensions.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_fast_cache.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_fast_cache_guards.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_formulas.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_holder_branch_fallback.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_holders.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_macro_cache_not_singleton.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_medium_fixes.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_microsimulation_person_accessor.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_microsimulation_weights.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_opt_out_cache.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_pandas3_compatibility.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_parameter_security.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_parameters.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_periods.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_projectors.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_reform_parameter_isolation.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_reform_period_keys.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_reforms.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_release_tagging.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_simulation_builder.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_simulations.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_stable_hash_seed.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_storage_anchored_periods.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_storage_delete_branch.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_subsample_baseline_branch.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_subsample_invalidates_cache.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_tax_benefit_system_cache_identity.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_tracers.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_yaml.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tools/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tools/test_assert_near.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tools/test_google_cloud.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tools/test_runner/test_yaml_runner.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_adds.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_annualize.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_bounds.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_defined_for.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_formula_randomness.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_subtracts.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_subtracts_sign.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_variable_clone.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_variable_formula_determinism.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_variables.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/appclient.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/entities.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/simulations.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/taxbenefitsystems.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/variables.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/__init__.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/directory/subdirectory/test_4.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/directory/test_1.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/directory/test_2.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/failing_test_absolute_error_margin.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/failing_test_relative_error_margin.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_absolute_error_margin.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_failure.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_name_filter.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_relative_error_margin.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_success.yml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_with_anchors.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_with_extension.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_with_reform.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_with_reform_2.yaml +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/smoke/test_country_init.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/smoke/test_us.py +0 -0
- {policyengine_core-3.32.7 → policyengine_core-3.32.9}/uv.lock +0 -0
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
## [3.32.9] - 2026-09-29
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
|
|
5
|
+
- Send the HUGGING_FACE_TOKEN when downloading from public but gated Hugging Face repos, not only private ones, so gated dataset downloads no longer fail with a 401 gated-repo error.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## [3.32.8] - 2026-09-27
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Uprating an input variable no longer raises `TypeError` when its uprating parameter has no value at the start of the known or the requested period (the parameter is held flat where it has no value), and it now always uprates from the latest known earlier period rather than one picked by list position.
|
|
13
|
+
|
|
14
|
+
|
|
1
15
|
## [3.32.7] - 2026-09-25
|
|
2
16
|
|
|
3
17
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: policyengine-core
|
|
3
|
-
Version: 3.32.
|
|
3
|
+
Version: 3.32.9
|
|
4
4
|
Summary: Core microsimulation engine enabling country-specific policy models.
|
|
5
5
|
Project-URL: Homepage, https://github.com/policyengine/policyengine-core
|
|
6
6
|
Author-email: PolicyEngine <hello@policyengine.org>
|
{policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/simulation.py
RENAMED
|
@@ -44,6 +44,36 @@ def _stable_hash_to_seed(value: str) -> int:
|
|
|
44
44
|
return int.from_bytes(digest[:4], "big") % 1000000
|
|
45
45
|
|
|
46
46
|
|
|
47
|
+
def _uprating_index_value(parameter, instant) -> Optional[float]:
|
|
48
|
+
"""Value of a variable's uprating index at ``instant``, held flat where
|
|
49
|
+
the index has no value.
|
|
50
|
+
|
|
51
|
+
Before the index's first value this returns that first value, as if the
|
|
52
|
+
earliest value had been extended backward (country packages backdate
|
|
53
|
+
parameters this way; a parameter itself returns ``None`` there). After an
|
|
54
|
+
explicit null it returns the last value before the null. A value known
|
|
55
|
+
for a period the index does not reach is therefore carried over
|
|
56
|
+
unchanged until the index starts, then uprated with it. Returns ``None``
|
|
57
|
+
only if the index has no non-null value at all.
|
|
58
|
+
"""
|
|
59
|
+
value = parameter(instant)
|
|
60
|
+
if value is not None:
|
|
61
|
+
return value
|
|
62
|
+
defined = [
|
|
63
|
+
value_at_instant
|
|
64
|
+
for value_at_instant in getattr(parameter, "values_list", [])
|
|
65
|
+
if value_at_instant.value is not None
|
|
66
|
+
]
|
|
67
|
+
if not defined:
|
|
68
|
+
return None
|
|
69
|
+
# ``values_list`` runs from the latest instant to the earliest.
|
|
70
|
+
instant_str = str(instant)
|
|
71
|
+
for value_at_instant in defined:
|
|
72
|
+
if value_at_instant.instant_str <= instant_str:
|
|
73
|
+
return value_at_instant.value
|
|
74
|
+
return defined[-1].value
|
|
75
|
+
|
|
76
|
+
|
|
47
77
|
if TYPE_CHECKING:
|
|
48
78
|
from policyengine_core.taxbenefitsystems import TaxBenefitSystem
|
|
49
79
|
|
|
@@ -836,14 +866,20 @@ class Simulation:
|
|
|
836
866
|
if array is None:
|
|
837
867
|
# Check if the variable has a previously defined value
|
|
838
868
|
known_periods = holder.get_known_periods()
|
|
839
|
-
|
|
840
|
-
|
|
869
|
+
earlier_known_periods = [
|
|
870
|
+
known_period
|
|
841
871
|
for known_period in known_periods
|
|
842
872
|
if known_period.unit == variable.definition_period
|
|
843
873
|
and known_period.start < period.start
|
|
844
874
|
]
|
|
845
|
-
if variable.uprating is not None and len(
|
|
846
|
-
|
|
875
|
+
if variable.uprating is not None and len(earlier_known_periods) > 0:
|
|
876
|
+
# Take the latest period from the filtered list itself.
|
|
877
|
+
# Indexing ``known_periods`` with a position in the
|
|
878
|
+
# filtered list picked the wrong period whenever a later
|
|
879
|
+
# one was stored first.
|
|
880
|
+
latest_known_period = max(
|
|
881
|
+
earlier_known_periods, key=lambda p: p.start
|
|
882
|
+
)
|
|
847
883
|
try:
|
|
848
884
|
uprating_parameter = get_parameter(
|
|
849
885
|
self.tax_benefit_system.parameters,
|
|
@@ -853,9 +889,17 @@ class Simulation:
|
|
|
853
889
|
raise ValueError(
|
|
854
890
|
f"Could not find uprating parameter {variable.uprating} when trying to uprate {variable_name}."
|
|
855
891
|
)
|
|
856
|
-
value_in_last_period =
|
|
857
|
-
|
|
858
|
-
|
|
892
|
+
value_in_last_period = _uprating_index_value(
|
|
893
|
+
uprating_parameter, latest_known_period.start
|
|
894
|
+
)
|
|
895
|
+
value_in_this_period = _uprating_index_value(
|
|
896
|
+
uprating_parameter, period.start
|
|
897
|
+
)
|
|
898
|
+
if (
|
|
899
|
+
value_in_last_period is None
|
|
900
|
+
or value_in_this_period is None
|
|
901
|
+
or value_in_last_period == 0
|
|
902
|
+
):
|
|
859
903
|
uprating_factor = 1
|
|
860
904
|
else:
|
|
861
905
|
uprating_factor = value_in_this_period / value_in_last_period
|
{policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/hugging_face.py
RENAMED
|
@@ -53,6 +53,14 @@ def download_huggingface_dataset(
|
|
|
53
53
|
"""
|
|
54
54
|
Download a PolicyEngine dataset file from the Hugging Face Hub.
|
|
55
55
|
|
|
56
|
+
Private repos and public-but-gated repos both require authentication,
|
|
57
|
+
so for either the token is resolved by get_or_prompt_hf_token()
|
|
58
|
+
(HUGGING_FACE_TOKEN, else an interactive prompt when stdin is a TTY,
|
|
59
|
+
else None) and passed explicitly to hf_hub_download. Public, ungated
|
|
60
|
+
repos are requested with token=None and never prompt; huggingface_hub
|
|
61
|
+
may still apply its own implicitly configured token (HF_TOKEN or the
|
|
62
|
+
login file) in that case.
|
|
63
|
+
|
|
56
64
|
Args:
|
|
57
65
|
repo: Hugging Face model repository identifier in ``owner/name``
|
|
58
66
|
format.
|
|
@@ -68,15 +76,23 @@ def download_huggingface_dataset(
|
|
|
68
76
|
"""
|
|
69
77
|
# Attempt connection to Hugging Face model_info endpoint
|
|
70
78
|
# (https://huggingface.co/docs/huggingface_hub/v0.26.5/en/package_reference/hf_api#huggingface_hub.HfApi.model_info)
|
|
71
|
-
# Attempt to fetch model info to determine if repo
|
|
79
|
+
# Attempt to fetch model info to determine if the repo requires
|
|
80
|
+
# authentication. Testing `private` alone is not enough: a public but
|
|
81
|
+
# gated repo still answers model_info() without a token, but the file
|
|
82
|
+
# download returns 401 unless a gate-approved token is sent.
|
|
83
|
+
# ModelInfo.gated is False for ungated repos, "auto" or "manual" for
|
|
84
|
+
# gated repos, and None if the field is absent, so a truthiness test
|
|
85
|
+
# covers every state (both gate modes need an authenticated request).
|
|
72
86
|
# A RepositoryNotFoundError & 401 likely means the repo is private,
|
|
73
87
|
# but this error will also surface for public repos with malformed URL, etc.
|
|
74
88
|
try:
|
|
75
89
|
fetched_model_info: ModelInfo = model_info(repo)
|
|
76
|
-
|
|
90
|
+
requires_authentication: bool = bool(fetched_model_info.private) or bool(
|
|
91
|
+
fetched_model_info.gated
|
|
92
|
+
)
|
|
77
93
|
except RepositoryNotFoundError as e:
|
|
78
94
|
# If this error type arises, it's likely the repo is private; see docs above
|
|
79
|
-
|
|
95
|
+
requires_authentication = True
|
|
80
96
|
pass
|
|
81
97
|
except Exception as e:
|
|
82
98
|
# Otherwise, there probably is just a download error
|
|
@@ -86,7 +102,7 @@ def download_huggingface_dataset(
|
|
|
86
102
|
)
|
|
87
103
|
|
|
88
104
|
authentication_token: str | None = None
|
|
89
|
-
if
|
|
105
|
+
if requires_authentication:
|
|
90
106
|
authentication_token = get_or_prompt_hf_token()
|
|
91
107
|
|
|
92
108
|
return hf_hub_download(
|
{policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/variable.py
RENAMED
|
@@ -123,7 +123,7 @@ class Variable:
|
|
|
123
123
|
"""List of variables that are subtracted from the variable. Alternatively, can be a parameter name."""
|
|
124
124
|
|
|
125
125
|
uprating: str = None
|
|
126
|
-
"""Name of a parameter used to uprate the variable."""
|
|
126
|
+
"""Name of a parameter used to uprate the variable. When the variable has no value for a requested period, its value in the latest known earlier period (an input, or a value already calculated or defaulted and cached) is multiplied by the ratio of this parameter at the two period starts, or carried over unchanged if the parameter is zero at the earlier start. Where the parameter has no value it is held flat: before its first value it takes that first value, and after an explicit null it keeps the last value before the null. The variable therefore carries over unchanged across any span the parameter does not cover."""
|
|
127
127
|
|
|
128
128
|
hidden_input: bool = False
|
|
129
129
|
"""Whether the variable is hidden from the input screen entirely on PolicyEngine."""
|
|
@@ -141,6 +141,153 @@ class TestHuggingFaceDownload:
|
|
|
141
141
|
local_dir=test_dir,
|
|
142
142
|
)
|
|
143
143
|
|
|
144
|
+
@pytest.mark.parametrize("gated", ["manual", "auto"])
|
|
145
|
+
def test_download_gated_public_repo_passes_env_token(self, gated):
|
|
146
|
+
"""A public but gated repo must receive HUGGING_FACE_TOKEN.
|
|
147
|
+
|
|
148
|
+
Regression test for PolicyEngine/policyengine-core#529: `private`
|
|
149
|
+
is False for a gated repo, but the file download still needs a
|
|
150
|
+
gate-approved token or the Hub answers 401.
|
|
151
|
+
"""
|
|
152
|
+
test_repo = "test_repo"
|
|
153
|
+
test_filename = "test_filename"
|
|
154
|
+
test_version = "test_version"
|
|
155
|
+
test_dir = "test_dir"
|
|
156
|
+
test_token = "gated_repo_test_token"
|
|
157
|
+
|
|
158
|
+
with patch.dict(os.environ, {"HUGGING_FACE_TOKEN": test_token}, clear=True):
|
|
159
|
+
with patch(
|
|
160
|
+
"policyengine_core.tools.hugging_face.hf_hub_download"
|
|
161
|
+
) as mock_download:
|
|
162
|
+
with patch(
|
|
163
|
+
"policyengine_core.tools.hugging_face.model_info"
|
|
164
|
+
) as mock_model_info:
|
|
165
|
+
mock_model_info.return_value = ModelInfo(
|
|
166
|
+
id=test_repo, private=False, gated=gated
|
|
167
|
+
)
|
|
168
|
+
|
|
169
|
+
download_huggingface_dataset(
|
|
170
|
+
test_repo, test_filename, test_version, test_dir
|
|
171
|
+
)
|
|
172
|
+
|
|
173
|
+
mock_download.assert_called_once_with(
|
|
174
|
+
repo_id=test_repo,
|
|
175
|
+
repo_type="model",
|
|
176
|
+
filename=test_filename,
|
|
177
|
+
revision=test_version,
|
|
178
|
+
token=test_token,
|
|
179
|
+
local_dir=test_dir,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def test_download_private_flag_repo_passes_env_token(self):
|
|
183
|
+
"""A repo reported as private=True by model_info still gets the token."""
|
|
184
|
+
test_repo = "test_repo"
|
|
185
|
+
test_filename = "test_filename"
|
|
186
|
+
test_version = "test_version"
|
|
187
|
+
test_dir = "test_dir"
|
|
188
|
+
test_token = "private_repo_test_token"
|
|
189
|
+
|
|
190
|
+
with patch.dict(os.environ, {"HUGGING_FACE_TOKEN": test_token}, clear=True):
|
|
191
|
+
with patch(
|
|
192
|
+
"policyengine_core.tools.hugging_face.hf_hub_download"
|
|
193
|
+
) as mock_download:
|
|
194
|
+
with patch(
|
|
195
|
+
"policyengine_core.tools.hugging_face.model_info"
|
|
196
|
+
) as mock_model_info:
|
|
197
|
+
mock_model_info.return_value = ModelInfo(
|
|
198
|
+
id=test_repo, private=True, gated=False
|
|
199
|
+
)
|
|
200
|
+
|
|
201
|
+
download_huggingface_dataset(
|
|
202
|
+
test_repo, test_filename, test_version, test_dir
|
|
203
|
+
)
|
|
204
|
+
|
|
205
|
+
mock_download.assert_called_once_with(
|
|
206
|
+
repo_id=test_repo,
|
|
207
|
+
repo_type="model",
|
|
208
|
+
filename=test_filename,
|
|
209
|
+
revision=test_version,
|
|
210
|
+
token=test_token,
|
|
211
|
+
local_dir=test_dir,
|
|
212
|
+
)
|
|
213
|
+
|
|
214
|
+
def test_download_gated_repo_non_interactive_without_token(self):
|
|
215
|
+
"""Gated repo in CI without secrets: no prompt, token=None is passed."""
|
|
216
|
+
test_repo = "test_repo"
|
|
217
|
+
test_filename = "test_filename"
|
|
218
|
+
test_version = "test_version"
|
|
219
|
+
test_dir = "test_dir"
|
|
220
|
+
|
|
221
|
+
with patch.dict(os.environ, {}, clear=True):
|
|
222
|
+
with patch("os.isatty", return_value=False):
|
|
223
|
+
with patch(
|
|
224
|
+
"policyengine_core.tools.hugging_face.getpass"
|
|
225
|
+
) as mock_getpass:
|
|
226
|
+
with patch(
|
|
227
|
+
"policyengine_core.tools.hugging_face.hf_hub_download"
|
|
228
|
+
) as mock_download:
|
|
229
|
+
with patch(
|
|
230
|
+
"policyengine_core.tools.hugging_face.model_info"
|
|
231
|
+
) as mock_model_info:
|
|
232
|
+
mock_model_info.return_value = ModelInfo(
|
|
233
|
+
id=test_repo, private=False, gated="manual"
|
|
234
|
+
)
|
|
235
|
+
|
|
236
|
+
download_huggingface_dataset(
|
|
237
|
+
test_repo, test_filename, test_version, test_dir
|
|
238
|
+
)
|
|
239
|
+
|
|
240
|
+
mock_getpass.assert_not_called()
|
|
241
|
+
mock_download.assert_called_once_with(
|
|
242
|
+
repo_id=test_repo,
|
|
243
|
+
repo_type="model",
|
|
244
|
+
filename=test_filename,
|
|
245
|
+
revision=test_version,
|
|
246
|
+
token=None,
|
|
247
|
+
local_dir=test_dir,
|
|
248
|
+
)
|
|
249
|
+
|
|
250
|
+
@pytest.mark.parametrize("gated", [False, None])
|
|
251
|
+
def test_download_public_ungated_repo_never_prompts(self, gated):
|
|
252
|
+
"""Public, ungated repo: no token lookup and no interactive prompt.
|
|
253
|
+
|
|
254
|
+
Guards against widening the predicate so far that every public
|
|
255
|
+
download on a developer machine asks for a token.
|
|
256
|
+
"""
|
|
257
|
+
test_repo = "test_repo"
|
|
258
|
+
test_filename = "test_filename"
|
|
259
|
+
test_version = "test_version"
|
|
260
|
+
test_dir = "test_dir"
|
|
261
|
+
|
|
262
|
+
with patch.dict(os.environ, {}, clear=True):
|
|
263
|
+
with patch("os.isatty", return_value=True):
|
|
264
|
+
with patch(
|
|
265
|
+
"policyengine_core.tools.hugging_face.getpass"
|
|
266
|
+
) as mock_getpass:
|
|
267
|
+
with patch(
|
|
268
|
+
"policyengine_core.tools.hugging_face.hf_hub_download"
|
|
269
|
+
) as mock_download:
|
|
270
|
+
with patch(
|
|
271
|
+
"policyengine_core.tools.hugging_face.model_info"
|
|
272
|
+
) as mock_model_info:
|
|
273
|
+
mock_model_info.return_value = ModelInfo(
|
|
274
|
+
id=test_repo, private=False, gated=gated
|
|
275
|
+
)
|
|
276
|
+
|
|
277
|
+
download_huggingface_dataset(
|
|
278
|
+
test_repo, test_filename, test_version, test_dir
|
|
279
|
+
)
|
|
280
|
+
|
|
281
|
+
mock_getpass.assert_not_called()
|
|
282
|
+
mock_download.assert_called_once_with(
|
|
283
|
+
repo_id=test_repo,
|
|
284
|
+
repo_type="model",
|
|
285
|
+
filename=test_filename,
|
|
286
|
+
revision=test_version,
|
|
287
|
+
token=None,
|
|
288
|
+
local_dir=test_dir,
|
|
289
|
+
)
|
|
290
|
+
|
|
144
291
|
|
|
145
292
|
class TestGetOrPromptHfToken:
|
|
146
293
|
def test_get_token_from_environment(self):
|
|
@@ -0,0 +1,244 @@
|
|
|
1
|
+
"""Uprating a variable from its latest known earlier period.
|
|
2
|
+
|
|
3
|
+
A variable with ``uprating`` and no value for the requested period takes its
|
|
4
|
+
latest known earlier value and multiplies it by the ratio of the uprating
|
|
5
|
+
index at the two period starts. Two bugs lived in that step:
|
|
6
|
+
|
|
7
|
+
* The index can have no value at the earlier instant (a value supplied for a
|
|
8
|
+
year before the index starts). The ratio then divided by ``None`` and
|
|
9
|
+
raised ``TypeError``. The index is now held flat where it has no value.
|
|
10
|
+
* The earlier period was chosen by indexing the unfiltered list of known
|
|
11
|
+
periods with a position in the filtered list, so a later period stored
|
|
12
|
+
first was used instead of the latest earlier one.
|
|
13
|
+
"""
|
|
14
|
+
|
|
15
|
+
import itertools
|
|
16
|
+
import math
|
|
17
|
+
|
|
18
|
+
import pytest
|
|
19
|
+
|
|
20
|
+
from policyengine_core.country_template import CountryTaxBenefitSystem
|
|
21
|
+
from policyengine_core.country_template.entities import Person
|
|
22
|
+
from policyengine_core.model_api import MONTH, YEAR, Variable
|
|
23
|
+
from policyengine_core.parameters import ParameterNode
|
|
24
|
+
from policyengine_core.periods import Instant, Period
|
|
25
|
+
from policyengine_core.simulations import SimulationBuilder
|
|
26
|
+
|
|
27
|
+
INDEX_START = 2015
|
|
28
|
+
# The index grows 10% a year from INDEX_START. Integer powers keep the
|
|
29
|
+
# expected ratios exact.
|
|
30
|
+
INDEX = {
|
|
31
|
+
f"{year}-01-01": 100 * 1.1 ** (year - INDEX_START) for year in range(2015, 2021)
|
|
32
|
+
}
|
|
33
|
+
VALUE = 5_000.0
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def build_system(index_values: dict) -> CountryTaxBenefitSystem:
|
|
37
|
+
system = CountryTaxBenefitSystem()
|
|
38
|
+
system.parameters.add_child(
|
|
39
|
+
"test_uprating",
|
|
40
|
+
ParameterNode("test_uprating", data={"index": {"values": index_values}}),
|
|
41
|
+
)
|
|
42
|
+
|
|
43
|
+
class uprated_income(Variable):
|
|
44
|
+
value_type = float
|
|
45
|
+
entity = Person
|
|
46
|
+
definition_period = YEAR
|
|
47
|
+
label = "Uprated yearly income"
|
|
48
|
+
uprating = "test_uprating.index"
|
|
49
|
+
|
|
50
|
+
class uprated_monthly_income(Variable):
|
|
51
|
+
value_type = float
|
|
52
|
+
entity = Person
|
|
53
|
+
definition_period = MONTH
|
|
54
|
+
label = "Uprated monthly income"
|
|
55
|
+
uprating = "test_uprating.index"
|
|
56
|
+
|
|
57
|
+
system.add_variable(uprated_income)
|
|
58
|
+
system.add_variable(uprated_monthly_income)
|
|
59
|
+
return system
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
@pytest.fixture(scope="module")
|
|
63
|
+
def system():
|
|
64
|
+
return build_system(INDEX)
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
@pytest.fixture(scope="module")
|
|
68
|
+
def backdated_system():
|
|
69
|
+
"""The same index with its first value explicitly extended back to 2000,
|
|
70
|
+
the way a country package backdates parameters."""
|
|
71
|
+
system = build_system(INDEX)
|
|
72
|
+
index = system.parameters.test_uprating.index
|
|
73
|
+
first = f"{INDEX_START}-01-01"
|
|
74
|
+
days = (Instant((INDEX_START, 1, 1)).date - Instant((2000, 1, 1)).date).days
|
|
75
|
+
index.update(
|
|
76
|
+
period=Period(("day", Instant((2000, 1, 1)), days)),
|
|
77
|
+
value=index(first),
|
|
78
|
+
)
|
|
79
|
+
assert index("2000-01-01") == index(first)
|
|
80
|
+
return system
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def simulate(system, inputs: dict, variable: str = "uprated_income"):
|
|
84
|
+
return SimulationBuilder().build_from_entities(
|
|
85
|
+
system, {"persons": {"p": {variable: inputs}}}
|
|
86
|
+
)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def calculate(system, inputs: dict, period, variable: str = "uprated_income"):
|
|
90
|
+
return float(simulate(system, inputs, variable).calculate(variable, period)[0])
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def index_at(year: int) -> float:
|
|
94
|
+
"""The index held flat before INDEX_START, as the fix reads it."""
|
|
95
|
+
return INDEX[f"{min(max(year, INDEX_START), 2020)}-01-01"]
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
# Regression tests.
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
def test_value_known_before_index_starts_is_uprated_from_index_start(system):
|
|
102
|
+
# Before the fix: TypeError: unsupported operand type(s) for /: 'float'
|
|
103
|
+
# and 'NoneType'.
|
|
104
|
+
assert calculate(system, {2013: VALUE}, 2018) == pytest.approx(
|
|
105
|
+
VALUE * INDEX["2018-01-01"] / INDEX["2015-01-01"]
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
def test_value_carried_over_unchanged_while_index_undefined(system):
|
|
110
|
+
# Before the fix: TypeError dividing None by None.
|
|
111
|
+
assert calculate(system, {2012: VALUE}, 2014) == pytest.approx(VALUE)
|
|
112
|
+
assert calculate(system, {2012: VALUE}, 2015) == pytest.approx(VALUE)
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
def test_monthly_value_known_before_index_starts(system):
|
|
116
|
+
assert calculate(
|
|
117
|
+
system, {"2014-12": VALUE}, "2016-01", "uprated_monthly_income"
|
|
118
|
+
) == pytest.approx(VALUE * INDEX["2016-01-01"] / INDEX["2015-01-01"])
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
def test_uprates_from_latest_earlier_period_when_later_period_stored_first(
|
|
122
|
+
system,
|
|
123
|
+
):
|
|
124
|
+
# Before the fix the 2020 value (stored first) was used: 999.
|
|
125
|
+
inputs = {2020: 999.0, 2015: VALUE}
|
|
126
|
+
assert calculate(system, inputs, 2018) == pytest.approx(
|
|
127
|
+
VALUE * INDEX["2018-01-01"] / INDEX["2015-01-01"]
|
|
128
|
+
)
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
def test_cached_default_before_input_does_not_pull_later_input_back(system):
|
|
132
|
+
# A formula reading an earlier year (a lagged-income lookup, say) caches
|
|
133
|
+
# the default there. Before the fix a later request between that year
|
|
134
|
+
# and the input year then deflated the later input instead of using the
|
|
135
|
+
# latest earlier period, so the result depended on evaluation order.
|
|
136
|
+
direct = calculate(system, {2018: VALUE}, 2017)
|
|
137
|
+
lagged_first = simulate(system, {2018: VALUE})
|
|
138
|
+
lagged_first.calculate("uprated_income", 2016)
|
|
139
|
+
assert direct == 0
|
|
140
|
+
assert float(lagged_first.calculate("uprated_income", 2017)[0]) == direct
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def test_index_gap_from_explicit_null_is_held_flat():
|
|
144
|
+
# ``update`` on a period before an index starts leaves an explicit null
|
|
145
|
+
# between the new value and the old first value.
|
|
146
|
+
system = build_system(INDEX)
|
|
147
|
+
index = system.parameters.test_uprating.index
|
|
148
|
+
index.update(period="2010", value=50)
|
|
149
|
+
assert index("2012-01-01") is None
|
|
150
|
+
# 2012 falls in the gap: the index is held at its 2010 value there.
|
|
151
|
+
assert calculate(system, {2012: VALUE}, 2016) == pytest.approx(
|
|
152
|
+
VALUE * INDEX["2016-01-01"] / 50
|
|
153
|
+
)
|
|
154
|
+
assert calculate(system, {2011: VALUE}, 2013) == pytest.approx(VALUE)
|
|
155
|
+
|
|
156
|
+
|
|
157
|
+
def test_index_with_no_values_carries_value_over():
|
|
158
|
+
system = build_system({"2015-01-01": None})
|
|
159
|
+
assert calculate(system, {2013: VALUE}, 2018) == pytest.approx(VALUE)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def test_index_value_helper():
|
|
163
|
+
# Imported here so the rest of the module also runs against code without
|
|
164
|
+
# the helper.
|
|
165
|
+
from policyengine_core.simulations.simulation import _uprating_index_value
|
|
166
|
+
|
|
167
|
+
system = build_system(INDEX)
|
|
168
|
+
index = system.parameters.test_uprating.index
|
|
169
|
+
# A null from 2030 with no end date: the index is undefined from then on.
|
|
170
|
+
index.update(start="2030-01-01", value=None)
|
|
171
|
+
assert _uprating_index_value(index, Instant((2010, 6, 1))) == INDEX["2015-01-01"]
|
|
172
|
+
assert _uprating_index_value(index, Instant((2017, 1, 1))) == INDEX["2017-01-01"]
|
|
173
|
+
# After an explicit null the last value before it holds.
|
|
174
|
+
assert index("2030-06-01") is None
|
|
175
|
+
assert _uprating_index_value(index, Instant((2030, 6, 1))) == INDEX["2020-01-01"]
|
|
176
|
+
assert _uprating_index_value(index, Instant((2040, 1, 1))) == INDEX["2020-01-01"]
|
|
177
|
+
empty = build_system({"2015-01-01": None}).parameters.test_uprating.index
|
|
178
|
+
assert _uprating_index_value(empty, Instant((2016, 1, 1))) is None
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
# Invariants, checked exhaustively over a grid of known and requested years
|
|
182
|
+
# (2008-2022), which spans the index start and its last value.
|
|
183
|
+
|
|
184
|
+
YEARS = range(2008, 2023)
|
|
185
|
+
PAIRS = [(known, requested) for known, requested in itertools.combinations(YEARS, 2)]
|
|
186
|
+
|
|
187
|
+
|
|
188
|
+
@pytest.mark.parametrize("known,requested", PAIRS)
|
|
189
|
+
def test_uprated_value_equals_value_times_flat_index_ratio(system, known, requested):
|
|
190
|
+
"""For every known year before every requested year, the result is the
|
|
191
|
+
known value times the ratio of the index held flat where undefined. Where
|
|
192
|
+
the index is defined at both years this is the ratio uprating always
|
|
193
|
+
used; where it is undefined at both the value carries over unchanged."""
|
|
194
|
+
result = calculate(system, {known: VALUE}, requested)
|
|
195
|
+
expected = VALUE * index_at(requested) / index_at(known)
|
|
196
|
+
assert math.isfinite(result)
|
|
197
|
+
assert result == pytest.approx(expected, rel=1e-6)
|
|
198
|
+
if requested <= INDEX_START:
|
|
199
|
+
assert result == pytest.approx(VALUE, rel=1e-6)
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
@pytest.mark.parametrize("known,requested", PAIRS)
|
|
203
|
+
def test_matches_explicitly_backdated_index(system, backdated_system, known, requested):
|
|
204
|
+
"""Differential: holding the index flat before it starts gives the same
|
|
205
|
+
result as a country package explicitly extending the index's first value
|
|
206
|
+
backward and uprating through the ordinary defined-index path."""
|
|
207
|
+
assert calculate(system, {known: VALUE}, requested) == pytest.approx(
|
|
208
|
+
calculate(backdated_system, {known: VALUE}, requested), rel=1e-6
|
|
209
|
+
)
|
|
210
|
+
|
|
211
|
+
|
|
212
|
+
@pytest.mark.parametrize("known", range(2008, 2016))
|
|
213
|
+
def test_result_does_not_depend_on_intermediate_years_computed(system, known):
|
|
214
|
+
"""Path independence: computing every year in turn (each uprating from the
|
|
215
|
+
one before, which is then known) gives the same final value as uprating
|
|
216
|
+
straight from the known year."""
|
|
217
|
+
stepwise = simulate(system, {known: VALUE})
|
|
218
|
+
for year in range(known + 1, 2022):
|
|
219
|
+
stepwise.calculate("uprated_income", year)
|
|
220
|
+
stepwise_result = float(stepwise.calculate("uprated_income", 2022)[0])
|
|
221
|
+
assert stepwise_result == pytest.approx(
|
|
222
|
+
calculate(system, {known: VALUE}, 2022), rel=1e-5
|
|
223
|
+
)
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
@pytest.mark.parametrize(
|
|
227
|
+
"stored_years", list(itertools.permutations([2015, 2017, 2019]))
|
|
228
|
+
)
|
|
229
|
+
def test_latest_earlier_period_wins_regardless_of_storage_order(system, stored_years):
|
|
230
|
+
"""Order independence: for any insertion order of the known periods, each
|
|
231
|
+
requested year uprates from the latest known year before it. All years
|
|
232
|
+
are inside the index's range, so only the choice of base period is
|
|
233
|
+
tested here."""
|
|
234
|
+
inputs = {year: 1_000.0 * (i + 1) for i, year in enumerate(stored_years)}
|
|
235
|
+
for requested in (2016, 2018, 2020):
|
|
236
|
+
latest = max(year for year in inputs if year < requested)
|
|
237
|
+
assert calculate(system, inputs, requested) == pytest.approx(
|
|
238
|
+
inputs[latest] * index_at(requested) / index_at(latest), rel=1e-6
|
|
239
|
+
)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def test_value_known_after_requested_period_is_not_used(system):
|
|
243
|
+
# Uprating only runs forward; a later value alone gives the default.
|
|
244
|
+
assert calculate(system, {2018: VALUE}, 2016) == 0
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/is-version-number-acceptable.sh
RENAMED
|
File without changes
|
|
File without changes
|
{policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/requirements/legacy-country-smoke.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|