diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 2bf713345..b7b783d30 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,34 @@ Changelog --------- +3.8.0 (Unreleased) +****************** + +Features: + +- The behavior of the ``unknown`` option can be further customized with a + second option, ``propagate_unknown``. When set to ``True``, any nested + schemas will receive the same ``unknown`` value as their parent if they did + not set an ``unknown`` value explicitly. + ``propagate_unknown`` itself propagates across any number of layers of + nesting and cannot be disabled by a child schema if it enabled in its parent. + (:issue:`1490`, :issue:`1428`) + Thanks :user:`lmignon` and :user:`mahenzon`. + +.. note:: + + In order to retain flexibility, when a schema is being loaded with + ``propagate_unknown=True``, you can still set ``unknown`` explicitly on child + schemas. However, be aware that such a value will be propagated to any of its + descendants. + + For example, a schema which specifies ``unknown=EXCLUDE`` will set + ``EXCLUDE`` in all of its children. If one of the children specifies + ``unknown=IGNORE``, then ``IGNORE`` will be passed to the relevant + grandchildren. + Other children of the original schema could specify ``unknown=RAISE``, and + this would apply to them equally well. + 3.7.1 (2020-07-20) ****************** diff --git a/src/marshmallow/fields.py b/src/marshmallow/fields.py index eb1b8a4af..d42fb9c15 100644 --- a/src/marshmallow/fields.py +++ b/src/marshmallow/fields.py @@ -459,6 +459,10 @@ class ParentSchema(Schema): :param many: Whether the field is a collection of objects. :param unknown: Whether to exclude, include, or raise an error for unknown fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`. + :param propagate_unknown: If ``True``, the value for ``unknown`` will be + applied to any ``Nested`` fields within the nested schema. Propagates down and allows + ``Nested`` fields to apply their own ``unknown`` value. Note that this + only has an effect when there are multiple layers of nesting :param kwargs: The same keyword arguments that :class:`Field` receives. """ diff --git a/src/marshmallow/schema.py b/src/marshmallow/schema.py index 690ded829..a0859b47a 100644 --- a/src/marshmallow/schema.py +++ b/src/marshmallow/schema.py @@ -287,6 +287,9 @@ class AlbumSchema(Schema): will be ignored. Use dot delimiters to specify nested fields. :param unknown: Whether to exclude, include, or raise an error for unknown fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`. + :param propagate_unknown: If ``True``, the value for ``unknown`` will be + applied to all ``Nested`` fields. Propagates down and allows + ``Nested`` fields to apply their own ``unknown`` value .. versionchanged:: 3.0.0 `prefix` parameter removed. @@ -364,6 +367,10 @@ class Meta: - ``dump_only``: Tuple or list of fields to exclude from deserialization - ``unknown``: Whether to exclude, include, or raise an error for unknown fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`. + - ``propagate_unknown`` If ``True``, the value for ``unknown`` will be + applied to all ``Nested`` fields. Propagates down, but if a ``Nested`` + field sets ``unknown``, it will begin to propagate that value, not the + where this is set. - ``register``: Whether to register the `Schema` with marshmallow's internal class registry. Must be `True` if you intend to refer to this `Schema` by class name in `Nested` fields. Only set this to `False` when memory @@ -619,6 +626,9 @@ def _deserialize( will be ignored. Use dot delimiters to specify nested fields. :param unknown: Whether to exclude, include, or raise an error for unknown fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`. + :param propagate_unknown: If ``True``, the value for ``unknown`` will be + applied to all ``Nested`` fields. Propagates down and allows + ``Nested`` fields to apply their own ``unknown`` value :param int index: Index of the item being serialized (for storing errors) if serializing a collection, otherwise `None`. :return: A dictionary of the deserialized data. @@ -733,6 +743,9 @@ def load( :param unknown: Whether to exclude, include, or raise an error for unknown fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`. If `None`, the value for `self.unknown` is used. + :param propagate_unknown: If ``True``, the value for ``unknown`` will be + applied to all ``Nested`` fields. Propagates down and allows + ``Nested`` fields to apply their own ``unknown`` value :return: Deserialized data .. versionadded:: 1.0.0 @@ -772,6 +785,9 @@ def loads( :param unknown: Whether to exclude, include, or raise an error for unknown fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`. If `None`, the value for `self.unknown` is used. + :param propagate_unknown: If ``True``, the value for ``unknown`` will be + applied to all ``Nested`` fields. Propagates down and allows + ``Nested`` fields to apply their own ``unknown`` value :return: Deserialized data .. versionadded:: 1.0.0 @@ -864,6 +880,9 @@ def _do_load( :param unknown: Whether to exclude, include, or raise an error for unknown fields in the data. Use `EXCLUDE`, `INCLUDE` or `RAISE`. If `None`, the value for `self.unknown` is used. + :param propagate_unknown: If ``True``, the value for ``unknown`` will be + applied to all ``Nested`` fields. Propagates down and allows + ``Nested`` fields to apply their own ``unknown`` value :param postprocess: Whether to run post_load methods.. :return: Deserialized data """