How can I make marshmallow make raise an exception when data is missing attributes?
Consider the following example:
In [8]: import marshmallow
In [9]: class Foo(marshmallow.Schema):
...: bar = marshmallow.fields.Str(required=True)
...:
In [10]: class Bar:
...: pass
...:
In [11]: bar = Bar()
In [12]: Foo().dumps(bar)
Out[12]: MarshalResult(data='{}', errors={})
In [13]: bar.bar
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
<ipython-input-13-6901e83d9f0c> in <module>()
----> 1 bar.bar
AttributeError: 'Bar' object has no attribute 'bar'
What's even worse, is this:
In [14]: foo.loads(foo.dumps(bar).data)
Out[14]: UnmarshalResult(data={}, errors={'bar': ['Missing data for required field.']})
The following quote from this issue explains the behavior you're describing in the first part of your question.
This is by design. Primarily for performance reasons, validation only happens on deserialization (
load
andvalidate
). The data passed todump
is assumed to be valid.
The expectation is that you'll explicitly call validate()
, if you need validation, e.g. from your example:
In [10]: foo.validate(foo.dump(foo).data)
---------------------------------------------------------------------------
ValidationError Traceback (most recent call last)
<ipython-input-40-4dfb5988e928> in <module>()
----> 1 foo.validate(foo.dump(foo).data)
...
ValidationError: {'bar': ['Missing data for required field.']}
Regarding the lack of validation during deserialization, for the version of marshmallow
that you're using you have to explicitly declare the schema to be 'strict' in order for validation to happen automatically. In your example, this can be accomplished with:
In [22]: class Foo(marshmallow.Schema):
...: bar = marshmallow.fields.Str(required=True)
...: class Meta:
...: strict = True
In [23]: foo = Foo()
In [24]: foo.loads(foo.dumps(bar).data)
---------------------------------------------------------------------------
...
ValidationError: {'bar': ['Missing data for required field.']}
As discussed in Issue 598, this behavior was changed and the latest version of marshamallow
defaults to this 'strict' behavior; it also removes the MarshalResult
/UnmarshalResult
wrappers.