Skip to content

Commit 55ff363

Browse files
committed
Add priority param to processors
1 parent 4a4d8ef commit 55ff363

3 files changed

Lines changed: 50 additions & 13 deletions

File tree

marshmallow/decorators.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -61,15 +61,16 @@ def validate_age(self, data):
6161
VALIDATES_SCHEMA = 'validates_schema'
6262

6363

64-
def validates(field_name):
64+
def validates(field_name, priority=0):
6565
"""Register a field validator.
6666
6767
:param str field_name: Name of the field that the method validates.
6868
"""
69-
return tag_processor(VALIDATES, None, False, field_name=field_name)
69+
return tag_processor(VALIDATES, None, False, priority=priority, field_name=field_name)
7070

7171

72-
def validates_schema(fn=None, pass_many=False, pass_original=False, skip_on_field_errors=True):
72+
def validates_schema(fn=None, pass_many=False, pass_original=False, skip_on_field_errors=True,
73+
priority=0):
7374
"""Register a schema-level validator.
7475
7576
By default, receives a single object at a time, regardless of whether ``many=True``
@@ -85,52 +86,52 @@ def validates_schema(fn=None, pass_many=False, pass_original=False, skip_on_fiel
8586
.. versionchanged:: 3.0.0b1
8687
``skip_on_field_errors`` defaults to `True`.
8788
"""
88-
return tag_processor(VALIDATES_SCHEMA, fn, pass_many, pass_original=pass_original,
89-
skip_on_field_errors=skip_on_field_errors)
89+
return tag_processor(VALIDATES_SCHEMA, fn, pass_many, priority=priority,
90+
pass_original=pass_original, skip_on_field_errors=skip_on_field_errors)
9091

9192

92-
def pre_dump(fn=None, pass_many=False):
93+
def pre_dump(fn=None, pass_many=False, priority=0):
9394
"""Register a method to invoke before serializing an object. The method
9495
receives the object to be serialized and returns the processed object.
9596
9697
By default, receives a single object at a time, regardless of whether ``many=True``
9798
is passed to the `Schema`. If ``pass_many=True``, the raw data (which may be a collection)
9899
and the value for ``many`` is passed.
99100
"""
100-
return tag_processor(PRE_DUMP, fn, pass_many)
101+
return tag_processor(PRE_DUMP, fn, pass_many, priority=priority)
101102

102103

103-
def post_dump(fn=None, pass_many=False, pass_original=False):
104+
def post_dump(fn=None, pass_many=False, pass_original=False, priority=0):
104105
"""Register a method to invoke after serializing an object. The method
105106
receives the serialized object and returns the processed object.
106107
107108
By default, receives a single object at a time, transparently handling the ``many``
108109
argument passed to the Schema. If ``pass_many=True``, the raw data
109110
(which may be a collection) and the value for ``many`` is passed.
110111
"""
111-
return tag_processor(POST_DUMP, fn, pass_many, pass_original=pass_original)
112+
return tag_processor(POST_DUMP, fn, pass_many, priority=priority, pass_original=pass_original)
112113

113114

114-
def pre_load(fn=None, pass_many=False):
115+
def pre_load(fn=None, pass_many=False, priority=0):
115116
"""Register a method to invoke before deserializing an object. The method
116117
receives the data to be deserialized and returns the processed data.
117118
118119
By default, receives a single datum at a time, transparently handling the ``many``
119120
argument passed to the Schema. If ``pass_many=True``, the raw data
120121
(which may be a collection) and the value for ``many`` is passed.
121122
"""
122-
return tag_processor(PRE_LOAD, fn, pass_many)
123+
return tag_processor(PRE_LOAD, fn, pass_many, priority=priority)
123124

124125

125-
def post_load(fn=None, pass_many=False, pass_original=False):
126+
def post_load(fn=None, pass_many=False, pass_original=False, priority=0):
126127
"""Register a method to invoke after deserializing an object. The method
127128
receives the deserialized data and returns the processed data.
128129
129130
By default, receives a single datum at a time, transparently handling the ``many``
130131
argument passed to the Schema. If ``pass_many=True``, the raw data
131132
(which may be a collection) and the value for ``many`` is passed.
132133
"""
133-
return tag_processor(POST_LOAD, fn, pass_many, pass_original=pass_original)
134+
return tag_processor(POST_LOAD, fn, pass_many, priority=priority, pass_original=pass_original)
134135

135136

136137
def tag_processor(tag_name, fn, pass_many, **kwargs):

marshmallow/schema.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,16 @@ def _resolve_processors(self):
173173
# the processor was a descriptor or something.
174174
self.__processors__[tag].append(attr_name)
175175

176+
# Sort all processor tags by priority, descending
177+
for tag, processors in self.__processors__.items():
178+
sorted_processors = sorted(processors,
179+
key=lambda proc: self._get_priority(proc, tag))
180+
self.__processors__[tag] = sorted_processors
181+
182+
def _get_priority(self, attr_name, tag):
183+
processor = getattr(self, attr_name)
184+
return processor.__marshmallow_kwargs__[tag].get('priority', 0)
185+
176186

177187
class SchemaOpts(object):
178188
"""class Meta options for the :class:`Schema`. Defines defaults."""

tests/test_decorators.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,3 +706,29 @@ def raise_value_error(self, item):
706706
schema.dump(object())
707707
assert exc.value.messages == {'foo': 'error'}
708708
schema.load({})
709+
710+
class TestProcessorPriorities:
711+
712+
def test_pass_ordered_processors(self):
713+
class MySchema(Schema):
714+
data = fields.Field()
715+
716+
@post_load(priority=1)
717+
def first_post_load(self, ret):
718+
ret['data'].append(1)
719+
return ret
720+
721+
@post_load(priority=10)
722+
def third_post_load(self, ret):
723+
ret['data'].append(10)
724+
return ret
725+
726+
@post_load(priority=5)
727+
def second_post_load(self, ret):
728+
ret['data'].append(5)
729+
return ret
730+
731+
schema = MySchema()
732+
datum = {'data': []}
733+
item_loaded = schema.load(datum).data
734+
assert item_loaded['data'] == [1, 5, 10]

0 commit comments

Comments
 (0)