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.
- openfisca_core/__init__.py +0 -0
- openfisca_core/commons/__init__.py +18 -0
- openfisca_core/commons/dummy.py +25 -0
- openfisca_core/commons/formulas.py +121 -0
- openfisca_core/commons/misc.py +109 -0
- openfisca_core/commons/py.typed +0 -0
- openfisca_core/commons/rates.py +114 -0
- openfisca_core/commons/tests/__init__.py +0 -0
- openfisca_core/commons/tests/test_dummy.py +9 -0
- openfisca_core/commons/tests/test_formulas.py +75 -0
- openfisca_core/commons/tests/test_rates.py +26 -0
- openfisca_core/data_storage/__init__.py +7 -0
- openfisca_core/data_storage/in_memory_storage.py +198 -0
- openfisca_core/data_storage/on_disk_storage.py +307 -0
- openfisca_core/data_storage/types.py +14 -0
- openfisca_core/entities/__init__.py +23 -0
- openfisca_core/entities/_core_entity.py +217 -0
- openfisca_core/entities/_description.py +55 -0
- openfisca_core/entities/entity.py +60 -0
- openfisca_core/entities/group_entity.py +123 -0
- openfisca_core/entities/helpers.py +165 -0
- openfisca_core/entities/py.typed +0 -0
- openfisca_core/entities/role.py +92 -0
- openfisca_core/entities/tests/__init__.py +0 -0
- openfisca_core/entities/tests/test_entity.py +10 -0
- openfisca_core/entities/tests/test_group_entity.py +70 -0
- openfisca_core/entities/tests/test_role.py +11 -0
- openfisca_core/entities/types.py +44 -0
- openfisca_core/errors/__init__.py +64 -0
- openfisca_core/errors/cycle_error.py +2 -0
- openfisca_core/errors/empty_argument_error.py +39 -0
- openfisca_core/errors/nan_creation_error.py +2 -0
- openfisca_core/errors/parameter_not_found_error.py +16 -0
- openfisca_core/errors/parameter_parsing_error.py +18 -0
- openfisca_core/errors/period_mismatch_error.py +9 -0
- openfisca_core/errors/situation_parsing_error.py +26 -0
- openfisca_core/errors/spiral_error.py +2 -0
- openfisca_core/errors/variable_name_config_error.py +2 -0
- openfisca_core/errors/variable_not_found_error.py +29 -0
- openfisca_core/experimental/__init__.py +9 -0
- openfisca_core/experimental/_errors.py +5 -0
- openfisca_core/experimental/_memory_config.py +41 -0
- openfisca_core/formula_helpers.py +9 -0
- openfisca_core/holders/__init__.py +33 -0
- openfisca_core/holders/helpers.py +93 -0
- openfisca_core/holders/holder.py +328 -0
- openfisca_core/holders/tests/__init__.py +0 -0
- openfisca_core/holders/tests/test_helpers.py +134 -0
- openfisca_core/holders/types.py +3 -0
- openfisca_core/indexed_enums/__init__.py +18 -0
- openfisca_core/indexed_enums/_enum_type.py +79 -0
- openfisca_core/indexed_enums/_errors.py +35 -0
- openfisca_core/indexed_enums/_guards.py +209 -0
- openfisca_core/indexed_enums/_utils.py +180 -0
- openfisca_core/indexed_enums/config.py +6 -0
- openfisca_core/indexed_enums/enum.py +218 -0
- openfisca_core/indexed_enums/enum_array.py +316 -0
- openfisca_core/indexed_enums/py.typed +0 -0
- openfisca_core/indexed_enums/tests/__init__.py +0 -0
- openfisca_core/indexed_enums/tests/test_enum.py +135 -0
- openfisca_core/indexed_enums/tests/test_enum_array.py +30 -0
- openfisca_core/indexed_enums/types.py +49 -0
- openfisca_core/memory_config.py +9 -0
- openfisca_core/model_api.py +71 -0
- openfisca_core/parameters/__init__.py +71 -0
- openfisca_core/parameters/at_instant_like.py +17 -0
- openfisca_core/parameters/config.py +55 -0
- openfisca_core/parameters/helpers.py +106 -0
- openfisca_core/parameters/parameter.py +217 -0
- openfisca_core/parameters/parameter_at_instant.py +75 -0
- openfisca_core/parameters/parameter_node.py +176 -0
- openfisca_core/parameters/parameter_node_at_instant.py +57 -0
- openfisca_core/parameters/parameter_scale.py +121 -0
- openfisca_core/parameters/parameter_scale_bracket.py +7 -0
- openfisca_core/parameters/values_history.py +5 -0
- openfisca_core/parameters/vectorial_parameter_node_at_instant.py +179 -0
- openfisca_core/periods/__init__.py +77 -0
- openfisca_core/periods/_errors.py +28 -0
- openfisca_core/periods/_parsers.py +122 -0
- openfisca_core/periods/config.py +20 -0
- openfisca_core/periods/date_unit.py +110 -0
- openfisca_core/periods/helpers.py +314 -0
- openfisca_core/periods/instant_.py +226 -0
- openfisca_core/periods/period_.py +919 -0
- openfisca_core/periods/py.typed +0 -0
- openfisca_core/periods/tests/__init__.py +0 -0
- openfisca_core/periods/tests/helpers/__init__.py +0 -0
- openfisca_core/periods/tests/helpers/test_helpers.py +65 -0
- openfisca_core/periods/tests/helpers/test_instant.py +73 -0
- openfisca_core/periods/tests/helpers/test_period.py +134 -0
- openfisca_core/periods/tests/test_instant.py +32 -0
- openfisca_core/periods/tests/test_parsers.py +129 -0
- openfisca_core/periods/tests/test_period.py +283 -0
- openfisca_core/populations/__init__.py +64 -0
- openfisca_core/populations/_core_population.py +454 -0
- openfisca_core/populations/_errors.py +65 -0
- openfisca_core/populations/group_population.py +326 -0
- openfisca_core/populations/population.py +142 -0
- openfisca_core/populations/tests/__init__.py +0 -0
- openfisca_core/populations/tests/test_members_position.py +116 -0
- openfisca_core/populations/types.py +110 -0
- openfisca_core/projectors/__init__.py +39 -0
- openfisca_core/projectors/entity_to_person_projector.py +12 -0
- openfisca_core/projectors/first_person_to_entity_projector.py +13 -0
- openfisca_core/projectors/helpers.py +139 -0
- openfisca_core/projectors/projector.py +38 -0
- openfisca_core/projectors/typing.py +27 -0
- openfisca_core/projectors/unique_role_to_entity_projector.py +14 -0
- openfisca_core/rates.py +9 -0
- openfisca_core/reforms/__init__.py +24 -0
- openfisca_core/reforms/in_yaml_test_reform.py +28 -0
- openfisca_core/reforms/reform.py +86 -0
- openfisca_core/scripts/__init__.py +106 -0
- openfisca_core/scripts/__pycache__/__init__.cpython-310-pytest-8.3.3.pyc +0 -0
- openfisca_core/scripts/__pycache__/__init__.cpython-310-pytest-8.4.2.pyc +0 -0
- openfisca_core/scripts/__pycache__/__init__.cpython-310.pyc +0 -0
- openfisca_core/scripts/__pycache__/__init__.cpython-311-pytest-8.3.3.pyc +0 -0
- openfisca_core/scripts/__pycache__/__init__.cpython-311-pytest-8.4.2.pyc +0 -0
- openfisca_core/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
- openfisca_core/scripts/__pycache__/__init__.cpython-312-pytest-8.4.2.pyc +0 -0
- openfisca_core/scripts/__pycache__/__init__.cpython-312.pyc +0 -0
- openfisca_core/scripts/__pycache__/__init__.cpython-313-pytest-8.3.3.pyc +0 -0
- openfisca_core/scripts/__pycache__/__init__.cpython-313-pytest-8.4.2.pyc +0 -0
- openfisca_core/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
- openfisca_core/scripts/__pycache__/find_placeholders.cpython-311.pyc +0 -0
- openfisca_core/scripts/__pycache__/find_placeholders.cpython-313.pyc +0 -0
- openfisca_core/scripts/__pycache__/measure_numpy_condition_notations.cpython-311.pyc +0 -0
- openfisca_core/scripts/__pycache__/measure_numpy_condition_notations.cpython-313.pyc +0 -0
- openfisca_core/scripts/__pycache__/measure_performances.cpython-311.pyc +0 -0
- openfisca_core/scripts/__pycache__/measure_performances.cpython-313.pyc +0 -0
- openfisca_core/scripts/__pycache__/measure_performances_fancy_indexing.cpython-311.pyc +0 -0
- openfisca_core/scripts/__pycache__/measure_performances_fancy_indexing.cpython-313.pyc +0 -0
- openfisca_core/scripts/__pycache__/openfisca_command.cpython-310.pyc +0 -0
- openfisca_core/scripts/__pycache__/openfisca_command.cpython-311.pyc +0 -0
- openfisca_core/scripts/__pycache__/openfisca_command.cpython-312.pyc +0 -0
- openfisca_core/scripts/__pycache__/openfisca_command.cpython-313.pyc +0 -0
- openfisca_core/scripts/__pycache__/remove_fuzzy.cpython-311.pyc +0 -0
- openfisca_core/scripts/__pycache__/remove_fuzzy.cpython-313.pyc +0 -0
- openfisca_core/scripts/__pycache__/run_test.cpython-310.pyc +0 -0
- openfisca_core/scripts/__pycache__/run_test.cpython-311.pyc +0 -0
- openfisca_core/scripts/__pycache__/run_test.cpython-312.pyc +0 -0
- openfisca_core/scripts/__pycache__/run_test.cpython-313.pyc +0 -0
- openfisca_core/scripts/__pycache__/simulation_generator.cpython-311.pyc +0 -0
- openfisca_core/scripts/__pycache__/simulation_generator.cpython-313.pyc +0 -0
- openfisca_core/scripts/assets/__init__.py +0 -0
- openfisca_core/scripts/assets/__pycache__/__init__.cpython-311.pyc +0 -0
- openfisca_core/scripts/assets/__pycache__/__init__.cpython-313.pyc +0 -0
- openfisca_core/scripts/assets/index.html +140 -0
- openfisca_core/scripts/find_placeholders.py +51 -0
- openfisca_core/scripts/measure_numpy_condition_notations.py +137 -0
- openfisca_core/scripts/measure_performances.py +291 -0
- openfisca_core/scripts/measure_performances_fancy_indexing.py +89 -0
- openfisca_core/scripts/migrations/__init__.py +0 -0
- openfisca_core/scripts/migrations/__pycache__/__init__.cpython-311.pyc +0 -0
- openfisca_core/scripts/migrations/__pycache__/__init__.cpython-313.pyc +0 -0
- openfisca_core/scripts/migrations/__pycache__/v24_to_25.cpython-311.pyc +0 -0
- openfisca_core/scripts/migrations/__pycache__/v24_to_25.cpython-313.pyc +0 -0
- openfisca_core/scripts/migrations/v16_2_to_v17/__init__.py +0 -0
- openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/__init__.cpython-311.pyc +0 -0
- openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/__init__.cpython-313.pyc +0 -0
- openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_country_template.cpython-311.pyc +0 -0
- openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_country_template.cpython-313.pyc +0 -0
- openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_extension_template.cpython-311.pyc +0 -0
- openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_extension_template.cpython-313.pyc +0 -0
- openfisca_core/scripts/migrations/v16_2_to_v17/legislation.xsd +102 -0
- openfisca_core/scripts/migrations/v16_2_to_v17/xml_to_yaml_country_template.py +30 -0
- openfisca_core/scripts/migrations/v16_2_to_v17/xml_to_yaml_extension_template.py +26 -0
- openfisca_core/scripts/migrations/v24_to_25.py +156 -0
- openfisca_core/scripts/openfisca_command.py +192 -0
- openfisca_core/scripts/remove_fuzzy.py +213 -0
- openfisca_core/scripts/run_test.py +51 -0
- openfisca_core/scripts/simulation_generator.py +90 -0
- openfisca_core/simulation_builder.py +16 -0
- openfisca_core/simulations/__init__.py +45 -0
- openfisca_core/simulations/_build_default_simulation.py +158 -0
- openfisca_core/simulations/_build_from_variables.py +230 -0
- openfisca_core/simulations/_type_guards.py +298 -0
- openfisca_core/simulations/helpers.py +111 -0
- openfisca_core/simulations/simulation.py +618 -0
- openfisca_core/simulations/simulation_builder.py +855 -0
- openfisca_core/simulations/typing.py +203 -0
- openfisca_core/taxbenefitsystems/__init__.py +26 -0
- openfisca_core/taxbenefitsystems/tax_benefit_system.py +584 -0
- openfisca_core/taxscales/__init__.py +35 -0
- openfisca_core/taxscales/abstract_rate_tax_scale.py +41 -0
- openfisca_core/taxscales/abstract_tax_scale.py +53 -0
- openfisca_core/taxscales/amount_tax_scale_like.py +55 -0
- openfisca_core/taxscales/helpers.py +44 -0
- openfisca_core/taxscales/linear_average_rate_tax_scale.py +76 -0
- openfisca_core/taxscales/marginal_amount_tax_scale.py +34 -0
- openfisca_core/taxscales/marginal_rate_tax_scale.py +286 -0
- openfisca_core/taxscales/rate_tax_scale_like.py +214 -0
- openfisca_core/taxscales/single_amount_tax_scale.py +32 -0
- openfisca_core/taxscales/tax_scale_like.py +65 -0
- openfisca_core/tools/__init__.py +94 -0
- openfisca_core/tools/parallel_plugin.py +55 -0
- openfisca_core/tools/simulation_dumper.py +137 -0
- openfisca_core/tools/test_runner.py +802 -0
- openfisca_core/tracers/__init__.py +40 -0
- openfisca_core/tracers/computation_log.py +196 -0
- openfisca_core/tracers/flat_trace.py +87 -0
- openfisca_core/tracers/full_tracer.py +172 -0
- openfisca_core/tracers/performance_log.py +133 -0
- openfisca_core/tracers/simple_tracer.py +64 -0
- openfisca_core/tracers/trace_node.py +121 -0
- openfisca_core/tracers/tracing_parameter_node_at_instant.py +81 -0
- openfisca_core/types.py +548 -0
- openfisca_core/variables/__init__.py +26 -0
- openfisca_core/variables/config.py +53 -0
- openfisca_core/variables/helpers.py +67 -0
- openfisca_core/variables/tests/__init__.py +0 -0
- openfisca_core/variables/tests/test_definition_period.py +43 -0
- openfisca_core/variables/variable.py +474 -0
- openfisca_core/warnings/__init__.py +25 -0
- openfisca_core/warnings/libyaml_warning.py +2 -0
- openfisca_core/warnings/tempfile_warning.py +2 -0
- openfisca_core_test-46.0.0.data/data/share/openfisca/openfisca-core/CHANGELOG.md +4209 -0
- openfisca_core_test-46.0.0.data/data/share/openfisca/openfisca-core/README.md +152 -0
- openfisca_core_test-46.0.0.dist-info/METADATA +194 -0
- openfisca_core_test-46.0.0.dist-info/RECORD +237 -0
- openfisca_core_test-46.0.0.dist-info/WHEEL +5 -0
- openfisca_core_test-46.0.0.dist-info/entry_points.txt +3 -0
- openfisca_core_test-46.0.0.dist-info/licenses/LICENSE +661 -0
- openfisca_core_test-46.0.0.dist-info/top_level.txt +2 -0
- openfisca_web_api/__init__.py +0 -0
- openfisca_web_api/app.py +226 -0
- openfisca_web_api/errors.py +11 -0
- openfisca_web_api/handlers.py +90 -0
- openfisca_web_api/loader/__init__.py +22 -0
- openfisca_web_api/loader/entities.py +28 -0
- openfisca_web_api/loader/parameters.py +122 -0
- openfisca_web_api/loader/spec.py +168 -0
- openfisca_web_api/loader/tax_benefit_system.py +27 -0
- openfisca_web_api/loader/variables.py +121 -0
- openfisca_web_api/openAPI.yml +434 -0
- openfisca_web_api/scripts/__init__.py +0 -0
- openfisca_web_api/scripts/serve.py +99 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import KeysView, MutableMapping
|
|
4
|
+
|
|
5
|
+
import numpy
|
|
6
|
+
|
|
7
|
+
from openfisca_core import periods
|
|
8
|
+
from openfisca_core.periods import DateUnit
|
|
9
|
+
|
|
10
|
+
from . import types as t
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class InMemoryStorage:
|
|
14
|
+
"""Storing and retrieving calculated vectors in memory.
|
|
15
|
+
|
|
16
|
+
Args:
|
|
17
|
+
is_eternal: Whether the storage is eternal.
|
|
18
|
+
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
#: Whether the storage is eternal.
|
|
22
|
+
is_eternal: bool
|
|
23
|
+
|
|
24
|
+
#: A dictionary containing data that has been stored in memory.
|
|
25
|
+
_arrays: MutableMapping[t.Period, t.Array[t.DTypeGeneric]]
|
|
26
|
+
|
|
27
|
+
def __init__(self, is_eternal: bool = False) -> None:
|
|
28
|
+
self._arrays = {}
|
|
29
|
+
self.is_eternal = is_eternal
|
|
30
|
+
|
|
31
|
+
def get(self, period: None | t.Period = None) -> None | t.Array[t.DTypeGeneric]:
|
|
32
|
+
"""Retrieve the data for the specified :obj:`.Period` from memory.
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
period: The :obj:`.Period` for which data should be retrieved.
|
|
36
|
+
|
|
37
|
+
Returns:
|
|
38
|
+
None: If no data is available.
|
|
39
|
+
EnumArray: The data for the specified :obj:`.Period`.
|
|
40
|
+
ndarray[generic]: The data for the specified :obj:`.Period`.
|
|
41
|
+
|
|
42
|
+
Examples:
|
|
43
|
+
>>> import numpy
|
|
44
|
+
|
|
45
|
+
>>> from openfisca_core import data_storage, periods
|
|
46
|
+
|
|
47
|
+
>>> storage = data_storage.InMemoryStorage()
|
|
48
|
+
>>> value = numpy.array([1, 2, 3])
|
|
49
|
+
>>> instant = periods.Instant((2017, 1, 1))
|
|
50
|
+
>>> period = periods.Period(("year", instant, 1))
|
|
51
|
+
|
|
52
|
+
>>> storage.put(value, period)
|
|
53
|
+
|
|
54
|
+
>>> storage.get(period)
|
|
55
|
+
array([1, 2, 3])
|
|
56
|
+
|
|
57
|
+
"""
|
|
58
|
+
if self.is_eternal:
|
|
59
|
+
period = periods.period(DateUnit.ETERNITY)
|
|
60
|
+
period = periods.period(period)
|
|
61
|
+
|
|
62
|
+
values = self._arrays.get(period)
|
|
63
|
+
if values is None:
|
|
64
|
+
return None
|
|
65
|
+
return values
|
|
66
|
+
|
|
67
|
+
def put(self, value: t.Array[t.DTypeGeneric], period: None | t.Period) -> None:
|
|
68
|
+
"""Store the specified data in memory for the specified :obj:`.Period`.
|
|
69
|
+
|
|
70
|
+
Args:
|
|
71
|
+
value: The data to store
|
|
72
|
+
period: The :obj:`.Period` for which the data should be stored.
|
|
73
|
+
|
|
74
|
+
Examples:
|
|
75
|
+
>>> import numpy
|
|
76
|
+
|
|
77
|
+
>>> from openfisca_core import data_storage, periods
|
|
78
|
+
|
|
79
|
+
>>> storage = data_storage.InMemoryStorage()
|
|
80
|
+
>>> value = numpy.array([1, "2", "salary"])
|
|
81
|
+
>>> instant = periods.Instant((2017, 1, 1))
|
|
82
|
+
>>> period = periods.Period(("year", instant, 1))
|
|
83
|
+
|
|
84
|
+
>>> storage.put(value, period)
|
|
85
|
+
|
|
86
|
+
>>> storage.get(period)
|
|
87
|
+
array(['1', '2', 'salary'], ...)
|
|
88
|
+
|
|
89
|
+
"""
|
|
90
|
+
if self.is_eternal:
|
|
91
|
+
period = periods.period(DateUnit.ETERNITY)
|
|
92
|
+
period = periods.period(period)
|
|
93
|
+
|
|
94
|
+
self._arrays[period] = value
|
|
95
|
+
|
|
96
|
+
def delete(self, period: None | t.Period = None) -> None:
|
|
97
|
+
"""Delete the data for the specified :obj:`.Period` from memory.
|
|
98
|
+
|
|
99
|
+
Args:
|
|
100
|
+
period: The :obj:`.Period` for which data should be deleted.
|
|
101
|
+
|
|
102
|
+
Note:
|
|
103
|
+
If ``period`` is specified, all data will be deleted.
|
|
104
|
+
|
|
105
|
+
Examples:
|
|
106
|
+
>>> import numpy
|
|
107
|
+
|
|
108
|
+
>>> from openfisca_core import data_storage, periods
|
|
109
|
+
|
|
110
|
+
>>> storage = data_storage.InMemoryStorage()
|
|
111
|
+
>>> value = numpy.array([1, 2, 3])
|
|
112
|
+
>>> instant = periods.Instant((2017, 1, 1))
|
|
113
|
+
>>> period = periods.Period(("year", instant, 1))
|
|
114
|
+
|
|
115
|
+
>>> storage.put(value, period)
|
|
116
|
+
|
|
117
|
+
>>> storage.get(period)
|
|
118
|
+
array([1, 2, 3])
|
|
119
|
+
|
|
120
|
+
>>> storage.delete(period)
|
|
121
|
+
|
|
122
|
+
>>> storage.get(period)
|
|
123
|
+
|
|
124
|
+
>>> storage.put(value, period)
|
|
125
|
+
|
|
126
|
+
>>> storage.delete()
|
|
127
|
+
|
|
128
|
+
>>> storage.get(period)
|
|
129
|
+
|
|
130
|
+
"""
|
|
131
|
+
if period is None:
|
|
132
|
+
self._arrays = {}
|
|
133
|
+
return
|
|
134
|
+
|
|
135
|
+
if self.is_eternal:
|
|
136
|
+
period = periods.period(DateUnit.ETERNITY)
|
|
137
|
+
period = periods.period(period)
|
|
138
|
+
|
|
139
|
+
self._arrays = {
|
|
140
|
+
period_item: value
|
|
141
|
+
for period_item, value in self._arrays.items()
|
|
142
|
+
if not period.contains(period_item)
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
def get_known_periods(self) -> KeysView[t.Period]:
|
|
146
|
+
"""List of storage's known periods.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
KeysView[Period]: A sequence containing the storage's known periods.
|
|
150
|
+
|
|
151
|
+
Examples:
|
|
152
|
+
>>> from openfisca_core import data_storage, periods
|
|
153
|
+
|
|
154
|
+
>>> storage = data_storage.InMemoryStorage()
|
|
155
|
+
>>> storage.get_known_periods()
|
|
156
|
+
dict_keys([])
|
|
157
|
+
|
|
158
|
+
>>> instant = periods.Instant((2017, 1, 1))
|
|
159
|
+
>>> period = periods.Period(("year", instant, 1))
|
|
160
|
+
>>> storage.put([], period)
|
|
161
|
+
|
|
162
|
+
>>> storage.get_known_periods()
|
|
163
|
+
dict_keys([Period(('year', Instant((2017, 1, 1)), 1))])
|
|
164
|
+
|
|
165
|
+
"""
|
|
166
|
+
return self._arrays.keys()
|
|
167
|
+
|
|
168
|
+
def get_memory_usage(self) -> t.MemoryUsage:
|
|
169
|
+
"""Memory usage of the storage.
|
|
170
|
+
|
|
171
|
+
Returns:
|
|
172
|
+
MemoryUsage: A dictionary representing the storage's memory usage.
|
|
173
|
+
|
|
174
|
+
Examples:
|
|
175
|
+
>>> from openfisca_core import data_storage
|
|
176
|
+
|
|
177
|
+
>>> storage = data_storage.InMemoryStorage()
|
|
178
|
+
>>> storage.get_memory_usage()
|
|
179
|
+
{'nb_arrays': 0, 'total_nb_bytes': 0, 'cell_size': nan}
|
|
180
|
+
|
|
181
|
+
"""
|
|
182
|
+
if not self._arrays:
|
|
183
|
+
return {
|
|
184
|
+
"nb_arrays": 0,
|
|
185
|
+
"total_nb_bytes": 0,
|
|
186
|
+
"cell_size": numpy.nan,
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
nb_arrays = len(self._arrays)
|
|
190
|
+
array = next(iter(self._arrays.values()))
|
|
191
|
+
return {
|
|
192
|
+
"nb_arrays": nb_arrays,
|
|
193
|
+
"total_nb_bytes": array.nbytes * nb_arrays,
|
|
194
|
+
"cell_size": array.itemsize,
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
__all__ = ["InMemoryStorage"]
|
|
@@ -0,0 +1,307 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import os
|
|
4
|
+
import shutil
|
|
5
|
+
from collections.abc import KeysView, MutableMapping
|
|
6
|
+
|
|
7
|
+
import numpy
|
|
8
|
+
|
|
9
|
+
from openfisca_core import periods
|
|
10
|
+
from openfisca_core.indexed_enums import EnumArray
|
|
11
|
+
from openfisca_core.periods import DateUnit
|
|
12
|
+
|
|
13
|
+
from . import types as t
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class OnDiskStorage:
|
|
17
|
+
"""Storing and retrieving calculated vectors on disk.
|
|
18
|
+
|
|
19
|
+
Args:
|
|
20
|
+
storage_dir: Path to store calculated vectors.
|
|
21
|
+
is_eternal: Whether the storage is eternal.
|
|
22
|
+
preserve_storage_dir: Whether to preserve the storage directory.
|
|
23
|
+
|
|
24
|
+
"""
|
|
25
|
+
|
|
26
|
+
#: A dictionary containing data that has been stored on disk.
|
|
27
|
+
storage_dir: str
|
|
28
|
+
|
|
29
|
+
#: Whether the storage is eternal.
|
|
30
|
+
is_eternal: bool
|
|
31
|
+
|
|
32
|
+
#: Whether to preserve the storage directory.
|
|
33
|
+
preserve_storage_dir: bool
|
|
34
|
+
|
|
35
|
+
#: Mapping of file paths to possible :class:`.Enum` values.
|
|
36
|
+
_enums: MutableMapping[str, type[t.Enum]]
|
|
37
|
+
|
|
38
|
+
#: Mapping of periods to file paths.
|
|
39
|
+
_files: MutableMapping[t.Period, str]
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
storage_dir: str,
|
|
44
|
+
is_eternal: bool = False,
|
|
45
|
+
preserve_storage_dir: bool = False,
|
|
46
|
+
enums: MutableMapping[str, type[t.Enum]] | None = None,
|
|
47
|
+
) -> None:
|
|
48
|
+
self._files = {}
|
|
49
|
+
self._enums = {} if enums is None else enums
|
|
50
|
+
self.is_eternal = is_eternal
|
|
51
|
+
self.preserve_storage_dir = preserve_storage_dir
|
|
52
|
+
self.storage_dir = storage_dir
|
|
53
|
+
|
|
54
|
+
def _decode_file(self, file: str) -> t.Array[t.DTypeGeneric]:
|
|
55
|
+
"""Decode a file by loading its contents as a :mod:`numpy` array.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
file: Path to the file to be decoded.
|
|
59
|
+
|
|
60
|
+
Returns:
|
|
61
|
+
EnumArray: Representing the data in the file.
|
|
62
|
+
ndarray[generic]: Representing the data in the file.
|
|
63
|
+
|
|
64
|
+
Note:
|
|
65
|
+
If the file is associated with :class:`~indexed_enums.Enum` values, the
|
|
66
|
+
array is converted back to an :obj:`~indexed_enums.EnumArray` object.
|
|
67
|
+
|
|
68
|
+
Examples:
|
|
69
|
+
>>> import tempfile
|
|
70
|
+
|
|
71
|
+
>>> import numpy
|
|
72
|
+
|
|
73
|
+
>>> from openfisca_core import data_storage, indexed_enums, periods
|
|
74
|
+
|
|
75
|
+
>>> class Housing(indexed_enums.Enum):
|
|
76
|
+
... OWNER = "Owner"
|
|
77
|
+
... TENANT = "Tenant"
|
|
78
|
+
... FREE_LODGER = "Free lodger"
|
|
79
|
+
... HOMELESS = "Homeless"
|
|
80
|
+
|
|
81
|
+
>>> array = numpy.array([1])
|
|
82
|
+
>>> value = indexed_enums.EnumArray(array, Housing)
|
|
83
|
+
>>> instant = periods.Instant((2017, 1, 1))
|
|
84
|
+
>>> period = periods.Period(("year", instant, 1))
|
|
85
|
+
|
|
86
|
+
>>> with tempfile.TemporaryDirectory() as directory:
|
|
87
|
+
... storage = data_storage.OnDiskStorage(directory)
|
|
88
|
+
... storage.put(value, period)
|
|
89
|
+
... storage._decode_file(storage._files[period])
|
|
90
|
+
EnumArray([Housing.TENANT])
|
|
91
|
+
|
|
92
|
+
"""
|
|
93
|
+
enum = self._enums.get(self.storage_dir)
|
|
94
|
+
|
|
95
|
+
if enum is not None:
|
|
96
|
+
return EnumArray(numpy.load(file), enum)
|
|
97
|
+
|
|
98
|
+
array: t.Array[t.DTypeGeneric] = numpy.load(file)
|
|
99
|
+
|
|
100
|
+
return array
|
|
101
|
+
|
|
102
|
+
def get(self, period: None | t.Period = None) -> None | t.Array[t.DTypeGeneric]:
|
|
103
|
+
"""Retrieve the data for the specified period from disk.
|
|
104
|
+
|
|
105
|
+
Args:
|
|
106
|
+
period: The period for which data should be retrieved.
|
|
107
|
+
|
|
108
|
+
Returns:
|
|
109
|
+
None: If no data is available.
|
|
110
|
+
EnumArray: Representing the data for the specified period.
|
|
111
|
+
ndarray[generic]: Representing the data for the specified period.
|
|
112
|
+
|
|
113
|
+
Examples:
|
|
114
|
+
>>> import tempfile
|
|
115
|
+
|
|
116
|
+
>>> import numpy
|
|
117
|
+
|
|
118
|
+
>>> from openfisca_core import data_storage, periods
|
|
119
|
+
|
|
120
|
+
>>> value = numpy.array([1, 2, 3])
|
|
121
|
+
>>> instant = periods.Instant((2017, 1, 1))
|
|
122
|
+
>>> period = periods.Period(("year", instant, 1))
|
|
123
|
+
|
|
124
|
+
>>> with tempfile.TemporaryDirectory() as directory:
|
|
125
|
+
... storage = data_storage.OnDiskStorage(directory)
|
|
126
|
+
... storage.put(value, period)
|
|
127
|
+
... storage.get(period)
|
|
128
|
+
array([1, 2, 3])
|
|
129
|
+
|
|
130
|
+
"""
|
|
131
|
+
if self.is_eternal:
|
|
132
|
+
period = periods.period(DateUnit.ETERNITY)
|
|
133
|
+
period = periods.period(period)
|
|
134
|
+
|
|
135
|
+
values = self._files.get(period)
|
|
136
|
+
if values is None:
|
|
137
|
+
return None
|
|
138
|
+
return self._decode_file(values)
|
|
139
|
+
|
|
140
|
+
def put(self, value: t.Array[t.DTypeGeneric], period: None | t.Period) -> None:
|
|
141
|
+
"""Store the specified data on disk for the specified period.
|
|
142
|
+
|
|
143
|
+
Args:
|
|
144
|
+
value: The data to store
|
|
145
|
+
period: The period for which the data should be stored.
|
|
146
|
+
|
|
147
|
+
Examples:
|
|
148
|
+
>>> import tempfile
|
|
149
|
+
|
|
150
|
+
>>> import numpy
|
|
151
|
+
|
|
152
|
+
>>> from openfisca_core import data_storage, periods
|
|
153
|
+
|
|
154
|
+
>>> value = numpy.array([1, "2", "salary"])
|
|
155
|
+
>>> instant = periods.Instant((2017, 1, 1))
|
|
156
|
+
>>> period = periods.Period(("year", instant, 1))
|
|
157
|
+
|
|
158
|
+
>>> with tempfile.TemporaryDirectory() as directory:
|
|
159
|
+
... storage = data_storage.OnDiskStorage(directory)
|
|
160
|
+
... storage.put(value, period)
|
|
161
|
+
... storage.get(period)
|
|
162
|
+
array(['1', '2', 'salary'], ...)
|
|
163
|
+
|
|
164
|
+
"""
|
|
165
|
+
if self.is_eternal:
|
|
166
|
+
period = periods.period(DateUnit.ETERNITY)
|
|
167
|
+
period = periods.period(period)
|
|
168
|
+
|
|
169
|
+
filename = str(period)
|
|
170
|
+
path = os.path.join(self.storage_dir, filename) + ".npy"
|
|
171
|
+
if isinstance(value, EnumArray) and value.possible_values is not None:
|
|
172
|
+
self._enums[self.storage_dir] = value.possible_values
|
|
173
|
+
value = value.view(numpy.ndarray)
|
|
174
|
+
numpy.save(path, value)
|
|
175
|
+
self._files[period] = path
|
|
176
|
+
|
|
177
|
+
def delete(self, period: None | t.Period = None) -> None:
|
|
178
|
+
"""Delete the data for the specified period from disk.
|
|
179
|
+
|
|
180
|
+
Args:
|
|
181
|
+
period: The period for which data should be deleted. If not
|
|
182
|
+
specified, all data will be deleted.
|
|
183
|
+
|
|
184
|
+
Examples:
|
|
185
|
+
>>> import tempfile
|
|
186
|
+
|
|
187
|
+
>>> import numpy
|
|
188
|
+
|
|
189
|
+
>>> from openfisca_core import data_storage, periods
|
|
190
|
+
|
|
191
|
+
>>> value = numpy.array([1, 2, 3])
|
|
192
|
+
>>> instant = periods.Instant((2017, 1, 1))
|
|
193
|
+
>>> period = periods.Period(("year", instant, 1))
|
|
194
|
+
|
|
195
|
+
>>> with tempfile.TemporaryDirectory() as directory:
|
|
196
|
+
... storage = data_storage.OnDiskStorage(directory)
|
|
197
|
+
... storage.put(value, period)
|
|
198
|
+
... storage.get(period)
|
|
199
|
+
array([1, 2, 3])
|
|
200
|
+
|
|
201
|
+
>>> with tempfile.TemporaryDirectory() as directory:
|
|
202
|
+
... storage = data_storage.OnDiskStorage(directory)
|
|
203
|
+
... storage.put(value, period)
|
|
204
|
+
... storage.delete(period)
|
|
205
|
+
... storage.get(period)
|
|
206
|
+
|
|
207
|
+
>>> with tempfile.TemporaryDirectory() as directory:
|
|
208
|
+
... storage = data_storage.OnDiskStorage(directory)
|
|
209
|
+
... storage.put(value, period)
|
|
210
|
+
... storage.delete()
|
|
211
|
+
... storage.get(period)
|
|
212
|
+
|
|
213
|
+
"""
|
|
214
|
+
if period is None:
|
|
215
|
+
self._files = {}
|
|
216
|
+
return
|
|
217
|
+
|
|
218
|
+
if self.is_eternal:
|
|
219
|
+
period = periods.period(DateUnit.ETERNITY)
|
|
220
|
+
period = periods.period(period)
|
|
221
|
+
|
|
222
|
+
self._files = {
|
|
223
|
+
period_item: value
|
|
224
|
+
for period_item, value in self._files.items()
|
|
225
|
+
if not period.contains(period_item)
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
def get_known_periods(self) -> KeysView[t.Period]:
|
|
229
|
+
"""List of storage's known periods.
|
|
230
|
+
|
|
231
|
+
Returns:
|
|
232
|
+
KeysView[Period]: A sequence containing the storage's known periods.
|
|
233
|
+
|
|
234
|
+
Examples:
|
|
235
|
+
>>> import tempfile
|
|
236
|
+
|
|
237
|
+
>>> from openfisca_core import data_storage, periods
|
|
238
|
+
|
|
239
|
+
>>> instant = periods.Instant((2017, 1, 1))
|
|
240
|
+
>>> period = periods.Period(("year", instant, 1))
|
|
241
|
+
|
|
242
|
+
>>> with tempfile.TemporaryDirectory() as directory:
|
|
243
|
+
... storage = data_storage.OnDiskStorage(directory)
|
|
244
|
+
... storage.get_known_periods()
|
|
245
|
+
dict_keys([])
|
|
246
|
+
|
|
247
|
+
>>> with tempfile.TemporaryDirectory() as directory:
|
|
248
|
+
... storage = data_storage.OnDiskStorage(directory)
|
|
249
|
+
... storage.put([], period)
|
|
250
|
+
... storage.get_known_periods()
|
|
251
|
+
dict_keys([Period(('year', Instant((2017, 1, 1)), 1))])
|
|
252
|
+
|
|
253
|
+
"""
|
|
254
|
+
return self._files.keys()
|
|
255
|
+
|
|
256
|
+
def restore(self) -> None:
|
|
257
|
+
"""Restore the storage from disk.
|
|
258
|
+
|
|
259
|
+
Examples:
|
|
260
|
+
>>> import tempfile
|
|
261
|
+
|
|
262
|
+
>>> import numpy
|
|
263
|
+
|
|
264
|
+
>>> from openfisca_core import data_storage, periods
|
|
265
|
+
|
|
266
|
+
>>> value = numpy.array([1, 2, 3])
|
|
267
|
+
>>> instant = periods.Instant((2017, 1, 1))
|
|
268
|
+
>>> period = periods.Period(("year", instant, 1))
|
|
269
|
+
>>> directory = tempfile.TemporaryDirectory()
|
|
270
|
+
|
|
271
|
+
>>> storage1 = data_storage.OnDiskStorage(directory.name)
|
|
272
|
+
>>> storage1.put(value, period)
|
|
273
|
+
>>> storage1._files
|
|
274
|
+
{Period(('year', Instant((2017, 1, 1)), 1)): '...2017.npy'}
|
|
275
|
+
|
|
276
|
+
>>> storage2 = data_storage.OnDiskStorage(directory.name)
|
|
277
|
+
>>> storage2._files
|
|
278
|
+
{}
|
|
279
|
+
|
|
280
|
+
>>> storage2.restore()
|
|
281
|
+
>>> storage2._files
|
|
282
|
+
{Period((<DateUnit.YEAR: 'year'>, Instant((2017, 1, 1...2017.npy'}
|
|
283
|
+
|
|
284
|
+
>>> directory.cleanup()
|
|
285
|
+
|
|
286
|
+
"""
|
|
287
|
+
self._files = files = {}
|
|
288
|
+
# Restore self._files from content of storage_dir.
|
|
289
|
+
for filename in os.listdir(self.storage_dir):
|
|
290
|
+
if not filename.endswith(".npy"):
|
|
291
|
+
continue
|
|
292
|
+
path = os.path.join(self.storage_dir, filename)
|
|
293
|
+
filename_core = filename.rsplit(".", 1)[0]
|
|
294
|
+
period = periods.period(filename_core)
|
|
295
|
+
files[period] = path
|
|
296
|
+
|
|
297
|
+
def __del__(self) -> None:
|
|
298
|
+
if self.preserve_storage_dir:
|
|
299
|
+
return
|
|
300
|
+
shutil.rmtree(self.storage_dir) # Remove the holder temporary files
|
|
301
|
+
# If the simulation temporary directory is empty, remove it
|
|
302
|
+
parent_dir = os.path.abspath(os.path.join(self.storage_dir, os.pardir))
|
|
303
|
+
if not os.listdir(parent_dir):
|
|
304
|
+
shutil.rmtree(parent_dir)
|
|
305
|
+
|
|
306
|
+
|
|
307
|
+
__all__ = ["OnDiskStorage"]
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from typing_extensions import TypedDict
|
|
2
|
+
|
|
3
|
+
from openfisca_core.types import Array, DTypeGeneric, Enum, Period
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class MemoryUsage(TypedDict, total=True):
|
|
7
|
+
"""Memory usage information."""
|
|
8
|
+
|
|
9
|
+
cell_size: float
|
|
10
|
+
nb_arrays: int
|
|
11
|
+
total_nb_bytes: int
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
__all__ = ["Array", "DTypeGeneric", "Enum", "Period"]
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"""Provide a way of representing the entities of a rule system."""
|
|
2
|
+
|
|
3
|
+
from . import types
|
|
4
|
+
from ._core_entity import CoreEntity
|
|
5
|
+
from .entity import Entity
|
|
6
|
+
from .group_entity import GroupEntity
|
|
7
|
+
from .helpers import build_entity, find_role
|
|
8
|
+
from .role import Role
|
|
9
|
+
|
|
10
|
+
SingleEntity = Entity
|
|
11
|
+
check_role_validity = CoreEntity.check_role_validity
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"CoreEntity",
|
|
15
|
+
"Entity",
|
|
16
|
+
"GroupEntity",
|
|
17
|
+
"Role",
|
|
18
|
+
"SingleEntity",
|
|
19
|
+
"build_entity",
|
|
20
|
+
"check_role_validity",
|
|
21
|
+
"find_role",
|
|
22
|
+
"types",
|
|
23
|
+
]
|