Skip to content

Commit 4f0b18b

Browse files
committed
Merge pull request flask-restful#214 from lyschoening/marshal-with-field
Added marshal_with_field decorator, see issue flask-restful#212
2 parents ea31676 + 0532093 commit 4f0b18b

File tree

4 files changed

+69
-13
lines changed

4 files changed

+69
-13
lines changed

docs/api.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ API Docs
88

99
.. autofunction:: marshal
1010
.. autofunction:: marshal_with
11+
.. autofunction:: marshal_with_field
1112
.. autofunction:: abort
1213

1314

flask_restful/__init__.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
except ImportError:
2222
from .utils.ordereddict import OrderedDict
2323

24-
__all__ = ('Api', 'Resource', 'marshal', 'marshal_with', 'abort')
24+
__all__ = ('Api', 'Resource', 'marshal', 'marshal_with', 'marshal_with_field', 'abort')
2525

2626

2727
def abort(http_status_code, **kwargs):
@@ -562,3 +562,39 @@ def wrapper(*args, **kwargs):
562562
else:
563563
return marshal(resp, self.fields)
564564
return wrapper
565+
566+
567+
class marshal_with_field(object):
568+
"""
569+
A decorator that formats the return values of your methods with a single field.
570+
571+
>>> from flask.ext.restful import marshal_with_field, fields
572+
>>> @marshal_with_field(fields.List(fields.Integer))
573+
... def get():
574+
... return ['1', 2, 3.0]
575+
...
576+
>>> get()
577+
[1, 2, 3]
578+
579+
see :meth:`flask.ext.restful.marshal_with`
580+
"""
581+
def __init__(self, field):
582+
"""
583+
:param field: a single field with which to marshal the output.
584+
"""
585+
if isinstance(field, type):
586+
self.field = field()
587+
else:
588+
self.field = field
589+
590+
def __call__(self, f):
591+
@wraps(f)
592+
def wrapper(*args, **kwargs):
593+
resp = f(*args, **kwargs)
594+
595+
if isinstance(resp, tuple):
596+
data, code, headers = unpack(resp)
597+
return self.field.format(data), code, headers
598+
return self.field.format(resp)
599+
600+
return wrapper

flask_restful/fields.py

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -145,22 +145,25 @@ def __init__(self, cls_or_instance, **kwargs):
145145
raise MarshallingException(error_msg)
146146
self.container = cls_or_instance
147147

148+
def format(self, value):
149+
# Convert all instances in typed list to container type
150+
if isinstance(value, set):
151+
value = list(value)
152+
153+
return [
154+
self.container.output(idx,
155+
val if isinstance(val, dict) and
156+
not isinstance(self.container, Nested)
157+
and not type(self.container) is Raw
158+
else value)
159+
for idx, val in enumerate(value)
160+
]
161+
148162
def output(self, key, data):
149163
value = get_value(key if self.attribute is None else self.attribute, data)
150164
# we cannot really test for external dict behavior
151165
if is_indexable_but_not_string(value) and not isinstance(value, dict):
152-
# Convert all instances in typed list to container type
153-
if isinstance(value, set):
154-
value = list(value)
155-
156-
return [
157-
self.container.output(idx,
158-
val if isinstance(val, dict) and
159-
not isinstance(self.container, Nested)
160-
and not type(self.container) is Raw
161-
else value)
162-
for idx, val in enumerate(value)
163-
]
166+
return self.format(value)
164167

165168
if value is None:
166169
return self.default

tests/test_api.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,22 @@ def try_me():
117117
return OrderedDict([('foo', 'bar'), ('bat', 'baz')]), 200, {'X-test': 123}
118118
self.assertEquals(try_me(), ({'foo': 'bar'}, 200, {'X-test': 123}))
119119

120+
def test_marshal_field_decorator(self):
121+
field = flask_restful.fields.Raw
122+
123+
@flask_restful.marshal_with_field(field)
124+
def try_me():
125+
return 'foo'
126+
self.assertEquals(try_me(), 'foo')
127+
128+
def test_marshal_field_decorator_tuple(self):
129+
field = flask_restful.fields.Raw
130+
131+
@flask_restful.marshal_with_field(field)
132+
def try_me():
133+
return 'foo', 200, {'X-test': 123}
134+
self.assertEquals(('foo', 200, {'X-test': 123}), try_me())
135+
120136
def test_marshal_field(self):
121137
fields = OrderedDict({'foo': flask_restful.fields.Raw()})
122138
marshal_fields = OrderedDict([('foo', 'bar'), ('bat', 'baz')])

0 commit comments

Comments
 (0)