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,454 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import traceback
|
|
4
|
+
from collections.abc import Sequence
|
|
5
|
+
from typing import TypeVar
|
|
6
|
+
|
|
7
|
+
import numpy
|
|
8
|
+
|
|
9
|
+
from openfisca_core import holders, periods
|
|
10
|
+
|
|
11
|
+
from . import types as t
|
|
12
|
+
from ._errors import (
|
|
13
|
+
IncompatibleOptionsError,
|
|
14
|
+
InvalidArraySizeError,
|
|
15
|
+
InvalidOptionError,
|
|
16
|
+
PeriodValidityError,
|
|
17
|
+
)
|
|
18
|
+
|
|
19
|
+
#: Type variable for a covariant data type.
|
|
20
|
+
_DT_co = TypeVar("_DT_co", covariant=True, bound=t.VarDType)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class CorePopulation:
|
|
24
|
+
"""Base class to build populations from.
|
|
25
|
+
|
|
26
|
+
Args:
|
|
27
|
+
entity: The :class:`~entities.CoreEntity` of the population.
|
|
28
|
+
*__args: Variable length argument list.
|
|
29
|
+
**__kwds: Arbitrary keyword arguments.
|
|
30
|
+
|
|
31
|
+
"""
|
|
32
|
+
|
|
33
|
+
#: The number :class:`~entities.CoreEntity` members in the population.
|
|
34
|
+
count: int = 0
|
|
35
|
+
|
|
36
|
+
#: The :class:`~entities.CoreEntity` of the population.
|
|
37
|
+
entity: t.CoreEntity
|
|
38
|
+
|
|
39
|
+
#: A pseudo index for the members of the population.
|
|
40
|
+
ids: Sequence[str] = []
|
|
41
|
+
|
|
42
|
+
#: The :class:`~simulations.Simulation` for which the population is calculated.
|
|
43
|
+
simulation: None | t.Simulation = None
|
|
44
|
+
|
|
45
|
+
def __init__(self, entity: t.CoreEntity, *__args: object, **__kwds: object) -> None:
|
|
46
|
+
self.entity = entity
|
|
47
|
+
self._holders: t.HolderByVariable = {}
|
|
48
|
+
|
|
49
|
+
def __call__(
|
|
50
|
+
self,
|
|
51
|
+
variable_name: t.VariableName,
|
|
52
|
+
period: t.PeriodLike,
|
|
53
|
+
options: None | Sequence[t.Option] = None,
|
|
54
|
+
) -> None | t.VarArray:
|
|
55
|
+
"""Calculate ``variable_name`` for ``period``, using the formula if it exists.
|
|
56
|
+
|
|
57
|
+
Args:
|
|
58
|
+
variable_name: The name of the variable to calculate.
|
|
59
|
+
period: The period to calculate the variable for.
|
|
60
|
+
options: The options to use for the calculation.
|
|
61
|
+
|
|
62
|
+
Returns:
|
|
63
|
+
None: If there is no :class:`~simulations.Simulation`.
|
|
64
|
+
ndarray[generic]: The result of the calculation.
|
|
65
|
+
|
|
66
|
+
Raises:
|
|
67
|
+
IncompatibleOptionsError: If the options are incompatible.
|
|
68
|
+
InvalidOptionError: If the option is invalid.
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
>>> from openfisca_core import (
|
|
72
|
+
... entities,
|
|
73
|
+
... periods,
|
|
74
|
+
... populations,
|
|
75
|
+
... simulations,
|
|
76
|
+
... taxbenefitsystems,
|
|
77
|
+
... variables,
|
|
78
|
+
... )
|
|
79
|
+
|
|
80
|
+
>>> class Person(entities.SingleEntity): ...
|
|
81
|
+
|
|
82
|
+
>>> person = Person("person", "people", "", "")
|
|
83
|
+
>>> period = periods.Period.eternity()
|
|
84
|
+
>>> population = populations.CorePopulation(person)
|
|
85
|
+
>>> population.count = 3
|
|
86
|
+
>>> population("salary", period)
|
|
87
|
+
|
|
88
|
+
>>> tbs = taxbenefitsystems.TaxBenefitSystem([person])
|
|
89
|
+
>>> person.set_tax_benefit_system(tbs)
|
|
90
|
+
>>> simulation = simulations.Simulation(tbs, {person.key: population})
|
|
91
|
+
>>> population("salary", period)
|
|
92
|
+
Traceback (most recent call last):
|
|
93
|
+
VariableNotFoundError: You tried to calculate or to set a value ...
|
|
94
|
+
|
|
95
|
+
>>> class Salary(variables.Variable):
|
|
96
|
+
... definition_period = periods.ETERNITY
|
|
97
|
+
... entity = person
|
|
98
|
+
... value_type = int
|
|
99
|
+
|
|
100
|
+
>>> tbs.add_variable(Salary)
|
|
101
|
+
<openfisca_core.populations._core_population.Salary object at...
|
|
102
|
+
|
|
103
|
+
>>> population(Salary().name, period)
|
|
104
|
+
array([0, 0, 0], dtype=int32)
|
|
105
|
+
|
|
106
|
+
>>> class Tax(Salary):
|
|
107
|
+
... default_value = 100.0
|
|
108
|
+
... definition_period = periods.ETERNITY
|
|
109
|
+
... entity = person
|
|
110
|
+
... value_type = float
|
|
111
|
+
|
|
112
|
+
>>> tbs.add_variable(Tax)
|
|
113
|
+
<openfisca_core.populations._core_population.Tax object at...
|
|
114
|
+
|
|
115
|
+
>>> population(Tax().name, period)
|
|
116
|
+
array([100., 100., 100.], dtype=float32)
|
|
117
|
+
|
|
118
|
+
>>> population(Tax().name, period, [populations.ADD])
|
|
119
|
+
Traceback (most recent call last):
|
|
120
|
+
ValueError: Unable to ADD constant variable 'Tax' over the perio...
|
|
121
|
+
|
|
122
|
+
>>> population(Tax().name, period, [populations.DIVIDE])
|
|
123
|
+
Traceback (most recent call last):
|
|
124
|
+
ValueError: Unable to DIVIDE constant variable 'Tax' over the pe...
|
|
125
|
+
|
|
126
|
+
>>> population(Tax().name, period, [populations.ADD, populations.DIVIDE])
|
|
127
|
+
Traceback (most recent call last):
|
|
128
|
+
IncompatibleOptionsError: Options ADD and DIVIDE are incompatibl...
|
|
129
|
+
|
|
130
|
+
>>> population(Tax().name, period, ["LAGRANGIAN"])
|
|
131
|
+
Traceback (most recent call last):
|
|
132
|
+
InvalidOptionError: Option LAGRANGIAN is not a valid option (try...
|
|
133
|
+
|
|
134
|
+
"""
|
|
135
|
+
if self.simulation is None:
|
|
136
|
+
return None
|
|
137
|
+
|
|
138
|
+
calculate = t.Calculate(
|
|
139
|
+
variable=variable_name,
|
|
140
|
+
period=periods.period(period),
|
|
141
|
+
option=options,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
self.entity.check_variable_defined_for_entity(calculate.variable)
|
|
145
|
+
self.check_period_validity(calculate.variable, calculate.period)
|
|
146
|
+
|
|
147
|
+
if not isinstance(calculate.option, Sequence):
|
|
148
|
+
return self.simulation.calculate(
|
|
149
|
+
calculate.variable,
|
|
150
|
+
calculate.period,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
if t.Option.ADD in calculate.option and t.Option.DIVIDE in calculate.option:
|
|
154
|
+
raise IncompatibleOptionsError(variable_name)
|
|
155
|
+
|
|
156
|
+
if t.Option.ADD in calculate.option:
|
|
157
|
+
return self.simulation.calculate_add(
|
|
158
|
+
calculate.variable,
|
|
159
|
+
calculate.period,
|
|
160
|
+
)
|
|
161
|
+
|
|
162
|
+
if t.Option.DIVIDE in calculate.option:
|
|
163
|
+
return self.simulation.calculate_divide(
|
|
164
|
+
calculate.variable,
|
|
165
|
+
calculate.period,
|
|
166
|
+
)
|
|
167
|
+
|
|
168
|
+
raise InvalidOptionError(calculate.option[0], variable_name)
|
|
169
|
+
|
|
170
|
+
def empty_array(self) -> t.FloatArray:
|
|
171
|
+
"""Return an empty array.
|
|
172
|
+
|
|
173
|
+
Returns:
|
|
174
|
+
ndarray[float32]: An empty array.
|
|
175
|
+
|
|
176
|
+
Examples:
|
|
177
|
+
>>> import numpy
|
|
178
|
+
|
|
179
|
+
>>> from openfisca_core import populations as p
|
|
180
|
+
|
|
181
|
+
>>> class Population(p.CorePopulation): ...
|
|
182
|
+
|
|
183
|
+
>>> population = Population(None)
|
|
184
|
+
>>> population.empty_array()
|
|
185
|
+
array([], dtype=float32)
|
|
186
|
+
|
|
187
|
+
>>> population.count = 3
|
|
188
|
+
>>> population.empty_array()
|
|
189
|
+
array([0., 0., 0.], dtype=float32)
|
|
190
|
+
|
|
191
|
+
"""
|
|
192
|
+
return numpy.zeros(self.count, dtype=t.FloatDType)
|
|
193
|
+
|
|
194
|
+
def filled_array(
|
|
195
|
+
self, value: _DT_co, dtype: None | t.DTypeLike = None
|
|
196
|
+
) -> t.Array[_DT_co]:
|
|
197
|
+
"""Return an array filled with a value.
|
|
198
|
+
|
|
199
|
+
Args:
|
|
200
|
+
value: The value to fill the array with.
|
|
201
|
+
dtype: The data type of the array.
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
ndarray[generic]: An array filled with the value.
|
|
205
|
+
|
|
206
|
+
Examples:
|
|
207
|
+
>>> import numpy
|
|
208
|
+
|
|
209
|
+
>>> from openfisca_core import populations
|
|
210
|
+
|
|
211
|
+
>>> class Population(populations.CorePopulation): ...
|
|
212
|
+
|
|
213
|
+
>>> population = Population(None)
|
|
214
|
+
>>> population.count = 3
|
|
215
|
+
>>> population.filled_array(1)
|
|
216
|
+
array([1, 1, 1])
|
|
217
|
+
|
|
218
|
+
>>> population.filled_array(numpy.float32(1))
|
|
219
|
+
array([1., 1., 1.], dtype=float32)
|
|
220
|
+
|
|
221
|
+
>>> population.filled_array(1, dtype=str)
|
|
222
|
+
array(['1', '1', '1'], dtype='<U1')
|
|
223
|
+
|
|
224
|
+
>>> population.filled_array("hola", dtype=numpy.uint8)
|
|
225
|
+
Traceback (most recent call last):
|
|
226
|
+
ValueError: could not convert string to float: 'hola'
|
|
227
|
+
|
|
228
|
+
"""
|
|
229
|
+
return numpy.full(self.count, value, dtype)
|
|
230
|
+
|
|
231
|
+
def get_index(self, id: str) -> int:
|
|
232
|
+
"""Return the index of an `id``.
|
|
233
|
+
|
|
234
|
+
Args:
|
|
235
|
+
id: The id to get the index for.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
int: The index of the id.
|
|
239
|
+
|
|
240
|
+
Examples:
|
|
241
|
+
>>> from openfisca_core import entities, populations
|
|
242
|
+
|
|
243
|
+
>>> class Person(entities.SingleEntity): ...
|
|
244
|
+
|
|
245
|
+
>>> person = Person("person", "people", "", "")
|
|
246
|
+
>>> population = populations.CorePopulation(person)
|
|
247
|
+
>>> population.ids = ["Juan", "Megan", "Brahim"]
|
|
248
|
+
|
|
249
|
+
>>> population.get_index("Megan")
|
|
250
|
+
1
|
|
251
|
+
|
|
252
|
+
>>> population.get_index("Ibrahim")
|
|
253
|
+
Traceback (most recent call last):
|
|
254
|
+
ValueError: 'Ibrahim' is not in list
|
|
255
|
+
|
|
256
|
+
"""
|
|
257
|
+
return self.ids.index(id)
|
|
258
|
+
|
|
259
|
+
# Calculations
|
|
260
|
+
|
|
261
|
+
def check_array_compatible_with_entity(self, array: t.VarArray) -> None:
|
|
262
|
+
"""Check if an array is compatible with the population.
|
|
263
|
+
|
|
264
|
+
Args:
|
|
265
|
+
array: The array to check.
|
|
266
|
+
|
|
267
|
+
Raises:
|
|
268
|
+
InvalidArraySizeError: If the array is not compatible.
|
|
269
|
+
|
|
270
|
+
Examples:
|
|
271
|
+
>>> import numpy
|
|
272
|
+
|
|
273
|
+
>>> from openfisca_core import entities, populations
|
|
274
|
+
|
|
275
|
+
>>> class Person(entities.SingleEntity): ...
|
|
276
|
+
|
|
277
|
+
>>> person = Person("person", "people", "", "")
|
|
278
|
+
>>> population = populations.CorePopulation(person)
|
|
279
|
+
>>> population.count = 3
|
|
280
|
+
|
|
281
|
+
>>> array = numpy.array([1, 2, 3])
|
|
282
|
+
>>> population.check_array_compatible_with_entity(array)
|
|
283
|
+
|
|
284
|
+
>>> array = numpy.array([1, 2, 3, 4])
|
|
285
|
+
>>> population.check_array_compatible_with_entity(array)
|
|
286
|
+
Traceback (most recent call last):
|
|
287
|
+
InvalidArraySizeError: Input [1 2 3 4] is not a valid value for t...
|
|
288
|
+
|
|
289
|
+
"""
|
|
290
|
+
if self.count == array.size:
|
|
291
|
+
return
|
|
292
|
+
raise InvalidArraySizeError(array, self.entity.key, self.count)
|
|
293
|
+
|
|
294
|
+
@staticmethod
|
|
295
|
+
def check_period_validity(
|
|
296
|
+
variable_name: t.VariableName,
|
|
297
|
+
period: None | t.PeriodLike = None,
|
|
298
|
+
) -> None:
|
|
299
|
+
"""Check if a period is valid.
|
|
300
|
+
|
|
301
|
+
Args:
|
|
302
|
+
variable_name: The name of the variable.
|
|
303
|
+
period: The period to check.
|
|
304
|
+
|
|
305
|
+
Raises:
|
|
306
|
+
PeriodValidityError: If the period is not valid.
|
|
307
|
+
|
|
308
|
+
Examples:
|
|
309
|
+
>>> from openfisca_core import entities, periods, populations
|
|
310
|
+
|
|
311
|
+
>>> class Person(entities.SingleEntity): ...
|
|
312
|
+
|
|
313
|
+
>>> person = Person("person", "people", "", "")
|
|
314
|
+
>>> period = periods.Period("2017-04")
|
|
315
|
+
>>> population = populations.CorePopulation(person)
|
|
316
|
+
|
|
317
|
+
>>> population.check_period_validity("salary")
|
|
318
|
+
Traceback (most recent call last):
|
|
319
|
+
PeriodValidityError: You requested computation of variable "sala...
|
|
320
|
+
|
|
321
|
+
>>> population.check_period_validity("salary", 2017)
|
|
322
|
+
|
|
323
|
+
>>> population.check_period_validity("salary", "2017-04")
|
|
324
|
+
|
|
325
|
+
>>> population.check_period_validity("salary", period)
|
|
326
|
+
|
|
327
|
+
"""
|
|
328
|
+
if isinstance(period, (int, str, periods.Period)):
|
|
329
|
+
return
|
|
330
|
+
stack = traceback.extract_stack()
|
|
331
|
+
filename, line_number, _, line_of_code = stack[-3]
|
|
332
|
+
raise PeriodValidityError(variable_name, filename, line_number, line_of_code)
|
|
333
|
+
|
|
334
|
+
# Helpers
|
|
335
|
+
|
|
336
|
+
def get_holder(self, variable_name: t.VariableName) -> t.Holder:
|
|
337
|
+
"""Return the holder of a variable.
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
variable_name: The name of the variable.
|
|
341
|
+
|
|
342
|
+
Returns:
|
|
343
|
+
Holder: The holder of the variable.
|
|
344
|
+
|
|
345
|
+
Examples:
|
|
346
|
+
>>> from openfisca_core import (
|
|
347
|
+
... entities,
|
|
348
|
+
... holders,
|
|
349
|
+
... periods,
|
|
350
|
+
... populations,
|
|
351
|
+
... simulations,
|
|
352
|
+
... taxbenefitsystems,
|
|
353
|
+
... simulations,
|
|
354
|
+
... variables,
|
|
355
|
+
... )
|
|
356
|
+
|
|
357
|
+
>>> class Person(entities.SingleEntity): ...
|
|
358
|
+
|
|
359
|
+
>>> person = Person("person", "people", "", "")
|
|
360
|
+
|
|
361
|
+
>>> class Salary(variables.Variable):
|
|
362
|
+
... definition_period = periods.WEEK
|
|
363
|
+
... entity = person
|
|
364
|
+
... value_type = int
|
|
365
|
+
|
|
366
|
+
>>> tbs = taxbenefitsystems.TaxBenefitSystem([person])
|
|
367
|
+
>>> person.set_tax_benefit_system(tbs)
|
|
368
|
+
>>> population = populations.SinglePopulation(person)
|
|
369
|
+
>>> simulation = simulations.Simulation(tbs, {person.key: population})
|
|
370
|
+
>>> population.get_holder("income_tax")
|
|
371
|
+
Traceback (most recent call last):
|
|
372
|
+
VariableNotFoundError: You tried to calculate or to set a value ...
|
|
373
|
+
|
|
374
|
+
>>> tbs.add_variable(Salary)
|
|
375
|
+
<openfisca_core.populations._core_population.Salary object at...
|
|
376
|
+
|
|
377
|
+
>>> salary = Salary()
|
|
378
|
+
>>> population.get_holder(salary.name)
|
|
379
|
+
<openfisca_core.holders.holder.Holder object at ...
|
|
380
|
+
|
|
381
|
+
"""
|
|
382
|
+
self.entity.check_variable_defined_for_entity(variable_name)
|
|
383
|
+
holder = self._holders.get(variable_name)
|
|
384
|
+
if holder:
|
|
385
|
+
return holder
|
|
386
|
+
variable = self.entity.get_variable(variable_name)
|
|
387
|
+
self._holders[variable_name] = holder = holders.Holder(variable, self)
|
|
388
|
+
return holder
|
|
389
|
+
|
|
390
|
+
def get_memory_usage(
|
|
391
|
+
self,
|
|
392
|
+
variables: None | Sequence[t.VariableName] = None,
|
|
393
|
+
) -> t.MemoryUsageByVariable:
|
|
394
|
+
"""Return the memory usage of the population per variable.
|
|
395
|
+
|
|
396
|
+
Args:
|
|
397
|
+
variables: The variables to get the memory usage for.
|
|
398
|
+
|
|
399
|
+
Returns:
|
|
400
|
+
MemoryUsageByVariable: The memory usage of the population per variable.
|
|
401
|
+
|
|
402
|
+
Examples:
|
|
403
|
+
>>> from openfisca_core import (
|
|
404
|
+
... entities,
|
|
405
|
+
... holders,
|
|
406
|
+
... periods,
|
|
407
|
+
... populations,
|
|
408
|
+
... simulations,
|
|
409
|
+
... taxbenefitsystems,
|
|
410
|
+
... simulations,
|
|
411
|
+
... variables,
|
|
412
|
+
... )
|
|
413
|
+
|
|
414
|
+
>>> class Person(entities.SingleEntity): ...
|
|
415
|
+
|
|
416
|
+
>>> person = Person("person", "people", "", "")
|
|
417
|
+
|
|
418
|
+
>>> class Salary(variables.Variable):
|
|
419
|
+
... definition_period = periods.WEEK
|
|
420
|
+
... entity = person
|
|
421
|
+
... value_type = int
|
|
422
|
+
|
|
423
|
+
>>> tbs = taxbenefitsystems.TaxBenefitSystem([person])
|
|
424
|
+
>>> population = populations.SinglePopulation(person)
|
|
425
|
+
>>> simulation = simulations.Simulation(tbs, {person.key: population})
|
|
426
|
+
>>> salary = Salary()
|
|
427
|
+
>>> holder = holders.Holder(salary, population)
|
|
428
|
+
>>> population._holders[salary.name] = holder
|
|
429
|
+
|
|
430
|
+
>>> population.get_memory_usage()
|
|
431
|
+
{'total_nb_bytes': 0, 'by_variable': {'Salary': {'nb_cells_by...}}}
|
|
432
|
+
|
|
433
|
+
>>> population.get_memory_usage([salary.name])
|
|
434
|
+
{'total_nb_bytes': 0, 'by_variable': {'Salary': {'nb_cells_by...}}}
|
|
435
|
+
|
|
436
|
+
"""
|
|
437
|
+
holders_memory_usage = {
|
|
438
|
+
variable_name: holder.get_memory_usage()
|
|
439
|
+
for variable_name, holder in self._holders.items()
|
|
440
|
+
if variables is None or variable_name in variables
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
total_memory_usage = sum(
|
|
444
|
+
holder_memory_usage["total_nb_bytes"]
|
|
445
|
+
for holder_memory_usage in holders_memory_usage.values()
|
|
446
|
+
)
|
|
447
|
+
|
|
448
|
+
return t.MemoryUsageByVariable(
|
|
449
|
+
total_nb_bytes=total_memory_usage,
|
|
450
|
+
by_variable=holders_memory_usage,
|
|
451
|
+
)
|
|
452
|
+
|
|
453
|
+
|
|
454
|
+
__all__ = ["CorePopulation"]
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
from . import types as t
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class IncompatibleOptionsError(ValueError):
|
|
5
|
+
"""Raised when two options are incompatible."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, variable_name: t.VariableName) -> None:
|
|
8
|
+
add, divide = t.Option
|
|
9
|
+
msg = (
|
|
10
|
+
f"Options {add} and {divide} are incompatible (trying to compute "
|
|
11
|
+
f"variable {variable_name})."
|
|
12
|
+
)
|
|
13
|
+
super().__init__(msg)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class InvalidOptionError(ValueError):
|
|
17
|
+
"""Raised when an option is invalid."""
|
|
18
|
+
|
|
19
|
+
def __init__(self, option: str, variable_name: t.VariableName) -> None:
|
|
20
|
+
msg = (
|
|
21
|
+
f"Option {option} is not a valid option (trying to compute "
|
|
22
|
+
f"variable {variable_name})."
|
|
23
|
+
)
|
|
24
|
+
super().__init__(msg)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
class InvalidArraySizeError(ValueError):
|
|
28
|
+
"""Raised when an array has an invalid size."""
|
|
29
|
+
|
|
30
|
+
def __init__(self, array: t.VarArray, entity: t.EntityKey, count: int) -> None:
|
|
31
|
+
msg = (
|
|
32
|
+
f"Input {array} is not a valid value for the entity {entity} "
|
|
33
|
+
f"(size = {array.size} != {count} = count)."
|
|
34
|
+
)
|
|
35
|
+
super().__init__(msg)
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
class PeriodValidityError(ValueError):
|
|
39
|
+
"""Raised when a period is not valid."""
|
|
40
|
+
|
|
41
|
+
def __init__(
|
|
42
|
+
self,
|
|
43
|
+
variable_name: t.VariableName,
|
|
44
|
+
filename: str,
|
|
45
|
+
line_number: int,
|
|
46
|
+
line_of_code: int,
|
|
47
|
+
) -> None:
|
|
48
|
+
msg = (
|
|
49
|
+
f'You requested computation of variable "{variable_name}", but '
|
|
50
|
+
f'you did not specify on which period in "{filename}:{line_number}": '
|
|
51
|
+
f"{line_of_code}. When you request the computation of a variable "
|
|
52
|
+
"within a formula, you must always specify the period as the second "
|
|
53
|
+
'parameter. The convention is to call this parameter "period". For '
|
|
54
|
+
'example: computed_salary = person("salary", period). More information at '
|
|
55
|
+
"<https://openfisca.org/doc/coding-the-legislation/35_periods.html#periods-in-variable-definition>."
|
|
56
|
+
)
|
|
57
|
+
super().__init__(msg)
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
__all__ = [
|
|
61
|
+
"IncompatibleOptionsError",
|
|
62
|
+
"InvalidArraySizeError",
|
|
63
|
+
"InvalidOptionError",
|
|
64
|
+
"PeriodValidityError",
|
|
65
|
+
]
|