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,230 @@
|
|
|
1
|
+
"""This module contains the _BuildFromVariables class."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from typing import Self
|
|
6
|
+
|
|
7
|
+
from openfisca_core import errors
|
|
8
|
+
|
|
9
|
+
from ._build_default_simulation import _BuildDefaultSimulation
|
|
10
|
+
from ._type_guards import is_variable_dated
|
|
11
|
+
from .simulation import Simulation
|
|
12
|
+
from .typing import Entity, Population, TaxBenefitSystem, Variables
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class _BuildFromVariables:
|
|
16
|
+
"""Build a simulation from variables.
|
|
17
|
+
|
|
18
|
+
Args:
|
|
19
|
+
tax_benefit_system(TaxBenefitSystem): The tax-benefit system.
|
|
20
|
+
params(Variables): The simulation parameters.
|
|
21
|
+
|
|
22
|
+
Examples:
|
|
23
|
+
>>> from openfisca_core import entities, periods, taxbenefitsystems, variables
|
|
24
|
+
|
|
25
|
+
>>> role = {"key": "stray", "plural": "stray", "label": "", "doc": ""}
|
|
26
|
+
>>> single_entity = entities.Entity("dog", "dogs", "", "")
|
|
27
|
+
>>> group_entity = entities.GroupEntity("pack", "packs", "", "", [role])
|
|
28
|
+
|
|
29
|
+
>>> class salary(variables.Variable):
|
|
30
|
+
... definition_period = periods.DateUnit.MONTH
|
|
31
|
+
... entity = single_entity
|
|
32
|
+
... value_type = int
|
|
33
|
+
|
|
34
|
+
>>> class taxes(variables.Variable):
|
|
35
|
+
... definition_period = periods.DateUnit.MONTH
|
|
36
|
+
... entity = group_entity
|
|
37
|
+
... value_type = int
|
|
38
|
+
|
|
39
|
+
>>> test_entities = [single_entity, group_entity]
|
|
40
|
+
>>> tax_benefit_system = taxbenefitsystems.TaxBenefitSystem(test_entities)
|
|
41
|
+
>>> tax_benefit_system.load_variable(salary)
|
|
42
|
+
<...salary object at ...>
|
|
43
|
+
>>> tax_benefit_system.load_variable(taxes)
|
|
44
|
+
<...taxes object at ...>
|
|
45
|
+
>>> period = "2023-12"
|
|
46
|
+
>>> variables = {"salary": {period: 10000}, "taxes": 5000}
|
|
47
|
+
>>> builder = (
|
|
48
|
+
... _BuildFromVariables(tax_benefit_system, variables, period)
|
|
49
|
+
... .add_dated_values()
|
|
50
|
+
... .add_undated_values()
|
|
51
|
+
... )
|
|
52
|
+
|
|
53
|
+
>>> dogs = builder.populations["dog"].get_holder("salary")
|
|
54
|
+
>>> dogs.get_array(period)
|
|
55
|
+
array([10000], dtype=int32)
|
|
56
|
+
|
|
57
|
+
>>> pack = builder.populations["pack"].get_holder("taxes")
|
|
58
|
+
>>> pack.get_array(period)
|
|
59
|
+
array([5000], dtype=int32)
|
|
60
|
+
|
|
61
|
+
"""
|
|
62
|
+
|
|
63
|
+
#: The number of Population.
|
|
64
|
+
count: int
|
|
65
|
+
|
|
66
|
+
#: The Simulation's default period.
|
|
67
|
+
default_period: str | None
|
|
68
|
+
|
|
69
|
+
#: The built populations.
|
|
70
|
+
populations: dict[str, Population[Entity]]
|
|
71
|
+
|
|
72
|
+
#: The built simulation.
|
|
73
|
+
simulation: Simulation
|
|
74
|
+
|
|
75
|
+
#: The simulation parameters.
|
|
76
|
+
variables: Variables
|
|
77
|
+
|
|
78
|
+
def __init__(
|
|
79
|
+
self,
|
|
80
|
+
tax_benefit_system: TaxBenefitSystem,
|
|
81
|
+
params: Variables,
|
|
82
|
+
default_period: str | None = None,
|
|
83
|
+
) -> None:
|
|
84
|
+
self.count = _person_count(params)
|
|
85
|
+
|
|
86
|
+
default_builder = (
|
|
87
|
+
_BuildDefaultSimulation(tax_benefit_system, self.count)
|
|
88
|
+
.add_count()
|
|
89
|
+
.add_ids()
|
|
90
|
+
.add_members_entity_id()
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
self.variables = params
|
|
94
|
+
self.simulation = default_builder.simulation
|
|
95
|
+
self.populations = default_builder.populations
|
|
96
|
+
self.default_period = default_period
|
|
97
|
+
|
|
98
|
+
def add_dated_values(self) -> Self:
|
|
99
|
+
"""Add the dated input values to the Simulation.
|
|
100
|
+
|
|
101
|
+
Returns:
|
|
102
|
+
_BuildFromVariables: The builder.
|
|
103
|
+
|
|
104
|
+
Examples:
|
|
105
|
+
>>> from openfisca_core import entities, periods, taxbenefitsystems, variables
|
|
106
|
+
|
|
107
|
+
>>> role = {"key": "stray", "plural": "stray", "label": "", "doc": ""}
|
|
108
|
+
>>> single_entity = entities.Entity("dog", "dogs", "", "")
|
|
109
|
+
>>> group_entity = entities.GroupEntity("pack", "packs", "", "", [role])
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
>>> class salary(variables.Variable):
|
|
113
|
+
... definition_period = periods.DateUnit.MONTH
|
|
114
|
+
... entity = single_entity
|
|
115
|
+
... value_type = int
|
|
116
|
+
|
|
117
|
+
>>> class taxes(variables.Variable):
|
|
118
|
+
... definition_period = periods.DateUnit.MONTH
|
|
119
|
+
... entity = group_entity
|
|
120
|
+
... value_type = int
|
|
121
|
+
|
|
122
|
+
>>> test_entities = [single_entity, group_entity]
|
|
123
|
+
>>> tax_benefit_system = taxbenefitsystems.TaxBenefitSystem(test_entities)
|
|
124
|
+
>>> tax_benefit_system.load_variable(salary)
|
|
125
|
+
<...salary object at ...>
|
|
126
|
+
>>> tax_benefit_system.load_variable(taxes)
|
|
127
|
+
<...taxes object at ...>
|
|
128
|
+
>>> period = "2023-12"
|
|
129
|
+
>>> variables = {"salary": {period: 10000}, "taxes": 5000}
|
|
130
|
+
>>> builder = _BuildFromVariables(tax_benefit_system, variables)
|
|
131
|
+
>>> builder.add_dated_values()
|
|
132
|
+
<..._BuildFromVariables object at ...>
|
|
133
|
+
|
|
134
|
+
>>> dogs = builder.populations["dog"].get_holder("salary")
|
|
135
|
+
>>> dogs.get_array(period)
|
|
136
|
+
array([10000], dtype=int32)
|
|
137
|
+
|
|
138
|
+
>>> pack = builder.populations["pack"].get_holder("taxes")
|
|
139
|
+
>>> pack.get_array(period)
|
|
140
|
+
|
|
141
|
+
"""
|
|
142
|
+
for variable, value in self.variables.items():
|
|
143
|
+
if is_variable_dated(dated_variable := value):
|
|
144
|
+
for period, dated_value in dated_variable.items():
|
|
145
|
+
self.simulation.set_input(variable, period, dated_value)
|
|
146
|
+
|
|
147
|
+
return self
|
|
148
|
+
|
|
149
|
+
def add_undated_values(self) -> Self:
|
|
150
|
+
"""Add the undated input values to the Simulation.
|
|
151
|
+
|
|
152
|
+
Returns:
|
|
153
|
+
_BuildFromVariables: The builder.
|
|
154
|
+
|
|
155
|
+
Raises:
|
|
156
|
+
SituationParsingError: If there is not a default period set.
|
|
157
|
+
|
|
158
|
+
Examples:
|
|
159
|
+
>>> from openfisca_core import entities, periods, taxbenefitsystems, variables
|
|
160
|
+
|
|
161
|
+
>>> role = {"key": "stray", "plural": "stray", "label": "", "doc": ""}
|
|
162
|
+
>>> single_entity = entities.Entity("dog", "dogs", "", "")
|
|
163
|
+
>>> group_entity = entities.GroupEntity("pack", "packs", "", "", [role])
|
|
164
|
+
|
|
165
|
+
>>> class salary(variables.Variable):
|
|
166
|
+
... definition_period = periods.DateUnit.MONTH
|
|
167
|
+
... entity = single_entity
|
|
168
|
+
... value_type = int
|
|
169
|
+
|
|
170
|
+
>>> class taxes(variables.Variable):
|
|
171
|
+
... definition_period = periods.DateUnit.MONTH
|
|
172
|
+
... entity = group_entity
|
|
173
|
+
... value_type = int
|
|
174
|
+
|
|
175
|
+
>>> test_entities = [single_entity, group_entity]
|
|
176
|
+
>>> tax_benefit_system = taxbenefitsystems.TaxBenefitSystem(test_entities)
|
|
177
|
+
>>> tax_benefit_system.load_variable(salary)
|
|
178
|
+
<...salary object at ...>
|
|
179
|
+
>>> tax_benefit_system.load_variable(taxes)
|
|
180
|
+
<...taxes object at ...>
|
|
181
|
+
>>> period = "2023-12"
|
|
182
|
+
>>> variables = {"salary": {period: 10000}, "taxes": 5000}
|
|
183
|
+
>>> builder = _BuildFromVariables(tax_benefit_system, variables)
|
|
184
|
+
>>> builder.add_undated_values()
|
|
185
|
+
Traceback (most recent call last):
|
|
186
|
+
openfisca_core.errors.situation_parsing_error.SituationParsingError
|
|
187
|
+
>>> builder.default_period = period
|
|
188
|
+
>>> builder.add_undated_values()
|
|
189
|
+
<..._BuildFromVariables object at ...>
|
|
190
|
+
|
|
191
|
+
>>> dogs = builder.populations["dog"].get_holder("salary")
|
|
192
|
+
>>> dogs.get_array(period)
|
|
193
|
+
|
|
194
|
+
>>> pack = builder.populations["pack"].get_holder("taxes")
|
|
195
|
+
>>> pack.get_array(period)
|
|
196
|
+
array([5000], dtype=int32)
|
|
197
|
+
|
|
198
|
+
"""
|
|
199
|
+
for variable, value in self.variables.items():
|
|
200
|
+
if not is_variable_dated(undated_value := value):
|
|
201
|
+
if (period := self.default_period) is None:
|
|
202
|
+
message = (
|
|
203
|
+
"Can't deal with type: expected object. Input "
|
|
204
|
+
"variables should be set for specific periods. For "
|
|
205
|
+
"instance: "
|
|
206
|
+
" {'salary': {'2017-01': 2000, '2017-02': 2500}}"
|
|
207
|
+
" {'birth_date': {'ETERNITY': '1980-01-01'}}"
|
|
208
|
+
)
|
|
209
|
+
|
|
210
|
+
raise errors.SituationParsingError([variable], message)
|
|
211
|
+
|
|
212
|
+
self.simulation.set_input(variable, period, undated_value)
|
|
213
|
+
|
|
214
|
+
return self
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
def _person_count(params: Variables) -> int:
|
|
218
|
+
try:
|
|
219
|
+
first_value = next(iter(params.values()))
|
|
220
|
+
|
|
221
|
+
if isinstance(first_value, dict):
|
|
222
|
+
first_value = next(iter(first_value.values()))
|
|
223
|
+
|
|
224
|
+
if isinstance(first_value, str):
|
|
225
|
+
return 1
|
|
226
|
+
|
|
227
|
+
return len(first_value)
|
|
228
|
+
|
|
229
|
+
except Exception:
|
|
230
|
+
return 1
|
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"""Type guards to help type narrowing simulation parameters."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections.abc import Iterable
|
|
6
|
+
from typing import TypeGuard
|
|
7
|
+
|
|
8
|
+
from .typing import (
|
|
9
|
+
Axes,
|
|
10
|
+
DatedVariable,
|
|
11
|
+
FullySpecifiedEntities,
|
|
12
|
+
ImplicitGroupEntities,
|
|
13
|
+
Params,
|
|
14
|
+
UndatedVariable,
|
|
15
|
+
Variables,
|
|
16
|
+
)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def are_entities_fully_specified(
|
|
20
|
+
params: Params,
|
|
21
|
+
items: Iterable[str],
|
|
22
|
+
) -> TypeGuard[FullySpecifiedEntities]:
|
|
23
|
+
"""Check if the params contain fully specified entities.
|
|
24
|
+
|
|
25
|
+
Args:
|
|
26
|
+
params(Params): Simulation parameters.
|
|
27
|
+
items(Iterable[str]): List of entities in plural form.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
bool: True if the params contain fully specified entities.
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
>>> entities = {"persons", "households"}
|
|
34
|
+
|
|
35
|
+
>>> params = {
|
|
36
|
+
... "axes": [
|
|
37
|
+
... [
|
|
38
|
+
... {
|
|
39
|
+
... "count": 2,
|
|
40
|
+
... "max": 3000,
|
|
41
|
+
... "min": 0,
|
|
42
|
+
... "name": "rent",
|
|
43
|
+
... "period": "2018-11",
|
|
44
|
+
... }
|
|
45
|
+
... ]
|
|
46
|
+
... ],
|
|
47
|
+
... "households": {
|
|
48
|
+
... "housea": {"parents": ["Alicia", "Javier"]},
|
|
49
|
+
... "houseb": {"parents": ["Tom"]},
|
|
50
|
+
... },
|
|
51
|
+
... "persons": {"Alicia": {"salary": {"2018-11": 0}}, "Javier": {}, "Tom": {}},
|
|
52
|
+
... }
|
|
53
|
+
|
|
54
|
+
>>> are_entities_fully_specified(params, entities)
|
|
55
|
+
True
|
|
56
|
+
|
|
57
|
+
>>> params = {"persons": {"Javier": {"salary": {"2018-11": [2000, 3000]}}}}
|
|
58
|
+
|
|
59
|
+
>>> are_entities_fully_specified(params, entities)
|
|
60
|
+
True
|
|
61
|
+
|
|
62
|
+
>>> params = {"persons": {"Javier": {"salary": {"2018-11": 2000}}}}
|
|
63
|
+
|
|
64
|
+
>>> are_entities_fully_specified(params, entities)
|
|
65
|
+
True
|
|
66
|
+
|
|
67
|
+
>>> params = {"household": {"parents": ["Javier"]}}
|
|
68
|
+
|
|
69
|
+
>>> are_entities_fully_specified(params, entities)
|
|
70
|
+
False
|
|
71
|
+
|
|
72
|
+
>>> params = {"salary": {"2016-10": 12000}}
|
|
73
|
+
|
|
74
|
+
>>> are_entities_fully_specified(params, entities)
|
|
75
|
+
False
|
|
76
|
+
|
|
77
|
+
>>> params = {"salary": 12000}
|
|
78
|
+
|
|
79
|
+
>>> are_entities_fully_specified(params, entities)
|
|
80
|
+
False
|
|
81
|
+
|
|
82
|
+
>>> params = {}
|
|
83
|
+
|
|
84
|
+
>>> are_entities_fully_specified(params, entities)
|
|
85
|
+
False
|
|
86
|
+
|
|
87
|
+
"""
|
|
88
|
+
if not params:
|
|
89
|
+
return False
|
|
90
|
+
|
|
91
|
+
return all(key in items for key in params if key != "axes")
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def are_entities_short_form(
|
|
95
|
+
params: Params,
|
|
96
|
+
items: Iterable[str],
|
|
97
|
+
) -> TypeGuard[ImplicitGroupEntities]:
|
|
98
|
+
"""Check if the params contain short form entities.
|
|
99
|
+
|
|
100
|
+
Args:
|
|
101
|
+
params(Params): Simulation parameters.
|
|
102
|
+
items(Iterable[str]): List of entities in singular form.
|
|
103
|
+
|
|
104
|
+
Returns:
|
|
105
|
+
bool: True if the params contain short form entities.
|
|
106
|
+
|
|
107
|
+
Examples:
|
|
108
|
+
>>> entities = {"person", "household"}
|
|
109
|
+
|
|
110
|
+
>>> params = {
|
|
111
|
+
... "persons": {"Javier": {"salary": {"2018-11": 2000}}},
|
|
112
|
+
... "households": {"household": {"parents": ["Javier"]}},
|
|
113
|
+
... "axes": [[{"count": 1, "max": 1, "min": 1, "name": "household"}]],
|
|
114
|
+
... }
|
|
115
|
+
|
|
116
|
+
>>> are_entities_short_form(params, entities)
|
|
117
|
+
False
|
|
118
|
+
|
|
119
|
+
>>> params = {"persons": {"Javier": {"salary": {"2018-11": 2000}}}}
|
|
120
|
+
|
|
121
|
+
>>> are_entities_short_form(params, entities)
|
|
122
|
+
False
|
|
123
|
+
|
|
124
|
+
>>> params = {
|
|
125
|
+
... "persons": {"Javier": {"salary": {"2018-11": 2000}}},
|
|
126
|
+
... "household": {"parents": ["Javier"]},
|
|
127
|
+
... "axes": [[{"count": 1, "max": 1, "min": 1, "name": "household"}]],
|
|
128
|
+
... }
|
|
129
|
+
|
|
130
|
+
>>> are_entities_short_form(params, entities)
|
|
131
|
+
True
|
|
132
|
+
|
|
133
|
+
>>> params = {
|
|
134
|
+
... "household": {"parents": ["Javier"]},
|
|
135
|
+
... "axes": [[{"count": 1, "max": 1, "min": 1, "name": "household"}]],
|
|
136
|
+
... }
|
|
137
|
+
|
|
138
|
+
>>> are_entities_short_form(params, entities)
|
|
139
|
+
True
|
|
140
|
+
|
|
141
|
+
>>> params = {"household": {"parents": ["Javier"]}}
|
|
142
|
+
|
|
143
|
+
>>> are_entities_short_form(params, entities)
|
|
144
|
+
True
|
|
145
|
+
|
|
146
|
+
>>> params = {"household": {"parents": "Javier"}}
|
|
147
|
+
|
|
148
|
+
>>> are_entities_short_form(params, entities)
|
|
149
|
+
True
|
|
150
|
+
|
|
151
|
+
>>> params = {"salary": {"2016-10": 12000}}
|
|
152
|
+
|
|
153
|
+
>>> are_entities_short_form(params, entities)
|
|
154
|
+
False
|
|
155
|
+
|
|
156
|
+
>>> params = {"salary": 12000}
|
|
157
|
+
|
|
158
|
+
>>> are_entities_short_form(params, entities)
|
|
159
|
+
False
|
|
160
|
+
|
|
161
|
+
>>> params = {}
|
|
162
|
+
|
|
163
|
+
>>> are_entities_short_form(params, entities)
|
|
164
|
+
False
|
|
165
|
+
|
|
166
|
+
"""
|
|
167
|
+
return bool(set(params).intersection(items))
|
|
168
|
+
|
|
169
|
+
|
|
170
|
+
def are_entities_specified(
|
|
171
|
+
params: Params,
|
|
172
|
+
items: Iterable[str],
|
|
173
|
+
) -> TypeGuard[Variables]:
|
|
174
|
+
"""Check if the params contains entities at all.
|
|
175
|
+
|
|
176
|
+
Args:
|
|
177
|
+
params(Params): Simulation parameters.
|
|
178
|
+
items(Iterable[str]): List of variables.
|
|
179
|
+
|
|
180
|
+
Returns:
|
|
181
|
+
bool: True if the params does not contain variables at the root level.
|
|
182
|
+
|
|
183
|
+
Examples:
|
|
184
|
+
>>> variables = {"salary"}
|
|
185
|
+
|
|
186
|
+
>>> params = {
|
|
187
|
+
... "persons": {"Javier": {"salary": {"2018-11": 2000}}},
|
|
188
|
+
... "households": {"household": {"parents": ["Javier"]}},
|
|
189
|
+
... "axes": [[{"count": 1, "max": 1, "min": 1, "name": "household"}]],
|
|
190
|
+
... }
|
|
191
|
+
|
|
192
|
+
>>> are_entities_specified(params, variables)
|
|
193
|
+
True
|
|
194
|
+
|
|
195
|
+
>>> params = {"persons": {"Javier": {"salary": {"2018-11": [2000, 3000]}}}}
|
|
196
|
+
|
|
197
|
+
>>> are_entities_specified(params, variables)
|
|
198
|
+
True
|
|
199
|
+
|
|
200
|
+
>>> params = {"persons": {"Javier": {"salary": {"2018-11": 2000}}}}
|
|
201
|
+
|
|
202
|
+
>>> are_entities_specified(params, variables)
|
|
203
|
+
True
|
|
204
|
+
|
|
205
|
+
>>> params = {"household": {"parents": ["Javier"]}}
|
|
206
|
+
|
|
207
|
+
>>> are_entities_specified(params, variables)
|
|
208
|
+
True
|
|
209
|
+
|
|
210
|
+
>>> params = {"salary": {"2016-10": [12000, 13000]}}
|
|
211
|
+
|
|
212
|
+
>>> are_entities_specified(params, variables)
|
|
213
|
+
False
|
|
214
|
+
|
|
215
|
+
>>> params = {"salary": {"2016-10": 12000}}
|
|
216
|
+
|
|
217
|
+
>>> are_entities_specified(params, variables)
|
|
218
|
+
False
|
|
219
|
+
|
|
220
|
+
>>> params = {"salary": [12000, 13000]}
|
|
221
|
+
|
|
222
|
+
>>> are_entities_specified(params, variables)
|
|
223
|
+
False
|
|
224
|
+
|
|
225
|
+
>>> params = {"salary": 12000}
|
|
226
|
+
|
|
227
|
+
>>> are_entities_specified(params, variables)
|
|
228
|
+
False
|
|
229
|
+
|
|
230
|
+
>>> params = {}
|
|
231
|
+
|
|
232
|
+
>>> are_entities_specified(params, variables)
|
|
233
|
+
False
|
|
234
|
+
|
|
235
|
+
"""
|
|
236
|
+
if not params:
|
|
237
|
+
return False
|
|
238
|
+
|
|
239
|
+
return not any(key in items for key in params)
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
def has_axes(params: Params) -> TypeGuard[Axes]:
|
|
243
|
+
"""Check if the params contains axes.
|
|
244
|
+
|
|
245
|
+
Args:
|
|
246
|
+
params(Params): Simulation parameters.
|
|
247
|
+
|
|
248
|
+
Returns:
|
|
249
|
+
bool: True if the params contain axes.
|
|
250
|
+
|
|
251
|
+
Examples:
|
|
252
|
+
>>> params = {
|
|
253
|
+
... "persons": {"Javier": {"salary": {"2018-11": 2000}}},
|
|
254
|
+
... "households": {"household": {"parents": ["Javier"]}},
|
|
255
|
+
... "axes": [[{"count": 1, "max": 1, "min": 1, "name": "household"}]],
|
|
256
|
+
... }
|
|
257
|
+
|
|
258
|
+
>>> has_axes(params)
|
|
259
|
+
True
|
|
260
|
+
|
|
261
|
+
>>> params = {"persons": {"Javier": {"salary": {"2018-11": [2000, 3000]}}}}
|
|
262
|
+
|
|
263
|
+
>>> has_axes(params)
|
|
264
|
+
False
|
|
265
|
+
|
|
266
|
+
"""
|
|
267
|
+
return params.get("axes", None) is not None
|
|
268
|
+
|
|
269
|
+
|
|
270
|
+
def is_variable_dated(
|
|
271
|
+
variable: DatedVariable | UndatedVariable,
|
|
272
|
+
) -> TypeGuard[DatedVariable]:
|
|
273
|
+
"""Check if the variable is dated.
|
|
274
|
+
|
|
275
|
+
Args:
|
|
276
|
+
variable(DatedVariable | UndatedVariable): A variable.
|
|
277
|
+
|
|
278
|
+
Returns:
|
|
279
|
+
bool: True if the variable is dated.
|
|
280
|
+
|
|
281
|
+
Examples:
|
|
282
|
+
>>> variable = {"2018-11": [2000, 3000]}
|
|
283
|
+
|
|
284
|
+
>>> is_variable_dated(variable)
|
|
285
|
+
True
|
|
286
|
+
|
|
287
|
+
>>> variable = {"2018-11": 2000}
|
|
288
|
+
|
|
289
|
+
>>> is_variable_dated(variable)
|
|
290
|
+
True
|
|
291
|
+
|
|
292
|
+
>>> variable = 2000
|
|
293
|
+
|
|
294
|
+
>>> is_variable_dated(variable)
|
|
295
|
+
False
|
|
296
|
+
|
|
297
|
+
"""
|
|
298
|
+
return isinstance(variable, dict)
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from collections.abc import Iterable
|
|
2
|
+
|
|
3
|
+
from openfisca_core import errors
|
|
4
|
+
|
|
5
|
+
from .typing import ParamsWithoutAxes
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def calculate_output_add(simulation, variable_name: str, period):
|
|
9
|
+
return simulation.calculate_add(variable_name, period)
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def calculate_output_divide(simulation, variable_name: str, period):
|
|
13
|
+
return simulation.calculate_divide(variable_name, period)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def check_type(input, input_type, path=None) -> None:
|
|
17
|
+
json_type_map = {
|
|
18
|
+
dict: "Object",
|
|
19
|
+
list: "Array",
|
|
20
|
+
str: "String",
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
if path is None:
|
|
24
|
+
path = []
|
|
25
|
+
|
|
26
|
+
if not isinstance(input, input_type):
|
|
27
|
+
raise errors.SituationParsingError(
|
|
28
|
+
path,
|
|
29
|
+
f"Invalid type: must be of type '{json_type_map[input_type]}'.",
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def check_unexpected_entities(
|
|
34
|
+
params: ParamsWithoutAxes,
|
|
35
|
+
entities: Iterable[str],
|
|
36
|
+
) -> None:
|
|
37
|
+
"""Check if the input contains entities that are not in the system.
|
|
38
|
+
|
|
39
|
+
Args:
|
|
40
|
+
params(ParamsWithoutAxes): Simulation parameters.
|
|
41
|
+
entities(Iterable[str]): List of entities in plural form.
|
|
42
|
+
|
|
43
|
+
Raises:
|
|
44
|
+
SituationParsingError: If there are entities that are not in the system.
|
|
45
|
+
|
|
46
|
+
Examples:
|
|
47
|
+
>>> entities = {"persons", "households"}
|
|
48
|
+
|
|
49
|
+
>>> params = {
|
|
50
|
+
... "persons": {"Javier": {"salary": {"2018-11": 2000}}},
|
|
51
|
+
... "households": {"household": {"parents": ["Javier"]}},
|
|
52
|
+
... }
|
|
53
|
+
|
|
54
|
+
>>> check_unexpected_entities(params, entities)
|
|
55
|
+
|
|
56
|
+
>>> params = {"dogs": {"Bart": {"damages": {"2018-11": 2000}}}}
|
|
57
|
+
|
|
58
|
+
>>> check_unexpected_entities(params, entities)
|
|
59
|
+
Traceback (most recent call last):
|
|
60
|
+
openfisca_core.errors.situation_parsing_error.SituationParsingError
|
|
61
|
+
|
|
62
|
+
"""
|
|
63
|
+
if has_unexpected_entities(params, entities):
|
|
64
|
+
unexpected_entities = [entity for entity in params if entity not in entities]
|
|
65
|
+
|
|
66
|
+
message = (
|
|
67
|
+
"Some entities in the situation are not defined in the loaded tax "
|
|
68
|
+
"and benefit system. "
|
|
69
|
+
f"These entities are not found: {', '.join(unexpected_entities)}. "
|
|
70
|
+
f"The defined entities are: {', '.join(entities)}."
|
|
71
|
+
)
|
|
72
|
+
|
|
73
|
+
raise errors.SituationParsingError([unexpected_entities[0]], message)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def has_unexpected_entities(params: ParamsWithoutAxes, entities: Iterable[str]) -> bool:
|
|
77
|
+
"""Check if the input contains entities that are not in the system.
|
|
78
|
+
|
|
79
|
+
Args:
|
|
80
|
+
params(ParamsWithoutAxes): Simulation parameters.
|
|
81
|
+
entities(Iterable[str]): List of entities in plural form.
|
|
82
|
+
|
|
83
|
+
Returns:
|
|
84
|
+
bool: True if the input contains entities that are not in the system.
|
|
85
|
+
|
|
86
|
+
Examples:
|
|
87
|
+
>>> entities = {"persons", "households"}
|
|
88
|
+
|
|
89
|
+
>>> params = {
|
|
90
|
+
... "persons": {"Javier": {"salary": {"2018-11": 2000}}},
|
|
91
|
+
... "households": {"household": {"parents": ["Javier"]}},
|
|
92
|
+
... }
|
|
93
|
+
|
|
94
|
+
>>> has_unexpected_entities(params, entities)
|
|
95
|
+
False
|
|
96
|
+
|
|
97
|
+
>>> params = {"dogs": {"Bart": {"damages": {"2018-11": 2000}}}}
|
|
98
|
+
|
|
99
|
+
>>> has_unexpected_entities(params, entities)
|
|
100
|
+
True
|
|
101
|
+
|
|
102
|
+
"""
|
|
103
|
+
return any(entity for entity in params if entity not in entities)
|
|
104
|
+
|
|
105
|
+
|
|
106
|
+
def transform_to_strict_syntax(data):
|
|
107
|
+
if isinstance(data, (str, int)):
|
|
108
|
+
data = [data]
|
|
109
|
+
if isinstance(data, list):
|
|
110
|
+
return [str(item) if isinstance(item, int) else item for item in data]
|
|
111
|
+
return data
|