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.
Files changed (405) hide show
  1. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/CHANGELOG.md +14 -0
  2. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/PKG-INFO +1 -1
  3. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/simulation.py +51 -7
  4. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/hugging_face.py +20 -4
  5. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/variable.py +1 -1
  6. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/pyproject.toml +1 -1
  7. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tools/test_hugging_face.py +147 -0
  8. policyengine_core-3.32.9/tests/core/variables/test_variable_uprating.py +244 -0
  9. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/ISSUE_TEMPLATE.md +0 -0
  10. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/PULL_REQUEST_TEMPLATE.md +0 -0
  11. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/bump_version.py +0 -0
  12. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/changelog_template.md +0 -0
  13. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/get-changelog-diff.sh +0 -0
  14. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/has-functional-changes.sh +0 -0
  15. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/is-version-number-acceptable.sh +0 -0
  16. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/publish-git-tag.sh +0 -0
  17. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/requirements/legacy-country-smoke.txt +0 -0
  18. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/workflows/pr.yaml +0 -0
  19. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.github/workflows/push.yaml +0 -0
  20. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.gitignore +0 -0
  21. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/.python-version +0 -0
  22. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/AGENTS.md +0 -0
  23. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/CLAUDE.md +0 -0
  24. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/CONTRIBUTING.md +0 -0
  25. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/LICENSE +0 -0
  26. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/MANIFEST.in +0 -0
  27. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/Makefile +0 -0
  28. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/README.md +0 -0
  29. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/_build/logs/myst.build.json +0 -0
  30. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/changelog.d/.gitkeep +0 -0
  31. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/_config.yml +0 -0
  32. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/_static/style.css +0 -0
  33. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/_toc.yml +0 -0
  34. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/add_plotly_to_book.py +0 -0
  35. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/contributing/intro.md +0 -0
  36. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/engineering/skills/README.md +0 -0
  37. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/engineering/skills/documentation_review.md +0 -0
  38. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/engineering/skills/github-prs.md +0 -0
  39. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/engineering/skills/testing.md +0 -0
  40. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/intro.md +0 -0
  41. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/logo.png +0 -0
  42. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/commons.md +0 -0
  43. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/country_template.md +0 -0
  44. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/data.md +0 -0
  45. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/data_storage.md +0 -0
  46. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/entities.md +0 -0
  47. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/enums.md +0 -0
  48. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/errors.md +0 -0
  49. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/experimental.md +0 -0
  50. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/extension_template.md +0 -0
  51. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/holders.md +0 -0
  52. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/parameters.md +0 -0
  53. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/periods.md +0 -0
  54. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/populations.md +0 -0
  55. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/projectors.md +0 -0
  56. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/reforms.md +0 -0
  57. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/scripts.md +0 -0
  58. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/simulations.md +0 -0
  59. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/taxbenefitsystems.md +0 -0
  60. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/taxscales.md +0 -0
  61. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/tools.md +0 -0
  62. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/tracers.md +0 -0
  63. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/types.md +0 -0
  64. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/variables.md +0 -0
  65. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/python_api/warnings.md +0 -0
  66. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/usage/country.ipynb +0 -0
  67. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/usage/datasets.ipynb +0 -0
  68. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/usage/parameters.md +0 -0
  69. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/usage/reforms.ipynb +0 -0
  70. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/docs/usage/simulation.ipynb +0 -0
  71. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/mypy.ini +0 -0
  72. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/__init__.py +0 -0
  73. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/build_metadata.py +0 -0
  74. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/charts/__init__.py +0 -0
  75. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/charts/api.py +0 -0
  76. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/charts/bar.py +0 -0
  77. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/charts/formatting.py +0 -0
  78. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/commons/__init__.py +0 -0
  79. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/commons/formulas.py +0 -0
  80. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/commons/misc.py +0 -0
  81. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/commons/rates.py +0 -0
  82. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/__init__.py +0 -0
  83. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/constants.py +0 -0
  84. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/data/__init__.py +0 -0
  85. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/data/datasets/__init__.py +0 -0
  86. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/data/datasets/country_template_dataset.py +0 -0
  87. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/entities.py +0 -0
  88. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/modelled_policies.yaml +0 -0
  89. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/benefits/basic_income.yaml +0 -0
  90. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/benefits/housing_allowance.yaml +0 -0
  91. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/benefits/index.yaml +0 -0
  92. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/benefits/parenting_allowance/amount.yaml +0 -0
  93. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/benefits/parenting_allowance/income_threshold.yaml +0 -0
  94. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/general/age_of_majority.yaml +0 -0
  95. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/general/age_of_retirement.yaml +0 -0
  96. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/taxes/housing_tax.yaml +0 -0
  97. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/taxes/income_tax_rate.yaml +0 -0
  98. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/parameters/taxes/social_security_contribution.yaml +0 -0
  99. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/__init__.py +0 -0
  100. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/add_dynamic_variable.py +0 -0
  101. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/add_new_tax.py +0 -0
  102. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/flat_social_security_contribution.py +0 -0
  103. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/modify_social_security_taxation.py +0 -0
  104. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/reforms/removal_basic_income.py +0 -0
  105. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/situation_examples/__init__.py +0 -0
  106. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/situation_examples/couple.json +0 -0
  107. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/situation_examples/housing.json +0 -0
  108. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/situation_examples/single.json +0 -0
  109. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/age.yaml +0 -0
  110. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/basic_income.yaml +0 -0
  111. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/disposable_income.yaml +0 -0
  112. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/housing_allowance.yaml +0 -0
  113. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/housing_tax.yaml +0 -0
  114. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/income_tax.yaml +0 -0
  115. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/reforms/add_dynamic_variable.yaml +0 -0
  116. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/reforms/add_new_tax.yaml +0 -0
  117. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/reforms/modify_social_security_taxation.yaml +0 -0
  118. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/situations/income_tax.yaml +0 -0
  119. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/situations/parenting_allowance.yaml +0 -0
  120. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/social_security_contribution.yaml +0 -0
  121. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/tests/test_microsimulation.py +0 -0
  122. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/__init__.py +0 -0
  123. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/benefits.py +0 -0
  124. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/demographics.py +0 -0
  125. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/housing.py +0 -0
  126. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/ids.py +0 -0
  127. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/income.py +0 -0
  128. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/stats.py +0 -0
  129. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/country_template/variables/taxes.py +0 -0
  130. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data/__init__.py +0 -0
  131. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data/dataset.py +0 -0
  132. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_storage/__init__.py +0 -0
  133. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_storage/in_memory_storage.py +0 -0
  134. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_storage/on_disk_storage.py +0 -0
  135. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_structures/__init__.py +0 -0
  136. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_structures/parameter_metadata.py +0 -0
  137. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_structures/parameter_node_metadata.py +0 -0
  138. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_structures/reference.py +0 -0
  139. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/data_structures/unit.py +0 -0
  140. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/entities/__init__.py +0 -0
  141. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/entities/entity.py +0 -0
  142. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/entities/group_entity.py +0 -0
  143. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/entities/helpers.py +0 -0
  144. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/entities/role.py +0 -0
  145. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/enums/__init__.py +0 -0
  146. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/enums/config.py +0 -0
  147. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/enums/enum.py +0 -0
  148. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/enums/enum_array.py +0 -0
  149. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/__init__.py +0 -0
  150. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/cycle_error.py +0 -0
  151. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/empty_argument_error.py +0 -0
  152. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/nan_creation_error.py +0 -0
  153. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/non_deterministic_formula_error.py +0 -0
  154. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/parameter_not_found_error.py +0 -0
  155. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/parameter_parsing_error.py +0 -0
  156. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/period_mismatch_error.py +0 -0
  157. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/situation_parsing_error.py +0 -0
  158. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/spiral_error.py +0 -0
  159. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/variable_name_conflict_error.py +0 -0
  160. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/errors/variable_not_found_error.py +0 -0
  161. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/experimental/__init__.py +0 -0
  162. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/experimental/memory_config.py +0 -0
  163. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/__init__.py +0 -0
  164. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/local_benefit.py +0 -0
  165. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/parameters/local_town/child_allowance/amount.yaml +0 -0
  166. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/parameters/local_town/child_allowance/index.yaml +0 -0
  167. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/parameters/local_town/index.yaml +0 -0
  168. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/extension_template/tests/local_benefit.yaml +0 -0
  169. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/holders/__init__.py +0 -0
  170. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/holders/helpers.py +0 -0
  171. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/holders/holder.py +0 -0
  172. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/model_api.py +0 -0
  173. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/__init__.py +0 -0
  174. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/at_instant_like.py +0 -0
  175. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/config.py +0 -0
  176. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/helpers.py +0 -0
  177. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/__init__.py +0 -0
  178. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/get_parameter.py +0 -0
  179. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/homogenize_parameters.py +0 -0
  180. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/interpolate_parameters.py +0 -0
  181. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/propagate_parameter_metadata.py +0 -0
  182. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/operations/uprate_parameters.py +0 -0
  183. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter.py +0 -0
  184. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter_at_instant.py +0 -0
  185. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter_node.py +0 -0
  186. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter_node_at_instant.py +0 -0
  187. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter_scale.py +0 -0
  188. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/parameter_scale_bracket.py +0 -0
  189. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/parameters/vectorial_parameter_node_at_instant.py +0 -0
  190. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/periods/__init__.py +0 -0
  191. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/periods/config.py +0 -0
  192. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/periods/helpers.py +0 -0
  193. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/periods/instant_.py +0 -0
  194. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/periods/period_.py +0 -0
  195. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/populations/__init__.py +0 -0
  196. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/populations/config.py +0 -0
  197. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/populations/group_population.py +0 -0
  198. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/populations/population.py +0 -0
  199. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/__init__.py +0 -0
  200. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/entity_to_person_projector.py +0 -0
  201. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/first_person_to_entity_projector.py +0 -0
  202. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/helpers.py +0 -0
  203. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/projector.py +0 -0
  204. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/projectors/unique_role_to_entity_projector.py +0 -0
  205. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/reforms/__init__.py +0 -0
  206. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/reforms/reform.py +0 -0
  207. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/__init__.py +0 -0
  208. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/assets/__init__.py +0 -0
  209. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/assets/index.html +0 -0
  210. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/policyengine_command.py +0 -0
  211. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/run_data.py +0 -0
  212. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/run_test.py +0 -0
  213. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/scripts/simulation_generator.py +0 -0
  214. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/__init__.py +0 -0
  215. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/helpers.py +0 -0
  216. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/individual_sim.py +0 -0
  217. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/microsimulation.py +0 -0
  218. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/simulation_builder.py +0 -0
  219. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/simulations/simulation_macro_cache.py +0 -0
  220. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxbenefitsystems/__init__.py +0 -0
  221. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxbenefitsystems/tax_benefit_system.py +0 -0
  222. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/__init__.py +0 -0
  223. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/abstract_rate_tax_scale.py +0 -0
  224. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/abstract_tax_scale.py +0 -0
  225. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/amount_tax_scale_like.py +0 -0
  226. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/helpers.py +0 -0
  227. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/linear_average_rate_tax_scale.py +0 -0
  228. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/marginal_amount_tax_scale.py +0 -0
  229. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/marginal_rate_tax_scale.py +0 -0
  230. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/rate_tax_scale_like.py +0 -0
  231. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/single_amount_tax_scale.py +0 -0
  232. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/taxscales/tax_scale_like.py +0 -0
  233. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/__init__.py +0 -0
  234. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/google_cloud.py +0 -0
  235. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/simulation_dumper.py +0 -0
  236. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/test_from_situation.py +0 -0
  237. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/test_runner.py +0 -0
  238. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tools/win_file_manager.py +0 -0
  239. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/__init__.py +0 -0
  240. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/computation_log.py +0 -0
  241. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/flat_trace.py +0 -0
  242. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/full_tracer.py +0 -0
  243. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/performance_log.py +0 -0
  244. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/simple_tracer.py +0 -0
  245. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/trace_node.py +0 -0
  246. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/tracing_parameter_node_at_instant.py +0 -0
  247. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/tracers/variable_graph.py +0 -0
  248. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/types/__init__.py +0 -0
  249. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/types/data_types/__init__.py +0 -0
  250. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/types/data_types/arrays.py +0 -0
  251. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/__init__.py +0 -0
  252. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/config.py +0 -0
  253. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/defined_for.py +0 -0
  254. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/formula_randomness.py +0 -0
  255. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/helpers.py +0 -0
  256. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/variables/typing.py +0 -0
  257. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/warnings/__init__.py +0 -0
  258. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/warnings/libyaml_warning.py +0 -0
  259. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/warnings/memory_config_warning.py +0 -0
  260. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/warnings/parameter_key_warning.py +0 -0
  261. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/policyengine_core/warnings/tempfile_warning.py +0 -0
  262. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/pytest.ini +0 -0
  263. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/__init__.py +0 -0
  264. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/conftest.py +0 -0
  265. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/__init__.py +0 -0
  266. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/__init__.py +0 -0
  267. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/test_between_function.py +0 -0
  268. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/test_formulas.py +0 -0
  269. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/test_is_in_function.py +0 -0
  270. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/test_random_seed.py +0 -0
  271. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/commons/test_rates.py +0 -0
  272. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/data/test_dataset.py +0 -0
  273. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/enums/test_enum.py +0 -0
  274. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/model_api/test_index_.py +0 -0
  275. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/__init__.py +0 -0
  276. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/array_type.yaml +0 -0
  277. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/duplicate_key.yaml +0 -0
  278. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/filesystem_hierarchy/empty_index_file/index.yaml +0 -0
  279. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/filesystem_hierarchy/node1/param.yaml +0 -0
  280. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/indentation.yaml +0 -0
  281. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/missing_value.yaml +0 -0
  282. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/parameter_for_unit_propagation.yaml +0 -0
  283. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/test_parameter_clone.py +0 -0
  284. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/test_parameter_validation.py +0 -0
  285. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/test_propagate_units.py +0 -0
  286. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/test_unknown_keys.py +0 -0
  287. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/unexpected_key_in_parameter.yaml +0 -0
  288. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/unexpected_key_in_scale.yaml +0 -0
  289. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/unexpected_key_in_value_at_instant.yaml +0 -0
  290. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/unexpected_key_in_value_history.yaml +0 -0
  291. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/unknown_key_beside_values.yaml +0 -0
  292. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/uprating_under_metadata.yaml +0 -0
  293. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_date.yaml +0 -0
  294. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_scale.yaml +0 -0
  295. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_type_in_bracket.yaml +0 -0
  296. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_type_in_brackets.yaml +0 -0
  297. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_type_in_parameter.yaml +0 -0
  298. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_type_in_scale.yaml +0 -0
  299. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_type_in_value_history.yaml +0 -0
  300. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/wrong_value.yaml +0 -0
  301. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameter_validation/yaml_hierarchy/node1.yaml +0 -0
  302. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/operations/test_interpolation.py +0 -0
  303. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/operations/test_nesting.py +0 -0
  304. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/operations/test_propagation.py +0 -0
  305. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/operations/test_scale_threshold_uprating.py +0 -0
  306. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/operations/test_uprating.py +0 -0
  307. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters/test_numpy2_structured_arrays.py +0 -0
  308. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters_fancy_indexing/__init__.py +0 -0
  309. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters_fancy_indexing/bareme.yaml +0 -0
  310. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters_fancy_indexing/local_tax.yaml +0 -0
  311. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters_fancy_indexing/rate.yaml +0 -0
  312. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/parameters_fancy_indexing/test_fancy_indexing.py +0 -0
  313. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/simulations/test_formula_randomness_concurrency.py +0 -0
  314. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/__init__.py +0 -0
  315. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_abstract_rate_tax_scale.py +0 -0
  316. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_abstract_tax_scale.py +0 -0
  317. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_linear_average_rate_tax_scale.py +0 -0
  318. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_marginal_amount_tax_scale.py +0 -0
  319. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_marginal_rate_tax_scale.py +0 -0
  320. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_rate_tax_scale_like.py +0 -0
  321. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_single_amount_tax_scale.py +0 -0
  322. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tax_scales/test_tax_scales_commons.py +0 -0
  323. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_apply_reform_invalidates_cache.py +0 -0
  324. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_apply_reform_preserves_user_inputs.py +0 -0
  325. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_assert_near_precision.py +0 -0
  326. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_axes.py +0 -0
  327. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_bincount_minlength.py +0 -0
  328. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_branch_scoped_delete_arrays.py +0 -0
  329. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_build_metadata.py +0 -0
  330. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_calculate_output.py +0 -0
  331. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_countries.py +0 -0
  332. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_cycles.py +0 -0
  333. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_dataset_getattr.py +0 -0
  334. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_dataset_unknown_column_warning.py +0 -0
  335. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_dump_restore.py +0 -0
  336. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_entities.py +0 -0
  337. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_eternity_subperiods.py +0 -0
  338. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_extensions.py +0 -0
  339. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_fast_cache.py +0 -0
  340. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_fast_cache_guards.py +0 -0
  341. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_formulas.py +0 -0
  342. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_holder_branch_fallback.py +0 -0
  343. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_holders.py +0 -0
  344. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_macro_cache_not_singleton.py +0 -0
  345. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_medium_fixes.py +0 -0
  346. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_microsimulation_person_accessor.py +0 -0
  347. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_microsimulation_weights.py +0 -0
  348. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_opt_out_cache.py +0 -0
  349. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_pandas3_compatibility.py +0 -0
  350. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_parameter_security.py +0 -0
  351. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_parameters.py +0 -0
  352. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_periods.py +0 -0
  353. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_projectors.py +0 -0
  354. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_reform_parameter_isolation.py +0 -0
  355. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_reform_period_keys.py +0 -0
  356. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_reforms.py +0 -0
  357. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_release_tagging.py +0 -0
  358. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_simulation_builder.py +0 -0
  359. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_simulations.py +0 -0
  360. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_stable_hash_seed.py +0 -0
  361. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_storage_anchored_periods.py +0 -0
  362. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_storage_delete_branch.py +0 -0
  363. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_subsample_baseline_branch.py +0 -0
  364. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_subsample_invalidates_cache.py +0 -0
  365. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_tax_benefit_system_cache_identity.py +0 -0
  366. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_tracers.py +0 -0
  367. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/test_yaml.py +0 -0
  368. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tools/__init__.py +0 -0
  369. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tools/test_assert_near.py +0 -0
  370. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tools/test_google_cloud.py +0 -0
  371. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/tools/test_runner/test_yaml_runner.py +0 -0
  372. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_adds.py +0 -0
  373. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_annualize.py +0 -0
  374. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_bounds.py +0 -0
  375. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_defined_for.py +0 -0
  376. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_formula_randomness.py +0 -0
  377. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_subtracts.py +0 -0
  378. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_subtracts_sign.py +0 -0
  379. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_variable_clone.py +0 -0
  380. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_variable_formula_determinism.py +0 -0
  381. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/core/variables/test_variables.py +0 -0
  382. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/__init__.py +0 -0
  383. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/appclient.py +0 -0
  384. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/entities.py +0 -0
  385. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/simulations.py +0 -0
  386. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/taxbenefitsystems.py +0 -0
  387. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/variables.py +0 -0
  388. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/__init__.py +0 -0
  389. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/directory/subdirectory/test_4.yaml +0 -0
  390. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/directory/test_1.yaml +0 -0
  391. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/directory/test_2.yaml +0 -0
  392. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/failing_test_absolute_error_margin.yaml +0 -0
  393. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/failing_test_relative_error_margin.yaml +0 -0
  394. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_absolute_error_margin.yaml +0 -0
  395. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_failure.yaml +0 -0
  396. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_name_filter.yaml +0 -0
  397. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_relative_error_margin.yaml +0 -0
  398. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_success.yml +0 -0
  399. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_with_anchors.yaml +0 -0
  400. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_with_extension.yaml +0 -0
  401. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_with_reform.yaml +0 -0
  402. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/fixtures/yaml_tests/test_with_reform_2.yaml +0 -0
  403. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/smoke/test_country_init.py +0 -0
  404. {policyengine_core-3.32.7 → policyengine_core-3.32.9}/tests/smoke/test_us.py +0 -0
  405. {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.7
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>
@@ -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
- start_instants = [
840
- str(known_period.start)
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(start_instants) > 0:
846
- latest_known_period = known_periods[np.argmax(start_instants)]
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 = uprating_parameter(latest_known_period.start)
857
- value_in_this_period = uprating_parameter(period.start)
858
- if value_in_last_period == 0:
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
@@ -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 is private
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
- is_repo_private = bool(fetched_model_info.private)
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
- is_repo_private = True
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 is_repo_private:
105
+ if requires_authentication:
90
106
  authentication_token = get_or_prompt_hf_token()
91
107
 
92
108
  return hf_hub_download(
@@ -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."""
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "policyengine-core"
3
- version = "3.32.7"
3
+ version = "3.32.9"
4
4
  description = "Core microsimulation engine enabling country-specific policy models."
5
5
  readme = "README.md"
6
6
  authors = [
@@ -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