diff --git a/AUTHORS.rst b/AUTHORS.rst index 5cf56d7cf..acb9cc176 100644 --- a/AUTHORS.rst +++ b/AUTHORS.rst @@ -157,3 +157,4 @@ Contributors (chronological) - Nadège Michel `@nadege `_ - Tamara `@infinityxxx `_ - Stephen Rosen `@sirosen `_ +- Ficapy `@ficapy `_ diff --git a/docs/quickstart.rst b/docs/quickstart.rst index bb1bd620f..8c79d0972 100644 --- a/docs/quickstart.rst +++ b/docs/quickstart.rst @@ -299,6 +299,8 @@ It is sometimes convenient to write validators as methods. Use the `validates typing.Dict[types.Tag, typing.List[str]]: """ mro = inspect.getmro(cls) - hooks = defaultdict(list) # type: typing.Dict[types.Tag, typing.List[str]] + hooks = defaultdict(list) # type: typing.Dict[types.Tag, typing.Any] for attr_name in dir(cls): # Need to look up the actual descriptor, not whatever might be @@ -185,12 +185,21 @@ def resolve_hooks(cls) -> typing.Dict[types.Tag, typing.List[str]]: except AttributeError: pass else: - for key in hook_config.keys(): + for key, value in hook_config.items(): # Use name here so we can get the bound method later, in # case the processor was a descriptor or something. - hooks[key].append(attr_name) + hooks[key].append( + {"order": value.get("order", 0), "attr_name": attr_name} + ) - return hooks + ordered_hooks = { + k: [ + i["attr_name"] + for i in sorted(v, key=lambda x: x["order"], reverse=True) + ] + for k, v in hooks.items() + } + return defaultdict(list, ordered_hooks) class SchemaOpts: diff --git a/tests/test_schema.py b/tests/test_schema.py index 4f5b871cb..5ab8dd8f0 100644 --- a/tests/test_schema.py +++ b/tests/test_schema.py @@ -2912,3 +2912,30 @@ class DefinitelyUniqueSchema(Schema): SchemaClass = class_registry.get_class(DefinitelyUniqueSchema.__name__) assert SchemaClass is DefinitelyUniqueSchema + + +def test_validates_order(): + class User(Schema): + name = fields.Str() + age = fields.Int() + sex = fields.Int() + + @validates("name", order=1) + def validate_name(self, value): + self.context["order"] += "1" + return value + + @validates("age", order=2) + def validate_age(self, value): + self.context["order"] += "2" + return value + + @validates("sex") + def validate_sex(self, value): + self.context["order"] += "0" + return value + + schema = User() + schema.context["order"] = "" + schema.load({"name": "name", "age": 24, "sex": 1}) + assert schema.context["order"] == "210"