Simplify marshalling.

This commit is contained in:
Alexis Lahouze 2017-05-18 21:37:57 +02:00
parent de59dc3bb0
commit e1190c872d
5 changed files with 24 additions and 76 deletions

View File

@ -1,44 +0,0 @@
# vim: set tw=80 ts=4 sw=4 sts=4:
"""
This file is part of Accountant.
Accountant is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Accountant is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>.
"""
from flask_restplus import marshal, fields
class Object(fields.Raw):
"""
Field to marshal an object with fields.
SQLAlchemy rows are viewed as tuples by Restful marshaller, and must be
translated into a dict before marshaling.
"""
def __init__(self, model, **kwargs):
"""
:param model: the target model of the object.
"""
self.model = model
super(Object, self).__init__(**kwargs)
def format(self, value):
# First transform object in dict with fields in attribute.
result = {key: getattr(value, key, None) for key in self.model.keys()}
# Marshal the dict
return marshal(result, self.model)
def schema(self):
return self.model.__schema__

View File

@ -16,14 +16,12 @@
""" """
import dateutil.parser import dateutil.parser
from flask_restplus import Namespace, Resource, fields, marshal_with_field from flask_restplus import Namespace, Resource, fields
from ..models import db from ..models import db
from ..models.accounts import Account from ..models.accounts import Account
from ..models.operations import Operation from ..models.operations import Operation
from ..fields import Object
from .users import requires_auth from .users import requires_auth
@ -144,7 +142,7 @@ class AccountListResource(Resource):
@requires_auth @requires_auth
@ns.response(200, 'OK', [account_model]) @ns.response(200, 'OK', [account_model])
@marshal_with_field(fields.List(Object(account_model))) @ns.marshal_list_with(account_model)
def get(self): def get(self):
""" Returns accounts with their balances.""" """ Returns accounts with their balances."""
@ -154,7 +152,7 @@ class AccountListResource(Resource):
@ns.expect(account_model) @ns.expect(account_model)
@ns.response(201, 'Account created', account_model) @ns.response(201, 'Account created', account_model)
@ns.response(406, 'Invalid account data') @ns.response(406, 'Invalid account data')
@marshal_with_field(Object(account_model)) @ns.marshal_with(account_model)
def post(self): def post(self):
"""Create a new account.""" """Create a new account."""
@ -195,7 +193,7 @@ class AccountResource(Resource):
@requires_auth @requires_auth
@ns.response(200, 'OK', account_model) @ns.response(200, 'OK', account_model)
@marshal_with_field(Object(account_model)) @ns.marshal_with(account_model)
def get(self, id): def get(self, id):
"""Get an account.""" """Get an account."""
@ -215,7 +213,7 @@ class AccountResource(Resource):
@ns.expect(account_model) @ns.expect(account_model)
@ns.response(200, 'OK', account_model) @ns.response(200, 'OK', account_model)
@ns.response(406, 'Invalid account data') @ns.response(406, 'Invalid account data')
@marshal_with_field(Object(account_model)) @ns.marshal_with(account_model)
def post(self, id): def post(self, id):
"""Update an account.""" """Update an account."""
@ -248,7 +246,7 @@ class AccountResource(Resource):
@requires_auth @requires_auth
@ns.response(204, 'Account deleted', account_model) @ns.response(204, 'Account deleted', account_model)
@marshal_with_field(Object(account_model)) @ns.marshal_with(account_model)
def delete(self, id): def delete(self, id):
"""Delete an account.""" """Delete an account."""
@ -278,7 +276,7 @@ class SoldsResource(Resource):
401: 'Unauthorized', 401: 'Unauthorized',
404: 'Account not found' 404: 'Account not found'
}) })
@marshal_with_field(Object(solds_model)) @ns.marshal_with(solds_model)
def get(self, id): def get(self, id):
"""Get solds for a specific account and date range.""" """Get solds for a specific account and date range."""
@ -308,7 +306,7 @@ class BalanceResource(Resource):
404: 'Account not found' 404: 'Account not found'
}) })
@ns.expect(range_parser) @ns.expect(range_parser)
@marshal_with_field(Object(balance_model)) @ns.marshal_with(balance_model)
def get(self, id): def get(self, id):
"""Get account balance for a specific date range.""" """Get account balance for a specific date range."""
@ -340,7 +338,7 @@ class CategoryResource(Resource):
404: 'Account not found' 404: 'Account not found'
}) })
@ns.expect(range_parser) @ns.expect(range_parser)
@marshal_with_field(fields.List(Object(category_model))) @ns.marshal_list_with(category_model)
def get(self, id): def get(self, id):
"""Get account category balances for a specific date range.""" """Get account category balances for a specific date range."""
@ -362,7 +360,7 @@ class OHLCResource(Resource):
404: 'Account not found' 404: 'Account not found'
}) })
@ns.expect(range_parser) @ns.expect(range_parser)
@marshal_with_field(fields.List(Object(ohlc_model))) @ns.marshal_list_with(ohlc_model)
def get(self, id): def get(self, id):
"""Get OHLC data for a specific date range and account.""" """Get OHLC data for a specific date range and account."""

