OpenFisca-Core-test 46.0.0__py3-none-any.whl

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 (237) hide show
  1. openfisca_core/__init__.py +0 -0
  2. openfisca_core/commons/__init__.py +18 -0
  3. openfisca_core/commons/dummy.py +25 -0
  4. openfisca_core/commons/formulas.py +121 -0
  5. openfisca_core/commons/misc.py +109 -0
  6. openfisca_core/commons/py.typed +0 -0
  7. openfisca_core/commons/rates.py +114 -0
  8. openfisca_core/commons/tests/__init__.py +0 -0
  9. openfisca_core/commons/tests/test_dummy.py +9 -0
  10. openfisca_core/commons/tests/test_formulas.py +75 -0
  11. openfisca_core/commons/tests/test_rates.py +26 -0
  12. openfisca_core/data_storage/__init__.py +7 -0
  13. openfisca_core/data_storage/in_memory_storage.py +198 -0
  14. openfisca_core/data_storage/on_disk_storage.py +307 -0
  15. openfisca_core/data_storage/types.py +14 -0
  16. openfisca_core/entities/__init__.py +23 -0
  17. openfisca_core/entities/_core_entity.py +217 -0
  18. openfisca_core/entities/_description.py +55 -0
  19. openfisca_core/entities/entity.py +60 -0
  20. openfisca_core/entities/group_entity.py +123 -0
  21. openfisca_core/entities/helpers.py +165 -0
  22. openfisca_core/entities/py.typed +0 -0
  23. openfisca_core/entities/role.py +92 -0
  24. openfisca_core/entities/tests/__init__.py +0 -0
  25. openfisca_core/entities/tests/test_entity.py +10 -0
  26. openfisca_core/entities/tests/test_group_entity.py +70 -0
  27. openfisca_core/entities/tests/test_role.py +11 -0
  28. openfisca_core/entities/types.py +44 -0
  29. openfisca_core/errors/__init__.py +64 -0
  30. openfisca_core/errors/cycle_error.py +2 -0
  31. openfisca_core/errors/empty_argument_error.py +39 -0
  32. openfisca_core/errors/nan_creation_error.py +2 -0
  33. openfisca_core/errors/parameter_not_found_error.py +16 -0
  34. openfisca_core/errors/parameter_parsing_error.py +18 -0
  35. openfisca_core/errors/period_mismatch_error.py +9 -0
  36. openfisca_core/errors/situation_parsing_error.py +26 -0
  37. openfisca_core/errors/spiral_error.py +2 -0
  38. openfisca_core/errors/variable_name_config_error.py +2 -0
  39. openfisca_core/errors/variable_not_found_error.py +29 -0
  40. openfisca_core/experimental/__init__.py +9 -0
  41. openfisca_core/experimental/_errors.py +5 -0
  42. openfisca_core/experimental/_memory_config.py +41 -0
  43. openfisca_core/formula_helpers.py +9 -0
  44. openfisca_core/holders/__init__.py +33 -0
  45. openfisca_core/holders/helpers.py +93 -0
  46. openfisca_core/holders/holder.py +328 -0
  47. openfisca_core/holders/tests/__init__.py +0 -0
  48. openfisca_core/holders/tests/test_helpers.py +134 -0
  49. openfisca_core/holders/types.py +3 -0
  50. openfisca_core/indexed_enums/__init__.py +18 -0
  51. openfisca_core/indexed_enums/_enum_type.py +79 -0
  52. openfisca_core/indexed_enums/_errors.py +35 -0
  53. openfisca_core/indexed_enums/_guards.py +209 -0
  54. openfisca_core/indexed_enums/_utils.py +180 -0
  55. openfisca_core/indexed_enums/config.py +6 -0
  56. openfisca_core/indexed_enums/enum.py +218 -0
  57. openfisca_core/indexed_enums/enum_array.py +316 -0
  58. openfisca_core/indexed_enums/py.typed +0 -0
  59. openfisca_core/indexed_enums/tests/__init__.py +0 -0
  60. openfisca_core/indexed_enums/tests/test_enum.py +135 -0
  61. openfisca_core/indexed_enums/tests/test_enum_array.py +30 -0
  62. openfisca_core/indexed_enums/types.py +49 -0
  63. openfisca_core/memory_config.py +9 -0
  64. openfisca_core/model_api.py +71 -0
  65. openfisca_core/parameters/__init__.py +71 -0
  66. openfisca_core/parameters/at_instant_like.py +17 -0
  67. openfisca_core/parameters/config.py +55 -0
  68. openfisca_core/parameters/helpers.py +106 -0
  69. openfisca_core/parameters/parameter.py +217 -0
  70. openfisca_core/parameters/parameter_at_instant.py +75 -0
  71. openfisca_core/parameters/parameter_node.py +176 -0
  72. openfisca_core/parameters/parameter_node_at_instant.py +57 -0
  73. openfisca_core/parameters/parameter_scale.py +121 -0
  74. openfisca_core/parameters/parameter_scale_bracket.py +7 -0
  75. openfisca_core/parameters/values_history.py +5 -0
  76. openfisca_core/parameters/vectorial_parameter_node_at_instant.py +179 -0
  77. openfisca_core/periods/__init__.py +77 -0
  78. openfisca_core/periods/_errors.py +28 -0
  79. openfisca_core/periods/_parsers.py +122 -0
  80. openfisca_core/periods/config.py +20 -0
  81. openfisca_core/periods/date_unit.py +110 -0
  82. openfisca_core/periods/helpers.py +314 -0
  83. openfisca_core/periods/instant_.py +226 -0
  84. openfisca_core/periods/period_.py +919 -0
  85. openfisca_core/periods/py.typed +0 -0
  86. openfisca_core/periods/tests/__init__.py +0 -0
  87. openfisca_core/periods/tests/helpers/__init__.py +0 -0
  88. openfisca_core/periods/tests/helpers/test_helpers.py +65 -0
  89. openfisca_core/periods/tests/helpers/test_instant.py +73 -0
  90. openfisca_core/periods/tests/helpers/test_period.py +134 -0
  91. openfisca_core/periods/tests/test_instant.py +32 -0
  92. openfisca_core/periods/tests/test_parsers.py +129 -0
  93. openfisca_core/periods/tests/test_period.py +283 -0
  94. openfisca_core/populations/__init__.py +64 -0
  95. openfisca_core/populations/_core_population.py +454 -0
  96. openfisca_core/populations/_errors.py +65 -0
  97. openfisca_core/populations/group_population.py +326 -0
  98. openfisca_core/populations/population.py +142 -0
  99. openfisca_core/populations/tests/__init__.py +0 -0
  100. openfisca_core/populations/tests/test_members_position.py +116 -0
  101. openfisca_core/populations/types.py +110 -0
  102. openfisca_core/projectors/__init__.py +39 -0
  103. openfisca_core/projectors/entity_to_person_projector.py +12 -0
  104. openfisca_core/projectors/first_person_to_entity_projector.py +13 -0
  105. openfisca_core/projectors/helpers.py +139 -0
  106. openfisca_core/projectors/projector.py +38 -0
  107. openfisca_core/projectors/typing.py +27 -0
  108. openfisca_core/projectors/unique_role_to_entity_projector.py +14 -0
  109. openfisca_core/rates.py +9 -0
  110. openfisca_core/reforms/__init__.py +24 -0
  111. openfisca_core/reforms/in_yaml_test_reform.py +28 -0
  112. openfisca_core/reforms/reform.py +86 -0
  113. openfisca_core/scripts/__init__.py +106 -0
  114. openfisca_core/scripts/__pycache__/__init__.cpython-310-pytest-8.3.3.pyc +0 -0
  115. openfisca_core/scripts/__pycache__/__init__.cpython-310-pytest-8.4.2.pyc +0 -0
  116. openfisca_core/scripts/__pycache__/__init__.cpython-310.pyc +0 -0
  117. openfisca_core/scripts/__pycache__/__init__.cpython-311-pytest-8.3.3.pyc +0 -0
  118. openfisca_core/scripts/__pycache__/__init__.cpython-311-pytest-8.4.2.pyc +0 -0
  119. openfisca_core/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  120. openfisca_core/scripts/__pycache__/__init__.cpython-312-pytest-8.4.2.pyc +0 -0
  121. openfisca_core/scripts/__pycache__/__init__.cpython-312.pyc +0 -0
  122. openfisca_core/scripts/__pycache__/__init__.cpython-313-pytest-8.3.3.pyc +0 -0
  123. openfisca_core/scripts/__pycache__/__init__.cpython-313-pytest-8.4.2.pyc +0 -0
  124. openfisca_core/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  125. openfisca_core/scripts/__pycache__/find_placeholders.cpython-311.pyc +0 -0
  126. openfisca_core/scripts/__pycache__/find_placeholders.cpython-313.pyc +0 -0
  127. openfisca_core/scripts/__pycache__/measure_numpy_condition_notations.cpython-311.pyc +0 -0
  128. openfisca_core/scripts/__pycache__/measure_numpy_condition_notations.cpython-313.pyc +0 -0
  129. openfisca_core/scripts/__pycache__/measure_performances.cpython-311.pyc +0 -0
  130. openfisca_core/scripts/__pycache__/measure_performances.cpython-313.pyc +0 -0
  131. openfisca_core/scripts/__pycache__/measure_performances_fancy_indexing.cpython-311.pyc +0 -0
  132. openfisca_core/scripts/__pycache__/measure_performances_fancy_indexing.cpython-313.pyc +0 -0
  133. openfisca_core/scripts/__pycache__/openfisca_command.cpython-310.pyc +0 -0
  134. openfisca_core/scripts/__pycache__/openfisca_command.cpython-311.pyc +0 -0
  135. openfisca_core/scripts/__pycache__/openfisca_command.cpython-312.pyc +0 -0
  136. openfisca_core/scripts/__pycache__/openfisca_command.cpython-313.pyc +0 -0
  137. openfisca_core/scripts/__pycache__/remove_fuzzy.cpython-311.pyc +0 -0
  138. openfisca_core/scripts/__pycache__/remove_fuzzy.cpython-313.pyc +0 -0
  139. openfisca_core/scripts/__pycache__/run_test.cpython-310.pyc +0 -0
  140. openfisca_core/scripts/__pycache__/run_test.cpython-311.pyc +0 -0
  141. openfisca_core/scripts/__pycache__/run_test.cpython-312.pyc +0 -0
  142. openfisca_core/scripts/__pycache__/run_test.cpython-313.pyc +0 -0
  143. openfisca_core/scripts/__pycache__/simulation_generator.cpython-311.pyc +0 -0
  144. openfisca_core/scripts/__pycache__/simulation_generator.cpython-313.pyc +0 -0
  145. openfisca_core/scripts/assets/__init__.py +0 -0
  146. openfisca_core/scripts/assets/__pycache__/__init__.cpython-311.pyc +0 -0
  147. openfisca_core/scripts/assets/__pycache__/__init__.cpython-313.pyc +0 -0
  148. openfisca_core/scripts/assets/index.html +140 -0
  149. openfisca_core/scripts/find_placeholders.py +51 -0
  150. openfisca_core/scripts/measure_numpy_condition_notations.py +137 -0
  151. openfisca_core/scripts/measure_performances.py +291 -0
  152. openfisca_core/scripts/measure_performances_fancy_indexing.py +89 -0
  153. openfisca_core/scripts/migrations/__init__.py +0 -0
  154. openfisca_core/scripts/migrations/__pycache__/__init__.cpython-311.pyc +0 -0
  155. openfisca_core/scripts/migrations/__pycache__/__init__.cpython-313.pyc +0 -0
  156. openfisca_core/scripts/migrations/__pycache__/v24_to_25.cpython-311.pyc +0 -0
  157. openfisca_core/scripts/migrations/__pycache__/v24_to_25.cpython-313.pyc +0 -0
  158. openfisca_core/scripts/migrations/v16_2_to_v17/__init__.py +0 -0
  159. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/__init__.cpython-311.pyc +0 -0
  160. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/__init__.cpython-313.pyc +0 -0
  161. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_country_template.cpython-311.pyc +0 -0
  162. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_country_template.cpython-313.pyc +0 -0
  163. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_extension_template.cpython-311.pyc +0 -0
  164. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_extension_template.cpython-313.pyc +0 -0
  165. openfisca_core/scripts/migrations/v16_2_to_v17/legislation.xsd +102 -0
  166. openfisca_core/scripts/migrations/v16_2_to_v17/xml_to_yaml_country_template.py +30 -0
  167. openfisca_core/scripts/migrations/v16_2_to_v17/xml_to_yaml_extension_template.py +26 -0
  168. openfisca_core/scripts/migrations/v24_to_25.py +156 -0
  169. openfisca_core/scripts/openfisca_command.py +192 -0
  170. openfisca_core/scripts/remove_fuzzy.py +213 -0
  171. openfisca_core/scripts/run_test.py +51 -0
  172. openfisca_core/scripts/simulation_generator.py +90 -0
  173. openfisca_core/simulation_builder.py +16 -0
  174. openfisca_core/simulations/__init__.py +45 -0
  175. openfisca_core/simulations/_build_default_simulation.py +158 -0
  176. openfisca_core/simulations/_build_from_variables.py +230 -0
  177. openfisca_core/simulations/_type_guards.py +298 -0
  178. openfisca_core/simulations/helpers.py +111 -0
  179. openfisca_core/simulations/simulation.py +618 -0
  180. openfisca_core/simulations/simulation_builder.py +855 -0
  181. openfisca_core/simulations/typing.py +203 -0
  182. openfisca_core/taxbenefitsystems/__init__.py +26 -0
  183. openfisca_core/taxbenefitsystems/tax_benefit_system.py +584 -0
  184. openfisca_core/taxscales/__init__.py +35 -0
  185. openfisca_core/taxscales/abstract_rate_tax_scale.py +41 -0
  186. openfisca_core/taxscales/abstract_tax_scale.py +53 -0
  187. openfisca_core/taxscales/amount_tax_scale_like.py +55 -0
  188. openfisca_core/taxscales/helpers.py +44 -0
  189. openfisca_core/taxscales/linear_average_rate_tax_scale.py +76 -0
  190. openfisca_core/taxscales/marginal_amount_tax_scale.py +34 -0
  191. openfisca_core/taxscales/marginal_rate_tax_scale.py +286 -0
  192. openfisca_core/taxscales/rate_tax_scale_like.py +214 -0
  193. openfisca_core/taxscales/single_amount_tax_scale.py +32 -0
  194. openfisca_core/taxscales/tax_scale_like.py +65 -0
  195. openfisca_core/tools/__init__.py +94 -0
  196. openfisca_core/tools/parallel_plugin.py +55 -0
  197. openfisca_core/tools/simulation_dumper.py +137 -0
  198. openfisca_core/tools/test_runner.py +802 -0
  199. openfisca_core/tracers/__init__.py +40 -0
  200. openfisca_core/tracers/computation_log.py +196 -0
  201. openfisca_core/tracers/flat_trace.py +87 -0
  202. openfisca_core/tracers/full_tracer.py +172 -0
  203. openfisca_core/tracers/performance_log.py +133 -0
  204. openfisca_core/tracers/simple_tracer.py +64 -0
  205. openfisca_core/tracers/trace_node.py +121 -0
  206. openfisca_core/tracers/tracing_parameter_node_at_instant.py +81 -0
  207. openfisca_core/types.py +548 -0
  208. openfisca_core/variables/__init__.py +26 -0
  209. openfisca_core/variables/config.py +53 -0
  210. openfisca_core/variables/helpers.py +67 -0
  211. openfisca_core/variables/tests/__init__.py +0 -0
  212. openfisca_core/variables/tests/test_definition_period.py +43 -0
  213. openfisca_core/variables/variable.py +474 -0
  214. openfisca_core/warnings/__init__.py +25 -0
  215. openfisca_core/warnings/libyaml_warning.py +2 -0
  216. openfisca_core/warnings/tempfile_warning.py +2 -0
  217. openfisca_core_test-46.0.0.data/data/share/openfisca/openfisca-core/CHANGELOG.md +4209 -0
  218. openfisca_core_test-46.0.0.data/data/share/openfisca/openfisca-core/README.md +152 -0
  219. openfisca_core_test-46.0.0.dist-info/METADATA +194 -0
  220. openfisca_core_test-46.0.0.dist-info/RECORD +237 -0
  221. openfisca_core_test-46.0.0.dist-info/WHEEL +5 -0
  222. openfisca_core_test-46.0.0.dist-info/entry_points.txt +3 -0
  223. openfisca_core_test-46.0.0.dist-info/licenses/LICENSE +661 -0
  224. openfisca_core_test-46.0.0.dist-info/top_level.txt +2 -0
  225. openfisca_web_api/__init__.py +0 -0
  226. openfisca_web_api/app.py +226 -0
  227. openfisca_web_api/errors.py +11 -0
  228. openfisca_web_api/handlers.py +90 -0
  229. openfisca_web_api/loader/__init__.py +22 -0
  230. openfisca_web_api/loader/entities.py +28 -0
  231. openfisca_web_api/loader/parameters.py +122 -0
  232. openfisca_web_api/loader/spec.py +168 -0
  233. openfisca_web_api/loader/tax_benefit_system.py +27 -0
  234. openfisca_web_api/loader/variables.py +121 -0
  235. openfisca_web_api/openAPI.yml +434 -0
  236. openfisca_web_api/scripts/__init__.py +0 -0
  237. openfisca_web_api/scripts/serve.py +99 -0
