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,39 @@
|
|
|
1
|
+
# Transitional imports to ensure non-breaking changes.
|
|
2
|
+
# Could be deprecated in the next major release.
|
|
3
|
+
#
|
|
4
|
+
# How imports are being used today:
|
|
5
|
+
#
|
|
6
|
+
# >>> from openfisca_core.module import symbol
|
|
7
|
+
#
|
|
8
|
+
# The previous example provokes cyclic dependency problems
|
|
9
|
+
# that prevent us from modularizing the different components
|
|
10
|
+
# of the library so to make them easier to test and to maintain.
|
|
11
|
+
#
|
|
12
|
+
# How could them be used after the next major release:
|
|
13
|
+
#
|
|
14
|
+
# >>> from openfisca_core import module
|
|
15
|
+
# >>> module.symbol()
|
|
16
|
+
#
|
|
17
|
+
# And for classes:
|
|
18
|
+
#
|
|
19
|
+
# >>> from openfisca_core.module import Symbol
|
|
20
|
+
# >>> Symbol()
|
|
21
|
+
#
|
|
22
|
+
# See: https://www.python.org/dev/peps/pep-0008/#imports
|
|
23
|
+
|
|
24
|
+
from . import typing
|
|
25
|
+
from .entity_to_person_projector import EntityToPersonProjector
|
|
26
|
+
from .first_person_to_entity_projector import FirstPersonToEntityProjector
|
|
27
|
+
from .helpers import get_projector_from_shortcut, projectable
|
|
28
|
+
from .projector import Projector
|
|
29
|
+
from .unique_role_to_entity_projector import UniqueRoleToEntityProjector
|
|
30
|
+
|
|
31
|
+
__all__ = [
|
|
32
|
+
"EntityToPersonProjector",
|
|
33
|
+
"FirstPersonToEntityProjector",
|
|
34
|
+
"Projector",
|
|
35
|
+
"UniqueRoleToEntityProjector",
|
|
36
|
+
"get_projector_from_shortcut",
|
|
37
|
+
"projectable",
|
|
38
|
+
"typing",
|
|
39
|
+
]
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from .projector import Projector
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class EntityToPersonProjector(Projector):
|
|
5
|
+
"""For instance person.family."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, entity, parent=None) -> None:
|
|
8
|
+
self.reference_entity = entity
|
|
9
|
+
self.parent = parent
|
|
10
|
+
|
|
11
|
+
def transform(self, result):
|
|
12
|
+
return self.reference_entity.project(result)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from .projector import Projector
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class FirstPersonToEntityProjector(Projector):
|
|
5
|
+
"""For instance famille.first_person."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, entity, parent=None) -> None:
|
|
8
|
+
self.target_entity = entity
|
|
9
|
+
self.reference_entity = entity.members
|
|
10
|
+
self.parent = parent
|
|
11
|
+
|
|
12
|
+
def transform(self, result):
|
|
13
|
+
return self.target_entity.value_from_first_person(result)
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
|
|
5
|
+
from openfisca_core import entities, projectors
|
|
6
|
+
from openfisca_core.types import GroupEntity, Role, SingleEntity
|
|
7
|
+
|
|
8
|
+
from .typing import GroupPopulation, Population
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def projectable(function):
|
|
12
|
+
"""Decorator to indicate that when called on a projector, the outcome of the function must be projected.
|
|
13
|
+
For instance person.household.sum(...) must be projected on person, while it would not make sense for person.household.get_holder.
|
|
14
|
+
"""
|
|
15
|
+
function.projectable = True
|
|
16
|
+
return function
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def get_projector_from_shortcut(
|
|
20
|
+
population: Population | GroupPopulation,
|
|
21
|
+
shortcut: str,
|
|
22
|
+
parent: projectors.Projector | None = None,
|
|
23
|
+
) -> projectors.Projector | None:
|
|
24
|
+
"""Get a projector from a shortcut.
|
|
25
|
+
|
|
26
|
+
Projectors are used to project an invidividual Population's or a
|
|
27
|
+
collective GroupPopulation's on to other populations.
|
|
28
|
+
|
|
29
|
+
The currently available cases are projecting:
|
|
30
|
+
- from an individual to a group
|
|
31
|
+
- from a group to an individual
|
|
32
|
+
- from a group to an individual with a unique role
|
|
33
|
+
|
|
34
|
+
For example, if there are two entities, person (Entity) and household
|
|
35
|
+
(GroupEntity), on which calculations can be run (Population and
|
|
36
|
+
GroupPopulation respectively), and there is a Variable "rent" defined for
|
|
37
|
+
the household entity, then `person.household("rent")` will assign a rent to
|
|
38
|
+
every person within that household.
|
|
39
|
+
|
|
40
|
+
Behind the scenes, this is done thanks to a Projector, and this function is
|
|
41
|
+
used to find the appropriate one for each case. In the above example, the
|
|
42
|
+
`shortcut` argument would be "household", and the `population` argument
|
|
43
|
+
would be the Population linked to the "person" Entity in the context
|
|
44
|
+
of a specific Simulation and TaxBenefitSystem.
|
|
45
|
+
|
|
46
|
+
Args:
|
|
47
|
+
population (Population | GroupPopulation): Where to project from.
|
|
48
|
+
shortcut (str): Where to project to.
|
|
49
|
+
parent: ???
|
|
50
|
+
|
|
51
|
+
Examples:
|
|
52
|
+
>>> from openfisca_core import (
|
|
53
|
+
... entities,
|
|
54
|
+
... populations,
|
|
55
|
+
... simulations,
|
|
56
|
+
... taxbenefitsystems,
|
|
57
|
+
... )
|
|
58
|
+
|
|
59
|
+
>>> entity = entities.Entity("person", "", "", "")
|
|
60
|
+
|
|
61
|
+
>>> group_entity_1 = entities.GroupEntity("family", "", "", "", [])
|
|
62
|
+
|
|
63
|
+
>>> roles = [
|
|
64
|
+
... {"key": "person", "max": 1},
|
|
65
|
+
... {"key": "animal", "subroles": ["cat", "dog"]},
|
|
66
|
+
... ]
|
|
67
|
+
|
|
68
|
+
>>> group_entity_2 = entities.GroupEntity("household", "", "", "", roles)
|
|
69
|
+
|
|
70
|
+
>>> population = populations.Population(entity)
|
|
71
|
+
|
|
72
|
+
>>> group_population_1 = populations.GroupPopulation(group_entity_1, [])
|
|
73
|
+
|
|
74
|
+
>>> group_population_2 = populations.GroupPopulation(group_entity_2, [])
|
|
75
|
+
|
|
76
|
+
>>> populations = {
|
|
77
|
+
... entity.key: population,
|
|
78
|
+
... group_entity_1.key: group_population_1,
|
|
79
|
+
... group_entity_2.key: group_population_2,
|
|
80
|
+
... }
|
|
81
|
+
|
|
82
|
+
>>> tax_benefit_system = taxbenefitsystems.TaxBenefitSystem(
|
|
83
|
+
... [entity, group_entity_1, group_entity_2]
|
|
84
|
+
... )
|
|
85
|
+
|
|
86
|
+
>>> simulation = simulations.Simulation(tax_benefit_system, populations)
|
|
87
|
+
|
|
88
|
+
>>> get_projector_from_shortcut(population, "person")
|
|
89
|
+
<...EntityToPersonProjector object at ...>
|
|
90
|
+
|
|
91
|
+
>>> get_projector_from_shortcut(population, "family")
|
|
92
|
+
<...EntityToPersonProjector object at ...>
|
|
93
|
+
|
|
94
|
+
>>> get_projector_from_shortcut(population, "household")
|
|
95
|
+
<...EntityToPersonProjector object at ...>
|
|
96
|
+
|
|
97
|
+
>>> get_projector_from_shortcut(group_population_2, "first_person")
|
|
98
|
+
<...FirstPersonToEntityProjector object at ...>
|
|
99
|
+
|
|
100
|
+
>>> get_projector_from_shortcut(group_population_2, "person")
|
|
101
|
+
<...UniqueRoleToEntityProjector object at ...>
|
|
102
|
+
|
|
103
|
+
>>> get_projector_from_shortcut(group_population_2, "cat")
|
|
104
|
+
<...UniqueRoleToEntityProjector object at ...>
|
|
105
|
+
|
|
106
|
+
>>> get_projector_from_shortcut(group_population_2, "dog")
|
|
107
|
+
<...UniqueRoleToEntityProjector object at ...>
|
|
108
|
+
|
|
109
|
+
"""
|
|
110
|
+
entity: SingleEntity | GroupEntity = population.entity
|
|
111
|
+
|
|
112
|
+
if isinstance(entity, entities.Entity):
|
|
113
|
+
populations: Mapping[
|
|
114
|
+
str,
|
|
115
|
+
Population | GroupPopulation,
|
|
116
|
+
] = population.simulation.populations
|
|
117
|
+
|
|
118
|
+
if shortcut not in populations:
|
|
119
|
+
return None
|
|
120
|
+
|
|
121
|
+
return projectors.EntityToPersonProjector(populations[shortcut], parent)
|
|
122
|
+
|
|
123
|
+
if shortcut == "first_person":
|
|
124
|
+
return projectors.FirstPersonToEntityProjector(population, parent)
|
|
125
|
+
|
|
126
|
+
if isinstance(entity, entities.GroupEntity):
|
|
127
|
+
role: Role | None = entities.find_role(entity.roles, shortcut, total=1)
|
|
128
|
+
|
|
129
|
+
if role is not None:
|
|
130
|
+
return projectors.UniqueRoleToEntityProjector(population, role, parent)
|
|
131
|
+
|
|
132
|
+
if shortcut in entity.containing_entities:
|
|
133
|
+
projector: projectors.Projector = getattr(
|
|
134
|
+
projectors.FirstPersonToEntityProjector(population, parent),
|
|
135
|
+
shortcut,
|
|
136
|
+
)
|
|
137
|
+
return projector
|
|
138
|
+
|
|
139
|
+
return None
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
from openfisca_core.projectors import helpers
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Projector:
|
|
5
|
+
reference_entity = None
|
|
6
|
+
parent = None
|
|
7
|
+
|
|
8
|
+
def __getattr__(self, attribute):
|
|
9
|
+
projector = helpers.get_projector_from_shortcut(
|
|
10
|
+
self.reference_entity,
|
|
11
|
+
attribute,
|
|
12
|
+
parent=self,
|
|
13
|
+
)
|
|
14
|
+
if projector:
|
|
15
|
+
return projector
|
|
16
|
+
|
|
17
|
+
reference_attr = getattr(self.reference_entity, attribute)
|
|
18
|
+
if not hasattr(reference_attr, "projectable"):
|
|
19
|
+
return reference_attr
|
|
20
|
+
|
|
21
|
+
def projector_function(*args, **kwargs):
|
|
22
|
+
result = reference_attr(*args, **kwargs)
|
|
23
|
+
return self.transform_and_bubble_up(result)
|
|
24
|
+
|
|
25
|
+
return projector_function
|
|
26
|
+
|
|
27
|
+
def __call__(self, *args, **kwargs):
|
|
28
|
+
result = self.reference_entity(*args, **kwargs)
|
|
29
|
+
return self.transform_and_bubble_up(result)
|
|
30
|
+
|
|
31
|
+
def transform_and_bubble_up(self, result):
|
|
32
|
+
transformed_result = self.transform(result)
|
|
33
|
+
if self.parent is None:
|
|
34
|
+
return transformed_result
|
|
35
|
+
return self.parent.transform_and_bubble_up(transformed_result)
|
|
36
|
+
|
|
37
|
+
def transform(self, result):
|
|
38
|
+
return NotImplementedError()
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
from typing import Protocol
|
|
5
|
+
|
|
6
|
+
from openfisca_core.types import GroupEntity, SingleEntity
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Population(Protocol):
|
|
10
|
+
@property
|
|
11
|
+
def entity(self) -> SingleEntity: ...
|
|
12
|
+
|
|
13
|
+
@property
|
|
14
|
+
def simulation(self) -> Simulation: ...
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class GroupPopulation(Protocol):
|
|
18
|
+
@property
|
|
19
|
+
def entity(self) -> GroupEntity: ...
|
|
20
|
+
|
|
21
|
+
@property
|
|
22
|
+
def simulation(self) -> Simulation: ...
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class Simulation(Protocol):
|
|
26
|
+
@property
|
|
27
|
+
def populations(self) -> Mapping[str, Population | GroupPopulation]: ...
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
from .projector import Projector
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class UniqueRoleToEntityProjector(Projector):
|
|
5
|
+
"""For instance famille.declarant_principal."""
|
|
6
|
+
|
|
7
|
+
def __init__(self, entity, role, parent=None) -> None:
|
|
8
|
+
self.target_entity = entity
|
|
9
|
+
self.reference_entity = entity.members
|
|
10
|
+
self.parent = parent
|
|
11
|
+
self.role = role
|
|
12
|
+
|
|
13
|
+
def transform(self, result):
|
|
14
|
+
return self.target_entity.value_from_person(result, self.role)
|
openfisca_core/rates.py
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The formula_helpers module has been deprecated since X.X.X,
|
|
2
|
+
# and will be removed in the future.
|
|
3
|
+
#
|
|
4
|
+
# The helpers have been moved to the commons module.
|
|
5
|
+
#
|
|
6
|
+
# The following are transitional imports to ensure non-breaking changes.
|
|
7
|
+
# Could be deprecated in the next major release.
|
|
8
|
+
|
|
9
|
+
from openfisca_core.commons import average_rate, marginal_rate # noqa: F401
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# Transitional imports to ensure non-breaking changes.
|
|
2
|
+
# Could be deprecated in the next major release.
|
|
3
|
+
#
|
|
4
|
+
# How imports are being used today:
|
|
5
|
+
#
|
|
6
|
+
# >>> from openfisca_core.module import symbol
|
|
7
|
+
#
|
|
8
|
+
# The previous example provokes cyclic dependency problems
|
|
9
|
+
# that prevent us from modularizing the different components
|
|
10
|
+
# of the library so to make them easier to test and to maintain.
|
|
11
|
+
#
|
|
12
|
+
# How could them be used after the next major release:
|
|
13
|
+
#
|
|
14
|
+
# >>> from openfisca_core import module
|
|
15
|
+
# >>> module.symbol()
|
|
16
|
+
#
|
|
17
|
+
# And for classes:
|
|
18
|
+
#
|
|
19
|
+
# >>> from openfisca_core.module import Symbol
|
|
20
|
+
# >>> Symbol()
|
|
21
|
+
#
|
|
22
|
+
# See: https://www.python.org/dev/peps/pep-0008/#imports
|
|
23
|
+
|
|
24
|
+
from .reform import Reform # noqa: F401
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from openfisca_core.parameters.parameter_node import ParameterNode
|
|
4
|
+
from openfisca_core.reforms import Reform
|
|
5
|
+
from openfisca_core.types import TaxBenefitSystem
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class InYamlTestReform(Reform):
|
|
9
|
+
"""A class representing a parametric reform directly defined in YAML test files."""
|
|
10
|
+
|
|
11
|
+
def __init__(
|
|
12
|
+
self,
|
|
13
|
+
baseline: TaxBenefitSystem,
|
|
14
|
+
reformed_parameters=dict,
|
|
15
|
+
) -> None:
|
|
16
|
+
"""Initialize the instance.
|
|
17
|
+
|
|
18
|
+
:param baseline: Baseline TaxBenefitSystem.
|
|
19
|
+
:param reformed_parameters: Yaml file `parameters` value similar to a parameter tree
|
|
20
|
+
"""
|
|
21
|
+
self.reformed_parameters = reformed_parameters
|
|
22
|
+
super().__init__(baseline)
|
|
23
|
+
|
|
24
|
+
def apply(self):
|
|
25
|
+
def modify_parameters(local_parameters: ParameterNode) -> ParameterNode:
|
|
26
|
+
return ParameterNode(data=self.reformed_parameters)
|
|
27
|
+
|
|
28
|
+
self.modify_parameters(modifier_function=modify_parameters)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import copy
|
|
4
|
+
|
|
5
|
+
from openfisca_core.parameters import ParameterNode
|
|
6
|
+
from openfisca_core.taxbenefitsystems import TaxBenefitSystem
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class Reform(TaxBenefitSystem):
|
|
10
|
+
"""A modified TaxBenefitSystem.
|
|
11
|
+
|
|
12
|
+
All reforms must subclass `Reform` and implement a method `apply()`.
|
|
13
|
+
|
|
14
|
+
In this method, the reform can add or replace variables and call `modify_parameters` to modify the parameters of the legislation.
|
|
15
|
+
|
|
16
|
+
Example:
|
|
17
|
+
>>> from openfisca_core import reforms
|
|
18
|
+
>>> from openfisca_core.parameters import load_parameter_file
|
|
19
|
+
>>>
|
|
20
|
+
>>> def modify_my_parameters(parameters):
|
|
21
|
+
>>> # Add new parameters
|
|
22
|
+
>>> new_parameters = load_parameter_file(name='reform_name', file_path='path_to_yaml_file.yaml')
|
|
23
|
+
>>> parameters.add_child('reform_name', new_parameters)
|
|
24
|
+
>>>
|
|
25
|
+
>>> # Update a value
|
|
26
|
+
>>> parameters.taxes.some_tax.some_param.update(period=some_period, value=1000.0)
|
|
27
|
+
>>>
|
|
28
|
+
>>> return parameters
|
|
29
|
+
>>>
|
|
30
|
+
>>> class MyReform(reforms.Reform):
|
|
31
|
+
>>> def apply(self):
|
|
32
|
+
>>> self.add_variable(some_variable)
|
|
33
|
+
>>> self.update_variable(some_other_variable)
|
|
34
|
+
>>> self.modify_parameters(modifier_function = modify_my_parameters)
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
|
|
38
|
+
name = None
|
|
39
|
+
|
|
40
|
+
def __init__(self, baseline) -> None:
|
|
41
|
+
""":param baseline: Baseline TaxBenefitSystem."""
|
|
42
|
+
super().__init__(baseline.entities)
|
|
43
|
+
self.baseline = baseline
|
|
44
|
+
self.parameters = baseline.parameters
|
|
45
|
+
self._parameters_at_instant_cache = baseline._parameters_at_instant_cache
|
|
46
|
+
self.variables = baseline.variables.copy()
|
|
47
|
+
self.decomposition_file_path = baseline.decomposition_file_path
|
|
48
|
+
self.key = self.__class__.__name__
|
|
49
|
+
if not hasattr(self, "apply"):
|
|
50
|
+
msg = f"Reform {self.key} must define an `apply` function"
|
|
51
|
+
raise Exception(msg)
|
|
52
|
+
self.apply()
|
|
53
|
+
|
|
54
|
+
def __getattr__(self, attribute):
|
|
55
|
+
return getattr(self.baseline, attribute)
|
|
56
|
+
|
|
57
|
+
@property
|
|
58
|
+
def full_key(self):
|
|
59
|
+
key = self.key
|
|
60
|
+
assert key is not None, (
|
|
61
|
+
f"key was not set for reform {self} (name: {self.name!r})"
|
|
62
|
+
)
|
|
63
|
+
if self.baseline is not None and hasattr(self.baseline, "key"):
|
|
64
|
+
baseline_full_key = self.baseline.full_key
|
|
65
|
+
key = f"{baseline_full_key}.{key}"
|
|
66
|
+
return key
|
|
67
|
+
|
|
68
|
+
def modify_parameters(self, modifier_function):
|
|
69
|
+
"""Make modifications on the parameters of the legislation.
|
|
70
|
+
|
|
71
|
+
Call this function in `apply()` if the reform asks for legislation parameter modifications.
|
|
72
|
+
|
|
73
|
+
Args:
|
|
74
|
+
modifier_function: A function that takes a :obj:`~parameters.ParameterNode`
|
|
75
|
+
and should return an object of the same type.
|
|
76
|
+
|
|
77
|
+
"""
|
|
78
|
+
baseline_parameters = self.baseline.parameters
|
|
79
|
+
baseline_parameters_copy = copy.deepcopy(baseline_parameters)
|
|
80
|
+
reform_parameters = modifier_function(baseline_parameters_copy)
|
|
81
|
+
if not isinstance(reform_parameters, ParameterNode):
|
|
82
|
+
raise ValueError(
|
|
83
|
+
f"modifier_function {modifier_function.__name__} in module {modifier_function.__module__} must return a ParameterNode",
|
|
84
|
+
)
|
|
85
|
+
self.parameters = reform_parameters
|
|
86
|
+
self._parameters_at_instant_cache = {}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import logging
|
|
3
|
+
import pkgutil
|
|
4
|
+
import traceback
|
|
5
|
+
from os import linesep
|
|
6
|
+
|
|
7
|
+
log = logging.getLogger(__name__)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def add_tax_benefit_system_arguments(parser):
|
|
11
|
+
parser.add_argument(
|
|
12
|
+
"-c",
|
|
13
|
+
"--country-package",
|
|
14
|
+
action="store",
|
|
15
|
+
help='country package to use. If not provided, an automatic detection will be attempted by scanning the python packages installed in your environment which name contains the word "openfisca".',
|
|
16
|
+
)
|
|
17
|
+
parser.add_argument(
|
|
18
|
+
"-e",
|
|
19
|
+
"--extensions",
|
|
20
|
+
action="store",
|
|
21
|
+
help="extensions to load",
|
|
22
|
+
nargs="*",
|
|
23
|
+
)
|
|
24
|
+
parser.add_argument(
|
|
25
|
+
"-r",
|
|
26
|
+
"--reforms",
|
|
27
|
+
action="store",
|
|
28
|
+
help="reforms to apply to the country package",
|
|
29
|
+
nargs="*",
|
|
30
|
+
)
|
|
31
|
+
|
|
32
|
+
return parser
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def build_tax_benefit_system(country_package_name, extensions, reforms):
|
|
36
|
+
if country_package_name is None:
|
|
37
|
+
country_package_name = detect_country_package()
|
|
38
|
+
try:
|
|
39
|
+
country_package = importlib.import_module(country_package_name)
|
|
40
|
+
except ImportError:
|
|
41
|
+
message = linesep.join(
|
|
42
|
+
[
|
|
43
|
+
traceback.format_exc(),
|
|
44
|
+
f"Could not import module `{country_package_name}`.",
|
|
45
|
+
"Are you sure it is installed in your environment? If so, look at the stack trace above to determine the origin of this error.",
|
|
46
|
+
"See more at <https://github.com/openfisca/country-template#installing>.",
|
|
47
|
+
],
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
raise ImportError(message)
|
|
51
|
+
if not hasattr(country_package, "CountryTaxBenefitSystem"):
|
|
52
|
+
msg = f"`{country_package_name}` does not seem to be a valid Openfisca country package."
|
|
53
|
+
raise ImportError(
|
|
54
|
+
msg,
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
country_package = importlib.import_module(country_package_name)
|
|
58
|
+
tax_benefit_system = country_package.CountryTaxBenefitSystem()
|
|
59
|
+
|
|
60
|
+
if extensions:
|
|
61
|
+
for extension in extensions:
|
|
62
|
+
tax_benefit_system.load_extension(extension)
|
|
63
|
+
|
|
64
|
+
if reforms:
|
|
65
|
+
for reform_path in reforms:
|
|
66
|
+
tax_benefit_system = tax_benefit_system.apply_reform(reform_path)
|
|
67
|
+
|
|
68
|
+
return tax_benefit_system
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
# For retro-compatibility:
|
|
72
|
+
build_tax_benefit_sytem = build_tax_benefit_system
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def detect_country_package():
|
|
76
|
+
installed_country_packages = []
|
|
77
|
+
for module_description in pkgutil.iter_modules():
|
|
78
|
+
module_name = module_description[1]
|
|
79
|
+
if "openfisca" in module_name.lower():
|
|
80
|
+
try:
|
|
81
|
+
module = importlib.import_module(module_name)
|
|
82
|
+
except ImportError:
|
|
83
|
+
message = linesep.join(
|
|
84
|
+
[
|
|
85
|
+
traceback.format_exc(),
|
|
86
|
+
f"Could not import module `{module_name}`.",
|
|
87
|
+
"Look at the stack trace above to determine the error that stopped installed modules detection.",
|
|
88
|
+
],
|
|
89
|
+
)
|
|
90
|
+
raise ImportError(message)
|
|
91
|
+
if hasattr(module, "CountryTaxBenefitSystem"):
|
|
92
|
+
installed_country_packages.append(module_name)
|
|
93
|
+
|
|
94
|
+
if len(installed_country_packages) == 0:
|
|
95
|
+
msg = "No country package has been detected on your environment. If your country package is installed but not detected, please use the --country-package option."
|
|
96
|
+
raise ImportError(
|
|
97
|
+
msg,
|
|
98
|
+
)
|
|
99
|
+
if len(installed_country_packages) > 1:
|
|
100
|
+
log.warning(
|
|
101
|
+
"Several country packages detected : `{}`. Using `{}` by default. To use another package, please use the --country-package option.".format(
|
|
102
|
+
", ".join(installed_country_packages),
|
|
103
|
+
installed_country_packages[0],
|
|
104
|
+
),
|
|
105
|
+
)
|
|
106
|
+
return installed_country_packages[0]
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
File without changes
|
|
Binary file
|
|
Binary file
|