From fc6f52a9ef0084222e3f040c1d75038548a1604c Mon Sep 17 00:00:00 2001 From: Stephen Rosen Date: Fri, 17 Jul 2020 02:55:43 +0000 Subject: [PATCH] Add changelog and docs for propagate_unknown The changelog entry, including credit to prior related work, covers the closed issues and describes how `propagate_unknown` is expected to behave. Inline documentation attempts to strike a balance between clarify and brevity. closes #1428, #1429, #1490, #1575 --- CHANGELOG.rst | 28 ++++++++++++++++++++++++++++ src/marshmallow/fields.py | 4 ++++ src/marshmallow/schema.py | 19 +++++++++++++++++++ 3 files changed, 51 insertions(+) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5c384e6d7..1fc2095a0 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.0 (2020-07-08) ****************** diff --git a/src/marshmallow/fields.py b/src/marshmallow/fields.py index 4926fecf0..775a918e6 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 """