@@ -0,0 +1,39 @@
1
+ # Transitional imports to ensure non-breaking changes.
2
+ # Could be deprecated in the next major release.
3
+ #
4
+ # How imports are being used today:
5
+ #
6
+ # >>> from openfisca_core.module import symbol
7
+ #
8
+ # The previous example provokes cyclic dependency problems
9
+ # that prevent us from modularizing the different components
10
+ # of the library so to make them easier to test and to maintain.
11
+ #
12
+ # How could them be used after the next major release:
13
+ #
14
+ # >>> from openfisca_core import module
15
+ # >>> module.symbol()
16
+ #
17
+ # And for classes:
18
+ #
19
+ # >>> from openfisca_core.module import Symbol
20
+ # >>> Symbol()
21
+ #
22
+ # See: https://www.python.org/dev/peps/pep-0008/#imports
23
+
24
+ from . import typing
25
+ from .entity_to_person_projector import EntityToPersonProjector
26
+ from .first_person_to_entity_projector import FirstPersonToEntityProjector
27
+ from .helpers import get_projector_from_shortcut, projectable
28
+ from .projector import Projector
29
+ from .unique_role_to_entity_projector import UniqueRoleToEntityProjector
30
+
31
+ __all__ = [
32
+ "EntityToPersonProjector",
33
+ "FirstPersonToEntityProjector",
34
+ "Projector",
35
+ "UniqueRoleToEntityProjector",
36
+ "get_projector_from_shortcut",
37
+ "projectable",
38
+ "typing",
39
+ ]
@@ -0,0 +1,12 @@
1
+ from .projector import Projector
2
+
3
+
4
+ class EntityToPersonProjector(Projector):
5
+ """For instance person.family."""
6
+
7
+ def __init__(self, entity, parent=None) -> None:
8
+ self.reference_entity = entity
9
+ self.parent = parent
10
+
11
+ def transform(self, result):
12
+ return self.reference_entity.project(result)
@@ -0,0 +1,13 @@
1
+ from .projector import Projector
2
+
3
+
4
+ class FirstPersonToEntityProjector(Projector):
5
+ """For instance famille.first_person."""
6
+
7
+ def __init__(self, entity, parent=None) -> None:
8
+ self.target_entity = entity
9
+ self.reference_entity = entity.members
10
+ self.parent = parent
11
+
12
+ def transform(self, result):
13
+ return self.target_entity.value_from_first_person(result)
@@ -0,0 +1,139 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+
5
+ from openfisca_core import entities, projectors
6
+ from openfisca_core.types import GroupEntity, Role, SingleEntity
7
+
8
+ from .typing import GroupPopulation, Population
9
+
10
+
11
+ def projectable(function):
12
+ """Decorator to indicate that when called on a projector, the outcome of the function must be projected.
13
+ For instance person.household.sum(...) must be projected on person, while it would not make sense for person.household.get_holder.
14
+ """
15
+ function.projectable = True
16
+ return function
17
+
18
+
19
+ def get_projector_from_shortcut(
20
+ population: Population | GroupPopulation,
21
+ shortcut: str,
22
+ parent: projectors.Projector | None = None,
23
+ ) -> projectors.Projector | None:
24
+ """Get a projector from a shortcut.
25
+
26
+ Projectors are used to project an invidividual Population's or a
27
+ collective GroupPopulation's on to other populations.
28
+
29
+ The currently available cases are projecting:
30
+ - from an individual to a group
31
+ - from a group to an individual
32
+ - from a group to an individual with a unique role
33
+
34
+ For example, if there are two entities, person (Entity) and household
35
+ (GroupEntity), on which calculations can be run (Population and
36
+ GroupPopulation respectively), and there is a Variable "rent" defined for
37
+ the household entity, then `person.household("rent")` will assign a rent to
38
+ every person within that household.
39
+
40
+ Behind the scenes, this is done thanks to a Projector, and this function is
41
+ used to find the appropriate one for each case. In the above example, the
42
+ `shortcut` argument would be "household", and the `population` argument
43
+ would be the Population linked to the "person" Entity in the context
44
+ of a specific Simulation and TaxBenefitSystem.
45
+
46
+ Args:
47
+ population (Population | GroupPopulation): Where to project from.
48
+ shortcut (str): Where to project to.
49
+ parent: ???
50
+
51
+ Examples:
52
+ >>> from openfisca_core import (
53
+ ... entities,
54
+ ... populations,
55
+ ... simulations,
56
+ ... taxbenefitsystems,
57
+ ... )
58
+
59
+ >>> entity = entities.Entity("person", "", "", "")
60
+
61
+ >>> group_entity_1 = entities.GroupEntity("family", "", "", "", [])
62
+
63
+ >>> roles = [
64
+ ... {"key": "person", "max": 1},
65
+ ... {"key": "animal", "subroles": ["cat", "dog"]},
66
+ ... ]
67
+
68
+ >>> group_entity_2 = entities.GroupEntity("household", "", "", "", roles)
69
+
70
+ >>> population = populations.Population(entity)
71
+
72
+ >>> group_population_1 = populations.GroupPopulation(group_entity_1, [])
73
+
74
+ >>> group_population_2 = populations.GroupPopulation(group_entity_2, [])
75
+
76
+ >>> populations = {
77
+ ... entity.key: population,
78
+ ... group_entity_1.key: group_population_1,
79
+ ... group_entity_2.key: group_population_2,
80
+ ... }
81
+
82
+ >>> tax_benefit_system = taxbenefitsystems.TaxBenefitSystem(
83
+ ... [entity, group_entity_1, group_entity_2]
84
+ ... )
85
+
86
+ >>> simulation = simulations.Simulation(tax_benefit_system, populations)
87
+
88
+ >>> get_projector_from_shortcut(population, "person")
89
+ <...EntityToPersonProjector object at ...>
90
+
91
+ >>> get_projector_from_shortcut(population, "family")
92
+ <...EntityToPersonProjector object at ...>
93
+
94
+ >>> get_projector_from_shortcut(population, "household")
95
+ <...EntityToPersonProjector object at ...>
96
+
97
+ >>> get_projector_from_shortcut(group_population_2, "first_person")
98
+ <...FirstPersonToEntityProjector object at ...>
99
+
100
+ >>> get_projector_from_shortcut(group_population_2, "person")
101
+ <...UniqueRoleToEntityProjector object at ...>
102
+
103
+ >>> get_projector_from_shortcut(group_population_2, "cat")
104
+ <...UniqueRoleToEntityProjector object at ...>
105
+
106
+ >>> get_projector_from_shortcut(group_population_2, "dog")
107
+ <...UniqueRoleToEntityProjector object at ...>
108
+
109
+ """
110
+ entity: SingleEntity | GroupEntity = population.entity
111
+
112
+ if isinstance(entity, entities.Entity):
113
+ populations: Mapping[
114
+ str,
115
+ Population | GroupPopulation,
116
+ ] = population.simulation.populations
117
+
118
+ if shortcut not in populations:
119
+ return None
120
+
121
+ return projectors.EntityToPersonProjector(populations[shortcut], parent)
122
+
123
+ if shortcut == "first_person":
124
+ return projectors.FirstPersonToEntityProjector(population, parent)
125
+
126
+ if isinstance(entity, entities.GroupEntity):
127
+ role: Role | None = entities.find_role(entity.roles, shortcut, total=1)
128
+
129
+ if role is not None:
130
+ return projectors.UniqueRoleToEntityProjector(population, role, parent)
131
+
132
+ if shortcut in entity.containing_entities:
133
+ projector: projectors.Projector = getattr(
134
+ projectors.FirstPersonToEntityProjector(population, parent),
135
+ shortcut,
136
+ )
137
+ return projector
138
+
139
+ return None
@@ -0,0 +1,38 @@
1
+ from openfisca_core.projectors import helpers
2
+
3
+
4
+ class Projector:
5
+ reference_entity = None
6
+ parent = None
7
+
8
+ def __getattr__(self, attribute):
9
+ projector = helpers.get_projector_from_shortcut(
10
+ self.reference_entity,
11
+ attribute,
12
+ parent=self,
13
+ )
14
+ if projector:
15
+ return projector
16
+
17
+ reference_attr = getattr(self.reference_entity, attribute)
18
+ if not hasattr(reference_attr, "projectable"):
19
+ return reference_attr
20
+
21
+ def projector_function(*args, **kwargs):
22
+ result = reference_attr(*args, **kwargs)
23
+ return self.transform_and_bubble_up(result)
24
+
25
+ return projector_function
26
+
27
+ def __call__(self, *args, **kwargs):
28
+ result = self.reference_entity(*args, **kwargs)
29
+ return self.transform_and_bubble_up(result)
30
+
31
+ def transform_and_bubble_up(self, result):
32
+ transformed_result = self.transform(result)
33
+ if self.parent is None:
34
+ return transformed_result
35
+ return self.parent.transform_and_bubble_up(transformed_result)
36
+
37
+ def transform(self, result):
38
+ return NotImplementedError()
@@ -0,0 +1,27 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Mapping
4
+ from typing import Protocol
5
+
6
+ from openfisca_core.types import GroupEntity, SingleEntity
7
+
8
+
9
+ class Population(Protocol):
10
+ @property
11
+ def entity(self) -> SingleEntity: ...
12
+
13
+ @property
14
+ def simulation(self) -> Simulation: ...
15
+
16
+
17
+ class GroupPopulation(Protocol):
18
+ @property
19
+ def entity(self) -> GroupEntity: ...
20
+
21
+ @property
22
+ def simulation(self) -> Simulation: ...
23
+
24
+
25
+ class Simulation(Protocol):
26
+ @property
27
+ def populations(self) -> Mapping[str, Population | GroupPopulation]: ...
@@ -0,0 +1,14 @@
1
+ from .projector import Projector
2
+
3
+
4
+ class UniqueRoleToEntityProjector(Projector):
5
+ """For instance famille.declarant_principal."""
6
+
7
+ def __init__(self, entity, role, parent=None) -> None:
8
+ self.target_entity = entity
9
+ self.reference_entity = entity.members
10
+ self.parent = parent
11
+ self.role = role
12
+
13
+ def transform(self, result):
14
+ return self.target_entity.value_from_person(result, self.role)
@@ -0,0 +1,9 @@
1
+ # The formula_helpers module has been deprecated since X.X.X,
2
+ # and will be removed in the future.
3
+ #
4
+ # The helpers have been moved to the commons module.
5
+ #
6
+ # The following are transitional imports to ensure non-breaking changes.
7
+ # Could be deprecated in the next major release.
8
+
9
+ from openfisca_core.commons import average_rate, marginal_rate # noqa: F401
@@ -0,0 +1,24 @@
1
+ # Transitional imports to ensure non-breaking changes.
2
+ # Could be deprecated in the next major release.
3
+ #
4
+ # How imports are being used today:
5
+ #
6
+ # >>> from openfisca_core.module import symbol
7
+ #
8
+ # The previous example provokes cyclic dependency problems
9
+ # that prevent us from modularizing the different components
10
+ # of the library so to make them easier to test and to maintain.
11
+ #
12
+ # How could them be used after the next major release:
13
+ #
14
+ # >>> from openfisca_core import module
15
+ # >>> module.symbol()
16
+ #
17
+ # And for classes:
18
+ #
19
+ # >>> from openfisca_core.module import Symbol
20
+ # >>> Symbol()
21
+ #
22
+ # See: https://www.python.org/dev/peps/pep-0008/#imports
23
+
24
+ from .reform import Reform # noqa: F401
@@ -0,0 +1,28 @@
1
+ from __future__ import annotations
2
+
3
+ from openfisca_core.parameters.parameter_node import ParameterNode
4
+ from openfisca_core.reforms import Reform
5
+ from openfisca_core.types import TaxBenefitSystem
6
+
7
+
8
+ class InYamlTestReform(Reform):
9
+ """A class representing a parametric reform directly defined in YAML test files."""
10
+
11
+ def __init__(
12
+ self,
13
+ baseline: TaxBenefitSystem,
14
+ reformed_parameters=dict,
15
+ ) -> None:
16
+ """Initialize the instance.
17
+
18
+ :param baseline: Baseline TaxBenefitSystem.
19
+ :param reformed_parameters: Yaml file `parameters` value similar to a parameter tree
20
+ """
21
+ self.reformed_parameters = reformed_parameters
22
+ super().__init__(baseline)
23
+
24
+ def apply(self):
25
+ def modify_parameters(local_parameters: ParameterNode) -> ParameterNode:
26
+ return ParameterNode(data=self.reformed_parameters)
27
+
28
+ self.modify_parameters(modifier_function=modify_parameters)
@@ -0,0 +1,86 @@
1
+ from __future__ import annotations
2
+
3
+ import copy
4
+
5
+ from openfisca_core.parameters import ParameterNode
6
+ from openfisca_core.taxbenefitsystems import TaxBenefitSystem
7
+
8
+
9
+ class Reform(TaxBenefitSystem):
10
+ """A modified TaxBenefitSystem.
11
+
12
+ All reforms must subclass `Reform` and implement a method `apply()`.
13
+
14
+ In this method, the reform can add or replace variables and call `modify_parameters` to modify the parameters of the legislation.
15
+
16
+ Example:
17
+ >>> from openfisca_core import reforms
18
+ >>> from openfisca_core.parameters import load_parameter_file
19
+ >>>
20
+ >>> def modify_my_parameters(parameters):
21
+ >>> # Add new parameters
22
+ >>> new_parameters = load_parameter_file(name='reform_name', file_path='path_to_yaml_file.yaml')
23
+ >>> parameters.add_child('reform_name', new_parameters)
24
+ >>>
25
+ >>> # Update a value
26
+ >>> parameters.taxes.some_tax.some_param.update(period=some_period, value=1000.0)
27
+ >>>
28
+ >>> return parameters
29
+ >>>
30
+ >>> class MyReform(reforms.Reform):
31
+ >>> def apply(self):
32
+ >>> self.add_variable(some_variable)
33
+ >>> self.update_variable(some_other_variable)
34
+ >>> self.modify_parameters(modifier_function = modify_my_parameters)
35
+
36
+ """
37
+
38
+ name = None
39
+
40
+ def __init__(self, baseline) -> None:
41
+ """:param baseline: Baseline TaxBenefitSystem."""
42
+ super().__init__(baseline.entities)
43
+ self.baseline = baseline
44
+ self.parameters = baseline.parameters
45
+ self._parameters_at_instant_cache = baseline._parameters_at_instant_cache
46
+ self.variables = baseline.variables.copy()
47
+ self.decomposition_file_path = baseline.decomposition_file_path
48
+ self.key = self.__class__.__name__
49
+ if not hasattr(self, "apply"):
50
+ msg = f"Reform {self.key} must define an `apply` function"
51
+ raise Exception(msg)
52
+ self.apply()
53
+
54
+ def __getattr__(self, attribute):
55
+ return getattr(self.baseline, attribute)
56
+
57
+ @property
58
+ def full_key(self):
59
+ key = self.key
60
+ assert key is not None, (
61
+ f"key was not set for reform {self} (name: {self.name!r})"
62
+ )
63
+ if self.baseline is not None and hasattr(self.baseline, "key"):
64
+ baseline_full_key = self.baseline.full_key
65
+ key = f"{baseline_full_key}.{key}"
66
+ return key
67
+
68
+ def modify_parameters(self, modifier_function):
69
+ """Make modifications on the parameters of the legislation.
70
+
71
+ Call this function in `apply()` if the reform asks for legislation parameter modifications.
72
+
73
+ Args:
74
+ modifier_function: A function that takes a :obj:`~parameters.ParameterNode`
75
+ and should return an object of the same type.
76
+
77
+ """
78
+ baseline_parameters = self.baseline.parameters
79
+ baseline_parameters_copy = copy.deepcopy(baseline_parameters)
80
+ reform_parameters = modifier_function(baseline_parameters_copy)
81
+ if not isinstance(reform_parameters, ParameterNode):
82
+ raise ValueError(
83
+ f"modifier_function {modifier_function.__name__} in module {modifier_function.__module__} must return a ParameterNode",
84
+ )
85
+ self.parameters = reform_parameters
86
+ self._parameters_at_instant_cache = {}
@@ -0,0 +1,106 @@
1
+ import importlib
2
+ import logging
3
+ import pkgutil
4
+ import traceback
5
+ from os import linesep
6
+
7
+ log = logging.getLogger(__name__)
8
+
9
+
10
+ def add_tax_benefit_system_arguments(parser):
11
+ parser.add_argument(
12
+ "-c",
13
+ "--country-package",
14
+ action="store",
15
+ help='country package to use. If not provided, an automatic detection will be attempted by scanning the python packages installed in your environment which name contains the word "openfisca".',
16
+ )
17
+ parser.add_argument(
18
+ "-e",
19
+ "--extensions",
20
+ action="store",
21
+ help="extensions to load",
22
+ nargs="*",
23
+ )
24
+ parser.add_argument(
25
+ "-r",
26
+ "--reforms",
27
+ action="store",
28
+ help="reforms to apply to the country package",
29
+ nargs="*",
30
+ )
31
+
32
+ return parser
33
+
34
+
35
+ def build_tax_benefit_system(country_package_name, extensions, reforms):
36
+ if country_package_name is None:
37
+ country_package_name = detect_country_package()
38
+ try:
39
+ country_package = importlib.import_module(country_package_name)
40
+ except ImportError:
41
+ message = linesep.join(
42
+ [
43
+ traceback.format_exc(),
44
+ f"Could not import module `{country_package_name}`.",
45
+ "Are you sure it is installed in your environment? If so, look at the stack trace above to determine the origin of this error.",
46
+ "See more at <https://github.com/openfisca/country-template#installing>.",
47
+ ],
48
+ )
49
+
50
+ raise ImportError(message)
51
+ if not hasattr(country_package, "CountryTaxBenefitSystem"):
52
+ msg = f"`{country_package_name}` does not seem to be a valid Openfisca country package."
53
+ raise ImportError(
54
+ msg,
55
+ )
56
+
57
+ country_package = importlib.import_module(country_package_name)
58
+ tax_benefit_system = country_package.CountryTaxBenefitSystem()
59
+
60
+ if extensions:
61
+ for extension in extensions:
62
+ tax_benefit_system.load_extension(extension)
63
+
64
+ if reforms:
65
+ for reform_path in reforms:
66
+ tax_benefit_system = tax_benefit_system.apply_reform(reform_path)
67
+
68
+ return tax_benefit_system
69
+
70
+
71
+ # For retro-compatibility:
72
+ build_tax_benefit_sytem = build_tax_benefit_system
73
+
74
+
75
+ def detect_country_package():
76
+ installed_country_packages = []
77
+ for module_description in pkgutil.iter_modules():
78
+ module_name = module_description[1]
79
+ if "openfisca" in module_name.lower():
80
+ try:
81
+ module = importlib.import_module(module_name)
82
+ except ImportError:
83
+ message = linesep.join(
84
+ [
85
+ traceback.format_exc(),
86
+ f"Could not import module `{module_name}`.",
87
+ "Look at the stack trace above to determine the error that stopped installed modules detection.",
88
+ ],
89
+ )
90
+ raise ImportError(message)
91
+ if hasattr(module, "CountryTaxBenefitSystem"):
92
+ installed_country_packages.append(module_name)
93
+
94
+ if len(installed_country_packages) == 0:
95
+ msg = "No country package has been detected on your environment. If your country package is installed but not detected, please use the --country-package option."
96
+ raise ImportError(
97
+ msg,
98
+ )
99
+ if len(installed_country_packages) > 1:
100
+ log.warning(
101
+ "Several country packages detected : `{}`. Using `{}` by default. To use another package, please use the --country-package option.".format(
102
+ ", ".join(installed_country_packages),
103
+ installed_country_packages[0],
104
+ ),
105
+ )
106
+ return installed_country_packages[0]
File without changes