-
Notifications
You must be signed in to change notification settings - Fork 76
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make parameters node accessible through the Web API #694
Changes from all commits
0d1f471
d5de9b6
b376e1b
5e6c3de
619c64e
7b5b329
78ed2fa
abc75ba
2fb0827
9d5fd6f
608d561
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,51 @@ | ||
# Changelog | ||
|
||
## 23.4.0 [#694](https://github.com/openfisca/openfisca-core/pull/694) | ||
|
||
* Use `/` rather than `.` in the path to access a parameter: | ||
- For instance `/parameter/benefits.basic_income` becomes `/parameter/benefits/basic_income` | ||
- Using `.` is for now still supported, but is considered deprecated and will be turned to a 301 redirection in the next major version. | ||
|
||
* Expose parameters `metadata` and `source` in the Web API and: | ||
|
||
For instance, `/parameter/benefits/basic_income` contains: | ||
|
||
```JSON | ||
{ | ||
"description": "Amount of the basic income", | ||
"id": "benefits.basic_income", | ||
"metadata": { | ||
"reference": "https://law.gov.example/basic-income/amount", | ||
"unit": "currency-EUR" | ||
}, | ||
"source": "https://github.com/openfisca/country-template/blob/3.2.2/openfisca_country_template/parameters/benefits/basic_income.yaml", | ||
"values": { | ||
"2015-12-01": 600.0 | ||
} | ||
} | ||
``` | ||
|
||
* Expose parameters nodes in the Web API | ||
- For instance, `/parameter/benefits` now exists and contains: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
||
```JSON | ||
{ | ||
"description": "Social benefits", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Explicit that a node might have metadata? 🤔 |
||
"id": "benefits", | ||
"metadata": {}, | ||
"source": "https://github.com/openfisca/country-template/blob/3.2.2/openfisca_country_template/parameters/benefits", | ||
"subparams": { | ||
"basic_income": { | ||
"description": "Amount of the basic income" | ||
}, | ||
"housing_allowance": { | ||
"description": "Housing allowance amount (as a fraction of the rent)" | ||
} | ||
} | ||
} | ||
``` | ||
|
||
Note that this route doesn't _recursively_ explore the node, and only exposes its direct children name and description. | ||
|
||
### 23.3.2 [#702](https://github.com/openfisca/openfisca-core/pull/702) | ||
|
||
|
@@ -13,7 +59,7 @@ Minor Change without any impact for country package developers and users: | |
|
||
* Send reference of the country-package and its version to the tracker so it will appear in the tracking statistics. | ||
|
||
### 23.3.0 [#681](https://github.com/openfisca/openfisca-core/pull/681) | ||
## 23.3.0 [#681](https://github.com/openfisca/openfisca-core/pull/681) | ||
|
||
* Change the way metadata are declared for Parameter. | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -62,9 +62,13 @@ def create_app(tax_benefit_system, | |
def get_parameters(): | ||
return jsonify(data['parameters_description']) | ||
|
||
@app.route('/parameter/<id>') | ||
def get_parameter(id): | ||
parameter = data['parameters'].get(id) | ||
@app.route('/parameter/<path:parameter_id>') | ||
def get_parameter(parameter_id): | ||
parameter = data['parameters'].get(parameter_id) | ||
if parameter is None: | ||
# Try legacy route | ||
parameter_new_id = parameter_id.replace('.', '/') | ||
parameter = data['parameters'].get(parameter_new_id) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Look for the parameter only when There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We are not looking into all parameters. The |
||
if parameter is None: | ||
raise abort(404) | ||
return jsonify(parameter) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,12 +4,12 @@ | |
from openfisca_core.parameters import Parameter, ParameterNode, Scale | ||
|
||
|
||
def transform_values_history(values_history): | ||
values_history_transformed = {} | ||
def build_api_values_history(values_history): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 👍 |
||
api_values_history = {} | ||
for value_at_instant in values_history.values_list: | ||
values_history_transformed[value_at_instant.instant_str] = value_at_instant.value | ||
api_values_history[value_at_instant.instant_str] = value_at_instant.value | ||
|
||
return values_history_transformed | ||
return api_values_history | ||
|
||
|
||
def get_value(date, values): | ||
|
@@ -25,61 +25,79 @@ def get_value(date, values): | |
return None | ||
|
||
|
||
def transform_scale(scale): | ||
def build_api_scale(scale): | ||
# preprocess brackets | ||
brackets = [{ | ||
'thresholds': transform_values_history(bracket.threshold), | ||
'rates': transform_values_history(bracket.rate), | ||
'thresholds': build_api_values_history(bracket.threshold), | ||
'rates': build_api_values_history(bracket.rate), | ||
} for bracket in scale.brackets] | ||
|
||
dates = set(sum( | ||
[list(bracket['thresholds'].keys()) + list(bracket['rates'].keys()) for bracket in brackets], | ||
[])) # flatten the dates and remove duplicates | ||
|
||
# We iterate on all dates as we need to build the whole scale for each of them | ||
brackets_transformed = {} | ||
api_scale = {} | ||
for date in dates: | ||
for bracket in brackets: | ||
threshold_value = get_value(date, bracket['thresholds']) | ||
if threshold_value is not None: | ||
rate_value = get_value(date, bracket['rates']) | ||
brackets_transformed[date] = brackets_transformed.get(date) or {} | ||
brackets_transformed[date][threshold_value] = rate_value | ||
api_scale[date] = api_scale.get(date) or {} | ||
api_scale[date][threshold_value] = rate_value | ||
|
||
# Handle stopped parameters: a parameter is stopped if its first bracket is stopped | ||
latest_date_first_threshold = max(brackets[0]['thresholds'].keys()) | ||
latest_value_first_threshold = brackets[0]['thresholds'][latest_date_first_threshold] | ||
if latest_value_first_threshold is None: | ||
brackets_transformed[latest_date_first_threshold] = None | ||
api_scale[latest_date_first_threshold] = None | ||
|
||
return brackets_transformed | ||
return api_scale | ||
|
||
|
||
def walk_node(node, parameters, path_fragments): | ||
def build_source_url(absolute_file_path, country_package_metadata): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fixed by openfisca/country-template#50 |
||
relative_path = absolute_file_path.replace(country_package_metadata['location'], '') | ||
return '{}/blob/{}{}'.format( | ||
country_package_metadata['repository_url'], | ||
country_package_metadata['version'], | ||
relative_path | ||
) | ||
|
||
|
||
def walk_node(node, parameters, path_fragments, country_package_metadata): | ||
children = node.children | ||
|
||
for child_name, child in children.items(): | ||
if isinstance(child, ParameterNode): | ||
walk_node(child, parameters, path_fragments + [child_name]) | ||
else: | ||
object_transformed = { | ||
'description': getattr(child, "description", None), | ||
'id': '.'.join(path_fragments + [child_name]), | ||
api_parameter = { | ||
'description': getattr(child, "description", None), | ||
'id': '.'.join(path_fragments + [child_name]), | ||
'metadata': child.metadata | ||
} | ||
if child.file_path: | ||
api_parameter['source'] = build_source_url(child.file_path, country_package_metadata) | ||
if isinstance(child, Parameter): | ||
api_parameter['values'] = build_api_values_history(child) | ||
elif isinstance(child, Scale): | ||
api_parameter['brackets'] = build_api_scale(child) | ||
elif isinstance(child, ParameterNode): | ||
api_parameter['subparams'] = { | ||
grandchild_name: { | ||
'description': grandchild.description, | ||
} | ||
for grandchild_name, grandchild in child.children.items() | ||
} | ||
if isinstance(child, Scale): | ||
object_transformed['brackets'] = transform_scale(child) | ||
elif isinstance(child, Parameter): | ||
object_transformed['values'] = transform_values_history(child) | ||
parameters.append(object_transformed) | ||
walk_node(child, parameters, path_fragments + [child_name], country_package_metadata) | ||
parameters.append(api_parameter) | ||
|
||
|
||
def build_parameters(tax_benefit_system): | ||
def build_parameters(tax_benefit_system, country_package_metadata): | ||
original_parameters = tax_benefit_system.parameters | ||
transformed_parameters = [] | ||
api_parameters = [] | ||
walk_node( | ||
original_parameters, | ||
parameters = transformed_parameters, | ||
parameters = api_parameters, | ||
path_fragments = [], | ||
country_package_metadata = country_package_metadata, | ||
) | ||
|
||
return {parameter['id']: parameter for parameter in transformed_parameters} | ||
return {parameter['id'].replace('.', '/'): parameter for parameter in api_parameters} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
# -*- coding: utf-8 -*- | ||
|
||
from __future__ import unicode_literals, print_function, division, absolute_import | ||
import pkg_resources | ||
from openfisca_web_api_preview.app import create_app | ||
from openfisca_core.scripts import build_tax_benefit_system | ||
|
||
TEST_COUNTRY_PACKAGE_NAME = 'openfisca_country_template' | ||
distribution = pkg_resources.get_distribution(TEST_COUNTRY_PACKAGE_NAME) | ||
tax_benefit_system = build_tax_benefit_system(TEST_COUNTRY_PACKAGE_NAME, extensions = None, reforms = None) | ||
subject = create_app(tax_benefit_system).test_client() |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK (see node below)