Skip to content

Commit

Permalink
Fix #908: Nested now defaults to unknown=RAISE not EXCLUDE (lik…
Browse files Browse the repository at this point in the history
…e `Schema`)
  • Loading branch information
tuukkamustonen committed Sep 3, 2018
1 parent f1b0428 commit 8a3f327
Show file tree
Hide file tree
Showing 5 changed files with 42 additions and 8 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.rst
Expand Up @@ -13,6 +13,12 @@ Features:
- Raise a `StringNotCollectionError` if ``only`` or ``exclude`` is
passed as a string to ``fields.Nested`` (:pr:`931`).

Other changes:

- *Backwards-incompatible*: ``Nested`` field now defaults to ``unknown=RAISE``
instead of ``EXCLUDE``. This harmonizes behavior with ``Schema`` that
already defaults to ``RAISE`` (:issue:`908`). Thanks :user:`tuukkamustonen`.

3.0.0b13 (2018-08-04)
+++++++++++++++++++++

Expand Down
4 changes: 2 additions & 2 deletions marshmallow/fields.py
Expand Up @@ -12,7 +12,7 @@

from marshmallow import validate, utils, class_registry
from marshmallow.base import FieldABC, SchemaABC
from marshmallow.utils import EXCLUDE, is_collection
from marshmallow.utils import RAISE, is_collection
from marshmallow.utils import missing as missing_
from marshmallow.compat import text_type, basestring
from marshmallow.exceptions import ValidationError, StringNotCollectionError
Expand Down Expand Up @@ -393,7 +393,7 @@ def __init__(self, nested, default=missing_, exclude=tuple(), only=None, **kwarg
self.only = only
self.exclude = exclude
self.many = kwargs.get('many', False)
self.unknown = kwargs.get('unknown', EXCLUDE)
self.unknown = kwargs.get('unknown', RAISE)
self.__schema = None # Cached Schema instance
self.__updated_fields = False
super(Nested, self).__init__(default=default, **kwargs)
Expand Down
2 changes: 1 addition & 1 deletion tests/test_decorators.py
Expand Up @@ -471,7 +471,7 @@ def validate_schema(self, data, original_data, many=False):
raise ValidationError('Method called')

class MySchema(Schema):
nested = fields.Nested(NestedSchema, required=True, many=True)
nested = fields.Nested(NestedSchema, required=True, many=True, unknown=EXCLUDE)

schema = MySchema()
errors = schema.validate({'nested': data})
Expand Down
2 changes: 1 addition & 1 deletion tests/test_deserialization.py
Expand Up @@ -942,7 +942,7 @@ def test_exclude(self):
def test_nested_single_deserialization_to_dict(self):
class SimpleBlogSerializer(Schema):
title = fields.String()
author = fields.Nested(SimpleUserSchema)
author = fields.Nested(SimpleUserSchema, unknown=EXCLUDE)

blog_dict = {
'title': 'Gimme Shelter',
Expand Down
36 changes: 32 additions & 4 deletions tests/test_schema.py
Expand Up @@ -10,7 +10,8 @@

import pytest

from marshmallow import Schema, fields, utils, validates, validates_schema, EXCLUDE
from marshmallow import Schema, fields, utils, validates, validates_schema, \
EXCLUDE, INCLUDE, RAISE
from marshmallow.exceptions import ValidationError, StringNotCollectionError

from tests.base import (
Expand Down Expand Up @@ -1132,13 +1133,13 @@ class ChildSchema(Schema):
str_dump_only = fields.String()
str_load_only = fields.String()
str_regular = fields.String()
grand_child = fields.Nested(GrandChildSchema)
grand_child = fields.Nested(GrandChildSchema, unknown=EXCLUDE)

class ParentSchema(Schema):
str_dump_only = fields.String()
str_load_only = fields.String()
str_regular = fields.String()
child = fields.Nested(ChildSchema)
child = fields.Nested(ChildSchema, unknown=EXCLUDE)

return ParentSchema(
dump_only=('str_dump_only', 'child.str_dump_only', 'child.grand_child.str_dump_only'),
Expand Down Expand Up @@ -1205,7 +1206,7 @@ class ParentSchema(Schema):
str_dump_only = fields.String()
str_load_only = fields.String()
str_regular = fields.String()
child = fields.List(fields.Nested(ChildSchema))
child = fields.List(fields.Nested(ChildSchema, unknown=EXCLUDE))

return ParentSchema(
dump_only=('str_dump_only', 'child.str_dump_only'),
Expand Down Expand Up @@ -1972,6 +1973,33 @@ class ParentSchema(Schema):
assert data == {'foo': {'bar': 42}, 'bar': 42}
assert errors == {'foo': {'foo': ['Not a valid integer.']}}

@pytest.mark.parametrize('data', ({'child': {'num': 1, 'extra': 1}},))
@pytest.mark.parametrize(
'child_unknown,errors,load_raises,load_out',
(
(None, {'child': {'extra': ['Unknown field.']}}, True, None),
(RAISE, {'child': {'extra': ['Unknown field.']}}, True, None),
(INCLUDE, {}, False, {'child': {'num': 1, 'extra': 1}}),
(EXCLUDE, {}, False, {'child': {'num': 1}}),
),
)
def test_nested_unknown_validation(self, child_unknown, errors, load_raises, load_out, data):

class ChildSchema(Schema):
num = fields.Int()

class ParentSchema(Schema):
child = fields.Nested(ChildSchema, unknown=child_unknown)

errs = ParentSchema().validate(data)
assert errs == errors
if load_raises:
with pytest.raises(ValidationError):
ParentSchema().load(data)
if load_out:
out = ParentSchema().load(data)
assert out == load_out


class TestPluckSchema:

Expand Down

0 comments on commit 8a3f327

Please sign in to comment.