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,27 @@
|
|
|
1
|
+
import importlib
|
|
2
|
+
import logging
|
|
3
|
+
import traceback
|
|
4
|
+
from os import linesep
|
|
5
|
+
|
|
6
|
+
log = logging.getLogger(__name__)
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def build_tax_benefit_system(country_package_name):
|
|
10
|
+
try:
|
|
11
|
+
country_package = importlib.import_module(country_package_name)
|
|
12
|
+
except ImportError:
|
|
13
|
+
message = linesep.join(
|
|
14
|
+
[
|
|
15
|
+
traceback.format_exc(),
|
|
16
|
+
f"Could not import module `{country_package_name}`.",
|
|
17
|
+
"Are you sure it is installed in your environment? If so, look at the stack trace above to determine the origin of this error.",
|
|
18
|
+
"See more at <https://github.com/openfisca/country-template#installing>.",
|
|
19
|
+
linesep,
|
|
20
|
+
],
|
|
21
|
+
)
|
|
22
|
+
raise ValueError(message)
|
|
23
|
+
try:
|
|
24
|
+
return country_package.CountryTaxBenefitSystem()
|
|
25
|
+
except NameError: # Gunicorn swallows NameErrors. Force printing the stack trace.
|
|
26
|
+
log.exception(traceback.format_exc())
|
|
27
|
+
raise
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import datetime
|
|
2
|
+
import inspect
|
|
3
|
+
import textwrap
|
|
4
|
+
|
|
5
|
+
from openfisca_core.indexed_enums import Enum
|
|
6
|
+
from openfisca_core.variables import VALUE_TYPES
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_next_day(date):
|
|
10
|
+
parsed_date = date
|
|
11
|
+
next_day = parsed_date + datetime.timedelta(days=1)
|
|
12
|
+
return next_day.isoformat().split("T")[0]
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def get_default_value(variable):
|
|
16
|
+
default_value = variable.default_value
|
|
17
|
+
if isinstance(default_value, datetime.date):
|
|
18
|
+
return default_value.isoformat()
|
|
19
|
+
|
|
20
|
+
if isinstance(default_value, Enum):
|
|
21
|
+
return default_value.name
|
|
22
|
+
|
|
23
|
+
return default_value
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def build_source_url(
|
|
27
|
+
country_package_metadata,
|
|
28
|
+
source_file_path,
|
|
29
|
+
start_line_number,
|
|
30
|
+
source_code,
|
|
31
|
+
):
|
|
32
|
+
nb_lines = source_code.count("\n")
|
|
33
|
+
return "{}/blob/{}{}#L{}-L{}".format(
|
|
34
|
+
country_package_metadata["repository_url"],
|
|
35
|
+
country_package_metadata["version"],
|
|
36
|
+
source_file_path,
|
|
37
|
+
start_line_number,
|
|
38
|
+
start_line_number + nb_lines - 1,
|
|
39
|
+
)
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def build_formula(formula, country_package_metadata, source_file_path):
|
|
43
|
+
source_code, start_line_number = inspect.getsourcelines(formula)
|
|
44
|
+
|
|
45
|
+
source_code = textwrap.dedent("".join(source_code))
|
|
46
|
+
|
|
47
|
+
api_formula = {
|
|
48
|
+
"source": build_source_url(
|
|
49
|
+
country_package_metadata,
|
|
50
|
+
source_file_path,
|
|
51
|
+
start_line_number,
|
|
52
|
+
source_code,
|
|
53
|
+
),
|
|
54
|
+
"content": source_code,
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
if formula.__doc__:
|
|
58
|
+
api_formula["documentation"] = textwrap.dedent(formula.__doc__)
|
|
59
|
+
|
|
60
|
+
return api_formula
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def build_formulas(formulas, country_package_metadata, source_file_path):
|
|
64
|
+
return {
|
|
65
|
+
start_date: build_formula(formula, country_package_metadata, source_file_path)
|
|
66
|
+
for start_date, formula in formulas.items()
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def build_variable(variable, country_package_metadata):
|
|
71
|
+
(
|
|
72
|
+
source_file_path,
|
|
73
|
+
source_code,
|
|
74
|
+
start_line_number,
|
|
75
|
+
) = variable.get_introspection_data()
|
|
76
|
+
result = {
|
|
77
|
+
"id": variable.name,
|
|
78
|
+
"description": variable.label,
|
|
79
|
+
"valueType": VALUE_TYPES[variable.value_type]["formatted_value_type"],
|
|
80
|
+
"defaultValue": get_default_value(variable),
|
|
81
|
+
"definitionPeriod": variable.definition_period.upper(),
|
|
82
|
+
"entity": variable.entity.key,
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
if source_code:
|
|
86
|
+
result["source"] = build_source_url(
|
|
87
|
+
country_package_metadata,
|
|
88
|
+
source_file_path,
|
|
89
|
+
start_line_number,
|
|
90
|
+
source_code,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
if variable.documentation:
|
|
94
|
+
result["documentation"] = variable.documentation.strip()
|
|
95
|
+
|
|
96
|
+
if variable.reference:
|
|
97
|
+
result["references"] = variable.reference
|
|
98
|
+
|
|
99
|
+
if len(variable.formulas) > 0:
|
|
100
|
+
result["formulas"] = build_formulas(
|
|
101
|
+
variable.formulas,
|
|
102
|
+
country_package_metadata,
|
|
103
|
+
source_file_path,
|
|
104
|
+
)
|
|
105
|
+
|
|
106
|
+
if variable.end:
|
|
107
|
+
result["formulas"][get_next_day(variable.end)] = None
|
|
108
|
+
|
|
109
|
+
if variable.value_type == Enum:
|
|
110
|
+
result["possibleValues"] = {
|
|
111
|
+
item.name: item.value for item in list(variable.possible_values)
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
return result
|
|
115
|
+
|
|
116
|
+
|
|
117
|
+
def build_variables(tax_benefit_system, country_package_metadata):
|
|
118
|
+
return {
|
|
119
|
+
name: build_variable(variable, country_package_metadata)
|
|
120
|
+
for name, variable in tax_benefit_system.variables.items()
|
|
121
|
+
}
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
openapi: "3.0.0"
|
|
2
|
+
|
|
3
|
+
info:
|
|
4
|
+
title: "{COUNTRY_PACKAGE_NAME} Web API"
|
|
5
|
+
description: "The OpenFisca Web API lets you get up-to-date information and formulas included in the {COUNTRY_PACKAGE_NAME} legislation."
|
|
6
|
+
version: "{COUNTRY_PACKAGE_VERSION}"
|
|
7
|
+
termsOfService: "https://openfisca.org/doc/licence.html"
|
|
8
|
+
contact:
|
|
9
|
+
email: "contact@openfisca.org"
|
|
10
|
+
license:
|
|
11
|
+
name: "AGPL"
|
|
12
|
+
url: "https://www.gnu.org/licenses/agpl-3.0"
|
|
13
|
+
|
|
14
|
+
tags:
|
|
15
|
+
- name: "Parameters"
|
|
16
|
+
description: "A parameter is a numeric property of the legislation that can evolve over time."
|
|
17
|
+
externalDocs:
|
|
18
|
+
description: "Parameters documentation"
|
|
19
|
+
url: "https://openfisca.org/doc/key-concepts/parameters.html"
|
|
20
|
+
|
|
21
|
+
- name: "Variables"
|
|
22
|
+
description: "A variable depends on a person, or an entity (e.g. zip code, salary, income tax)."
|
|
23
|
+
externalDocs:
|
|
24
|
+
description: "Variables documentation"
|
|
25
|
+
url: "https://openfisca.org/doc/key-concepts/variables.html"
|
|
26
|
+
|
|
27
|
+
- name: "Entities"
|
|
28
|
+
description: "An entity is a person of a group of individuals (such as a household)."
|
|
29
|
+
externalDocs:
|
|
30
|
+
description: "Entities documentation"
|
|
31
|
+
url: "https://openfisca.org/doc/key-concepts/person,_entities,_role.html"
|
|
32
|
+
|
|
33
|
+
- name: "Calculations"
|
|
34
|
+
|
|
35
|
+
- name: "Documentation"
|
|
36
|
+
|
|
37
|
+
components:
|
|
38
|
+
schemas:
|
|
39
|
+
Parameter:
|
|
40
|
+
type: "object"
|
|
41
|
+
properties:
|
|
42
|
+
values:
|
|
43
|
+
$ref: "#/components/schemas/Values"
|
|
44
|
+
brackets:
|
|
45
|
+
type: "object"
|
|
46
|
+
additionalProperties:
|
|
47
|
+
$ref: "#/components/schemas/Brackets"
|
|
48
|
+
subparams:
|
|
49
|
+
type: "object"
|
|
50
|
+
additionalProperties:
|
|
51
|
+
type: "object"
|
|
52
|
+
properties:
|
|
53
|
+
definition:
|
|
54
|
+
type: "string"
|
|
55
|
+
metadata:
|
|
56
|
+
type: "object"
|
|
57
|
+
description:
|
|
58
|
+
type: "string"
|
|
59
|
+
id:
|
|
60
|
+
type: "integer"
|
|
61
|
+
format: "string"
|
|
62
|
+
source:
|
|
63
|
+
type: "string"
|
|
64
|
+
|
|
65
|
+
Parameters:
|
|
66
|
+
type: "object"
|
|
67
|
+
additionalProperties:
|
|
68
|
+
type: "object"
|
|
69
|
+
properties:
|
|
70
|
+
description:
|
|
71
|
+
type: "string"
|
|
72
|
+
href:
|
|
73
|
+
type: "string"
|
|
74
|
+
|
|
75
|
+
Variable:
|
|
76
|
+
type: "object"
|
|
77
|
+
properties:
|
|
78
|
+
defaultValue:
|
|
79
|
+
type: "string"
|
|
80
|
+
definitionPeriod:
|
|
81
|
+
type: "string"
|
|
82
|
+
enum:
|
|
83
|
+
- "MONTH"
|
|
84
|
+
- "YEAR"
|
|
85
|
+
- "ETERNITY"
|
|
86
|
+
description:
|
|
87
|
+
type: "string"
|
|
88
|
+
entity:
|
|
89
|
+
type: "string"
|
|
90
|
+
formulas:
|
|
91
|
+
type: "object"
|
|
92
|
+
additionalProperties:
|
|
93
|
+
$ref: "#/components/schemas/Formula"
|
|
94
|
+
id:
|
|
95
|
+
type: "string"
|
|
96
|
+
reference:
|
|
97
|
+
type: "array"
|
|
98
|
+
items:
|
|
99
|
+
type: "string"
|
|
100
|
+
source:
|
|
101
|
+
type: "string"
|
|
102
|
+
valueType:
|
|
103
|
+
type: "string"
|
|
104
|
+
enum:
|
|
105
|
+
- "Int"
|
|
106
|
+
- "Float"
|
|
107
|
+
- "Boolean"
|
|
108
|
+
- "Date"
|
|
109
|
+
- "String"
|
|
110
|
+
|
|
111
|
+
Variables:
|
|
112
|
+
type: "object"
|
|
113
|
+
additionalProperties:
|
|
114
|
+
type: "object"
|
|
115
|
+
properties:
|
|
116
|
+
description:
|
|
117
|
+
type: "string"
|
|
118
|
+
href:
|
|
119
|
+
type: "string"
|
|
120
|
+
|
|
121
|
+
Formula:
|
|
122
|
+
type: "object"
|
|
123
|
+
properties:
|
|
124
|
+
content:
|
|
125
|
+
type: "string"
|
|
126
|
+
source:
|
|
127
|
+
type: "string"
|
|
128
|
+
|
|
129
|
+
Brackets:
|
|
130
|
+
type: "object"
|
|
131
|
+
additionalProperties:
|
|
132
|
+
type: "number"
|
|
133
|
+
format: "float"
|
|
134
|
+
|
|
135
|
+
Values:
|
|
136
|
+
description: "All keys are ISO dates. Values can be numbers, booleans, or arrays of a single type (number, boolean or string)."
|
|
137
|
+
type: "object"
|
|
138
|
+
additionalProperties:
|
|
139
|
+
$ref: "#/components/schemas/Value"
|
|
140
|
+
# propertyNames: # this keyword is part of JSON Schema but is not supported in OpenAPI v3.0.0
|
|
141
|
+
# pattern: "^[12][0-9]{3}-[01][0-9]-[0-3][0-9]$" # all keys are ISO dates
|
|
142
|
+
|
|
143
|
+
Value:
|
|
144
|
+
oneOf:
|
|
145
|
+
- type: "boolean"
|
|
146
|
+
- type: "number"
|
|
147
|
+
format: "float"
|
|
148
|
+
- type: "array"
|
|
149
|
+
items:
|
|
150
|
+
oneOf:
|
|
151
|
+
- type: "string"
|
|
152
|
+
- type: "number"
|
|
153
|
+
|
|
154
|
+
Entities:
|
|
155
|
+
type: "object"
|
|
156
|
+
properties:
|
|
157
|
+
description:
|
|
158
|
+
type: "string"
|
|
159
|
+
documentation:
|
|
160
|
+
type: "string"
|
|
161
|
+
plural:
|
|
162
|
+
type: "string"
|
|
163
|
+
roles:
|
|
164
|
+
type: "object"
|
|
165
|
+
additionalProperties:
|
|
166
|
+
$ref: "#/components/schemas/Roles"
|
|
167
|
+
|
|
168
|
+
Roles:
|
|
169
|
+
type: "object"
|
|
170
|
+
properties:
|
|
171
|
+
description:
|
|
172
|
+
type: "string"
|
|
173
|
+
max:
|
|
174
|
+
type: "integer"
|
|
175
|
+
plural:
|
|
176
|
+
type: "string"
|
|
177
|
+
|
|
178
|
+
Trace:
|
|
179
|
+
type: "object"
|
|
180
|
+
properties:
|
|
181
|
+
requestedCalculations:
|
|
182
|
+
type: "array"
|
|
183
|
+
items:
|
|
184
|
+
type: "string"
|
|
185
|
+
entitiesDescription:
|
|
186
|
+
type: "object"
|
|
187
|
+
additionalProperties: false # Will be dynamically added by the Web API
|
|
188
|
+
trace:
|
|
189
|
+
type: "object"
|
|
190
|
+
additionalProperties:
|
|
191
|
+
type: "object"
|
|
192
|
+
properties:
|
|
193
|
+
value:
|
|
194
|
+
type: "array"
|
|
195
|
+
items: {}
|
|
196
|
+
dependencies:
|
|
197
|
+
type: "array"
|
|
198
|
+
items:
|
|
199
|
+
type: "string"
|
|
200
|
+
parameters:
|
|
201
|
+
type: "object"
|
|
202
|
+
additionalProperties:
|
|
203
|
+
type: "object"
|
|
204
|
+
|
|
205
|
+
headers:
|
|
206
|
+
Country-Package:
|
|
207
|
+
description: "The name of the country package currently loaded in this API server"
|
|
208
|
+
schema:
|
|
209
|
+
type: "string"
|
|
210
|
+
|
|
211
|
+
Country-Package-Version:
|
|
212
|
+
description: "The version of the country package currently loaded in this API server"
|
|
213
|
+
schema:
|
|
214
|
+
type: "string"
|
|
215
|
+
pattern: "^(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)\\.(0|[1-9][0-9]*)(?:-((?:0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*)(?:\\.(?:0|[1-9][0-9]*|[0-9]*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\\+([0-9a-zA-Z-]+(?:\\.[0-9a-zA-Z-]+)*))?$" # adapted from https://semver.org/#is-there-a-suggested-regular-expression-regex-to-check-a-semver-string
|
|
216
|
+
|
|
217
|
+
paths:
|
|
218
|
+
/calculate:
|
|
219
|
+
post:
|
|
220
|
+
summary: "Run a simulation"
|
|
221
|
+
tags:
|
|
222
|
+
- "Calculations"
|
|
223
|
+
operationId: "calculate"
|
|
224
|
+
requestBody:
|
|
225
|
+
description: "Describe the situation (persons and entities). Add the variable you wish to calculate in the proper entity, with null as the value. Learn more in our official documentation: https://openfisca.org/doc/openfisca-web-api/input-output-data.html"
|
|
226
|
+
required: true
|
|
227
|
+
content:
|
|
228
|
+
application/json:
|
|
229
|
+
schema:
|
|
230
|
+
$ref: "#/components/schemas/SituationInput"
|
|
231
|
+
responses:
|
|
232
|
+
200:
|
|
233
|
+
description: "The calculation result is sent back in the response body"
|
|
234
|
+
content:
|
|
235
|
+
application/json:
|
|
236
|
+
schema:
|
|
237
|
+
$ref: "#/components/schemas/SituationOutput"
|
|
238
|
+
headers:
|
|
239
|
+
Country-Package:
|
|
240
|
+
$ref: "#/components/headers/Country-Package"
|
|
241
|
+
Country-Package-Version:
|
|
242
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
243
|
+
404:
|
|
244
|
+
description: "A variable mentioned in the input situation does not exist in the loaded tax and benefit system. Details are sent back in the response body"
|
|
245
|
+
headers:
|
|
246
|
+
Country-Package:
|
|
247
|
+
$ref: "#/components/headers/Country-Package"
|
|
248
|
+
Country-Package-Version:
|
|
249
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
250
|
+
400:
|
|
251
|
+
description: "The request is invalid. Details about the error are sent back in the response body"
|
|
252
|
+
headers:
|
|
253
|
+
Country-Package:
|
|
254
|
+
$ref: "#/components/headers/Country-Package"
|
|
255
|
+
Country-Package-Version:
|
|
256
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
257
|
+
|
|
258
|
+
/parameters:
|
|
259
|
+
get:
|
|
260
|
+
tags:
|
|
261
|
+
- "Parameters"
|
|
262
|
+
summary: "List all available parameters"
|
|
263
|
+
operationId: "getParameters"
|
|
264
|
+
responses:
|
|
265
|
+
200:
|
|
266
|
+
description: "The list of parameters is sent back in the response body"
|
|
267
|
+
content:
|
|
268
|
+
application/json:
|
|
269
|
+
schema:
|
|
270
|
+
$ref: "#/components/schemas/Parameters"
|
|
271
|
+
headers:
|
|
272
|
+
Country-Package:
|
|
273
|
+
$ref: "#/components/headers/Country-Package"
|
|
274
|
+
Country-Package-Version:
|
|
275
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
276
|
+
|
|
277
|
+
/parameter/{parameterID}:
|
|
278
|
+
get:
|
|
279
|
+
tags:
|
|
280
|
+
- "Parameters"
|
|
281
|
+
summary: "Get information about a specific parameter"
|
|
282
|
+
operationId: "getParameter"
|
|
283
|
+
parameters:
|
|
284
|
+
- name: "parameterID"
|
|
285
|
+
in: "path"
|
|
286
|
+
description: "ID of parameter. IDs can be obtained by enumerating the /parameters endpoint"
|
|
287
|
+
required: true
|
|
288
|
+
schema:
|
|
289
|
+
type: "string"
|
|
290
|
+
responses:
|
|
291
|
+
200:
|
|
292
|
+
description: "The requested parameter's information is sent back in the response body"
|
|
293
|
+
content:
|
|
294
|
+
application/json:
|
|
295
|
+
schema:
|
|
296
|
+
$ref: "#/components/schemas/Parameter"
|
|
297
|
+
headers:
|
|
298
|
+
Country-Package:
|
|
299
|
+
$ref: "#/components/headers/Country-Package"
|
|
300
|
+
Country-Package-Version:
|
|
301
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
302
|
+
404:
|
|
303
|
+
description: "The requested parameter does not exist"
|
|
304
|
+
headers:
|
|
305
|
+
Country-Package:
|
|
306
|
+
$ref: "#/components/headers/Country-Package"
|
|
307
|
+
Country-Package-Version:
|
|
308
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
309
|
+
|
|
310
|
+
/variables:
|
|
311
|
+
get:
|
|
312
|
+
tags:
|
|
313
|
+
- "Variables"
|
|
314
|
+
summary: "List all available variables"
|
|
315
|
+
operationId: "getVariables"
|
|
316
|
+
responses:
|
|
317
|
+
200:
|
|
318
|
+
description: "The list of variables is sent back in the response body"
|
|
319
|
+
content:
|
|
320
|
+
application/json:
|
|
321
|
+
schema:
|
|
322
|
+
$ref: "#/components/schemas/Variables"
|
|
323
|
+
headers:
|
|
324
|
+
Country-Package:
|
|
325
|
+
$ref: "#/components/headers/Country-Package"
|
|
326
|
+
Country-Package-Version:
|
|
327
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
328
|
+
|
|
329
|
+
/variable/{variableID}:
|
|
330
|
+
get:
|
|
331
|
+
tags:
|
|
332
|
+
- "Variables"
|
|
333
|
+
summary: "Get information about a specific variable"
|
|
334
|
+
operationId: "getVariable"
|
|
335
|
+
parameters:
|
|
336
|
+
- name: "variableID"
|
|
337
|
+
in: "path"
|
|
338
|
+
description: "ID of a variable. IDs can be obtained by enumerating the /variables endpoint."
|
|
339
|
+
required: true
|
|
340
|
+
schema:
|
|
341
|
+
type: "string"
|
|
342
|
+
responses:
|
|
343
|
+
200:
|
|
344
|
+
description: "The requested variable's information is sent back in the response body"
|
|
345
|
+
content:
|
|
346
|
+
application/json:
|
|
347
|
+
schema:
|
|
348
|
+
$ref: "#/components/schemas/Variable"
|
|
349
|
+
headers:
|
|
350
|
+
Country-Package:
|
|
351
|
+
$ref: "#/components/headers/Country-Package"
|
|
352
|
+
Country-Package-Version:
|
|
353
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
354
|
+
404:
|
|
355
|
+
description: "The requested variable does not exist"
|
|
356
|
+
headers:
|
|
357
|
+
Country-Package:
|
|
358
|
+
$ref: "#/components/headers/Country-Package"
|
|
359
|
+
Country-Package-Version:
|
|
360
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
361
|
+
|
|
362
|
+
/entities:
|
|
363
|
+
get:
|
|
364
|
+
tags:
|
|
365
|
+
- "Entities"
|
|
366
|
+
summary: "List all available Entities"
|
|
367
|
+
operationId: "getEntities"
|
|
368
|
+
responses:
|
|
369
|
+
200:
|
|
370
|
+
description: "The list of the entities as well as their information is sent back in the response body"
|
|
371
|
+
content:
|
|
372
|
+
application/json:
|
|
373
|
+
schema:
|
|
374
|
+
$ref: "#/components/schemas/Entities"
|
|
375
|
+
headers:
|
|
376
|
+
Country-Package:
|
|
377
|
+
$ref: "#/components/headers/Country-Package"
|
|
378
|
+
Country-Package-Version:
|
|
379
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
380
|
+
|
|
381
|
+
/trace:
|
|
382
|
+
post:
|
|
383
|
+
summary: "Explore a simulation's steps in details."
|
|
384
|
+
tags:
|
|
385
|
+
- "Calculations"
|
|
386
|
+
operationId: "trace"
|
|
387
|
+
requestBody:
|
|
388
|
+
description: "Describe the situation (persons and entities). Add the variable you wish to calculate in the proper entity, with null as the value."
|
|
389
|
+
required: true
|
|
390
|
+
content:
|
|
391
|
+
application/json:
|
|
392
|
+
schema:
|
|
393
|
+
$ref: "#/components/schemas/SituationInput"
|
|
394
|
+
responses:
|
|
395
|
+
200:
|
|
396
|
+
description: "The calculation details are sent back in the response body"
|
|
397
|
+
content:
|
|
398
|
+
application/json:
|
|
399
|
+
schema:
|
|
400
|
+
$ref: "#/components/schemas/Trace"
|
|
401
|
+
headers:
|
|
402
|
+
Country-Package:
|
|
403
|
+
$ref: "#/components/headers/Country-Package"
|
|
404
|
+
Country-Package-Version:
|
|
405
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
406
|
+
404:
|
|
407
|
+
description: "A variable mentioned in the input situation does not exist in the loaded tax and benefit system. Details are sent back in the response body"
|
|
408
|
+
headers:
|
|
409
|
+
Country-Package:
|
|
410
|
+
$ref: "#/components/headers/Country-Package"
|
|
411
|
+
Country-Package-Version:
|
|
412
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
413
|
+
400:
|
|
414
|
+
description: "The request is invalid. Details about the error are sent back in the response body"
|
|
415
|
+
headers:
|
|
416
|
+
Country-Package:
|
|
417
|
+
$ref: "#/components/headers/Country-Package"
|
|
418
|
+
Country-Package-Version:
|
|
419
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
420
|
+
|
|
421
|
+
/spec:
|
|
422
|
+
get:
|
|
423
|
+
summary: "Provide the API documentation in an OpenAPI format"
|
|
424
|
+
tags:
|
|
425
|
+
- "Documentation"
|
|
426
|
+
operationId: "spec"
|
|
427
|
+
responses:
|
|
428
|
+
200:
|
|
429
|
+
description: "The API documentation is sent back in the response body"
|
|
430
|
+
headers:
|
|
431
|
+
Country-Package:
|
|
432
|
+
$ref: "#/components/headers/Country-Package"
|
|
433
|
+
Country-Package-Version:
|
|
434
|
+
$ref: "#/components/headers/Country-Package-Version"
|
|
File without changes
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from openfisca_core.scripts import build_tax_benefit_system
|
|
5
|
+
from openfisca_web_api.app import create_app
|
|
6
|
+
from openfisca_web_api.errors import handle_import_error
|
|
7
|
+
|
|
8
|
+
try:
|
|
9
|
+
from gunicorn import config
|
|
10
|
+
from gunicorn.app.base import BaseApplication
|
|
11
|
+
except ImportError as error:
|
|
12
|
+
handle_import_error(error)
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
"""
|
|
16
|
+
Define the `openfisca serve` command line interface.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
DEFAULT_PORT = "5000"
|
|
20
|
+
HOST = "127.0.0.1"
|
|
21
|
+
DEFAULT_WORKERS_NUMBER = "3"
|
|
22
|
+
DEFAULT_TIMEOUT = 1200
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
log = logging.getLogger(__name__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def read_user_configuration(default_configuration, command_line_parser):
|
|
29
|
+
configuration = default_configuration
|
|
30
|
+
args, unknown_args = command_line_parser.parse_known_args()
|
|
31
|
+
|
|
32
|
+
if args.configuration_file:
|
|
33
|
+
file_configuration = {}
|
|
34
|
+
with open(args.configuration_file) as file:
|
|
35
|
+
exec(file.read(), {}, file_configuration)
|
|
36
|
+
|
|
37
|
+
# Configuration file overloads default configuration
|
|
38
|
+
update(configuration, file_configuration)
|
|
39
|
+
|
|
40
|
+
# Command line configuration overloads all configuration
|
|
41
|
+
gunicorn_parser = config.Config().parser()
|
|
42
|
+
configuration = update(configuration, vars(args))
|
|
43
|
+
configuration = update(
|
|
44
|
+
configuration,
|
|
45
|
+
vars(gunicorn_parser.parse_args(unknown_args)),
|
|
46
|
+
)
|
|
47
|
+
if configuration["args"]:
|
|
48
|
+
command_line_parser.print_help()
|
|
49
|
+
log.error("Unexpected positional argument {}".format(configuration["args"]))
|
|
50
|
+
sys.exit(1)
|
|
51
|
+
|
|
52
|
+
return configuration
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def update(configuration, new_options):
|
|
56
|
+
for key, value in new_options.items():
|
|
57
|
+
if value is not None:
|
|
58
|
+
configuration[key] = value
|
|
59
|
+
if key == "port":
|
|
60
|
+
configuration["bind"] = configuration["bind"][:-4] + str(
|
|
61
|
+
configuration["port"],
|
|
62
|
+
)
|
|
63
|
+
return configuration
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class OpenFiscaWebAPIApplication(BaseApplication):
|
|
67
|
+
def __init__(self, options) -> None:
|
|
68
|
+
self.options = options
|
|
69
|
+
super().__init__()
|
|
70
|
+
|
|
71
|
+
def load_config(self) -> None:
|
|
72
|
+
for key, value in self.options.items():
|
|
73
|
+
if key in self.cfg.settings:
|
|
74
|
+
self.cfg.set(key.lower(), value)
|
|
75
|
+
|
|
76
|
+
def load(self):
|
|
77
|
+
tax_benefit_system = build_tax_benefit_system(
|
|
78
|
+
self.options.get("country_package"),
|
|
79
|
+
self.options.get("extensions"),
|
|
80
|
+
self.options.get("reforms"),
|
|
81
|
+
)
|
|
82
|
+
return create_app(
|
|
83
|
+
tax_benefit_system,
|
|
84
|
+
self.options.get("tracker_url"),
|
|
85
|
+
self.options.get("tracker_idsite"),
|
|
86
|
+
self.options.get("tracker_token"),
|
|
87
|
+
self.options.get("welcome_message"),
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def main(parser) -> None:
|
|
92
|
+
configuration = {
|
|
93
|
+
"port": DEFAULT_PORT,
|
|
94
|
+
"bind": f"{HOST}:{DEFAULT_PORT}",
|
|
95
|
+
"workers": DEFAULT_WORKERS_NUMBER,
|
|
96
|
+
"timeout": DEFAULT_TIMEOUT,
|
|
97
|
+
}
|
|
98
|
+
configuration = read_user_configuration(configuration, parser)
|
|
99
|
+
OpenFiscaWebAPIApplication(configuration).run()
|