View File

@ -16,7 +16,7 @@
""" """
import dateutil.parser import dateutil.parser
from flask_restplus import Namespace, Resource, fields, marshal_with_field from flask_restplus import Namespace, Resource, fields
from ..models import db from ..models import db
from ..models.accounts import Account from ..models.accounts import Account
@ -24,8 +24,6 @@ from ..models.operations import Operation
from .users import requires_auth from .users import requires_auth
from ..fields import Object
# pylint: disable=invalid-name # pylint: disable=invalid-name
ns = Namespace('operation', description='Operation management') ns = Namespace('operation', description='Operation management')
@ -115,7 +113,7 @@ class OperationListResource(Resource):
@requires_auth @requires_auth
@ns.response(200, 'OK', [operation_with_sold_model]) @ns.response(200, 'OK', [operation_with_sold_model])
@ns.expect(parser=account_range_parser) @ns.expect(parser=account_range_parser)
@marshal_with_field(fields.List(Object(operation_with_sold_model))) @ns.marshal_list_with(operation_with_sold_model)
def get(self): def get(self):
"""Get operations with solds for a specific account.""" """Get operations with solds for a specific account."""
@ -132,7 +130,7 @@ class OperationListResource(Resource):
@ns.response(201, 'Operation created', operation_model) @ns.response(201, 'Operation created', operation_model)
@ns.response(404, 'Account not found') @ns.response(404, 'Account not found')
@ns.response(406, 'Invalid operation data') @ns.response(406, 'Invalid operation data')
@marshal_with_field(Object(operation_model)) @ns.marshal_with(operation_model)
def post(self): def post(self):
"""Create a new operation.""" """Create a new operation."""
@ -176,7 +174,7 @@ class OperationResource(Resource):
@requires_auth @requires_auth
@ns.response(200, 'OK', operation_model) @ns.response(200, 'OK', operation_model)
@marshal_with_field(Object(operation_model)) @ns.marshal_with(operation_model)
def get(self, id): def get(self, id):
"""Get operation.""" """Get operation."""
@ -194,7 +192,7 @@ class OperationResource(Resource):
@ns.expect(operation_model) @ns.expect(operation_model)
@ns.response(200, 'OK', operation_model) @ns.response(200, 'OK', operation_model)
@ns.response(406, 'Invalid operation data') @ns.response(406, 'Invalid operation data')
@marshal_with_field(Object(operation_model)) @ns.marshal_with(operation_model)
def post(self, id): def post(self, id):
"""Update an operation.""" """Update an operation."""
@ -227,7 +225,7 @@ class OperationResource(Resource):
@requires_auth @requires_auth
@ns.response(204, 'Operation deleted', operation_model) @ns.response(204, 'Operation deleted', operation_model)
@marshal_with_field(Object(operation_model)) @ns.marshal_with(operation_model)
def delete(self, id): def delete(self, id):
"""Delete an operation.""" """Delete an operation."""

View File

