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
|
File without changes
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
"""Common tools for contributors and users."""
|
|
2
|
+
|
|
3
|
+
from .dummy import Dummy
|
|
4
|
+
from .formulas import apply_thresholds, concat, switch
|
|
5
|
+
from .misc import empty_clone, eval_expression, stringify_array
|
|
6
|
+
from .rates import average_rate, marginal_rate
|
|
7
|
+
|
|
8
|
+
__all__ = [
|
|
9
|
+
"Dummy",
|
|
10
|
+
"apply_thresholds",
|
|
11
|
+
"average_rate",
|
|
12
|
+
"concat",
|
|
13
|
+
"empty_clone",
|
|
14
|
+
"eval_expression",
|
|
15
|
+
"marginal_rate",
|
|
16
|
+
"stringify_array",
|
|
17
|
+
"switch",
|
|
18
|
+
]
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Dummy:
|
|
5
|
+
"""A class that did nothing.
|
|
6
|
+
|
|
7
|
+
Examples:
|
|
8
|
+
>>> Dummy()
|
|
9
|
+
<openfisca_core.commons.dummy.Dummy object...
|
|
10
|
+
|
|
11
|
+
.. deprecated:: 34.7.0
|
|
12
|
+
:class:`.Dummy` has been deprecated and it will be removed in the
|
|
13
|
+
future.
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(self) -> None:
|
|
18
|
+
message = [
|
|
19
|
+
"The 'Dummy' class has been deprecated since version 34.7.0,",
|
|
20
|
+
"and will be removed in the future.",
|
|
21
|
+
]
|
|
22
|
+
warnings.warn(" ".join(message), DeprecationWarning, stacklevel=2)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__all__ = ["Dummy"]
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from collections.abc import Mapping
|
|
4
|
+
|
|
5
|
+
import numpy
|
|
6
|
+
|
|
7
|
+
from openfisca_core import types as t
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def apply_thresholds(
|
|
11
|
+
input: t.FloatArray,
|
|
12
|
+
thresholds: t.ArrayLike[float],
|
|
13
|
+
choices: t.ArrayLike[float],
|
|
14
|
+
) -> t.FloatArray:
|
|
15
|
+
"""Makes a choice based on an input and thresholds.
|
|
16
|
+
|
|
17
|
+
From a list of ``choices``, this function selects one of these values
|
|
18
|
+
based on a list of inputs, depending on the value of each ``input`` within
|
|
19
|
+
a list of ``thresholds``.
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
input: A list of inputs to make a choice from.
|
|
23
|
+
thresholds: A list of thresholds to choose.
|
|
24
|
+
choices: A list of the possible values to choose from.
|
|
25
|
+
|
|
26
|
+
Returns:
|
|
27
|
+
ndarray[float32]: A list of the values chosen.
|
|
28
|
+
|
|
29
|
+
Examples:
|
|
30
|
+
>>> input = numpy.array([4, 5, 6, 7, 8])
|
|
31
|
+
>>> thresholds = [5, 7]
|
|
32
|
+
>>> choices = [10, 15, 20]
|
|
33
|
+
>>> apply_thresholds(input, thresholds, choices)
|
|
34
|
+
array([10, 10, 15, 15, 20])
|
|
35
|
+
|
|
36
|
+
"""
|
|
37
|
+
condlist: list[t.Array[numpy.bool_] | bool]
|
|
38
|
+
condlist = [input <= threshold for threshold in thresholds]
|
|
39
|
+
|
|
40
|
+
if len(condlist) == len(choices) - 1:
|
|
41
|
+
# If a choice is provided for input > highest threshold, last condition
|
|
42
|
+
# must be true to return it.
|
|
43
|
+
condlist += [True]
|
|
44
|
+
|
|
45
|
+
msg = (
|
|
46
|
+
"'apply_thresholds' must be called with the same number of thresholds "
|
|
47
|
+
"than choices, or one more choice."
|
|
48
|
+
)
|
|
49
|
+
assert len(condlist) == len(choices), msg
|
|
50
|
+
|
|
51
|
+
return numpy.select(condlist, choices)
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def concat(
|
|
55
|
+
this: t.StrArray | t.ArrayLike[object],
|
|
56
|
+
that: t.StrArray | t.ArrayLike[object],
|
|
57
|
+
) -> t.StrArray:
|
|
58
|
+
"""Concatenate the values of two arrays.
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
this: An array to concatenate.
|
|
62
|
+
that: Another array to concatenate.
|
|
63
|
+
|
|
64
|
+
Returns:
|
|
65
|
+
ndarray[str_]: An array with the concatenated values.
|
|
66
|
+
|
|
67
|
+
Examples:
|
|
68
|
+
>>> this = ["this", "that"]
|
|
69
|
+
>>> that = numpy.array([1, 2.5])
|
|
70
|
+
>>> concat(this, that)
|
|
71
|
+
array(['this1.0', 'that2.5']...)
|
|
72
|
+
|
|
73
|
+
"""
|
|
74
|
+
if not isinstance(this, numpy.ndarray):
|
|
75
|
+
this = numpy.array(this)
|
|
76
|
+
|
|
77
|
+
if not numpy.issubdtype(this.dtype, numpy.str_):
|
|
78
|
+
this = this.astype("str")
|
|
79
|
+
|
|
80
|
+
if not isinstance(that, numpy.ndarray):
|
|
81
|
+
that = numpy.array(that)
|
|
82
|
+
|
|
83
|
+
if not numpy.issubdtype(that.dtype, numpy.str_):
|
|
84
|
+
that = that.astype("str")
|
|
85
|
+
|
|
86
|
+
return numpy.char.add(this, that)
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
def switch(
|
|
90
|
+
conditions: t.FloatArray | t.ArrayLike[float],
|
|
91
|
+
value_by_condition: Mapping[float, float],
|
|
92
|
+
) -> t.FloatArray:
|
|
93
|
+
"""Mimic a switch statement.
|
|
94
|
+
|
|
95
|
+
Given an array of conditions, returns an array of the same size,
|
|
96
|
+
replacing each condition item with the matching given value.
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
conditions: An array of conditions.
|
|
100
|
+
value_by_condition: Values to replace for each condition.
|
|
101
|
+
|
|
102
|
+
Returns:
|
|
103
|
+
ndarray[float32]: An array with the replaced values.
|
|
104
|
+
|
|
105
|
+
Examples:
|
|
106
|
+
>>> conditions = numpy.array([1, 1, 1, 2])
|
|
107
|
+
>>> value_by_condition = {1: 80, 2: 90}
|
|
108
|
+
>>> switch(conditions, value_by_condition)
|
|
109
|
+
array([80, 80, 80, 90])
|
|
110
|
+
|
|
111
|
+
"""
|
|
112
|
+
assert len(value_by_condition) > 0, (
|
|
113
|
+
"'switch' must be called with at least one value."
|
|
114
|
+
)
|
|
115
|
+
|
|
116
|
+
condlist = [conditions == condition for condition in value_by_condition]
|
|
117
|
+
|
|
118
|
+
return numpy.select(condlist, tuple(value_by_condition.values()))
|
|
119
|
+
|
|
120
|
+
|
|
121
|
+
__all__ = ["apply_thresholds", "concat", "switch"]
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import numexpr
|
|
4
|
+
|
|
5
|
+
from openfisca_core import types as t
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def empty_clone(original: object) -> object:
|
|
9
|
+
"""Create an empty instance of the same class of the original object.
|
|
10
|
+
|
|
11
|
+
Args:
|
|
12
|
+
original: An object to clone.
|
|
13
|
+
|
|
14
|
+
Returns:
|
|
15
|
+
object: The cloned, empty, object.
|
|
16
|
+
|
|
17
|
+
Examples:
|
|
18
|
+
>>> Foo = type("Foo", (list,), {})
|
|
19
|
+
>>> foo = Foo([1, 2, 3])
|
|
20
|
+
>>> foo
|
|
21
|
+
[1, 2, 3]
|
|
22
|
+
|
|
23
|
+
>>> bar = empty_clone(foo)
|
|
24
|
+
>>> bar
|
|
25
|
+
[]
|
|
26
|
+
|
|
27
|
+
>>> isinstance(bar, Foo)
|
|
28
|
+
True
|
|
29
|
+
|
|
30
|
+
"""
|
|
31
|
+
|
|
32
|
+
def __init__(_: object) -> None: ...
|
|
33
|
+
|
|
34
|
+
Dummy = type(
|
|
35
|
+
"Dummy",
|
|
36
|
+
(original.__class__,),
|
|
37
|
+
{"__init__": __init__},
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
new = Dummy()
|
|
41
|
+
new.__class__ = original.__class__
|
|
42
|
+
return new
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def stringify_array(array: None | t.VarArray) -> str:
|
|
46
|
+
"""Generate a clean string representation of a numpy array.
|
|
47
|
+
|
|
48
|
+
Args:
|
|
49
|
+
array: An array.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
str: ``"None"`` if the ``array`` is ``None``.
|
|
53
|
+
str: The stringified ``array`` otherwise.
|
|
54
|
+
|
|
55
|
+
Examples:
|
|
56
|
+
>>> import numpy
|
|
57
|
+
>>> stringify_array(None)
|
|
58
|
+
'None'
|
|
59
|
+
|
|
60
|
+
>>> array = numpy.array([10, 20.0])
|
|
61
|
+
>>> stringify_array(array)
|
|
62
|
+
'[10.0, 20.0]'
|
|
63
|
+
|
|
64
|
+
>>> array = numpy.array(["10", "Twenty"])
|
|
65
|
+
>>> stringify_array(array)
|
|
66
|
+
'[10, Twenty]'
|
|
67
|
+
|
|
68
|
+
>>> array = numpy.array([list, dict(), stringify_array])
|
|
69
|
+
>>> stringify_array(array)
|
|
70
|
+
"[<class 'list'>, {}, <function stringify_array...]"
|
|
71
|
+
|
|
72
|
+
"""
|
|
73
|
+
if array is None:
|
|
74
|
+
return "None"
|
|
75
|
+
|
|
76
|
+
return f"[{', '.join(str(cell) for cell in array)}]"
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def eval_expression(
|
|
80
|
+
expression: str,
|
|
81
|
+
) -> str | t.BoolArray | t.IntArray | t.FloatArray:
|
|
82
|
+
"""Evaluate a string expression to a numpy array.
|
|
83
|
+
|
|
84
|
+
Args:
|
|
85
|
+
expression: An expression to evaluate.
|
|
86
|
+
|
|
87
|
+
Returns:
|
|
88
|
+
ndarray: The result of the evaluation.
|
|
89
|
+
str: The expression if it couldn't be evaluated.
|
|
90
|
+
|
|
91
|
+
Examples:
|
|
92
|
+
>>> eval_expression("1 + 2")
|
|
93
|
+
array(3, dtype=int32)
|
|
94
|
+
|
|
95
|
+
>>> eval_expression("salary")
|
|
96
|
+
'salary'
|
|
97
|
+
|
|
98
|
+
>>> eval_expression("date of birth")
|
|
99
|
+
'date of birth'
|
|
100
|
+
|
|
101
|
+
"""
|
|
102
|
+
try:
|
|
103
|
+
return numexpr.evaluate(expression)
|
|
104
|
+
|
|
105
|
+
except (KeyError, TypeError, SyntaxError):
|
|
106
|
+
return expression
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
__all__ = ["empty_clone", "eval_expression", "stringify_array"]
|
|
File without changes
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import numpy
|
|
4
|
+
|
|
5
|
+
from openfisca_core import types as t
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def average_rate(
|
|
9
|
+
target: t.FloatArray,
|
|
10
|
+
varying: t.FloatArray | t.ArrayLike[float],
|
|
11
|
+
trim: None | t.ArrayLike[float] = None,
|
|
12
|
+
) -> t.FloatArray:
|
|
13
|
+
"""Compute the average rate of a target net income.
|
|
14
|
+
|
|
15
|
+
Given a ``target`` net income, and according to the ``varying`` gross
|
|
16
|
+
income. Optionally, a ``trim`` can be applied consisting of the lower and
|
|
17
|
+
upper bounds of the average rate to be computed.
|
|
18
|
+
|
|
19
|
+
Note:
|
|
20
|
+
Usually, ``target`` and ``varying`` are the same size.
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
target: The targeted net income.
|
|
24
|
+
varying: The varying gross income.
|
|
25
|
+
trim: The lower and upper bounds of the average rate.
|
|
26
|
+
|
|
27
|
+
Returns:
|
|
28
|
+
ndarray[float32]: The average rate for each target. When ``trim``
|
|
29
|
+
is provided, values that are out of the provided bounds are
|
|
30
|
+
replaced by :obj:`numpy.nan`.
|
|
31
|
+
|
|
32
|
+
Examples:
|
|
33
|
+
>>> target = numpy.array([1, 2, 3])
|
|
34
|
+
>>> varying = [2, 2, 2]
|
|
35
|
+
>>> trim = [-1, 0.25]
|
|
36
|
+
>>> average_rate(target, varying, trim)
|
|
37
|
+
array([ nan, 0. , -0.5])
|
|
38
|
+
|
|
39
|
+
"""
|
|
40
|
+
if not isinstance(varying, numpy.ndarray):
|
|
41
|
+
varying = numpy.array(varying, dtype=numpy.float32)
|
|
42
|
+
|
|
43
|
+
average_rate = 1 - target / varying
|
|
44
|
+
|
|
45
|
+
if trim is not None:
|
|
46
|
+
average_rate = numpy.where(
|
|
47
|
+
average_rate <= max(trim),
|
|
48
|
+
average_rate,
|
|
49
|
+
numpy.nan,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
average_rate = numpy.where(
|
|
53
|
+
average_rate >= min(trim),
|
|
54
|
+
average_rate,
|
|
55
|
+
numpy.nan,
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
return average_rate
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
def marginal_rate(
|
|
62
|
+
target: t.FloatArray,
|
|
63
|
+
varying: t.FloatArray | t.ArrayLike[float],
|
|
64
|
+
trim: None | t.ArrayLike[float] = None,
|
|
65
|
+
) -> t.FloatArray:
|
|
66
|
+
"""Compute the marginal rate of a target net income.
|
|
67
|
+
|
|
68
|
+
Given a ``target`` net income, and according to the ``varying`` gross
|
|
69
|
+
income. Optionally, a ``trim`` can be applied consisting of the lower and
|
|
70
|
+
upper bounds of the marginal rate to be computed.
|
|
71
|
+
|
|
72
|
+
Note:
|
|
73
|
+
Usually, ``target`` and ``varying`` are the same size.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
target: The targeted net income.
|
|
77
|
+
varying: The varying gross income.
|
|
78
|
+
trim: The lower and upper bounds of the marginal rate.
|
|
79
|
+
|
|
80
|
+
Returns:
|
|
81
|
+
ndarray[float32]: The marginal rate for each target. When ``trim``
|
|
82
|
+
is provided, values that are out of the provided bounds are
|
|
83
|
+
replaced by :class:`numpy.nan`.
|
|
84
|
+
|
|
85
|
+
Examples:
|
|
86
|
+
>>> target = numpy.array([1, 2, 3])
|
|
87
|
+
>>> varying = numpy.array([1, 2, 4])
|
|
88
|
+
>>> trim = [0.25, 0.75]
|
|
89
|
+
>>> marginal_rate(target, varying, trim)
|
|
90
|
+
array([nan, 0.5])
|
|
91
|
+
|
|
92
|
+
"""
|
|
93
|
+
if not isinstance(varying, numpy.ndarray):
|
|
94
|
+
varying = numpy.array(varying, dtype=numpy.float32)
|
|
95
|
+
|
|
96
|
+
marginal_rate = +1 - (target[:-1] - target[1:]) / (varying[:-1] - varying[1:])
|
|
97
|
+
|
|
98
|
+
if trim is not None:
|
|
99
|
+
marginal_rate = numpy.where(
|
|
100
|
+
marginal_rate <= max(trim),
|
|
101
|
+
marginal_rate,
|
|
102
|
+
numpy.nan,
|
|
103
|
+
)
|
|
104
|
+
|
|
105
|
+
marginal_rate = numpy.where(
|
|
106
|
+
marginal_rate >= min(trim),
|
|
107
|
+
marginal_rate,
|
|
108
|
+
numpy.nan,
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
return marginal_rate
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
__all__ = ["average_rate", "marginal_rate"]
|
|
File without changes
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import numpy
|
|
2
|
+
import pytest
|
|
3
|
+
from numpy.testing import assert_array_equal
|
|
4
|
+
|
|
5
|
+
from openfisca_core import commons
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def test_apply_thresholds_when_several_inputs() -> None:
|
|
9
|
+
"""Make a choice for any given input."""
|
|
10
|
+
input_ = numpy.array([4, 5, 6, 7, 8, 9, 10])
|
|
11
|
+
thresholds = [5, 7, 9]
|
|
12
|
+
choices = [10, 15, 20, 25]
|
|
13
|
+
|
|
14
|
+
result = commons.apply_thresholds(input_, thresholds, choices)
|
|
15
|
+
|
|
16
|
+
assert_array_equal(result, [10, 10, 15, 15, 20, 20, 25])
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_apply_thresholds_when_too_many_thresholds() -> None:
|
|
20
|
+
"""Raise an AssertionError when thresholds > choices."""
|
|
21
|
+
input_ = numpy.array([6])
|
|
22
|
+
thresholds = [5, 7, 9, 11]
|
|
23
|
+
choices = [10, 15, 20]
|
|
24
|
+
|
|
25
|
+
with pytest.raises(AssertionError):
|
|
26
|
+
assert commons.apply_thresholds(input_, thresholds, choices)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_apply_thresholds_when_too_many_choices() -> None:
|
|
30
|
+
"""Raise an AssertionError when thresholds < choices - 1."""
|
|
31
|
+
input_ = numpy.array([6])
|
|
32
|
+
thresholds = [5, 7]
|
|
33
|
+
choices = [10, 15, 20, 25]
|
|
34
|
+
|
|
35
|
+
with pytest.raises(AssertionError):
|
|
36
|
+
assert commons.apply_thresholds(input_, thresholds, choices)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def test_concat_when_this_is_array_not_str() -> None:
|
|
40
|
+
"""Cast ``this`` to ``str`` when it is a NumPy array other than string."""
|
|
41
|
+
this = numpy.array([1, 2])
|
|
42
|
+
that = numpy.array(["la", "o"])
|
|
43
|
+
|
|
44
|
+
result = commons.concat(this, that)
|
|
45
|
+
|
|
46
|
+
assert_array_equal(result, ["1la", "2o"])
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
def test_concat_when_that_is_array_not_str() -> None:
|
|
50
|
+
"""Cast ``that`` to ``str`` when it is a NumPy array other than string."""
|
|
51
|
+
this = numpy.array(["ho", "cha"])
|
|
52
|
+
that = numpy.array([1, 2])
|
|
53
|
+
|
|
54
|
+
result = commons.concat(this, that)
|
|
55
|
+
|
|
56
|
+
assert_array_equal(result, ["ho1", "cha2"])
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def test_concat_when_args_not_str_array_like() -> None:
|
|
60
|
+
"""Cast ``this`` and ``that`` to a NumPy array or strings."""
|
|
61
|
+
this = (1, 2)
|
|
62
|
+
that = (3, 4)
|
|
63
|
+
|
|
64
|
+
result = commons.concat(this, that)
|
|
65
|
+
|
|
66
|
+
assert_array_equal(result, ["13", "24"])
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def test_switch_when_values_are_empty() -> None:
|
|
70
|
+
"""Raise an AssertionError when the values are empty."""
|
|
71
|
+
conditions = [1, 1, 1, 2]
|
|
72
|
+
value_by_condition = {}
|
|
73
|
+
|
|
74
|
+
with pytest.raises(AssertionError):
|
|
75
|
+
assert commons.switch(conditions, value_by_condition)
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import math
|
|
2
|
+
|
|
3
|
+
import numpy
|
|
4
|
+
from numpy.testing import assert_array_equal
|
|
5
|
+
|
|
6
|
+
from openfisca_core import commons
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def test_average_rate_when_varying_is_zero() -> None:
|
|
10
|
+
"""Yield infinity when the varying gross income crosses zero."""
|
|
11
|
+
target = numpy.array([1, 2, 3])
|
|
12
|
+
varying = [0, 0, 0]
|
|
13
|
+
|
|
14
|
+
result = commons.average_rate(target, varying)
|
|
15
|
+
|
|
16
|
+
assert_array_equal(result, numpy.array([-math.inf, -math.inf, -math.inf]))
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def test_marginal_rate_when_varying_is_zero() -> None:
|
|
20
|
+
"""Yield infinity when the varying gross income crosses zero."""
|
|
21
|
+
target = numpy.array([1, 2, 3])
|
|
22
|
+
varying = numpy.array([0, 0, 0])
|
|
23
|
+
|
|
24
|
+
result = commons.marginal_rate(target, varying)
|
|
25
|
+
|
|
26
|
+
assert_array_equal(result, numpy.array([math.inf, math.inf]))
|