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.
Files changed (237) hide show
  1. openfisca_core/__init__.py +0 -0
  2. openfisca_core/commons/__init__.py +18 -0
  3. openfisca_core/commons/dummy.py +25 -0
  4. openfisca_core/commons/formulas.py +121 -0
  5. openfisca_core/commons/misc.py +109 -0
  6. openfisca_core/commons/py.typed +0 -0
  7. openfisca_core/commons/rates.py +114 -0
  8. openfisca_core/commons/tests/__init__.py +0 -0
  9. openfisca_core/commons/tests/test_dummy.py +9 -0
  10. openfisca_core/commons/tests/test_formulas.py +75 -0
  11. openfisca_core/commons/tests/test_rates.py +26 -0
  12. openfisca_core/data_storage/__init__.py +7 -0
  13. openfisca_core/data_storage/in_memory_storage.py +198 -0
  14. openfisca_core/data_storage/on_disk_storage.py +307 -0
  15. openfisca_core/data_storage/types.py +14 -0
  16. openfisca_core/entities/__init__.py +23 -0
  17. openfisca_core/entities/_core_entity.py +217 -0
  18. openfisca_core/entities/_description.py +55 -0
  19. openfisca_core/entities/entity.py +60 -0
  20. openfisca_core/entities/group_entity.py +123 -0
  21. openfisca_core/entities/helpers.py +165 -0
  22. openfisca_core/entities/py.typed +0 -0
  23. openfisca_core/entities/role.py +92 -0
  24. openfisca_core/entities/tests/__init__.py +0 -0
  25. openfisca_core/entities/tests/test_entity.py +10 -0
  26. openfisca_core/entities/tests/test_group_entity.py +70 -0
  27. openfisca_core/entities/tests/test_role.py +11 -0
  28. openfisca_core/entities/types.py +44 -0
  29. openfisca_core/errors/__init__.py +64 -0
  30. openfisca_core/errors/cycle_error.py +2 -0
  31. openfisca_core/errors/empty_argument_error.py +39 -0
  32. openfisca_core/errors/nan_creation_error.py +2 -0
  33. openfisca_core/errors/parameter_not_found_error.py +16 -0
  34. openfisca_core/errors/parameter_parsing_error.py +18 -0
  35. openfisca_core/errors/period_mismatch_error.py +9 -0
  36. openfisca_core/errors/situation_parsing_error.py +26 -0
  37. openfisca_core/errors/spiral_error.py +2 -0
  38. openfisca_core/errors/variable_name_config_error.py +2 -0
  39. openfisca_core/errors/variable_not_found_error.py +29 -0
  40. openfisca_core/experimental/__init__.py +9 -0
  41. openfisca_core/experimental/_errors.py +5 -0
  42. openfisca_core/experimental/_memory_config.py +41 -0
  43. openfisca_core/formula_helpers.py +9 -0
  44. openfisca_core/holders/__init__.py +33 -0
  45. openfisca_core/holders/helpers.py +93 -0
  46. openfisca_core/holders/holder.py +328 -0
  47. openfisca_core/holders/tests/__init__.py +0 -0
  48. openfisca_core/holders/tests/test_helpers.py +134 -0
  49. openfisca_core/holders/types.py +3 -0
  50. openfisca_core/indexed_enums/__init__.py +18 -0
  51. openfisca_core/indexed_enums/_enum_type.py +79 -0
  52. openfisca_core/indexed_enums/_errors.py +35 -0
  53. openfisca_core/indexed_enums/_guards.py +209 -0
  54. openfisca_core/indexed_enums/_utils.py +180 -0
  55. openfisca_core/indexed_enums/config.py +6 -0
  56. openfisca_core/indexed_enums/enum.py +218 -0
  57. openfisca_core/indexed_enums/enum_array.py +316 -0
  58. openfisca_core/indexed_enums/py.typed +0 -0
  59. openfisca_core/indexed_enums/tests/__init__.py +0 -0
  60. openfisca_core/indexed_enums/tests/test_enum.py +135 -0
  61. openfisca_core/indexed_enums/tests/test_enum_array.py +30 -0
  62. openfisca_core/indexed_enums/types.py +49 -0
  63. openfisca_core/memory_config.py +9 -0
  64. openfisca_core/model_api.py +71 -0
  65. openfisca_core/parameters/__init__.py +71 -0
  66. openfisca_core/parameters/at_instant_like.py +17 -0
  67. openfisca_core/parameters/config.py +55 -0
  68. openfisca_core/parameters/helpers.py +106 -0
  69. openfisca_core/parameters/parameter.py +217 -0
  70. openfisca_core/parameters/parameter_at_instant.py +75 -0
  71. openfisca_core/parameters/parameter_node.py +176 -0
  72. openfisca_core/parameters/parameter_node_at_instant.py +57 -0
  73. openfisca_core/parameters/parameter_scale.py +121 -0
  74. openfisca_core/parameters/parameter_scale_bracket.py +7 -0
  75. openfisca_core/parameters/values_history.py +5 -0
  76. openfisca_core/parameters/vectorial_parameter_node_at_instant.py +179 -0
  77. openfisca_core/periods/__init__.py +77 -0
  78. openfisca_core/periods/_errors.py +28 -0
  79. openfisca_core/periods/_parsers.py +122 -0
  80. openfisca_core/periods/config.py +20 -0
  81. openfisca_core/periods/date_unit.py +110 -0
  82. openfisca_core/periods/helpers.py +314 -0
  83. openfisca_core/periods/instant_.py +226 -0
  84. openfisca_core/periods/period_.py +919 -0
  85. openfisca_core/periods/py.typed +0 -0
  86. openfisca_core/periods/tests/__init__.py +0 -0
  87. openfisca_core/periods/tests/helpers/__init__.py +0 -0
  88. openfisca_core/periods/tests/helpers/test_helpers.py +65 -0
  89. openfisca_core/periods/tests/helpers/test_instant.py +73 -0
  90. openfisca_core/periods/tests/helpers/test_period.py +134 -0
  91. openfisca_core/periods/tests/test_instant.py +32 -0
  92. openfisca_core/periods/tests/test_parsers.py +129 -0
  93. openfisca_core/periods/tests/test_period.py +283 -0
  94. openfisca_core/populations/__init__.py +64 -0
  95. openfisca_core/populations/_core_population.py +454 -0
  96. openfisca_core/populations/_errors.py +65 -0
  97. openfisca_core/populations/group_population.py +326 -0
  98. openfisca_core/populations/population.py +142 -0
  99. openfisca_core/populations/tests/__init__.py +0 -0
  100. openfisca_core/populations/tests/test_members_position.py +116 -0
  101. openfisca_core/populations/types.py +110 -0
  102. openfisca_core/projectors/__init__.py +39 -0
  103. openfisca_core/projectors/entity_to_person_projector.py +12 -0
  104. openfisca_core/projectors/first_person_to_entity_projector.py +13 -0
  105. openfisca_core/projectors/helpers.py +139 -0
  106. openfisca_core/projectors/projector.py +38 -0
  107. openfisca_core/projectors/typing.py +27 -0
  108. openfisca_core/projectors/unique_role_to_entity_projector.py +14 -0
  109. openfisca_core/rates.py +9 -0
  110. openfisca_core/reforms/__init__.py +24 -0
  111. openfisca_core/reforms/in_yaml_test_reform.py +28 -0
  112. openfisca_core/reforms/reform.py +86 -0
  113. openfisca_core/scripts/__init__.py +106 -0
  114. openfisca_core/scripts/__pycache__/__init__.cpython-310-pytest-8.3.3.pyc +0 -0
  115. openfisca_core/scripts/__pycache__/__init__.cpython-310-pytest-8.4.2.pyc +0 -0
  116. openfisca_core/scripts/__pycache__/__init__.cpython-310.pyc +0 -0
  117. openfisca_core/scripts/__pycache__/__init__.cpython-311-pytest-8.3.3.pyc +0 -0
  118. openfisca_core/scripts/__pycache__/__init__.cpython-311-pytest-8.4.2.pyc +0 -0
  119. openfisca_core/scripts/__pycache__/__init__.cpython-311.pyc +0 -0
  120. openfisca_core/scripts/__pycache__/__init__.cpython-312-pytest-8.4.2.pyc +0 -0
  121. openfisca_core/scripts/__pycache__/__init__.cpython-312.pyc +0 -0
  122. openfisca_core/scripts/__pycache__/__init__.cpython-313-pytest-8.3.3.pyc +0 -0
  123. openfisca_core/scripts/__pycache__/__init__.cpython-313-pytest-8.4.2.pyc +0 -0
  124. openfisca_core/scripts/__pycache__/__init__.cpython-313.pyc +0 -0
  125. openfisca_core/scripts/__pycache__/find_placeholders.cpython-311.pyc +0 -0
  126. openfisca_core/scripts/__pycache__/find_placeholders.cpython-313.pyc +0 -0
  127. openfisca_core/scripts/__pycache__/measure_numpy_condition_notations.cpython-311.pyc +0 -0
  128. openfisca_core/scripts/__pycache__/measure_numpy_condition_notations.cpython-313.pyc +0 -0
  129. openfisca_core/scripts/__pycache__/measure_performances.cpython-311.pyc +0 -0
  130. openfisca_core/scripts/__pycache__/measure_performances.cpython-313.pyc +0 -0
  131. openfisca_core/scripts/__pycache__/measure_performances_fancy_indexing.cpython-311.pyc +0 -0
  132. openfisca_core/scripts/__pycache__/measure_performances_fancy_indexing.cpython-313.pyc +0 -0
  133. openfisca_core/scripts/__pycache__/openfisca_command.cpython-310.pyc +0 -0
  134. openfisca_core/scripts/__pycache__/openfisca_command.cpython-311.pyc +0 -0
  135. openfisca_core/scripts/__pycache__/openfisca_command.cpython-312.pyc +0 -0
  136. openfisca_core/scripts/__pycache__/openfisca_command.cpython-313.pyc +0 -0
  137. openfisca_core/scripts/__pycache__/remove_fuzzy.cpython-311.pyc +0 -0
  138. openfisca_core/scripts/__pycache__/remove_fuzzy.cpython-313.pyc +0 -0
  139. openfisca_core/scripts/__pycache__/run_test.cpython-310.pyc +0 -0
  140. openfisca_core/scripts/__pycache__/run_test.cpython-311.pyc +0 -0
  141. openfisca_core/scripts/__pycache__/run_test.cpython-312.pyc +0 -0
  142. openfisca_core/scripts/__pycache__/run_test.cpython-313.pyc +0 -0
  143. openfisca_core/scripts/__pycache__/simulation_generator.cpython-311.pyc +0 -0
  144. openfisca_core/scripts/__pycache__/simulation_generator.cpython-313.pyc +0 -0
  145. openfisca_core/scripts/assets/__init__.py +0 -0
  146. openfisca_core/scripts/assets/__pycache__/__init__.cpython-311.pyc +0 -0
  147. openfisca_core/scripts/assets/__pycache__/__init__.cpython-313.pyc +0 -0
  148. openfisca_core/scripts/assets/index.html +140 -0
  149. openfisca_core/scripts/find_placeholders.py +51 -0
  150. openfisca_core/scripts/measure_numpy_condition_notations.py +137 -0
  151. openfisca_core/scripts/measure_performances.py +291 -0
  152. openfisca_core/scripts/measure_performances_fancy_indexing.py +89 -0
  153. openfisca_core/scripts/migrations/__init__.py +0 -0
  154. openfisca_core/scripts/migrations/__pycache__/__init__.cpython-311.pyc +0 -0
  155. openfisca_core/scripts/migrations/__pycache__/__init__.cpython-313.pyc +0 -0
  156. openfisca_core/scripts/migrations/__pycache__/v24_to_25.cpython-311.pyc +0 -0
  157. openfisca_core/scripts/migrations/__pycache__/v24_to_25.cpython-313.pyc +0 -0
  158. openfisca_core/scripts/migrations/v16_2_to_v17/__init__.py +0 -0
  159. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/__init__.cpython-311.pyc +0 -0
  160. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/__init__.cpython-313.pyc +0 -0
  161. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_country_template.cpython-311.pyc +0 -0
  162. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_country_template.cpython-313.pyc +0 -0
  163. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_extension_template.cpython-311.pyc +0 -0
  164. openfisca_core/scripts/migrations/v16_2_to_v17/__pycache__/xml_to_yaml_extension_template.cpython-313.pyc +0 -0
  165. openfisca_core/scripts/migrations/v16_2_to_v17/legislation.xsd +102 -0
  166. openfisca_core/scripts/migrations/v16_2_to_v17/xml_to_yaml_country_template.py +30 -0
  167. openfisca_core/scripts/migrations/v16_2_to_v17/xml_to_yaml_extension_template.py +26 -0
  168. openfisca_core/scripts/migrations/v24_to_25.py +156 -0
  169. openfisca_core/scripts/openfisca_command.py +192 -0
  170. openfisca_core/scripts/remove_fuzzy.py +213 -0
  171. openfisca_core/scripts/run_test.py +51 -0
  172. openfisca_core/scripts/simulation_generator.py +90 -0
  173. openfisca_core/simulation_builder.py +16 -0
  174. openfisca_core/simulations/__init__.py +45 -0
  175. openfisca_core/simulations/_build_default_simulation.py +158 -0
  176. openfisca_core/simulations/_build_from_variables.py +230 -0
  177. openfisca_core/simulations/_type_guards.py +298 -0
  178. openfisca_core/simulations/helpers.py +111 -0
  179. openfisca_core/simulations/simulation.py +618 -0
  180. openfisca_core/simulations/simulation_builder.py +855 -0
  181. openfisca_core/simulations/typing.py +203 -0
  182. openfisca_core/taxbenefitsystems/__init__.py +26 -0
  183. openfisca_core/taxbenefitsystems/tax_benefit_system.py +584 -0
  184. openfisca_core/taxscales/__init__.py +35 -0
  185. openfisca_core/taxscales/abstract_rate_tax_scale.py +41 -0
  186. openfisca_core/taxscales/abstract_tax_scale.py +53 -0
  187. openfisca_core/taxscales/amount_tax_scale_like.py +55 -0
  188. openfisca_core/taxscales/helpers.py +44 -0
  189. openfisca_core/taxscales/linear_average_rate_tax_scale.py +76 -0
  190. openfisca_core/taxscales/marginal_amount_tax_scale.py +34 -0
  191. openfisca_core/taxscales/marginal_rate_tax_scale.py +286 -0
  192. openfisca_core/taxscales/rate_tax_scale_like.py +214 -0
  193. openfisca_core/taxscales/single_amount_tax_scale.py +32 -0
  194. openfisca_core/taxscales/tax_scale_like.py +65 -0
  195. openfisca_core/tools/__init__.py +94 -0
  196. openfisca_core/tools/parallel_plugin.py +55 -0
  197. openfisca_core/tools/simulation_dumper.py +137 -0
  198. openfisca_core/tools/test_runner.py +802 -0
  199. openfisca_core/tracers/__init__.py +40 -0
  200. openfisca_core/tracers/computation_log.py +196 -0
  201. openfisca_core/tracers/flat_trace.py +87 -0
  202. openfisca_core/tracers/full_tracer.py +172 -0
  203. openfisca_core/tracers/performance_log.py +133 -0
  204. openfisca_core/tracers/simple_tracer.py +64 -0
  205. openfisca_core/tracers/trace_node.py +121 -0
  206. openfisca_core/tracers/tracing_parameter_node_at_instant.py +81 -0
  207. openfisca_core/types.py +548 -0
  208. openfisca_core/variables/__init__.py +26 -0
  209. openfisca_core/variables/config.py +53 -0
  210. openfisca_core/variables/helpers.py +67 -0
  211. openfisca_core/variables/tests/__init__.py +0 -0
  212. openfisca_core/variables/tests/test_definition_period.py +43 -0
  213. openfisca_core/variables/variable.py +474 -0
  214. openfisca_core/warnings/__init__.py +25 -0
  215. openfisca_core/warnings/libyaml_warning.py +2 -0
  216. openfisca_core/warnings/tempfile_warning.py +2 -0
  217. openfisca_core_test-46.0.0.data/data/share/openfisca/openfisca-core/CHANGELOG.md +4209 -0
  218. openfisca_core_test-46.0.0.data/data/share/openfisca/openfisca-core/README.md +152 -0
  219. openfisca_core_test-46.0.0.dist-info/METADATA +194 -0
  220. openfisca_core_test-46.0.0.dist-info/RECORD +237 -0
  221. openfisca_core_test-46.0.0.dist-info/WHEEL +5 -0
  222. openfisca_core_test-46.0.0.dist-info/entry_points.txt +3 -0
  223. openfisca_core_test-46.0.0.dist-info/licenses/LICENSE +661 -0
  224. openfisca_core_test-46.0.0.dist-info/top_level.txt +2 -0
  225. openfisca_web_api/__init__.py +0 -0
  226. openfisca_web_api/app.py +226 -0
  227. openfisca_web_api/errors.py +11 -0
  228. openfisca_web_api/handlers.py +90 -0
  229. openfisca_web_api/loader/__init__.py +22 -0
  230. openfisca_web_api/loader/entities.py +28 -0
  231. openfisca_web_api/loader/parameters.py +122 -0
  232. openfisca_web_api/loader/spec.py +168 -0
  233. openfisca_web_api/loader/tax_benefit_system.py +27 -0
  234. openfisca_web_api/loader/variables.py +121 -0
  235. openfisca_web_api/openAPI.yml +434 -0
  236. openfisca_web_api/scripts/__init__.py +0 -0
  237. 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()