@ -14,7 +14,7 @@
You should have received a copy of the GNU Affero General Public License You should have received a copy of the GNU Affero General Public License
along with Accountant. If not, see <http://www.gnu.org/licenses/>. along with Accountant. If not, see <http://www.gnu.org/licenses/>.
""" """
from flask_restplus import Namespace, Resource, fields, marshal_with_field from flask_restplus import Namespace, Resource, fields
from sqlalchemy import true from sqlalchemy import true
@ -25,8 +25,6 @@ from ..models.scheduled_operations import ScheduledOperation
from .users import requires_auth from .users import requires_auth
from ..fields import Object
# pylint: disable=invalid-name # pylint: disable=invalid-name
ns = Namespace( ns = Namespace(
'scheduled_operation', 'scheduled_operation',
@ -92,7 +90,7 @@ class ScheduledOperationListResource(Resource):
@requires_auth @requires_auth
@ns.expect(account_id_parser) @ns.expect(account_id_parser)
@ns.response(200, 'OK', [scheduled_operation_model]) @ns.response(200, 'OK', [scheduled_operation_model])
@marshal_with_field(fields.List(Object(scheduled_operation_model))) @ns.marshal_list_with(scheduled_operation_model)
def get(self): def get(self):
"""Get all scheduled operation for an account.""" """Get all scheduled operation for an account."""
@ -105,7 +103,7 @@ class ScheduledOperationListResource(Resource):
@ns.response(200, 'OK', scheduled_operation_model) @ns.response(200, 'OK', scheduled_operation_model)
@ns.response(404, 'Account not found') @ns.response(404, 'Account not found')
@ns.response(406, 'Invalid operation data') @ns.response(406, 'Invalid operation data')
@marshal_with_field(Object(scheduled_operation_model)) @ns.marshal_with(scheduled_operation_model)
def post(self): def post(self):
"""Add a new scheduled operation.""" """Add a new scheduled operation."""
@ -153,7 +151,7 @@ class ScheduledOperationResource(Resource):
@requires_auth @requires_auth
@ns.response(200, 'OK', scheduled_operation_model) @ns.response(200, 'OK', scheduled_operation_model)
@marshal_with_field(Object(scheduled_operation_model)) @ns.marshal_with(scheduled_operation_model)
def get(self, id): def get(self, id):
"""Get scheduled operation.""" """Get scheduled operation."""
@ -171,7 +169,7 @@ class ScheduledOperationResource(Resource):
@ns.response(200, 'OK', scheduled_operation_model) @ns.response(200, 'OK', scheduled_operation_model)
@ns.response(406, 'Invalid scheduled operation data') @ns.response(406, 'Invalid scheduled operation data')
@ns.expect(scheduled_operation_model) @ns.expect(scheduled_operation_model)
@marshal_with_field(Object(scheduled_operation_model)) @ns.marshal_with(scheduled_operation_model)
def post(self, id): def post(self, id):
"""Update a scheduled operation.""" """Update a scheduled operation."""
@ -209,7 +207,7 @@ class ScheduledOperationResource(Resource):
@requires_auth @requires_auth
@ns.response(200, 'OK', scheduled_operation_model) @ns.response(200, 'OK', scheduled_operation_model)
@ns.response(409, 'Cannot be deleted') @ns.response(409, 'Cannot be deleted')
@marshal_with_field(Object(scheduled_operation_model)) @ns.marshal_with(scheduled_operation_model)
def delete(self, id): def delete(self, id):
"""Delete a scheduled operation.""" """Delete a scheduled operation."""

View File

@ -20,9 +20,7 @@ from functools import wraps
import arrow import arrow
from flask import request, g, current_app as app from flask import request, g, current_app as app
from flask_restplus import Namespace, Resource, fields, marshal_with_field from flask_restplus import Namespace, Resource, fields
from ..fields import Object
from ..models.users import User from ..models.users import User
@ -144,7 +142,7 @@ class LoginResource(Resource):
responses={ responses={
200: ('OK', user_model) 200: ('OK', user_model)
}) })
@marshal_with_field(Object(user_model)) @ns.marshal_with(user_model)
def get(self): def get(self):
"""Get authenticated user information.""" """Get authenticated user information."""