policyengine-core 3.32.26__tar.gz → 3.32.28__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.26 → policyengine_core-3.32.28}/CHANGELOG.md +15 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/PKG-INFO +1 -1
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/data_storage/on_disk_storage.py +31 -4
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/holders/holder.py +217 -8
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/simulations/simulation.py +94 -17
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/pyproject.toml +1 -1
- policyengine_core-3.32.28/tests/core/test_disk_period_filenames.py +167 -0
- policyengine_core-3.32.28/tests/core/test_input_tier_invalidation.py +129 -0
- policyengine_core-3.32.28/tests/core/test_option_result_cache.py +268 -0
- policyengine_core-3.32.28/tests/core/test_option_result_cache_property.py +136 -0
- policyengine_core-3.32.28/tests/core/test_option_result_input_provenance.py +120 -0
- policyengine_core-3.32.28/tests/core/test_registered_input_deletion.py +93 -0
- policyengine_core-3.32.28/tests/core/test_restore_input_provenance.py +50 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_restore_input_registry_property.py +109 -53
- policyengine_core-3.32.28/tests/core/test_user_input_keys.py +615 -0
- policyengine_core-3.32.28/tests/core/test_user_input_keys_property.py +611 -0
- policyengine_core-3.32.28/tests/core/test_user_input_keys_soundness.py +414 -0
- policyengine_core-3.32.28/tests/fixtures/option_caches.py +98 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/ISSUE_TEMPLATE.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/actionlint.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/bump_version.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/changelog_template.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/get-changelog-diff.sh +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/has-functional-changes.sh +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/is-version-number-acceptable.sh +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/publish-git-tag.sh +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/requirements/legacy-country-smoke.txt +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/workflows/pr.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.github/workflows/push.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.gitignore +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/.python-version +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/AGENTS.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/CLAUDE.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/CONTRIBUTING.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/LICENSE +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/MANIFEST.in +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/Makefile +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/README.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/_build/logs/myst.build.json +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/changelog.d/.gitkeep +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/_config.yml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/_static/style.css +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/_toc.yml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/add_plotly_to_book.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/contributing/intro.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/engineering/skills/README.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/engineering/skills/documentation_review.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/engineering/skills/github-prs.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/engineering/skills/testing.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/intro.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/logo.png +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/commons.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/country_template.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/data.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/data_storage.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/entities.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/enums.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/errors.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/experimental.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/extension_template.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/holders.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/parameters.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/periods.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/populations.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/projectors.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/reforms.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/scripts.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/simulations.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/taxbenefitsystems.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/taxscales.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/tools.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/tracers.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/types.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/variables.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/python_api/warnings.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/usage/country.ipynb +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/usage/datasets.ipynb +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/usage/parameters.md +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/usage/reforms.ipynb +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/docs/usage/simulation.ipynb +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/mypy.ini +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/build_metadata.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/charts/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/charts/api.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/charts/bar.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/charts/formatting.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/commons/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/commons/formulas.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/commons/misc.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/commons/rates.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/constants.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/data/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/data/datasets/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/data/datasets/country_template_dataset.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/entities.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/modelled_policies.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/parameters/benefits/basic_income.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/parameters/benefits/housing_allowance.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/parameters/benefits/index.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/parameters/benefits/parenting_allowance/amount.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/parameters/benefits/parenting_allowance/income_threshold.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/parameters/general/age_of_majority.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/parameters/general/age_of_retirement.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/parameters/taxes/housing_tax.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/parameters/taxes/income_tax_rate.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/parameters/taxes/social_security_contribution.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/reforms/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/reforms/add_dynamic_variable.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/reforms/add_new_tax.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/reforms/flat_social_security_contribution.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/reforms/modify_social_security_taxation.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/reforms/removal_basic_income.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/situation_examples/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/situation_examples/couple.json +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/situation_examples/housing.json +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/situation_examples/single.json +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/age.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/basic_income.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/disposable_income.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/housing_allowance.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/housing_tax.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/income_tax.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/reforms/add_dynamic_variable.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/reforms/add_new_tax.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/reforms/modify_social_security_taxation.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/situations/income_tax.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/situations/parenting_allowance.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/social_security_contribution.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/tests/test_microsimulation.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/variables/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/variables/benefits.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/variables/demographics.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/variables/housing.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/variables/ids.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/variables/income.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/variables/stats.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/country_template/variables/taxes.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/data/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/data/dataset.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/data_storage/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/data_storage/in_memory_storage.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/data_storage/storage_directory.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/data_structures/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/data_structures/parameter_metadata.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/data_structures/parameter_node_metadata.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/data_structures/reference.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/data_structures/unit.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/entities/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/entities/entity.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/entities/group_entity.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/entities/helpers.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/entities/role.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/enums/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/enums/config.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/enums/enum.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/enums/enum_array.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/cycle_error.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/empty_argument_error.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/nan_creation_error.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/non_deterministic_formula_error.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/parameter_not_found_error.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/parameter_parsing_error.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/period_mismatch_error.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/situation_parsing_error.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/spiral_error.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/variable_name_conflict_error.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/errors/variable_not_found_error.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/experimental/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/experimental/memory_config.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/extension_template/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/extension_template/local_benefit.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/extension_template/parameters/local_town/child_allowance/amount.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/extension_template/parameters/local_town/child_allowance/index.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/extension_template/parameters/local_town/index.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/extension_template/tests/local_benefit.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/holders/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/holders/helpers.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/model_api.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/at_instant_like.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/config.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/helpers.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/operations/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/operations/get_parameter.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/operations/homogenize_parameters.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/operations/interpolate_parameters.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/operations/propagate_parameter_metadata.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/operations/uprate_parameters.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/parameter.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/parameter_at_instant.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/parameter_node.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/parameter_node_at_instant.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/parameter_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/parameter_scale_bracket.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/parameters/vectorial_parameter_node_at_instant.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/periods/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/periods/config.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/periods/helpers.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/periods/instant_.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/periods/period_.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/populations/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/populations/config.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/populations/group_population.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/populations/population.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/projectors/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/projectors/entity_to_person_projector.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/projectors/first_person_to_entity_projector.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/projectors/helpers.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/projectors/projector.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/projectors/unique_role_to_entity_projector.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/reforms/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/reforms/reform.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/scripts/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/scripts/assets/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/scripts/assets/index.html +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/scripts/policyengine_command.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/scripts/run_data.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/scripts/run_test.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/scripts/simulation_generator.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/simulations/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/simulations/helpers.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/simulations/individual_sim.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/simulations/microsimulation.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/simulations/simulation_builder.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/simulations/simulation_macro_cache.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxbenefitsystems/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxbenefitsystems/tax_benefit_system.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxscales/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxscales/abstract_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxscales/abstract_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxscales/amount_tax_scale_like.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxscales/helpers.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxscales/linear_average_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxscales/marginal_amount_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxscales/marginal_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxscales/rate_tax_scale_like.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxscales/single_amount_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/taxscales/tax_scale_like.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tools/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tools/google_cloud.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tools/hugging_face.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tools/simulation_dumper.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tools/test_from_situation.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tools/test_runner.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tools/win_file_manager.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tracers/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tracers/computation_log.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tracers/flat_trace.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tracers/full_tracer.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tracers/performance_log.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tracers/simple_tracer.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tracers/trace_node.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tracers/tracing_parameter_node_at_instant.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/tracers/variable_graph.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/types/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/types/data_types/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/types/data_types/arrays.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/variables/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/variables/config.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/variables/defined_for.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/variables/formula_randomness.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/variables/helpers.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/variables/typing.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/variables/variable.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/warnings/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/warnings/libyaml_warning.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/warnings/memory_config_warning.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/warnings/parameter_key_warning.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/warnings/tempfile_warning.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/pytest.ini +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/conftest.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/commons/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/commons/test_between_function.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/commons/test_formulas.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/commons/test_is_in_function.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/commons/test_random_seed.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/commons/test_rates.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/data/test_dataset.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/enums/test_enum.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/model_api/test_index_.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/array_type.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/duplicate_key.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/filesystem_hierarchy/empty_index_file/index.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/filesystem_hierarchy/node1/param.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/indentation.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/missing_value.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/parameter_for_unit_propagation.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/test_parameter_clone.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/test_parameter_validation.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/test_propagate_units.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/test_unknown_keys.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/unexpected_key_in_parameter.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/unexpected_key_in_scale.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/unexpected_key_in_value_at_instant.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/unexpected_key_in_value_history.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/unknown_key_beside_values.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/uprating_under_metadata.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/wrong_date.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/wrong_scale.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/wrong_type_in_bracket.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/wrong_type_in_brackets.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/wrong_type_in_parameter.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/wrong_type_in_scale.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/wrong_type_in_value_history.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/wrong_value.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameter_validation/yaml_hierarchy/node1.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters/operations/test_interpolation.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters/operations/test_nesting.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters/operations/test_propagation.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters/operations/test_scale_threshold_uprating.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters/operations/test_uprating.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters/test_numpy2_structured_arrays.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters/test_vectorial_parameter_node_copy.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters/test_vectorial_parameter_node_copy_property.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters_fancy_indexing/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters_fancy_indexing/bareme.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters_fancy_indexing/local_tax.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters_fancy_indexing/rate.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/parameters_fancy_indexing/test_fancy_indexing.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/simulations/test_formula_randomness_concurrency.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tax_scales/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tax_scales/test_abstract_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tax_scales/test_abstract_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tax_scales/test_linear_average_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tax_scales/test_marginal_amount_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tax_scales/test_marginal_rate_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tax_scales/test_rate_tax_scale_like.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tax_scales/test_single_amount_tax_scale.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tax_scales/test_tax_scales_commons.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_apply_reform_invalidates_cache.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_apply_reform_preserves_user_inputs.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_assert_near_precision.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_axes.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_bincount_minlength.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_branch_scoped_delete_arrays.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_branch_shared_arrays.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_branch_shared_arrays_differential.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_build_metadata.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_calculate_output.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_carry_over_order.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_carry_over_order_property.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_clone_invalidated_caches.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_clone_rebinding.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_clone_rebinding_property.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_clone_reform_baseline.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_clone_reform_baseline_property.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_countries.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_cycles.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_data_storage_dir.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_data_storage_dir_property.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_dataset_getattr.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_dataset_unknown_column_warning.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_disk_storage_differential.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_disk_storage_ownership.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_docs_deployment.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_dump_restore.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_entities.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_eternity_subperiods.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_extensions.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_fast_cache.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_fast_cache_contained_periods.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_fast_cache_contained_periods_property.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_fast_cache_guards.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_formulas.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_holder_branch_fallback.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_holder_write_fast_cache.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_holder_write_fast_cache_property.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_holders.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_macro_cache_not_singleton.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_medium_fixes.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_microsimulation_person_accessor.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_microsimulation_weights.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_on_disk_storage_clones.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_opt_out_cache.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_pandas3_compatibility.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_parameter_security.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_parameters.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_periods.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_projectors.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_reform_baseline_system.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_reform_parameter_isolation.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_reform_period_keys.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_reforms.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_release_tagging.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_rerun_fixture_isolation.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_restore_input_registry.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_simulation_builder.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_simulation_copy_pickle.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_simulation_copy_pickle_property.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_simulations.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_stable_hash_seed.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_storage_anchored_periods.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_storage_delete_branch.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_storage_input_index.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_storage_shared_index.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_storage_shared_index_differential.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_subsample_baseline_branch.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_subsample_invalidates_cache.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_tax_benefit_system_cache_identity.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_tracers.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_tracing_parameter_isolation.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_tracing_parameter_isolation_properties.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_uprating_order.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_uprating_order_property.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/test_yaml.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tools/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tools/test_assert_near.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tools/test_google_cloud.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tools/test_hugging_face.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/tools/test_runner/test_yaml_runner.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_adds.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_annualize.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_bounds.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_defined_for.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_formula_randomness.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_non_numeric_uprating_and_defined_for.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_subtracts.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_subtracts_sign.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_variable_clone.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_variable_formula_determinism.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_variable_uprating.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/core/variables/test_variables.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/appclient.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/branch_shared_arrays.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/carry_over.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/data_storage_dir.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/disk_storage.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/entities.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/fast_cache_contained_periods.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/simulation_copy.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/simulations.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/taxbenefitsystems.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/tracing.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/uprated_inputs.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/uprating_order.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/variables.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/vectorial_parameter_nodes.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/__init__.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/directory/subdirectory/test_4.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/directory/test_1.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/directory/test_2.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/failing_test_absolute_error_margin.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/failing_test_relative_error_margin.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/test_absolute_error_margin.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/test_failure.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/test_name_filter.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/test_relative_error_margin.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/test_success.yml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/test_with_anchors.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/test_with_extension.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/test_with_reform.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/fixtures/yaml_tests/test_with_reform_2.yaml +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/smoke/test_country_init.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/tests/smoke/test_us.py +0 -0
- {policyengine_core-3.32.26 → policyengine_core-3.32.28}/uv.lock +0 -0
|
@@ -1,3 +1,18 @@
|
|
|
1
|
+
## [3.32.28] - 2026-10-09
|
|
2
|
+
|
|
3
|
+
### Fixed
|
|
4
|
+
|
|
5
|
+
- Cache `calculate_add` and `calculate_divide` results as derived only where a plain read returns them without changing dtype, preserving visible inputs and allowing explicit aggregate refresh after an input changes or is deleted.
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
## [3.32.27] - 2026-10-09
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Fix compound period disk storage on Windows while preserving legacy filename restores and clone isolation.
|
|
13
|
+
- Keep input records aligned with memory/disk storage across deletion, copies, handlers, subsampling, period aliases, and early years; custom handlers must use `holder._set` or `holder.set_input` for inputs, since `put_in_cache` values are excluded from input export and reform replay and no longer redirected to the input's branch.
|
|
14
|
+
|
|
15
|
+
|
|
1
16
|
## [3.32.26] - 2026-10-09
|
|
2
17
|
|
|
3
18
|
### Fixed
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.5
|
|
2
2
|
Name: policyengine-core
|
|
3
|
-
Version: 3.32.
|
|
3
|
+
Version: 3.32.28
|
|
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>
|
|
@@ -51,6 +51,11 @@ def _epoch() -> tuple:
|
|
|
51
51
|
class OnDiskStorage:
|
|
52
52
|
"""
|
|
53
53
|
Low-level class responsible for storing and retrieving calculated vectors on disk
|
|
54
|
+
|
|
55
|
+
Compound periods contain colons, which Windows forbids in filenames.
|
|
56
|
+
Their physical filenames use semicolons in the period suffix instead;
|
|
57
|
+
logical storage keys keep the original period strings. ``restore`` reads
|
|
58
|
+
both these portable filenames and legacy filenames containing colons.
|
|
54
59
|
"""
|
|
55
60
|
|
|
56
61
|
# Defaults for ``__del__``, which also runs on an instance whose
|
|
@@ -315,13 +320,19 @@ class OnDiskStorage:
|
|
|
315
320
|
own = self._own_paths.get(filename)
|
|
316
321
|
if own is not None:
|
|
317
322
|
return own
|
|
318
|
-
|
|
323
|
+
# A period string can contain colons, which Windows forbids in
|
|
324
|
+
# filenames. Period strings never contain semicolons or underscores,
|
|
325
|
+
# so translating only the final suffix is reversible and leaves
|
|
326
|
+
# branch names untouched.
|
|
327
|
+
branch, separator, period_string = filename.rpartition("_")
|
|
328
|
+
portable_filename = f"{branch}{separator}{period_string.replace(':', ';')}"
|
|
329
|
+
path = os.path.join(self.storage_dir, portable_filename) + ".npy"
|
|
319
330
|
if path not in self._family_files and not self._writes_only_new_files():
|
|
320
331
|
return path
|
|
321
332
|
directory = os.path.join(self.storage_dir, REPLACEMENTS_DIR)
|
|
322
333
|
os.makedirs(directory, exist_ok=True)
|
|
323
334
|
descriptor, path = tempfile.mkstemp(
|
|
324
|
-
prefix=f"{
|
|
335
|
+
prefix=f"{portable_filename}.", suffix=".npy", dir=directory
|
|
325
336
|
)
|
|
326
337
|
os.close(descriptor)
|
|
327
338
|
return path
|
|
@@ -365,13 +376,21 @@ class OnDiskStorage:
|
|
|
365
376
|
"""Read back the values stored in this storage's directory: for each
|
|
366
377
|
key, the file named for it (not those in ``REPLACEMENTS_DIR``).
|
|
367
378
|
|
|
368
|
-
This storage writes over
|
|
379
|
+
This storage writes over portable files, as over those it wrote, until
|
|
369
380
|
it is cloned or copied, or this process forks: from then on it writes
|
|
370
381
|
a new file instead, since the clone, copy or forked process reads
|
|
371
382
|
them. A storage made separately for the directory, the one that wrote
|
|
372
383
|
them say, still writes over them, as before. So may another storage
|
|
373
384
|
in this one's family, when ``restore`` runs after it was cloned and
|
|
374
385
|
this process has not forked since.
|
|
386
|
+
|
|
387
|
+
The period suffix of new filenames uses semicolons for the colons
|
|
388
|
+
in compound period strings. Legacy filenames containing colons are
|
|
389
|
+
still accepted. If both versions of a key exist after updating a
|
|
390
|
+
legacy value, the portable filename holds the current value and wins
|
|
391
|
+
regardless of directory listing order. Readers still indexed to the
|
|
392
|
+
legacy file keep its old value until they restore again. Branch names
|
|
393
|
+
are unchanged.
|
|
375
394
|
"""
|
|
376
395
|
self._files = files = {}
|
|
377
396
|
# Files read back from a directory carry no derived marks.
|
|
@@ -382,7 +401,15 @@ class OnDiskStorage:
|
|
|
382
401
|
continue
|
|
383
402
|
path = os.path.join(self.storage_dir, filename)
|
|
384
403
|
filename_core = filename.rsplit(".", 1)[0]
|
|
385
|
-
|
|
404
|
+
branch, separator, period_string = filename_core.rpartition("_")
|
|
405
|
+
key = filename_core
|
|
406
|
+
if separator:
|
|
407
|
+
key = f"{branch}{separator}{period_string.replace(';', ':')}"
|
|
408
|
+
# Updating a legacy value may leave its old colon filename
|
|
409
|
+
# beside the portable file. Prefer the latter, independent of
|
|
410
|
+
# directory listing order, without parsing arbitrary basenames.
|
|
411
|
+
if key not in files or key != filename_core:
|
|
412
|
+
files[key] = path
|
|
386
413
|
self._restored_paths.update(files.values())
|
|
387
414
|
|
|
388
415
|
def __del__(self, _rmtree=shutil.rmtree, _getpid=os.getpid) -> None:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import tempfile
|
|
3
3
|
import warnings
|
|
4
|
-
from typing import TYPE_CHECKING, Any, List, Tuple
|
|
4
|
+
from typing import TYPE_CHECKING, Any, List, Optional, Tuple
|
|
5
5
|
|
|
6
6
|
import numpy
|
|
7
7
|
import psutil
|
|
@@ -23,6 +23,8 @@ class Holder:
|
|
|
23
23
|
A holder keeps tracks of a variable values after they have been calculated, or set as an input.
|
|
24
24
|
"""
|
|
25
25
|
|
|
26
|
+
_user_input_storage: dict[tuple[str, str], tuple[Period, frozenset[str]]]
|
|
27
|
+
|
|
26
28
|
def __init__(self, variable: "Variable", population: "Population"):
|
|
27
29
|
self.population = population
|
|
28
30
|
self.variable = variable
|
|
@@ -63,6 +65,7 @@ class Holder:
|
|
|
63
65
|
"simulation",
|
|
64
66
|
"_memory_storage",
|
|
65
67
|
"_disk_storage",
|
|
68
|
+
"_user_input_storage",
|
|
66
69
|
):
|
|
67
70
|
new_dict[key] = value
|
|
68
71
|
|
|
@@ -74,6 +77,9 @@ class Holder:
|
|
|
74
77
|
new._disk_storage = (
|
|
75
78
|
self._disk_storage.clone() if self._disk_storage is not None else None
|
|
76
79
|
)
|
|
80
|
+
if hasattr(self, "_user_input_storage"):
|
|
81
|
+
# Locations are immutable; only the holder's index needs copying.
|
|
82
|
+
new._user_input_storage = self._user_input_storage.copy()
|
|
77
83
|
|
|
78
84
|
new_dict["population"] = population
|
|
79
85
|
new_dict["simulation"] = population.simulation
|
|
@@ -116,13 +122,186 @@ class Holder:
|
|
|
116
122
|
If ``period`` is ``None``, remove all known values of the variable.
|
|
117
123
|
|
|
118
124
|
If ``period`` is not ``None``, only remove all values for any period included in period (e.g. if period is "2017", values for "2017-01", "2017-07", etc. would be removed)
|
|
125
|
+
|
|
126
|
+
A deleted value set with ``set_input`` stops counting as an input, so
|
|
127
|
+
a value calculated later for the same period is not taken for one.
|
|
119
128
|
"""
|
|
129
|
+
simulation = getattr(self, "simulation", None)
|
|
130
|
+
user_input_keys = getattr(simulation, "_user_input_keys", None)
|
|
131
|
+
stored_before = self._stored_keys() if user_input_keys else None
|
|
120
132
|
|
|
121
133
|
self._memory_storage.delete(period, branch_name)
|
|
122
134
|
if self._disk_storage:
|
|
123
135
|
self._disk_storage.delete(period, branch_name)
|
|
124
136
|
self._evict_fast_cache(period, branch_name, contained=True)
|
|
125
137
|
|
|
138
|
+
if user_input_keys:
|
|
139
|
+
self._forget_deleted_inputs(user_input_keys, stored_before)
|
|
140
|
+
|
|
141
|
+
def _stored_keys(self) -> Tuple[set, set]:
|
|
142
|
+
"""The keys memory and disk storage hold values under."""
|
|
143
|
+
return (
|
|
144
|
+
set(self._memory_storage._arrays),
|
|
145
|
+
set(self._disk_storage._files) if self._disk_storage is not None else set(),
|
|
146
|
+
)
|
|
147
|
+
|
|
148
|
+
def _forget_deleted_inputs(
|
|
149
|
+
self, user_input_keys: set, stored_before: Tuple[set, set]
|
|
150
|
+
) -> None:
|
|
151
|
+
"""Drop the simulation's record of the inputs ``delete_arrays`` deleted.
|
|
152
|
+
|
|
153
|
+
``_user_input_keys`` records each (variable, branch, period) stored
|
|
154
|
+
through ``set_input``, with the period as storage keys it (see
|
|
155
|
+
``_set``). ``_invalidate_all_caches`` keeps the values it names and
|
|
156
|
+
``to_input_dataframe`` exports them, so an entry left behind for a
|
|
157
|
+
deleted value would make a formula result stored later for that
|
|
158
|
+
period count as an input.
|
|
159
|
+
|
|
160
|
+
The keys the deletion removed are found by comparing the keys each
|
|
161
|
+
storage holds before and after, so the cost depends on what this
|
|
162
|
+
holder stores, not on the size of the record, and no stored file is
|
|
163
|
+
read. An entry for a removed key stays only while a storage still
|
|
164
|
+
holds an input for it. A computed disk value does not become an input
|
|
165
|
+
when the memory input for the same key is deleted.
|
|
166
|
+
"""
|
|
167
|
+
name = self.variable.name
|
|
168
|
+
memory_before, disk_before = stored_before
|
|
169
|
+
arrays = self._memory_storage._arrays
|
|
170
|
+
files = self._disk_storage._files if self._disk_storage is not None else {}
|
|
171
|
+
# Memory keys are "{branch}:{period}"; branch names cannot contain ":".
|
|
172
|
+
removed = [key.split(":", 1) for key in memory_before if key not in arrays]
|
|
173
|
+
# Disk keys are "{branch}_{period}"; branch names can contain "_" but
|
|
174
|
+
# period strings cannot, so the period follows the last "_".
|
|
175
|
+
removed += [key.rsplit("_", 1) for key in disk_before if key not in files]
|
|
176
|
+
forgotten = []
|
|
177
|
+
recorded = getattr(self, "_user_input_storage", {})
|
|
178
|
+
for branch, period_string in removed:
|
|
179
|
+
slot = (branch, period_string)
|
|
180
|
+
input_storage = recorded.get(slot)
|
|
181
|
+
if input_storage is not None:
|
|
182
|
+
input_period, locations = input_storage
|
|
183
|
+
locations = frozenset(
|
|
184
|
+
location
|
|
185
|
+
for location in locations
|
|
186
|
+
if (
|
|
187
|
+
f"{branch}:{period_string}" in arrays
|
|
188
|
+
if location == "memory"
|
|
189
|
+
else f"{branch}_{period_string}" in files
|
|
190
|
+
)
|
|
191
|
+
)
|
|
192
|
+
recorded[slot] = (input_period, locations)
|
|
193
|
+
else:
|
|
194
|
+
try:
|
|
195
|
+
# Storage strings omit early years' leading zeros;
|
|
196
|
+
# the period parser requires a four-digit year.
|
|
197
|
+
components = period_string.split(":")
|
|
198
|
+
date_index = 1 if len(components) > 1 else 0
|
|
199
|
+
date_components = components[date_index].split("-")
|
|
200
|
+
date_components[0] = date_components[0].zfill(4)
|
|
201
|
+
components[date_index] = "-".join(date_components)
|
|
202
|
+
input_period = periods.period(":".join(components))
|
|
203
|
+
except ValueError:
|
|
204
|
+
# Not a key ``put`` wrote (say, a file ``restore`` found).
|
|
205
|
+
continue
|
|
206
|
+
key = (name, branch, input_period)
|
|
207
|
+
if key in user_input_keys and not self._stores_user_input(
|
|
208
|
+
input_period, branch
|
|
209
|
+
):
|
|
210
|
+
forgotten.append(key)
|
|
211
|
+
recorded.pop(slot, None)
|
|
212
|
+
user_input_keys.difference_update(forgotten)
|
|
213
|
+
|
|
214
|
+
def _seed_input_storage(self, period: Period, branch_name: str) -> None:
|
|
215
|
+
"""Capture registered input locations before their first new write.
|
|
216
|
+
|
|
217
|
+
Restoration can register inputs without this holder's tier metadata.
|
|
218
|
+
Only an already-recorded slot can inherit storage's input marks: an
|
|
219
|
+
unrecorded cache value must never become a replayable input.
|
|
220
|
+
"""
|
|
221
|
+
recorded = getattr(self, "_user_input_storage", None)
|
|
222
|
+
slot = (branch_name, str(period))
|
|
223
|
+
if recorded is not None and slot in recorded:
|
|
224
|
+
return
|
|
225
|
+
keys = getattr(self.simulation, "_user_input_keys", ())
|
|
226
|
+
if (self.variable.name, branch_name, period) not in keys:
|
|
227
|
+
return
|
|
228
|
+
locations = frozenset(
|
|
229
|
+
location
|
|
230
|
+
for location, storage in (
|
|
231
|
+
("memory", self._memory_storage),
|
|
232
|
+
("disk", self._disk_storage),
|
|
233
|
+
)
|
|
234
|
+
if storage is not None
|
|
235
|
+
and storage.has(period, branch_name)
|
|
236
|
+
and not storage.is_derived(period, branch_name)
|
|
237
|
+
)
|
|
238
|
+
if recorded is None:
|
|
239
|
+
recorded = self._user_input_storage = {}
|
|
240
|
+
recorded[slot] = (period, locations)
|
|
241
|
+
|
|
242
|
+
def _record_input_storage(
|
|
243
|
+
self, period: Period, branch_name: str, storage: str, is_input: bool = True
|
|
244
|
+
) -> None:
|
|
245
|
+
"""Remember which tier received the actual ``set_input`` value.
|
|
246
|
+
|
|
247
|
+
Storage's carry-over marks are broader: ``put_in_cache`` defaults to
|
|
248
|
+
``derived=False`` without making its value a replay/export input.
|
|
249
|
+
Keep this metadata only for slots that have received an input, with
|
|
250
|
+
immutable locations so clones can copy the index independently.
|
|
251
|
+
"""
|
|
252
|
+
recorded = getattr(self, "_user_input_storage", None)
|
|
253
|
+
slot = (branch_name, str(period))
|
|
254
|
+
if not is_input and (recorded is None or slot not in recorded):
|
|
255
|
+
return
|
|
256
|
+
if recorded is None:
|
|
257
|
+
recorded = self._user_input_storage = {}
|
|
258
|
+
_, locations = recorded.get(slot, (period, frozenset()))
|
|
259
|
+
locations = locations | {storage} if is_input else locations - {storage}
|
|
260
|
+
recorded[slot] = (period, locations)
|
|
261
|
+
|
|
262
|
+
def _stores_user_input(self, period: Period, branch_name: str) -> bool:
|
|
263
|
+
"""Whether an actual input survives in either tier, without reading it.
|
|
264
|
+
|
|
265
|
+
Called only for a slot already in the simulation's replay record.
|
|
266
|
+
Register-only inputs (including restored inputs) may have no location
|
|
267
|
+
metadata yet; their existing storage marks identify the surviving
|
|
268
|
+
tier. Marks never add an unrecorded slot to the replay record.
|
|
269
|
+
"""
|
|
270
|
+
recorded = getattr(self, "_user_input_storage", {}).get(
|
|
271
|
+
(branch_name, str(period))
|
|
272
|
+
)
|
|
273
|
+
locations = recorded[1] if recorded is not None else {"memory", "disk"}
|
|
274
|
+
for location, storage in (
|
|
275
|
+
("memory", self._memory_storage),
|
|
276
|
+
("disk", self._disk_storage),
|
|
277
|
+
):
|
|
278
|
+
if (
|
|
279
|
+
location in locations
|
|
280
|
+
and storage is not None
|
|
281
|
+
and storage.has(period, branch_name)
|
|
282
|
+
and not storage.is_derived(period, branch_name)
|
|
283
|
+
):
|
|
284
|
+
return True
|
|
285
|
+
return False
|
|
286
|
+
|
|
287
|
+
def _storage_period(self, period: Period) -> Period:
|
|
288
|
+
"""The period storage keys a value for ``period`` under.
|
|
289
|
+
|
|
290
|
+
Match the string key's aliases using the period fields: eternity for
|
|
291
|
+
an eternal variable, and a year for twelve months. Do not reparse the
|
|
292
|
+
string: valid early-year periods stringify without leading zeros.
|
|
293
|
+
"""
|
|
294
|
+
if self._memory_storage.is_eternal:
|
|
295
|
+
return periods.period(periods.ETERNITY)
|
|
296
|
+
period = periods.period(period)
|
|
297
|
+
if period.unit in (periods.MONTH, periods.YEAR):
|
|
298
|
+
unit, size = period.unit, period.size
|
|
299
|
+
if unit == periods.MONTH and size == 12:
|
|
300
|
+
unit, size = periods.YEAR, 1
|
|
301
|
+
start = periods.instant((period.start.year, period.start.month, 1))
|
|
302
|
+
return Period((unit, start, size))
|
|
303
|
+
return period
|
|
304
|
+
|
|
126
305
|
def _get_array_from_storage(
|
|
127
306
|
self, period: Period, branch_name: str = "default"
|
|
128
307
|
) -> ArrayLike:
|
|
@@ -257,6 +436,10 @@ class Holder:
|
|
|
257
436
|
|
|
258
437
|
|
|
259
438
|
If a ``set_input`` property has been set for the variable, this method may accept inputs for periods not matching the ``definition_period`` of the variable. To read more about this, check the `documentation <https://openfisca.org/doc/coding-the-legislation/35_periods.html#set-input-automatically-process-variable-inputs-defined-for-periods-not-matching-the-definition-period>`_.
|
|
439
|
+
|
|
440
|
+
Custom handlers store replayable inputs with ``holder._set`` or
|
|
441
|
+
``holder.set_input``. Values written through ``put_in_cache`` are
|
|
442
|
+
excluded from input export and reform replay.
|
|
260
443
|
"""
|
|
261
444
|
|
|
262
445
|
period = periods.period(period)
|
|
@@ -365,15 +548,18 @@ class Holder:
|
|
|
365
548
|
branch_name: str = "default",
|
|
366
549
|
validate_nan: bool = False,
|
|
367
550
|
derived: bool = False,
|
|
551
|
+
is_input: Optional[bool] = None,
|
|
368
552
|
) -> None:
|
|
369
553
|
simulation = getattr(self, "simulation", None)
|
|
370
|
-
# A value calculated while an input is being set (say, by a
|
|
371
|
-
# ``set_input`` helper that calculates) is not part of that input: it
|
|
372
|
-
# belongs to the branch it was calculated on.
|
|
373
554
|
user_input_contexts = (
|
|
374
555
|
None if derived else getattr(simulation, "_user_input_contexts", None)
|
|
375
556
|
)
|
|
376
|
-
|
|
557
|
+
# A value is an input when stored while ``set_input`` runs, unless the
|
|
558
|
+
# caller says otherwise: ``put_in_cache`` stores calculated values,
|
|
559
|
+
# including those a custom ``set_input`` handler calculates.
|
|
560
|
+
if is_input is None:
|
|
561
|
+
is_input = bool(user_input_contexts)
|
|
562
|
+
if is_input and user_input_contexts and branch_name == "default":
|
|
377
563
|
branch_name = user_input_contexts[-1]
|
|
378
564
|
value = self._to_array(value, validate_nan=validate_nan)
|
|
379
565
|
if self.variable.definition_period != periods.ETERNITY:
|
|
@@ -389,15 +575,38 @@ class Holder:
|
|
|
389
575
|
>= self.simulation.memory_config.max_memory_occupation_pc
|
|
390
576
|
)
|
|
391
577
|
|
|
578
|
+
stored_period = (
|
|
579
|
+
self._storage_period(period)
|
|
580
|
+
if is_input
|
|
581
|
+
or hasattr(self, "_user_input_storage")
|
|
582
|
+
or (not derived and getattr(simulation, "_user_input_keys", None))
|
|
583
|
+
else None
|
|
584
|
+
)
|
|
585
|
+
if stored_period is not None:
|
|
586
|
+
self._seed_input_storage(stored_period, branch_name)
|
|
587
|
+
|
|
392
588
|
if should_store_on_disk:
|
|
393
589
|
self._disk_storage.put(value, period, branch_name, derived=derived)
|
|
394
590
|
else:
|
|
395
591
|
self._memory_storage.put(value, period, branch_name, derived=derived)
|
|
396
592
|
self._evict_fast_cache(period, branch_name)
|
|
397
|
-
if
|
|
593
|
+
if stored_period is not None:
|
|
594
|
+
self._record_input_storage(
|
|
595
|
+
stored_period,
|
|
596
|
+
branch_name,
|
|
597
|
+
"disk" if should_store_on_disk else "memory",
|
|
598
|
+
is_input=is_input,
|
|
599
|
+
)
|
|
600
|
+
if is_input and simulation is not None:
|
|
398
601
|
if not hasattr(simulation, "_user_input_keys"):
|
|
399
602
|
simulation._user_input_keys = set()
|
|
400
|
-
|
|
603
|
+
# Record the period as storage keys the value (eternity for an
|
|
604
|
+
# eternal variable, whatever period it was set for; the year for
|
|
605
|
+
# twelve months starting on the first of a month), so each entry
|
|
606
|
+
# names one stored value.
|
|
607
|
+
simulation._user_input_keys.add(
|
|
608
|
+
(self.variable.name, branch_name, stored_period)
|
|
609
|
+
)
|
|
401
610
|
|
|
402
611
|
def put_in_cache(
|
|
403
612
|
self,
|
|
@@ -436,7 +645,7 @@ class Holder:
|
|
|
436
645
|
):
|
|
437
646
|
return
|
|
438
647
|
|
|
439
|
-
self._set(period, value, branch_name, derived=derived)
|
|
648
|
+
self._set(period, value, branch_name, is_input=False, derived=derived)
|
|
440
649
|
|
|
441
650
|
def default_array(self) -> ArrayLike:
|
|
442
651
|
"""
|
{policyengine_core-3.32.26 → policyengine_core-3.32.28}/policyengine_core/simulations/simulation.py
RENAMED
|
@@ -301,7 +301,11 @@ class Simulation:
|
|
|
301
301
|
# populates so ``_invalidate_all_caches`` can tell user-provided
|
|
302
302
|
# source data apart from formula-computed caches. Without this the
|
|
303
303
|
# post-``apply_reform`` cache wipe would also wipe the dataset the
|
|
304
|
-
# simulation was loaded from.
|
|
304
|
+
# simulation was loaded from. The record follows this simulation's
|
|
305
|
+
# storage: each entry names one stored value (the period is the one
|
|
306
|
+
# storage keys it under), ``delete_arrays`` drops the entries for the
|
|
307
|
+
# values it deletes, and ``clone`` (so also ``get_branch``) gives the
|
|
308
|
+
# copy its own record.
|
|
305
309
|
self._user_input_keys: set[tuple[str, str, Period]] = set()
|
|
306
310
|
self.debug: bool = False
|
|
307
311
|
self.trace: bool = trace
|
|
@@ -433,11 +437,11 @@ class Simulation:
|
|
|
433
437
|
Called after ``apply_reform`` and any other operation that changes
|
|
434
438
|
the tax-benefit system underneath an already-calculated simulation.
|
|
435
439
|
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
(formula outputs, cached short-path results, on-disk caches) is
|
|
440
|
+
Still-present supplied inputs are preserved from the tiers that
|
|
441
|
+
hold them, so a structural reform applied after dataset load
|
|
442
|
+
doesn't silently discard the dataset. A cache write replacing an
|
|
443
|
+
input does not make that cached value a supplied input. Everything
|
|
444
|
+
else (formula outputs, cached short-path results, on-disk caches) is
|
|
441
445
|
wiped so the next ``calculate`` recomputes under the new
|
|
442
446
|
tax-benefit system.
|
|
443
447
|
"""
|
|
@@ -451,7 +455,16 @@ class Simulation:
|
|
|
451
455
|
user_input_keys = getattr(self, "_user_input_keys", None) or set()
|
|
452
456
|
for variable_name, branch_name, period in user_input_keys:
|
|
453
457
|
holder = self.get_holder(variable_name)
|
|
454
|
-
|
|
458
|
+
holder._seed_input_storage(period, branch_name)
|
|
459
|
+
locations = holder._user_input_storage[(branch_name, str(period))][1]
|
|
460
|
+
# Carry-over marks also include external cache writes. Replay
|
|
461
|
+
# only tiers that still hold the recorded, supplied input.
|
|
462
|
+
stored_value = (
|
|
463
|
+
holder._memory_storage.get(period, branch_name)
|
|
464
|
+
if "memory" in locations
|
|
465
|
+
and not holder._memory_storage.is_derived(period, branch_name)
|
|
466
|
+
else None
|
|
467
|
+
)
|
|
455
468
|
if stored_value is not None:
|
|
456
469
|
preserved.append(
|
|
457
470
|
PreservedUserInput(
|
|
@@ -463,7 +476,11 @@ class Simulation:
|
|
|
463
476
|
)
|
|
464
477
|
)
|
|
465
478
|
continue
|
|
466
|
-
if
|
|
479
|
+
if (
|
|
480
|
+
"disk" in locations
|
|
481
|
+
and holder._disk_storage is not None
|
|
482
|
+
and not holder._disk_storage.is_derived(period, branch_name)
|
|
483
|
+
):
|
|
467
484
|
disk_period = (
|
|
468
485
|
periods.period(periods.ETERNITY)
|
|
469
486
|
if holder._disk_storage.is_eternal
|
|
@@ -484,6 +501,10 @@ class Simulation:
|
|
|
484
501
|
disk_enum=holder._disk_storage._enums.get(disk_file),
|
|
485
502
|
)
|
|
486
503
|
)
|
|
504
|
+
self._user_input_keys = {
|
|
505
|
+
(user_input.variable_name, user_input.branch_name, user_input.period)
|
|
506
|
+
for user_input in preserved
|
|
507
|
+
}
|
|
487
508
|
# Iterate only over holders that already exist on each population —
|
|
488
509
|
# lazy-creating a holder for every variable in the tax-benefit
|
|
489
510
|
# system (thousands in policyengine-us) inflated the cost of
|
|
@@ -497,6 +518,8 @@ class Simulation:
|
|
|
497
518
|
if holder._disk_storage is not None:
|
|
498
519
|
holder._disk_storage._files = {}
|
|
499
520
|
holder._disk_storage._derived = set()
|
|
521
|
+
if hasattr(holder, "_user_input_storage"):
|
|
522
|
+
holder._user_input_storage = {}
|
|
500
523
|
# Replay preserved user inputs so ``calculate`` still sees them.
|
|
501
524
|
for user_input in preserved:
|
|
502
525
|
holder = self.get_holder(user_input.variable_name)
|
|
@@ -512,6 +535,9 @@ class Simulation:
|
|
|
512
535
|
user_input.period,
|
|
513
536
|
user_input.branch_name,
|
|
514
537
|
)
|
|
538
|
+
holder._record_input_storage(
|
|
539
|
+
user_input.period, user_input.branch_name, user_input.storage
|
|
540
|
+
)
|
|
515
541
|
for branch in self.branches.values():
|
|
516
542
|
branch._invalidate_all_caches()
|
|
517
543
|
|
|
@@ -1316,12 +1342,7 @@ class Simulation:
|
|
|
1316
1342
|
result = sum(
|
|
1317
1343
|
self.calculate(variable_name, sub_period) for sub_period in sub_periods
|
|
1318
1344
|
)
|
|
1319
|
-
|
|
1320
|
-
# single sub-period's value is already stored, as an input or
|
|
1321
|
-
# derived, by ``calculate``.
|
|
1322
|
-
if len(sub_periods) > 1:
|
|
1323
|
-
holder = self.get_holder(variable.name)
|
|
1324
|
-
holder.put_in_cache(result, period, self.branch_name, derived=True)
|
|
1345
|
+
self._cache_option_result(variable, period, result)
|
|
1325
1346
|
return result
|
|
1326
1347
|
|
|
1327
1348
|
def calculate_divide(
|
|
@@ -1353,8 +1374,7 @@ class Simulation:
|
|
|
1353
1374
|
if period.unit == periods.MONTH:
|
|
1354
1375
|
computation_period = period.this_year
|
|
1355
1376
|
result = self.calculate(variable_name, period=computation_period) / 12.0
|
|
1356
|
-
|
|
1357
|
-
holder.put_in_cache(result, period, self.branch_name, derived=True)
|
|
1377
|
+
self._cache_option_result(variable, period, result)
|
|
1358
1378
|
return result
|
|
1359
1379
|
elif period.unit == periods.YEAR:
|
|
1360
1380
|
return self.calculate(variable_name, period)
|
|
@@ -1365,6 +1385,55 @@ class Simulation:
|
|
|
1365
1385
|
)
|
|
1366
1386
|
)
|
|
1367
1387
|
|
|
1388
|
+
def _cache_option_result(
|
|
1389
|
+
self, variable: Variable, period: Period, result: ArrayLike
|
|
1390
|
+
) -> None:
|
|
1391
|
+
"""Cache an ADD or DIVIDE result at ``period`` if a plain read would return it.
|
|
1392
|
+
|
|
1393
|
+
A value cached at ``period`` is what every later ``calculate`` of the
|
|
1394
|
+
variable at ``period`` returns. ``_calculate`` computes a FLOW
|
|
1395
|
+
variable over a period of another unit with these same options (a
|
|
1396
|
+
monthly variable over a year with ``calculate_add``, a yearly one over
|
|
1397
|
+
a month with ``calculate_divide``), so their result is the plain value
|
|
1398
|
+
there and is cached. Anywhere else it is not:
|
|
1399
|
+
|
|
1400
|
+
- A STOCK variable's plain value over a year is its last month's, and
|
|
1401
|
+
over a month the year's, not the sum or the twelfth.
|
|
1402
|
+
- Over several periods of the variable's own unit, a plain read
|
|
1403
|
+
raises instead.
|
|
1404
|
+
- A day variable's plain read over a month or a year does not sum.
|
|
1405
|
+
- Over a single period of its own unit, the sum is the value
|
|
1406
|
+
``calculate`` has already stored.
|
|
1407
|
+
|
|
1408
|
+
Caching there would make a later plain read depend on whether the
|
|
1409
|
+
option ran first. Nor is an option result cached when storing it would
|
|
1410
|
+
change it (the twelfth of an integer or a count of true months is
|
|
1411
|
+
stored as the variable's own type, so a later read would return the
|
|
1412
|
+
truncated value where the first returned the exact one).
|
|
1413
|
+
|
|
1414
|
+
The result is cached as derived, so auto-carry-over and uprating
|
|
1415
|
+
never take it for an input, and ``put_in_cache`` keeps an input a
|
|
1416
|
+
plain read finds at ``period`` (in this branch, an ancestor or
|
|
1417
|
+
``default``) instead of storing it. It does replace a value
|
|
1418
|
+
calculated there before, which may predate a change to the inputs.
|
|
1419
|
+
Whether the value read is an input comes from the storage's mark for
|
|
1420
|
+
the first visible value, which every write sets. The simulation's
|
|
1421
|
+
supplied-input record follows inputs across storage tiers for replay
|
|
1422
|
+
and export; it can name a disk input hidden by a derived memory value,
|
|
1423
|
+
and raw holder inputs need not be registered there. Accepted cache
|
|
1424
|
+
writes never register the aggregate as a supplied input.
|
|
1425
|
+
"""
|
|
1426
|
+
if variable.quantity_type == QuantityType.STOCK:
|
|
1427
|
+
return
|
|
1428
|
+
routed = (variable.definition_period == MONTH and period.unit == YEAR) or (
|
|
1429
|
+
variable.definition_period == YEAR and period.unit == MONTH
|
|
1430
|
+
)
|
|
1431
|
+
if not routed or np.asarray(result).dtype != variable.dtype:
|
|
1432
|
+
return
|
|
1433
|
+
self.get_holder(variable.name).put_in_cache(
|
|
1434
|
+
result, period, self.branch_name, derived=True
|
|
1435
|
+
)
|
|
1436
|
+
|
|
1368
1437
|
def calculate_output(self, variable_name: str, period: Period = None) -> ArrayLike:
|
|
1369
1438
|
"""
|
|
1370
1439
|
Calculate the value of a variable using the ``calculate_output`` attribute of the variable.
|
|
@@ -1628,6 +1697,9 @@ class Simulation:
|
|
|
1628
1697
|
The calling branch, each ancestor branch, and the default branch are
|
|
1629
1698
|
purged from this simulation's private holder storage. Other branch
|
|
1630
1699
|
names and the parent simulation's holder storage remain unchanged.
|
|
1700
|
+
Deleted inputs stop counting as inputs: a value calculated later for
|
|
1701
|
+
the same period is a formula result, which ``apply_reform`` discards
|
|
1702
|
+
and ``to_input_dataframe`` does not export.
|
|
1631
1703
|
|
|
1632
1704
|
:param variable: the variable whose cached values should be deleted
|
|
1633
1705
|
:param period: the period to delete, or all periods when omitted
|
|
@@ -1884,6 +1956,8 @@ class Simulation:
|
|
|
1884
1956
|
new.tax_benefit_system = self.tax_benefit_system
|
|
1885
1957
|
new.debug = debug
|
|
1886
1958
|
new.trace = trace
|
|
1959
|
+
# A ``set_input`` running on this simulation is not running on the copy.
|
|
1960
|
+
new._user_input_contexts = []
|
|
1887
1961
|
|
|
1888
1962
|
# A branch shares its parent's baseline: formulas that run in a
|
|
1889
1963
|
# branch read the parent's baseline values through it. That holds for
|
|
@@ -2371,8 +2445,11 @@ class Simulation:
|
|
|
2371
2445
|
|
|
2372
2446
|
df = subset_df
|
|
2373
2447
|
|
|
2374
|
-
# Update the dataset and rebuild the simulation
|
|
2448
|
+
# Update the dataset and rebuild the simulation. Rebuilding replaces
|
|
2449
|
+
# every stored value, so the record of inputs starts again with the
|
|
2450
|
+
# ones the rebuild sets.
|
|
2375
2451
|
self.dataset = Dataset.from_dataframe(df, self.dataset.time_period)
|
|
2452
|
+
self._user_input_keys = set()
|
|
2376
2453
|
self.build_from_dataset()
|
|
2377
2454
|
|
|
2378
2455
|
# Purge ``_fast_cache`` entries populated by ``to_input_dataframe``
|