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,92 @@
1
+ from __future__ import annotations
2
+
3
+ from collections.abc import Iterable
4
+
5
+ from . import types as t
6
+ from ._description import _Description
7
+
8
+
9
+ class Role:
10
+ """The role of an ``Entity`` within a ``GroupEntity``.
11
+
12
+ Each ``Entity`` related to a ``GroupEntity`` has a ``Role``. For example,
13
+ if you have a family, its roles could include a parent, a child, and so on.
14
+ Or if you have a tax household, its roles could include the taxpayer, a
15
+ spouse, several dependents, and the like.
16
+
17
+ Args:
18
+ description: A description of the Role.
19
+ entity: The Entity to which the Role belongs.
20
+
21
+ Examples:
22
+ >>> from openfisca_core import entities
23
+
24
+ >>> entity = entities.GroupEntity("key", "plural", "label", "doc", [])
25
+ >>> role = entities.Role({"key": "parent"}, entity)
26
+
27
+ >>> repr(entities.Role)
28
+ "<class 'openfisca_core.entities.role.Role'>"
29
+
30
+ >>> repr(role)
31
+ 'Role(parent)'
32
+
33
+ >>> str(role)
34
+ 'Role(parent)'
35
+
36
+ >>> {role}
37
+ {Role(parent)}
38
+
39
+ >>> role.key
40
+ 'parent'
41
+
42
+ """
43
+
44
+ #: The ``GroupEntity`` the Role belongs to.
45
+ entity: t.GroupEntity
46
+
47
+ #: A description of the ``Role``.
48
+ description: _Description
49
+
50
+ #: Max number of members.
51
+ max: None | int = None
52
+
53
+ #: A list of subroles.
54
+ subroles: None | Iterable[Role] = None
55
+
56
+ @property
57
+ def key(self) -> t.RoleKey:
58
+ """A key to identify the ``Role``."""
59
+ return t.RoleKey(self.description.key)
60
+
61
+ @property
62
+ def plural(self) -> None | t.RolePlural:
63
+ """The ``key`` pluralised."""
64
+ if (plural := self.description.plural) is None:
65
+ return None
66
+ return t.RolePlural(plural)
67
+
68
+ @property
69
+ def label(self) -> None | str:
70
+ """A summary description."""
71
+ return self.description.label
72
+
73
+ @property
74
+ def doc(self) -> None | str:
75
+ """A full description, non-indented."""
76
+ return self.description.doc
77
+
78
+ def __init__(self, description: t.RoleParams, entity: t.GroupEntity) -> None:
79
+ self.description = _Description(
80
+ key=description["key"],
81
+ plural=description.get("plural"),
82
+ label=description.get("label"),
83
+ doc=description.get("doc"),
84
+ )
85
+ self.entity = entity
86
+ self.max = description.get("max")
87
+
88
+ def __repr__(self) -> str:
89
+ return f"Role({self.key})"
90
+
91
+
92
+ __all__ = ["Role"]
File without changes
@@ -0,0 +1,10 @@
1
+ from openfisca_core import entities
2
+
3
+
4
+ def test_init_when_doc_indented() -> None:
5
+ """De-indent the ``doc`` attribute if it is passed at initialisation."""
6
+ key = "\tkey"
7
+ doc = "\tdoc"
8
+ entity = entities.Entity(key, "label", "plural", doc)
9
+ assert entity.key == key
10
+ assert entity.doc == doc.lstrip()
@@ -0,0 +1,70 @@
1
+ from collections.abc import Mapping
2
+ from typing import Any
3
+
4
+ import pytest
5
+
6
+ from openfisca_core import entities
7
+
8
+
9
+ @pytest.fixture
10
+ def parent() -> str:
11
+ return "parent"
12
+
13
+
14
+ @pytest.fixture
15
+ def uncle() -> str:
16
+ return "uncle"
17
+
18
+
19
+ @pytest.fixture
20
+ def first_parent() -> str:
21
+ return "first_parent"
22
+
23
+
24
+ @pytest.fixture
25
+ def second_parent() -> str:
26
+ return "second_parent"
27
+
28
+
29
+ @pytest.fixture
30
+ def third_parent() -> str:
31
+ return "third_parent"
32
+
33
+
34
+ @pytest.fixture
35
+ def role(parent: str, first_parent: str, third_parent: str) -> Mapping[str, Any]:
36
+ return {"key": parent, "subroles": {first_parent, third_parent}}
37
+
38
+
39
+ @pytest.fixture
40
+ def group_entity(role: Mapping[str, Any]) -> entities.GroupEntity:
41
+ return entities.GroupEntity("key", "label", "plural", "doc", (role,))
42
+
43
+
44
+ def test_init_when_doc_indented() -> None:
45
+ """De-indent the ``doc`` attribute if it is passed at initialisation."""
46
+ key = "\tkey"
47
+ doc = "\tdoc"
48
+ group_entity = entities.GroupEntity(key, "label", "plural", doc, ())
49
+ assert group_entity.key == key
50
+ assert group_entity.doc == doc.lstrip()
51
+
52
+
53
+ def test_group_entity_with_roles(
54
+ group_entity: entities.GroupEntity,
55
+ parent: str,
56
+ uncle: str,
57
+ ) -> None:
58
+ """Assign a Role for each role-like passed as argument."""
59
+ assert hasattr(group_entity, parent.upper())
60
+ assert not hasattr(group_entity, uncle.upper())
61
+
62
+
63
+ def test_group_entity_with_subroles(
64
+ group_entity: entities.GroupEntity,
65
+ first_parent: str,
66
+ second_parent: str,
67
+ ) -> None:
68
+ """Assign a Role for each subrole-like passed as argument."""
69
+ assert hasattr(group_entity, first_parent.upper())
70
+ assert not hasattr(group_entity, second_parent.upper())
@@ -0,0 +1,11 @@
1
+ from openfisca_core import entities
2
+
3
+
4
+ def test_init_when_doc_indented() -> None:
5
+ """De-indent the ``doc`` attribute if it is passed at initialisation."""
6
+ key = "\tkey"
7
+ doc = "\tdoc"
8
+ entity = entities.GroupEntity("key", "plural", "label", "doc", [])
9
+ role = entities.Role({"key": key, "doc": doc}, entity)
10
+ assert role.key == key
11
+ assert role.doc == doc.lstrip()
@@ -0,0 +1,44 @@
1
+ from typing import Required
2
+
3
+ from typing_extensions import TypedDict
4
+
5
+ from openfisca_core.types import (
6
+ CoreEntity,
7
+ EntityKey,
8
+ EntityPlural,
9
+ GroupEntity,
10
+ Role,
11
+ RoleKey,
12
+ RolePlural,
13
+ SingleEntity,
14
+ TaxBenefitSystem,
15
+ Variable,
16
+ VariableName,
17
+ )
18
+
19
+ # Entities
20
+
21
+
22
+ class RoleParams(TypedDict, total=False):
23
+ key: Required[str]
24
+ plural: str
25
+ label: str
26
+ doc: str
27
+ max: int
28
+ subroles: list[str]
29
+
30
+
31
+ __all__ = [
32
+ "CoreEntity",
33
+ "EntityKey",
34
+ "EntityPlural",
35
+ "GroupEntity",
36
+ "Role",
37
+ "RoleKey",
38
+ "RoleParams",
39
+ "RolePlural",
40
+ "SingleEntity",
41
+ "TaxBenefitSystem",
42
+ "Variable",
43
+ "VariableName",
44
+ ]
@@ -0,0 +1,64 @@
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 .cycle_error import CycleError
25
+ from .empty_argument_error import EmptyArgumentError
26
+ from .nan_creation_error import NaNCreationError
27
+ from .parameter_not_found_error import (
28
+ ParameterNotFoundError,
29
+ )
30
+ from .parameter_not_found_error import (
31
+ ParameterNotFoundError as ParameterNotFound,
32
+ )
33
+ from .parameter_parsing_error import ParameterParsingError
34
+ from .period_mismatch_error import PeriodMismatchError
35
+ from .situation_parsing_error import SituationParsingError
36
+ from .spiral_error import SpiralError
37
+ from .variable_name_config_error import (
38
+ VariableNameConflictError,
39
+ )
40
+ from .variable_name_config_error import (
41
+ VariableNameConflictError as VariableNameConflict,
42
+ )
43
+ from .variable_not_found_error import (
44
+ VariableNotFoundError,
45
+ )
46
+ from .variable_not_found_error import (
47
+ VariableNotFoundError as VariableNotFound,
48
+ )
49
+
50
+ __all__ = [
51
+ "CycleError",
52
+ "EmptyArgumentError",
53
+ "NaNCreationError",
54
+ "ParameterNotFound", # Deprecated alias for "ParameterNotFoundError
55
+ "ParameterNotFoundError",
56
+ "ParameterParsingError",
57
+ "PeriodMismatchError",
58
+ "SituationParsingError",
59
+ "SpiralError",
60
+ "VariableNameConflict", # Deprecated alias for "VariableNameConflictError"
61
+ "VariableNameConflictError",
62
+ "VariableNotFound", # Deprecated alias for "VariableNotFoundError"
63
+ "VariableNotFoundError",
64
+ ]
@@ -0,0 +1,2 @@
1
+ class CycleError(Exception):
2
+ """Simulation error."""
@@ -0,0 +1,39 @@
1
+ import os
2
+ import traceback
3
+
4
+ import numpy
5
+
6
+
7
+ class EmptyArgumentError(IndexError):
8
+ """Exception raised when a method is called with an empty argument."""
9
+
10
+ message: str
11
+
12
+ def __init__(
13
+ self,
14
+ class_name: str,
15
+ method_name: str,
16
+ arg_name: str,
17
+ arg_value: list | numpy.ndarray,
18
+ ) -> None:
19
+ message = [
20
+ f"'{class_name}.{method_name}' can't be run with an empty '{arg_name}':\n",
21
+ f">>> {arg_name}",
22
+ f"{arg_value}\n",
23
+ "Here are some hints to help you get this working:\n",
24
+ f"- Check that '{class_name}' isn't empty (see '{class_name}.add_bracket')",
25
+ (
26
+ f"- Check that '{arg_name}' is being properly assigned "
27
+ f"('{arg_name}' should be a non empty '{type(arg_value).__name__}')\n"
28
+ ),
29
+ "For further support, please do not hesitate to:\n",
30
+ "- Take a look at the official documentation https://openfisca.org/doc",
31
+ "- Open an issue on https://github.com/openfisca/openfisca-core/issues/new",
32
+ "- Mention us via https://twitter.com/openfisca",
33
+ "- Drop us a line to contact@openfisca.org\n",
34
+ "😃",
35
+ ]
36
+ stacktrace = os.linesep.join(traceback.format_stack())
37
+ self.message = os.linesep.join([f" {line}" for line in message])
38
+ self.message = os.linesep.join([stacktrace, self.message])
39
+ super().__init__(self.message)
@@ -0,0 +1,2 @@
1
+ class NaNCreationError(Exception):
2
+ """Simulation error."""
@@ -0,0 +1,16 @@
1
+ class ParameterNotFoundError(AttributeError):
2
+ """Exception raised when a parameter is not found in the parameters."""
3
+
4
+ def __init__(self, name, instant_str, variable_name=None) -> None:
5
+ """:param name: Name of the parameter
6
+ :param instant_str: Instant where the parameter does not exist, in the format `YYYY-MM-DD`.
7
+ :param variable_name: If the parameter was queried during the computation of a variable, name of that variable.
8
+ """
9
+ self.name = name
10
+ self.instant_str = instant_str
11
+ self.variable_name = variable_name
12
+ message = f"The parameter '{name}'"
13
+ if variable_name is not None:
14
+ message += f" requested by variable '{variable_name}'"
15
+ message += f" was not found in the {instant_str} tax and benefit system."
16
+ super().__init__(message)
@@ -0,0 +1,18 @@
1
+ import os
2
+
3
+
4
+ class ParameterParsingError(Exception):
5
+ """Exception raised when a parameter cannot be parsed."""
6
+
7
+ def __init__(self, message, file=None, traceback=None) -> None:
8
+ """:param message: Error message
9
+ :param file: Parameter file which caused the error (optional)
10
+ :param traceback: Traceback (optional)
11
+ """
12
+ if file is not None:
13
+ message = os.linesep.join(
14
+ [f"Error parsing parameter file '{file}':", message],
15
+ )
16
+ if traceback is not None:
17
+ message = os.linesep.join([traceback, message])
18
+ super().__init__(message)
@@ -0,0 +1,9 @@
1
+ class PeriodMismatchError(ValueError):
2
+ """Exception raised when one tries to set a variable value for a period that doesn't match its definition period."""
3
+
4
+ def __init__(self, variable_name: str, period, definition_period, message) -> None:
5
+ self.variable_name = variable_name
6
+ self.period = period
7
+ self.definition_period = definition_period
8
+ self.message = message
9
+ ValueError.__init__(self, self.message)
@@ -0,0 +1,26 @@
1
+ from __future__ import annotations
2
+
3
+ import os
4
+ from collections.abc import Iterable
5
+
6
+ import dpath
7
+
8
+
9
+ class SituationParsingError(Exception):
10
+ """Exception raised when the situation provided as an input for a simulation cannot be parsed."""
11
+
12
+ def __init__(
13
+ self,
14
+ path: Iterable[str],
15
+ message: str,
16
+ code: int | None = None,
17
+ ) -> None:
18
+ self.error = {}
19
+ dpath_path = "/".join([str(item) for item in path])
20
+ message = str(message).strip(os.linesep).replace(os.linesep, " ")
21
+ dpath.new(self.error, dpath_path, message)
22
+ self.code = code
23
+ Exception.__init__(self, str(self.error))
24
+
25
+ def __str__(self) -> str:
26
+ return str(self.error)
@@ -0,0 +1,2 @@
1
+ class SpiralError(Exception):
2
+ """Simulation error."""
@@ -0,0 +1,2 @@
1
+ class VariableNameConflictError(Exception):
2
+ """Exception raised when two variables with the same name are added to a tax and benefit system."""
@@ -0,0 +1,29 @@
1
+ import os
2
+
3
+
4
+ class VariableNotFoundError(Exception):
5
+ """Exception raised when a variable has been queried but is not defined in the TaxBenefitSystem."""
6
+
7
+ def __init__(self, variable_name: str, tax_benefit_system) -> None:
8
+ """:param variable_name: Name of the variable that was queried.
9
+ :param tax_benefit_system: Tax benefits system that does not contain `variable_name`
10
+ """
11
+ country_package_metadata = tax_benefit_system.get_package_metadata()
12
+ country_package_name = country_package_metadata["name"]
13
+ country_package_version = country_package_metadata["version"]
14
+ if country_package_version:
15
+ country_package_id = f"{country_package_name}@{country_package_version}"
16
+ else:
17
+ country_package_id = country_package_name
18
+ message = os.linesep.join(
19
+ [
20
+ f"You tried to calculate or to set a value for variable '{variable_name}', but it was not found in the loaded tax and benefit system ({country_package_id}).",
21
+ f"Are you sure you spelled '{variable_name}' correctly?",
22
+ "If this code used to work and suddenly does not, this is most probably linked to an update of the tax and benefit system.",
23
+ "Look at its changelog to learn about renames and removals and update your code. If it is an official package,",
24
+ f"it is probably available on <https://github.com/openfisca/{country_package_name}/blob/main/CHANGELOG.md>.",
25
+ ],
26
+ )
27
+ self.message = message
28
+ self.variable_name = variable_name
29
+ Exception.__init__(self, self.message)
@@ -0,0 +1,9 @@
1
+ """Experimental features of OpenFisca-Core."""
2
+
3
+ from ._errors import MemoryConfigWarning
4
+ from ._memory_config import MemoryConfig
5
+
6
+ __all__ = [
7
+ "MemoryConfig",
8
+ "MemoryConfigWarning",
9
+ ]
@@ -0,0 +1,5 @@
1
+ class MemoryConfigWarning(UserWarning):
2
+ """Custom warning for MemoryConfig."""
3
+
4
+
5
+ __all__ = ["MemoryConfigWarning"]
@@ -0,0 +1,41 @@
1
+ from __future__ import annotations
2
+
3
+ import warnings
4
+ from collections.abc import Iterable
5
+
6
+ from ._errors import MemoryConfigWarning
7
+
8
+
9
+ class MemoryConfig:
10
+ """Experimental memory configuration."""
11
+
12
+ #: Maximum memory occupation allowed.
13
+ max_memory_occupation: float
14
+
15
+ #: Priority variables.
16
+ priority_variables: frozenset[str]
17
+
18
+ #: Variables to drop.
19
+ variables_to_drop: frozenset[str]
20
+
21
+ def __init__(
22
+ self,
23
+ max_memory_occupation: str | float,
24
+ priority_variables: Iterable[str] = frozenset(),
25
+ variables_to_drop: Iterable[str] = frozenset(),
26
+ ) -> None:
27
+ message = (
28
+ "Memory configuration is a feature that is still currently under ",
29
+ "experimentation. You are very welcome to use it and send us ",
30
+ "precious feedback, but keep in mind that the way it is used might ",
31
+ "change without any major version bump.",
32
+ )
33
+ warnings.warn(message, MemoryConfigWarning, stacklevel=2)
34
+
35
+ self.max_memory_occupation = float(max_memory_occupation)
36
+ if self.max_memory_occupation > 1:
37
+ msg = "max_memory_occupation must be <= 1"
38
+ raise ValueError(msg)
39
+ self.max_memory_occupation_pc = self.max_memory_occupation * 100
40
+ self.priority_variables = frozenset(priority_variables)
41
+ self.variables_to_drop = frozenset(variables_to_drop)
@@ -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 apply_thresholds, concat, switch # noqa: F401
@@ -0,0 +1,33 @@
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 types
25
+ from .helpers import set_input_dispatch_by_period, set_input_divide_by_period
26
+ from .holder import Holder
27
+
28
+ __all__ = [
29
+ "Holder",
30
+ "set_input_dispatch_by_period",
31
+ "set_input_divide_by_period",
32
+ "types",
33
+ ]
@@ -0,0 +1,93 @@
1
+ import logging
2
+
3
+ import numpy
4
+
5
+ from openfisca_core import periods
6
+
7
+ log = logging.getLogger(__name__)
8
+
9
+
10
+ def set_input_dispatch_by_period(holder, period, array) -> None:
11
+ """This function can be declared as a ``set_input`` attribute of a variable.
12
+
13
+ In this case, the variable will accept inputs on larger periods that its definition period, and the value for the larger period will be applied to all its subperiods.
14
+
15
+ To read more about ``set_input`` attributes, check the `documentation <https://openfisca.org/doc/coding-the-legislation/35_periods.html#set-input-automatically-process-variable-inputs-defined-for-periods-not-matching-the-definition-period>`_.
16
+ """
17
+ array = holder._to_array(array)
18
+
19
+ period_size = period.size
20
+ period_unit = period.unit
21
+
22
+ if holder.variable.definition_period not in (
23
+ periods.DateUnit.isoformat + periods.DateUnit.isocalendar
24
+ ):
25
+ msg = "set_input_dispatch_by_period can't be used for eternal variables."
26
+ raise ValueError(
27
+ msg,
28
+ )
29
+
30
+ cached_period_unit = holder.variable.definition_period
31
+ after_instant = period.start.offset(period_size, period_unit)
32
+
33
+ # Cache the input data, skipping the existing cached months
34
+ sub_period = periods.Period((cached_period_unit, period.start, 1))
35
+ while sub_period.start < after_instant:
36
+ existing_array = holder.get_array(sub_period)
37
+ if existing_array is None:
38
+ holder._set(sub_period, array)
39
+ else:
40
+ # The array of the current sub-period is reused for the next ones.
41
+ # TODO: refactor or document this behavior
42
+ array = existing_array
43
+ sub_period = sub_period.offset(1)
44
+
45
+
46
+ def set_input_divide_by_period(holder, period, array) -> None:
47
+ """This function can be declared as a ``set_input`` attribute of a variable.
48
+
49
+ In this case, the variable will accept inputs on larger periods that its definition period, and the value for the larger period will be divided between its subperiods.
50
+
51
+ To read more about ``set_input`` attributes, check the `documentation <https://openfisca.org/doc/coding-the-legislation/35_periods.html#set-input-automatically-process-variable-inputs-defined-for-periods-not-matching-the-definition-period>`_.
52
+ """
53
+ if not isinstance(array, numpy.ndarray):
54
+ array = numpy.array(array)
55
+ period_size = period.size
56
+ period_unit = period.unit
57
+
58
+ if holder.variable.definition_period not in (
59
+ periods.DateUnit.isoformat + periods.DateUnit.isocalendar
60
+ ):
61
+ msg = "set_input_divide_by_period can't be used for eternal variables."
62
+ raise ValueError(
63
+ msg,
64
+ )
65
+
66
+ cached_period_unit = holder.variable.definition_period
67
+ after_instant = period.start.offset(period_size, period_unit)
68
+
69
+ # Count the number of elementary periods to change, and the difference with what is already known.
70
+ remaining_array = array.copy()
71
+ sub_period = periods.Period((cached_period_unit, period.start, 1))
72
+ sub_periods_count = 0
73
+ while sub_period.start < after_instant:
74
+ existing_array = holder.get_array(sub_period)
75
+ if existing_array is not None:
76
+ remaining_array -= existing_array
77
+ else:
78
+ sub_periods_count += 1
79
+ sub_period = sub_period.offset(1)
80
+
81
+ # Cache the input data
82
+ if sub_periods_count > 0:
83
+ divided_array = remaining_array / sub_periods_count
84
+ sub_period = periods.Period((cached_period_unit, period.start, 1))
85
+ while sub_period.start < after_instant:
86
+ if holder.get_array(sub_period) is None:
87
+ holder._set(sub_period, divided_array)
88
+ sub_period = sub_period.offset(1)
89
+ elif not (remaining_array == 0).all():
90
+ msg = f"Inconsistent input: variable {holder.variable.name} has already been set for all months contained in period {period}, and value {array} provided for {period} doesn't match the total ({array - remaining_array}). This error may also be thrown if you try to call set_input twice for the same variable and period."
91
+ raise ValueError(
92
+ msg,
93
+ )