Hello community,
here is the log from the commit of package python-marshmallow for
openSUSE:Leap:15.2 checked in at 2020-04-05 17:07:42
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Leap:15.2/python-marshmallow (Old)
and /work/SRC/openSUSE:Leap:15.2/.python-marshmallow.new.3248 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-marshmallow"
Sun Apr 5 17:07:42 2020 rev:12 rq:791336 version:3.5.1
Changes:
--------
--- /work/SRC/openSUSE:Leap:15.2/python-marshmallow/python-marshmallow.changes
2020-03-09 18:08:40.176964726 +0100
+++
/work/SRC/openSUSE:Leap:15.2/.python-marshmallow.new.3248/python-marshmallow.changes
2020-04-05 17:07:47.990260006 +0200
@@ -1,0 +2,21 @@
+Wed Apr 1 09:10:03 UTC 2020 - [email protected]
+
+- version update to 3.5.1
+ - Includes bug fix from 2.21.0.
+ - Fix list of nullable nested fields ``List(Nested(Field, allow_none=True)``
+ (:issue:`1497`). Because this fix reverts an optimization introduced to
+ speed-up serialization and deserialization of lists of nested fields, a
+ negative impact on performance in this specific case is expected.
+ - Improve type coverage (:issue:`1479`). Thanks :user:`Reskov`.
+ - Fix typing for ``data`` param of ``Schema.load`` and ``ValidationError``
(:issue:`1492`).
+ Thanks :user:`mehdigmira` for reporting and thanks :user:`dfirst` for the
PR.
+ - Remove unnecessary typecasts (:pr:`1500`). Thanks :user:`hukkinj1`.
+ - Remove useless ``_serialize`` override in ``UUID`` field (:pr:`1489`).
+ - ``fields.Nested`` may take a callable that returns a schema instance.
+ Use this to resolve order-of-declaration issues when schemas nest each
other (:issue:`1146`).
+ - Passing the string ``"self"`` to ``fields.Nested`` is deprecated.
+ Use a callable instead.
+ - Fix typing for ``Number._format_num`` (:pr:`1466`). Thanks
:user:`hukkinj1`.
+ - Make mypy stricter and remove dead code (:pr:`1467`). Thanks again,
:user:`hukkinj1`.
+
+-------------------------------------------------------------------
Old:
----
marshmallow-3.2.2.tar.gz
New:
----
marshmallow-3.5.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-marshmallow.spec ++++++
--- /var/tmp/diff_new_pack.w8psnT/_old 2020-04-05 17:07:48.450260496 +0200
+++ /var/tmp/diff_new_pack.w8psnT/_new 2020-04-05 17:07:48.450260496 +0200
@@ -1,7 +1,7 @@
#
# spec file for package python-marshmallow
#
-# Copyright (c) 2019 SUSE LLC.
+# Copyright (c) 2020 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -19,7 +19,7 @@
%{?!python_module:%define python_module() python-%{**} python3-%{**}}
%define skip_python2 1
Name: python-marshmallow
-Version: 3.2.2
+Version: 3.5.1
Release: 0
Summary: ORM/ODM/framework-agnostic library to convert datatypes
from/to Python types
License: MIT AND BSD-3-Clause
++++++ marshmallow-3.2.2.tar.gz -> marshmallow-3.5.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/AUTHORS.rst
new/marshmallow-3.5.1/AUTHORS.rst
--- old/marshmallow-3.2.2/AUTHORS.rst 2019-11-04 22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/AUTHORS.rst 2020-03-05 14:05:11.000000000 +0100
@@ -140,3 +140,9 @@
- `@phrfpeixoto <https://github.com/phrfpeixoto>`_
- `@jceresini <https://github.com/jceresini>`_
- Nikolay Shebanov `@killthekitten <https://github.com/killthekitten>`_
+- Taneli Hukkinen `@hukkinj1 <https://github.com/hukkinj1>`_
+- `@Reskov <https://github.com/Reskov>`_
+- Albert Tugushev `@atugushev <https://github.com/atugushev>`_
+- `@dfirst <https://github.com/dfirst>`_
+- Tim Gates `@timgates42 <https://github.com/timgates42>`_
+- Nathan `@nbanmp <https://github.com/nbanmp>`_
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/CHANGELOG.rst
new/marshmallow-3.5.1/CHANGELOG.rst
--- old/marshmallow-3.2.2/CHANGELOG.rst 2019-11-04 22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/CHANGELOG.rst 2020-03-05 14:05:11.000000000 +0100
@@ -1,17 +1,107 @@
Changelog
---------
+3.5.1 (2020-03-05)
+******************
+
+Bug fixes:
+
+- Includes bug fix from 2.21.0.
+
+3.5.0 (2020-02-19)
+******************
+
+Bug fixes:
+
+- Fix list of nullable nested fields ``List(Nested(Field, allow_none=True)``
+ (:issue:`1497`). Because this fix reverts an optimization introduced to
+ speed-up serialization and deserialization of lists of nested fields, a
+ negative impact on performance in this specific case is expected.
+
+3.4.0 (2020-02-02)
+******************
+
+Features:
+
+- Improve type coverage (:issue:`1479`). Thanks :user:`Reskov`.
+
+Bug fixes:
+
+- Fix typing for ``data`` param of ``Schema.load`` and ``ValidationError``
(:issue:`1492`).
+ Thanks :user:`mehdigmira` for reporting and thanks :user:`dfirst` for the PR.
+
+Other changes:
+
+- Remove unnecessary typecasts (:pr:`1500`). Thanks :user:`hukkinj1`.
+- Remove useless ``_serialize`` override in ``UUID`` field (:pr:`1489`).
+
+3.3.0 (2019-12-05)
+******************
+
+Features:
+
+- ``fields.Nested`` may take a callable that returns a schema instance.
+ Use this to resolve order-of-declaration issues when schemas nest each other
(:issue:`1146`).
+
+.. code-block:: python
+
+ # <3.3
+ class AlbumSchema(Schema):
+ title = fields.Str()
+ artist = fields.Nested("ArtistSchema", only=("name",))
+
+
+ class ArtistSchema(Schema):
+ name = fields.Str()
+ albums = fields.List(fields.Nested(AlbumSchema))
+
+
+ # >=3.3
+ class AlbumSchema(Schema):
+ title = fields.Str()
+ artist = fields.Nested(lambda: ArtistSchema(only=("name",)))
+
+
+ class ArtistSchema(Schema):
+ name = fields.Str()
+ albums = fields.List(fields.Nested(AlbumSchema))
+
+Deprecations:
+
+- Passing the string ``"self"`` to ``fields.Nested`` is deprecated.
+ Use a callable instead.
+
+.. code-block:: python
+
+ from marshmallow import Schema, fields
+
+ # <3.3
+ class PersonSchema(Schema):
+ partner = fields.Nested("self", exclude=("partner",))
+ friends = fields.List(fields.Nested("self"))
+
+
+ # >=3.3
+ class PersonSchema(Schema):
+ partner = fields.Nested(lambda: PersonSchema(exclude=("partner")))
+ friends = fields.List(fields.Nested(lambda: PersonSchema()))
+
+Other changes:
+
+- Fix typing for ``Number._format_num`` (:pr:`1466`). Thanks :user:`hukkinj1`.
+- Make mypy stricter and remove dead code (:pr:`1467`). Thanks again,
:user:`hukkinj1`.
+
3.2.2 (2019-11-04)
******************
Bug fixes:
-- Don't load fields for which ``load_only`` and ``dump_only`` are both
``True`` (:pr:`1448`).
+- Don't load fields for which ``load_only`` and ``dump_only`` are both
``True`` (:pr:`1448`).
- Fix types in ``marshmallow.validate`` (:pr:`1446`).
Support:
-- Test against Python 3.8 (pr:`1431`).
+- Test against Python 3.8 (:pr:`1431`).
3.2.1 (2019-09-30)
++++++++++++++++++
@@ -125,7 +215,7 @@
- *Backwards-incompatible*: Validation does not occur on serialization
(:issue:`1132`).
This significantly improves serialization performance.
- *Backwards-incompatible*: ``DateTime`` does not affect timezone information
- on serialization and deserialization (:issue:`1234`, :pr:`1287`).
+ on serialization and deserialization (:issue:`1234`, :pr:`1278`).
- Add ``NaiveDateTime`` and ``AwareDateTime`` to enforce timezone awareness
(:issue:`1234`, :pr:`1287`).
- *Backwards-incompatible*: ``List`` does not wrap single values in a list on
@@ -691,6 +781,18 @@
- Remove ``func`` parameter of ``fields.Function``. Remove ``method_name``
parameter of ``fields.Method`` (issue:`325`). Use the ``serialize`` parameter
instead.
- Remove ``extra`` parameter from ``Schema``. Use a ``@post_dump`` method to
add additional data.
+2.21.0 (2020-03-05)
++++++++++++++++++++
+
+Bug fixes:
+
+- Don't match string-ending newlines in ``URL`` and ``Email`` fields
+ (:issue:`1522`). Thanks :user:`nbanmp` for the PR.
+
+Other changes:
+
+- Drop support for Python 3.4 (:pr:`1525`).
+
2.20.5 (2019-09-15)
+++++++++++++++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/LICENSE
new/marshmallow-3.5.1/LICENSE
--- old/marshmallow-3.2.2/LICENSE 2019-11-04 22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/LICENSE 2020-03-05 14:05:11.000000000 +0100
@@ -1,4 +1,4 @@
-Copyright 2019 Steven Loria and contributors
+Copyright 2020 Steven Loria and contributors
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/PKG-INFO
new/marshmallow-3.5.1/PKG-INFO
--- old/marshmallow-3.2.2/PKG-INFO 2019-11-04 22:15:05.000000000 +0100
+++ new/marshmallow-3.5.1/PKG-INFO 2020-03-05 14:05:19.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: marshmallow
-Version: 3.2.2
+Version: 3.5.1
Summary: A lightweight library for converting complex datatypes to and from
native Python datatypes.
Home-page: https://github.com/marshmallow-code/marshmallow
Author: Steven Loria
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/docs/nesting.rst
new/marshmallow-3.5.1/docs/nesting.rst
--- old/marshmallow-3.2.2/docs/nesting.rst 2019-11-04 22:14:53.000000000
+0100
+++ new/marshmallow-3.5.1/docs/nesting.rst 2020-03-05 14:05:11.000000000
+0100
@@ -22,7 +22,7 @@
self.title = title
self.author = author # A User object
-Use a :class:`Nested <marshmallow.fields.Nested>` field to represent the
relationship, passing in a nested schema class.
+Use a :class:`Nested <marshmallow.fields.Nested>` field to represent the
relationship, passing in a nested schema.
.. code-block:: python
@@ -53,24 +53,24 @@
# 'created_at': '2014-08-17T14:58:57.600623+00:00'}}
.. note::
- If the field is a collection of nested objects, you must set ``many=True``.
+ If the field is a collection of nested objects, pass the `Nested
<marshmallow.fields.Nested>` field to `List <marshmallow.fields.List>`.
.. code-block:: python
- collaborators = fields.Nested(UserSchema, many=True)
+ collaborators = fields.List(fields.Nested(UserSchema))
.. _specifying-nested-fields:
Specifying Which Fields to Nest
-------------------------------
-You can explicitly specify which attributes of the nested objects you want to
serialize with the ``only`` argument.
+You can explicitly specify which attributes of the nested objects you want to
(de)serialize with the ``only`` argument to the schema.
.. code-block:: python
class BlogSchema2(Schema):
title = fields.String()
- author = fields.Nested(UserSchema, only=["email"])
+ author = fields.Nested(UserSchema(only=("email",)))
schema = BlogSchema2()
@@ -81,7 +81,7 @@
# 'author': {'email': u'[email protected]'}
# }
-You can represent the attributes of deeply nested objects using dot delimiters.
+Dotted paths may be passed to ``only`` and ``exclude`` to specify nested
attributes.
.. code-block:: python
@@ -89,7 +89,7 @@
blog = fields.Nested(BlogSchema2)
- schema = SiteSchema(only=["blog.author.email"])
+ schema = SiteSchema(only=("blog.author.email",))
result = schema.dump(site)
pprint(result)
# {
@@ -125,8 +125,6 @@
# }
-You can also exclude fields by passing in an ``exclude`` list. This argument
also allows representing the attributes of deeply nested objects using dot
delimiters.
-
.. _partial-loading:
Partial Loading
@@ -168,27 +166,29 @@
Two-way Nesting
---------------
-If you have two objects that nest each other, you can refer to a nested schema
by its class name. This allows you to nest Schemas that have not yet been
defined.
-
+If you have two objects that nest each other, you can pass a callable to
`Nested <marshmallow.fields.Nested>`.
+This allows you to resolve order-of-declaration issues, such as when one
schema nests a schema that is declared below it.
-For example, a representation of an ``Author`` model might include the books
that have a foreign-key (many-to-one) relationship to it. Correspondingly, a
representation of a ``Book`` will include its author representation.
+For example, a representation of an ``Author`` model might include the books
that have a many-to-one relationship to it.
+Correspondingly, a representation of a ``Book`` will include its author
representation.
.. code-block:: python
- class AuthorSchema(Schema):
- # Make sure to use the 'only' or 'exclude' params
+ class BookSchema(Schema):
+ id = fields.Int(dump_only=True)
+ title = fields.Str()
+
+ # Make sure to use the 'only' or 'exclude'
# to avoid infinite recursion
- books = fields.Nested("BookSchema", many=True, exclude=("author",))
+ author = fields.Nested(lambda: AuthorSchema(only=("id", "title")))
- class Meta:
- fields = ("id", "name", "books")
+ class AuthorSchema(Schema):
+ id = fields.Int(dump_only=True)
+ title = fields.Str()
- class BookSchema(Schema):
- author = fields.Nested(AuthorSchema, only=("id", "name"))
+ books = fields.List(fields.Nested(BookSchema(exclude=("author",))))
- class Meta:
- fields = ("id", "title", "author")
.. code-block:: python
@@ -221,27 +221,54 @@
# ]
# }
+You can also pass a class name as a string to `Nested
<marshmallow.fields.Nested>`.
+This is useful for avoiding circular imports when your schemas are located in
different modules.
+
+.. code-block:: python
+
+ # books.py
+ from marshmallow import Schema, fields
+
+
+ class BookSchema(Schema):
+ id = fields.Int(dump_only=True)
+ title = fields.Str()
+
+ author = fields.Nested("AuthorSchema", only=("id", "title"))
+
+.. code-block:: python
+
+ # authors.py
+ from marshmallow import Schema, fields
+
+
+ class AuthorSchema(Schema):
+ id = fields.Int(dump_only=True)
+ title = fields.Str()
+
+ books = fields.List(fields.Nested("BookSchema", exclude=("author",)))
+
.. note::
- If you need to, you can also pass the full, module-qualified path to
`fields.Nested`. ::
- books = fields.Nested('path.to.BookSchema',
- many=True, exclude=('author', ))
+ If you have multiple schemas with the same class name, you must pass the
full, module-qualified path. ::
+
+ author = fields.Nested("authors.BookSchema", only=("id", "title"))
.. _self-nesting:
Nesting A Schema Within Itself
------------------------------
-If the object to be marshalled has a relationship to an object of the same
type, you can nest the `Schema` within itself by passing ``"self"`` (with
quotes) to the :class:`Nested <marshmallow.fields.Nested>` constructor.
+If the object to be marshalled has a relationship to an object of the same
type, you can nest the `Schema` within itself by passing a callable that
returns an instance of the same schema.
.. code-block:: python
class UserSchema(Schema):
name = fields.String()
email = fields.Email()
- friends = fields.Nested("self", many=True)
# Use the 'exclude' argument to avoid infinite recursion
- employer = fields.Nested("self", exclude=("employer",), default=None)
+ employer = fields.Nested(lambda: UserSchema(exclude=("employer",)))
+ friends = fields.List(fields.Nested(lambda: UserSchema()))
user = User("Steve", "[email protected]")
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/docs/upgrading.rst
new/marshmallow-3.5.1/docs/upgrading.rst
--- old/marshmallow-3.2.2/docs/upgrading.rst 2019-11-04 22:14:53.000000000
+0100
+++ new/marshmallow-3.5.1/docs/upgrading.rst 2020-03-05 14:05:11.000000000
+0100
@@ -3,6 +3,55 @@
This section documents migration paths to new releases.
+Upgrading to 3.3
+++++++++++++++++
+
+In 3.3, `fields.Nested <marshmallow.fields.Nested>` may take a callable that
returns a schema instance.
+Use this to resolve order-of-declaration issues when schemas nest each other.
+
+.. code-block:: python
+
+ from marshmallow import Schema, fields
+
+ # <3.3
+ class AlbumSchema(Schema):
+ title = fields.Str()
+ artist = fields.Nested("ArtistSchema", only=("name",))
+
+
+ class ArtistSchema(Schema):
+ name = fields.Str()
+ albums = fields.List(fields.Nested(AlbumSchema))
+
+
+ # >=3.3
+ class AlbumSchema(Schema):
+ title = fields.Str()
+ artist = fields.Nested(lambda: ArtistSchema(only=("name",)))
+
+
+ class ArtistSchema(Schema):
+ name = fields.Str()
+ albums = fields.List(fields.Nested(AlbumSchema))
+
+A callable should also be used when nesting a schema within itself.
+Passing ``"self"`` is deprecated.
+
+.. code-block:: python
+
+ from marshmallow import Schema, fields
+
+ # <3.3
+ class PersonSchema(Schema):
+ partner = fields.Nested("self", exclude=("partner",))
+ friends = fields.List(fields.Nested("self"))
+
+
+ # >=3.3
+ class PersonSchema(Schema):
+ partner = fields.Nested(lambda: PersonSchema(exclude=("partner")))
+ friends = fields.List(fields.Nested(lambda: PersonSchema()))
+
.. _upgrading_3_0:
Upgrading to 3.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/docs/why.rst
new/marshmallow-3.5.1/docs/why.rst
--- old/marshmallow-3.2.2/docs/why.rst 2019-11-04 22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/docs/why.rst 2020-03-05 14:05:11.000000000 +0100
@@ -33,8 +33,8 @@
class GameStateSchema(Schema):
_id = fields.UUID(required=True)
- players = fields.Nested(PlayerSchema, many=True)
score = fields.Nested(ScoreSchema)
+ players = fields.List(fields.Nested(PlayerSchema))
last_changed = fields.DateTime(format="rfc")
class Meta:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/examples/peewee_example.py
new/marshmallow-3.5.1/examples/peewee_example.py
--- old/marshmallow-3.2.2/examples/peewee_example.py 2019-11-04
22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/examples/peewee_example.py 2020-03-05
14:05:11.000000000 +0100
@@ -77,7 +77,7 @@
class TodoSchema(Schema):
id = fields.Int(dump_only=True)
done = fields.Boolean(attribute="is_done", missing=False)
- user = fields.Nested(UserSchema, exclude=("joined_on", "password"),
dump_only=True)
+ user = fields.Nested(UserSchema(exclude=("joined_on", "password")),
dump_only=True)
content = fields.Str(required=True)
posted_on = fields.DateTime(dump_only=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/pyproject.toml
new/marshmallow-3.5.1/pyproject.toml
--- old/marshmallow-3.2.2/pyproject.toml 1970-01-01 01:00:00.000000000
+0100
+++ new/marshmallow-3.5.1/pyproject.toml 2020-03-05 14:05:11.000000000
+0100
@@ -0,0 +1,3 @@
+[tool.black]
+line-length = 88
+target-version = ['py35', 'py36', 'py37', 'py38']
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/setup.cfg
new/marshmallow-3.5.1/setup.cfg
--- old/marshmallow-3.2.2/setup.cfg 2019-11-04 22:15:05.000000000 +0100
+++ new/marshmallow-3.5.1/setup.cfg 2020-03-05 14:05:19.000000000 +0100
@@ -5,7 +5,7 @@
universal = 1
[flake8]
-ignore = E203, E266, E501, W503, E731, B903
+extend-ignore = E203, E266, E501, E731, B903
max-line-length = 90
max-complexity = 18
select = B,C,E,F,W,T4,B9
@@ -16,6 +16,9 @@
[mypy]
ignore_missing_imports = true
+warn_unreachable = true
+warn_unused_ignores = true
+warn_redundant_casts = true
[egg_info]
tag_build =
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/setup.py
new/marshmallow-3.5.1/setup.py
--- old/marshmallow-3.2.2/setup.py 2019-11-04 22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/setup.py 2020-03-05 14:05:11.000000000 +0100
@@ -4,13 +4,13 @@
EXTRAS_REQUIRE = {
"tests": ["pytest", "pytz", "simplejson"],
"lint": [
- "mypy==0.740",
+ "mypy==0.761",
"flake8==3.7.9",
- "flake8-bugbear==19.8.0",
- "pre-commit~=1.20",
+ "flake8-bugbear==20.1.4",
+ "pre-commit>=1.20,<3.0",
],
"docs": [
- "sphinx==2.2.1",
+ "sphinx==2.4.3",
"sphinx-issues==1.2.0",
"alabaster==0.7.12",
"sphinx-version-warning==1.1.2",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/src/marshmallow/__init__.py
new/marshmallow-3.5.1/src/marshmallow/__init__.py
--- old/marshmallow-3.2.2/src/marshmallow/__init__.py 2019-11-04
22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/src/marshmallow/__init__.py 2020-03-05
14:05:11.000000000 +0100
@@ -13,7 +13,7 @@
from marshmallow.exceptions import ValidationError
from distutils.version import LooseVersion
-__version__ = "3.2.2"
+__version__ = "3.5.1"
__version_info__ = tuple(LooseVersion(__version__).version)
__all__ = [
"EXCLUDE",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/src/marshmallow/exceptions.py
new/marshmallow-3.5.1/src/marshmallow/exceptions.py
--- old/marshmallow-3.2.2/src/marshmallow/exceptions.py 2019-11-04
22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/src/marshmallow/exceptions.py 2020-03-05
14:05:11.000000000 +0100
@@ -27,7 +27,10 @@
self,
message: typing.Union[str, typing.List, typing.Dict],
field_name: str = SCHEMA,
- data: typing.Mapping[str, typing.Any] = None,
+ data: typing.Union[
+ typing.Mapping[str, typing.Any],
+ typing.Iterable[typing.Mapping[str, typing.Any]],
+ ] = None,
valid_data: typing.Union[
typing.List[typing.Dict[str, typing.Any]], typing.Dict[str,
typing.Any]
] = None,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/src/marshmallow/fields.py
new/marshmallow-3.5.1/src/marshmallow/fields.py
--- old/marshmallow-3.2.2/src/marshmallow/fields.py 2019-11-04
22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/src/marshmallow/fields.py 2020-03-05
14:05:11.000000000 +0100
@@ -146,8 +146,7 @@
attribute: str = None,
validate: typing.Union[
typing.Callable[[typing.Any], typing.Any],
- typing.Sequence[typing.Callable[[typing.Any], typing.Any]],
- typing.Generator[typing.Callable[[typing.Any], typing.Any], None,
None],
+ typing.Iterable[typing.Callable[[typing.Any], typing.Any]],
] = None,
required: bool = False,
allow_none: bool = None,
@@ -160,20 +159,12 @@
self.attribute = attribute
self.data_key = data_key
self.validate = validate
- if utils.is_iterable_but_not_string(validate):
- if not utils.is_generator(validate):
- self.validators = typing.cast(
- typing.Sequence[typing.Callable[[typing.Any],
typing.Any]], validate
- )
- else:
- validators = typing.cast(
- typing.Sequence[typing.Callable[[typing.Any],
typing.Any]], validate
- )
- self.validators = list(validators)
+ if validate is None:
+ self.validators = []
elif callable(validate):
self.validators = [validate]
- elif validate is None:
- self.validators = []
+ elif utils.is_iterable_but_not_string(validate):
+ self.validators = list(validate)
else:
raise ValueError(
"The 'validate' parameter must be a callable "
@@ -437,10 +428,19 @@
Examples: ::
- user = fields.Nested(UserSchema)
- user2 = fields.Nested('UserSchema') # Equivalent to above
- collaborators = fields.Nested(UserSchema, many=True, only=('id',))
- parent = fields.Nested('self')
+ class ChildSchema(Schema):
+ id = fields.Str()
+ name = fields.Str()
+ # Use lambda functions when you need two-way nesting or
self-nesting
+ parent = fields.Nested(lambda: ParentSchema(only=("id",)),
dump_only=True)
+ siblings = fields.List(fields.Nested(lambda:
ChildSchema(only=("id", "name"))))
+
+ class ParentSchema(Schema):
+ id = fields.Str()
+ children = fields.List(
+ fields.Nested(ChildSchema(only=("id", "parent", "siblings")))
+ )
+ spouse = fields.Nested(lambda: ParentSchema(only=("id",)))
When passing a `Schema <marshmallow.Schema>` instance as the first
argument,
the instance's ``exclude``, ``only``, and ``many`` attributes will be
respected.
@@ -471,7 +471,7 @@
def __init__(
self,
- nested: typing.Union[SchemaABC, type, str],
+ nested: typing.Union[SchemaABC, type, str, typing.Callable[[],
SchemaABC]],
*,
default: typing.Any = missing_,
only: types.StrSequenceOrSet = None,
@@ -483,10 +483,16 @@
# Raise error if only or exclude is passed as string, not list of
strings
if only is not None and not is_collection(only):
raise StringNotCollectionError('"only" should be a collection of
strings.')
- if exclude is not None and not is_collection(exclude):
+ if not is_collection(exclude):
raise StringNotCollectionError(
'"exclude" should be a collection of strings.'
)
+ if nested == "self":
+ warnings.warn(
+ "Passing 'self' to `Nested` is deprecated. "
+ "Use `Nested(lambda: MySchema(...))` instead.",
+ DeprecationWarning,
+ )
self.nested = nested
self.only = only
self.exclude = exclude
@@ -505,8 +511,13 @@
if not self._schema:
# Inherit context from parent.
context = getattr(self.parent, "context", {})
- if isinstance(self.nested, SchemaABC):
- self._schema = copy.copy(self.nested)
+ if callable(self.nested) and not isinstance(self.nested, type):
+ nested = self.nested()
+ else:
+ nested = self.nested
+
+ if isinstance(nested, SchemaABC):
+ self._schema = copy.copy(nested)
self._schema.context.update(context)
# Respect only and exclude passed from parent and
re-initialize fields
set_class = self._schema.set_class
@@ -521,20 +532,17 @@
self._schema.exclude =
set_class(self.exclude).union(original)
self._schema._init_fields()
else:
- if isinstance(self.nested, type) and issubclass(self.nested,
SchemaABC):
- schema_class = self.nested
- elif not isinstance(self.nested, (str, bytes)):
+ if isinstance(nested, type) and issubclass(nested, SchemaABC):
+ schema_class = nested
+ elif not isinstance(nested, (str, bytes)):
raise ValueError(
- "Nested fields must be passed a "
- "Schema, not {}.".format(self.nested.__class__)
+ "`Nested` fields must be passed a "
+ "`Schema`, not {}.".format(nested.__class__)
)
- elif self.nested == "self":
- ret = self
- while not isinstance(ret, SchemaABC):
- ret = ret.parent
- schema_class = ret.__class__
+ elif nested == "self":
+ schema_class = self.root.__class__
else:
- schema_class = class_registry.get_class(self.nested)
+ schema_class = class_registry.get_class(nested)
self._schema = schema_class(
many=self.many,
only=self.only,
@@ -553,33 +561,30 @@
if field.startswith(nested_field)
]
- def _serialize(self, nested_obj, attr, obj, many=False, **kwargs):
+ def _serialize(self, nested_obj, attr, obj, **kwargs):
# Load up the schema first. This allows a RegistryError to be raised
# if an invalid schema name was passed
schema = self.schema
if nested_obj is None:
return None
- many = schema.many or self.many or many
- return schema.dump(nested_obj, many=self.many or many)
+ many = schema.many or self.many
+ return schema.dump(nested_obj, many=many)
- def _test_collection(self, value, many=False):
- many = self.schema.many or self.many or many
+ def _test_collection(self, value):
+ many = self.schema.many or self.many
if many and not utils.is_collection(value):
raise self.make_error("type", input=value,
type=value.__class__.__name__)
- def _load(self, value, data, partial=None, many=False):
- many = self.schema.many or self.many or many
+ def _load(self, value, data, partial=None):
try:
- valid_data = self.schema.load(
- value, unknown=self.unknown, partial=partial, many=many
- )
+ valid_data = self.schema.load(value, unknown=self.unknown,
partial=partial)
except ValidationError as error:
raise ValidationError(
error.messages, valid_data=error.valid_data
) from error
return valid_data
- def _deserialize(self, value, attr, data, partial=None, many=False,
**kwargs):
+ def _deserialize(self, value, attr, data, partial=None, **kwargs):
"""Same as :meth:`Field._deserialize` with additional ``partial``
argument.
:param bool|tuple partial: For nested schemas, the ``partial``
@@ -588,8 +593,8 @@
.. versionchanged:: 3.0.0
Add ``partial`` parameter.
"""
- self._test_collection(value, many=many)
- return self._load(value, data, partial=partial, many=many)
+ self._test_collection(value)
+ return self._load(value, data, partial=partial)
class Pluck(Nested):
@@ -617,7 +622,12 @@
:param kwargs: The same keyword arguments that :class:`Nested` receives.
"""
- def __init__(self, nested, field_name, **kwargs):
+ def __init__(
+ self,
+ nested: typing.Union[SchemaABC, type, str, typing.Callable[[],
SchemaABC]],
+ field_name: str,
+ **kwargs
+ ):
super().__init__(nested, only=(field_name,), **kwargs)
self.field_name = field_name
@@ -690,17 +700,11 @@
) -> typing.Optional[typing.List[typing.Any]]:
if value is None:
return None
- # Optimize dumping a list of Nested objects by calling dump(many=True)
- if isinstance(self.inner, Nested) and not self.inner.many:
- return self.inner._serialize(value, attr, obj, many=True, **kwargs)
return [self.inner._serialize(each, attr, obj, **kwargs) for each in
value]
def _deserialize(self, value, attr, data, **kwargs) ->
typing.List[typing.Any]:
if not utils.is_collection(value):
raise self.make_error("invalid")
- # Optimize loading a list of Nested objects by calling load(many=True)
- if isinstance(self.inner, Nested) and not self.inner.many:
- return self.inner.deserialize(value, many=True, **kwargs)
result = []
errors = {}
@@ -843,10 +847,6 @@
except (ValueError, AttributeError, TypeError) as error:
raise self.make_error("invalid_uuid") from error
- def _serialize(self, value, attr, obj, **kwargs) -> typing.Optional[str]:
- val = str(value) if value is not None else None
- return super()._serialize(val, attr, obj, **kwargs)
-
def _deserialize(self, value, attr, data, **kwargs) ->
typing.Optional[uuid.UUID]:
return self._validated(value)
@@ -865,11 +865,11 @@
"too_large": "Number too large.",
}
- def __init__(self, *, as_string=False, **kwargs):
+ def __init__(self, *, as_string: bool = False, **kwargs):
self.as_string = as_string
super().__init__(**kwargs)
- def _format_num(self, value) -> _T:
+ def _format_num(self, value) -> typing.Any:
"""Return the number value for value, given this field's `num_type`."""
return self.num_type(value)
@@ -943,7 +943,7 @@
"special": "Special numeric values (nan or infinity) are not
permitted."
}
- def __init__(self, *, allow_nan=False, as_string=False, **kwargs):
+ def __init__(self, *, allow_nan: bool = False, as_string: bool = False,
**kwargs):
self.allow_nan = allow_nan
super().__init__(as_string=as_string, **kwargs)
@@ -1580,18 +1580,13 @@
self.relative = relative
self.require_tld = require_tld
# Insert validation into self.validators so that multiple errors can
be stored.
- original_validators = list(self.validators)
- # FIXME: Why doesn't mypy think validate.URL is a callable here?
- validator = typing.cast(
- typing.Callable[[typing.Any], typing.Any],
- validate.URL(
- relative=self.relative,
- schemes=schemes,
- require_tld=self.require_tld,
- error=self.error_messages["invalid"],
- ),
+ validator = validate.URL(
+ relative=self.relative,
+ schemes=schemes,
+ require_tld=self.require_tld,
+ error=self.error_messages["invalid"],
)
- self.validators = [validator] + original_validators
+ self.validators.insert(0, validator)
class Email(String):
@@ -1607,9 +1602,8 @@
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Insert validation into self.validators so that multiple errors can
be stored.
- original_validators = list(self.validators)
validator = validate.Email(error=self.error_messages["invalid"])
- self.validators = [validator] + original_validators
+ self.validators.insert(0, validator)
class Method(Field):
@@ -1635,7 +1629,7 @@
_CHECK_ATTRIBUTE = False
- def __init__(self, serialize=None, deserialize=None, **kwargs):
+ def __init__(self, serialize: str = None, deserialize: str = None,
**kwargs):
# Set dump_only and load_only based on arguments
kwargs["dump_only"] = bool(serialize) and not bool(deserialize)
kwargs["load_only"] = bool(deserialize) and not bool(serialize)
@@ -1735,7 +1729,7 @@
_CHECK_ATTRIBUTE = False
- def __init__(self, constant, **kwargs):
+ def __init__(self, constant: typing.Any, **kwargs):
super().__init__(**kwargs)
self.constant = constant
self.missing = constant
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/src/marshmallow/schema.py
new/marshmallow-3.5.1/src/marshmallow/schema.py
--- old/marshmallow-3.2.2/src/marshmallow/schema.py 2019-11-04
22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/src/marshmallow/schema.py 2020-03-05
14:05:11.000000000 +0100
@@ -133,7 +133,7 @@
inherited_fields: typing.List,
dict_cls: type,
):
- """Returns a dictionary of field_name => `Field` pairs declard on the
class.
+ """Returns a dictionary of field_name => `Field` pairs declared on the
class.
This is exposed mainly so that plugins can add additional fields, e.g.
fields
computed from class Meta options.
@@ -242,15 +242,18 @@
from marshmallow import Schema, fields
+
@dataclass
class Album:
title: str
release_date: dt.date
+
class AlbumSchema(Schema):
title = fields.Str()
release_date = fields.Date()
+
album = Album("Beggars Banquet", dt.date(1968, 12, 6))
schema = AlbumSchema()
data = schema.dump(album)
@@ -373,7 +376,7 @@
# Raise error if only or exclude is passed as string, not list of
strings
if only is not None and not is_collection(only):
raise StringNotCollectionError('"only" should be a list of
strings')
- if exclude is not None and not is_collection(exclude):
+ if not is_collection(exclude):
raise StringNotCollectionError('"exclude" should be a list of
strings')
# copy declared fields from metaclass
self.declared_fields = copy.deepcopy(self._declared_fields)
@@ -579,7 +582,10 @@
def _deserialize(
self,
- data: typing.Union[typing.Dict, typing.Iterable],
+ data: typing.Union[
+ typing.Mapping[str, typing.Any],
+ typing.Iterable[typing.Mapping[str, typing.Any]],
+ ],
*,
error_store: ErrorStore,
many: bool = False,
@@ -613,7 +619,7 @@
typing.cast(
_T,
self._deserialize(
- d,
+ typing.cast(typing.Mapping[str, typing.Any], d),
error_store=error_store,
many=False,
partial=partial,
@@ -684,7 +690,10 @@
def load(
self,
- data: typing.Mapping,
+ data: typing.Union[
+ typing.Mapping[str, typing.Any],
+ typing.Iterable[typing.Mapping[str, typing.Any]],
+ ],
*,
many: bool = None,
partial: typing.Union[bool, types.StrSequenceOrSet] = None,
@@ -797,7 +806,10 @@
def _do_load(
self,
- data: typing.Mapping,
+ data: typing.Union[
+ typing.Mapping[str, typing.Any],
+ typing.Iterable[typing.Mapping[str, typing.Any]],
+ ],
*,
many: bool = None,
partial: typing.Union[bool, types.StrSequenceOrSet] = None,
@@ -1025,9 +1037,13 @@
try:
field_obj._bind_to_schema(field_name, self)
except TypeError as error:
- # field declared as a class, not an instance
- if isinstance(field_obj, type) and issubclass(field_obj,
base.FieldABC):
- msg = (
+ # Field declared as a class, not an instance. Ignore type checking
because
+ # we handle unsupported arg types, i.e. this is dead code from
+ # the type checker's perspective.
+ if isinstance(field_obj, type) and issubclass( # type: ignore
+ field_obj, base.FieldABC
+ ):
+ msg = ( # type: ignore
'Field for "{}" must be declared as a '
"Field instance, not a class. "
'Did you mean "fields.{}()"?'.format(field_name,
field_obj.__name__)
@@ -1193,12 +1209,7 @@
processor_kwargs = processor.__marshmallow_hook__[key]
pass_original = processor_kwargs.get("pass_original", False)
- if pass_many:
- if pass_original:
- data = processor(data, original_data, many=many, **kwargs)
- else:
- data = processor(data, many=many, **kwargs)
- elif many:
+ if many and not pass_many:
if pass_original:
data = [
processor(item, original, many=many, **kwargs)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/src/marshmallow/validate.py
new/marshmallow-3.5.1/src/marshmallow/validate.py
--- old/marshmallow-3.2.2/src/marshmallow/validate.py 2019-11-04
22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/src/marshmallow/validate.py 2020-03-05
14:05:11.000000000 +0100
@@ -70,7 +70,7 @@
r")?"
if relative
else r"", # host is optional, allow for relative URLs
- r"(?:/?|[/?]\S+)$",
+ r"(?:/?|[/?]\S+)\Z",
)
),
re.IGNORECASE,
@@ -134,19 +134,19 @@
"""
USER_REGEX = re.compile(
- r"(^[-!#$%&'*+/=?^`{}|~\w]+(\.[-!#$%&'*+/=?^`{}|~\w]+)*$" # dot-atom
+ r"(^[-!#$%&'*+/=?^`{}|~\w]+(\.[-!#$%&'*+/=?^`{}|~\w]+)*\Z" # dot-atom
# quoted-string
r'|^"([\001-\010\013\014\016-\037!#-\[\]-\177]'
- r'|\\[\001-\011\013\014\016-\177])*"$)',
+ r'|\\[\001-\011\013\014\016-\177])*"\Z)',
re.IGNORECASE | re.UNICODE,
)
DOMAIN_REGEX = re.compile(
# domain
- r"(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+"
r"(?:[A-Z]{2,6}|[A-Z0-9-]{2,})$"
+ r"(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+"
r"(?:[A-Z]{2,6}|[A-Z0-9-]{2,})\Z"
# literal form, ipv4 address (SMTP 4.1.3)
r"|^\[(25[0-5]|2[0-4]\d|[0-1]?\d?\d)"
- r"(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]$",
+ r"(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\]\Z",
re.IGNORECASE | re.UNICODE,
)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/src/marshmallow.egg-info/PKG-INFO
new/marshmallow-3.5.1/src/marshmallow.egg-info/PKG-INFO
--- old/marshmallow-3.2.2/src/marshmallow.egg-info/PKG-INFO 2019-11-04
22:15:05.000000000 +0100
+++ new/marshmallow-3.5.1/src/marshmallow.egg-info/PKG-INFO 2020-03-05
14:05:19.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: marshmallow
-Version: 3.2.2
+Version: 3.5.1
Summary: A lightweight library for converting complex datatypes to and from
native Python datatypes.
Home-page: https://github.com/marshmallow-code/marshmallow
Author: Steven Loria
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/marshmallow-3.2.2/src/marshmallow.egg-info/SOURCES.txt
new/marshmallow-3.5.1/src/marshmallow.egg-info/SOURCES.txt
--- old/marshmallow-3.2.2/src/marshmallow.egg-info/SOURCES.txt 2019-11-04
22:15:05.000000000 +0100
+++ new/marshmallow-3.5.1/src/marshmallow.egg-info/SOURCES.txt 2020-03-05
14:05:19.000000000 +0100
@@ -5,6 +5,7 @@
MANIFEST.in
NOTICE
README.rst
+pyproject.toml
setup.cfg
setup.py
docs/.gitignore
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/marshmallow-3.2.2/src/marshmallow.egg-info/requires.txt
new/marshmallow-3.5.1/src/marshmallow.egg-info/requires.txt
--- old/marshmallow-3.2.2/src/marshmallow.egg-info/requires.txt 2019-11-04
22:15:05.000000000 +0100
+++ new/marshmallow-3.5.1/src/marshmallow.egg-info/requires.txt 2020-03-05
14:05:19.000000000 +0100
@@ -3,23 +3,23 @@
pytest
pytz
simplejson
-mypy==0.740
+mypy==0.761
flake8==3.7.9
-flake8-bugbear==19.8.0
-pre-commit~=1.20
+flake8-bugbear==20.1.4
+pre-commit<3.0,>=1.20
tox
[docs]
-sphinx==2.2.1
+sphinx==2.4.3
sphinx-issues==1.2.0
alabaster==0.7.12
sphinx-version-warning==1.1.2
[lint]
-mypy==0.740
+mypy==0.761
flake8==3.7.9
-flake8-bugbear==19.8.0
-pre-commit~=1.20
+flake8-bugbear==20.1.4
+pre-commit<3.0,>=1.20
[tests]
pytest
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/tests/base.py
new/marshmallow-3.5.1/tests/base.py
--- old/marshmallow-3.2.2/tests/base.py 2019-11-04 22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/tests/base.py 2020-03-05 14:05:11.000000000 +0100
@@ -275,21 +275,21 @@
class BlogSchema(Schema):
title = fields.String()
user = fields.Nested(UserSchema)
- collaborators = fields.Nested(UserSchema, many=True)
+ collaborators = fields.List(fields.Nested(UserSchema()))
categories = fields.List(fields.String)
id = fields.String()
class BlogUserMetaSchema(Schema):
user = fields.Nested(UserMetaSchema())
- collaborators = fields.Nested(UserMetaSchema, many=True)
+ collaborators = fields.List(fields.Nested(UserMetaSchema()))
class BlogSchemaMeta(Schema):
"""Same as BlogSerializer but using ``fields`` options."""
user = fields.Nested(UserSchema)
- collaborators = fields.Nested(UserSchema, many=True)
+ collaborators = fields.List(fields.Nested(UserSchema()))
class Meta:
fields = ("title", "user", "collaborators", "categories", "id")
@@ -298,7 +298,7 @@
class BlogOnlySchema(Schema):
title = fields.String()
user = fields.Nested(UserSchema)
- collaborators = fields.Nested(UserSchema, only=("id",), many=True)
+ collaborators = fields.List(fields.Nested(UserSchema(only=("id",))))
class BlogSchemaExclude(BlogSchema):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/tests/test_deserialization.py
new/marshmallow-3.5.1/tests/test_deserialization.py
--- old/marshmallow-3.2.2/tests/test_deserialization.py 2019-11-04
22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/tests/test_deserialization.py 2020-03-05
14:05:11.000000000 +0100
@@ -38,6 +38,15 @@
field = fields.Tuple([fields.String()], allow_none=True)
assert field.deserialize(None) is None
+ def test_list_of_nested_allow_none_deserialize_none_to_none(self):
+ field = fields.List(fields.Nested(Schema(), allow_none=True))
+ assert field.deserialize([None]) == [None]
+
+ def
test_list_of_nested_non_allow_none_deserialize_none_to_validation_error(self):
+ field = fields.List(fields.Nested(Schema(), allow_none=False))
+ with pytest.raises(ValidationError):
+ field.deserialize([None])
+
class TestFieldDeserialization:
def test_float_field_deserialization(self):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/tests/test_fields.py
new/marshmallow-3.5.1/tests/test_fields.py
--- old/marshmallow-3.2.2/tests/test_fields.py 2019-11-04 22:14:53.000000000
+0100
+++ new/marshmallow-3.5.1/tests/test_fields.py 2020-03-05 14:05:11.000000000
+0100
@@ -377,6 +377,34 @@
"children": [{"name": "Lily"}]
}
+ @pytest.mark.parametrize(
+ ("param", "expected_attribute", "expected_dump"),
+ (
+ ("only", {"name"}, {"children": [{"name": "Lily"}]}),
+ ("exclude", {"name", "surname", "age"}, {"children": [{}]}),
+ ),
+ )
+ def test_list_nested_lambda_only_and_exclude_merged_with_nested(
+ self, param, expected_attribute, expected_dump
+ ):
+ class Child(Schema):
+ name = fields.String()
+ surname = fields.String()
+ age = fields.Integer()
+
+ class Family(Schema):
+ children = fields.List(
+ fields.Nested(lambda: Child(**{param: ("name", "surname")}))
+ )
+
+ schema = Family(**{param: ["children.name", "children.age"]})
+ assert (
+ getattr(schema.fields["children"].inner.schema, param) ==
expected_attribute
+ )
+
+ family = {"children": [{"name": "Lily", "surname": "Martinez", "age":
15}]}
+ assert schema.dump(family) == expected_dump
+
def test_list_nested_partial_propagated_to_nested(self):
class Child(Schema):
name = fields.String(required=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/tests/test_schema.py
new/marshmallow-3.5.1/tests/test_schema.py
--- old/marshmallow-3.2.2/tests/test_schema.py 2019-11-04 22:14:53.000000000
+0100
+++ new/marshmallow-3.5.1/tests/test_schema.py 2020-03-05 14:05:11.000000000
+0100
@@ -1136,11 +1136,9 @@
def test_nested_custom_set_not_implementing_getitem():
- """
- This test checks that Marshmallow can serialize implementations of
- :mod:`collections.abc.MutableSequence`, with ``__getitem__`` arguments
- that are not integers.
- """
+ # This test checks that marshmallow can serialize implementations of
+ # :mod:`collections.abc.MutableSequence`, with ``__getitem__`` arguments
+ # that are not integers.
class ListLikeParent:
"""
@@ -1226,6 +1224,55 @@
assert "bah" not in grand_child
+def test_nested_lambda():
+ class ChildSchema(Schema):
+ id = fields.Str()
+ name = fields.Str()
+ parent = fields.Nested(lambda: ParentSchema(only=("id",)),
dump_only=True)
+ siblings = fields.List(fields.Nested(lambda: ChildSchema(only=("id",
"name"))))
+
+ class ParentSchema(Schema):
+ id = fields.Str()
+ spouse = fields.Nested(lambda: ParentSchema(only=("id",)))
+ children = fields.List(
+ fields.Nested(lambda: ChildSchema(only=("id", "parent",
"siblings")))
+ )
+
+ sch = ParentSchema()
+ data_to_load = {
+ "id": "p1",
+ "spouse": {"id": "p2"},
+ "children": [{"id": "c1", "siblings": [{"id": "c2", "name": "sis"}]}],
+ }
+ loaded = sch.load(data_to_load)
+ assert loaded == data_to_load
+
+ data_to_dump = dict(
+ id="p2",
+ spouse=dict(id="p2"),
+ children=[
+ dict(
+ id="c1",
+ name="bar",
+ parent=dict(id="p2"),
+ siblings=[dict(id="c2", name="sis")],
+ )
+ ],
+ )
+ dumped = sch.dump(data_to_dump)
+ assert dumped == {
+ "id": "p2",
+ "spouse": {"id": "p2"},
+ "children": [
+ {
+ "id": "c1",
+ "parent": {"id": "p2"},
+ "siblings": [{"id": "c2", "name": "sis"}],
+ }
+ ],
+ }
+
+
@pytest.mark.parametrize("data_key", ("f1", "f5", None))
def test_data_key_collision(data_key):
class MySchema(Schema):
@@ -1888,17 +1935,6 @@
)
return blog
- class FlatBlogSchema(Schema):
- name = fields.String()
- user = fields.Nested(UserSchema, only="name")
- collaborators = fields.Nested(UserSchema, only="name", many=True)
-
- s = FlatBlogSchema()
- data = s.dump(blog)
- assert data["user"] == blog.user.name
- for i, name in enumerate(data["collaborators"]):
- assert name == blog.collaborators[i].name
-
# regression test for
https://github.com/marshmallow-code/marshmallow/issues/64
def test_nested_many_with_missing_attribute(self, user):
class SimpleBlogSchema(Schema):
@@ -2163,13 +2199,15 @@
def user(self, employer):
return User(name="Tom", employer=employer, age=28)
- def test_nesting_schema_within_itself(self, user, employer):
- class SelfSchema(Schema):
- name = fields.String()
- age = fields.Integer()
- employer = fields.Nested("self", exclude=("employer",))
+ def test_nesting_schema_by_passing_lambda(self, user, employer):
+ class SelfReferencingSchema(Schema):
+ name = fields.Str()
+ age = fields.Int()
+ employer = fields.Nested(
+ lambda: SelfReferencingSchema(exclude=("employer",))
+ )
- data = SelfSchema().dump(user)
+ data = SelfReferencingSchema().dump(user)
assert data["name"] == user.name
assert data["employer"]["name"] == employer.name
assert data["employer"]["age"] == employer.age
@@ -2185,9 +2223,24 @@
assert data["employer"]["name"] == employer.name
assert data["employer"]["age"] == employer.age
+ def test_nesting_schema_self_string(self, user, employer):
+ with pytest.warns(
+ DeprecationWarning, match="Passing 'self' to `Nested` is
deprecated"
+ ):
+
+ class SelfSchema(Schema):
+ name = fields.String()
+ age = fields.Integer()
+ employer = fields.Nested("self", exclude=("employer",))
+
+ data = SelfSchema().dump(user)
+ assert data["name"] == user.name
+ assert data["employer"]["name"] == employer.name
+ assert data["employer"]["age"] == employer.age
+
def test_nesting_within_itself_meta(self, user, employer):
class SelfSchema(Schema):
- employer = fields.Nested("self", exclude=("employer",))
+ employer = fields.Nested(lambda: SelfSchema(exclude=("employer",)))
class Meta:
additional = ("name", "age")
@@ -2200,7 +2253,7 @@
def test_nested_self_with_only_param(self, user, employer):
class SelfSchema(Schema):
- employer = fields.Nested("self", only=("name",))
+ employer = fields.Nested(lambda: SelfSchema(only=("name",)))
class Meta:
fields = ("name", "employer")
@@ -2210,10 +2263,14 @@
assert data["employer"]["name"] == employer.name
assert "age" not in data["employer"]
- def test_multiple_pluck_self_field(self, user):
+ def test_multiple_pluck_self_lambda(self, user):
class MultipleSelfSchema(Schema):
- emp = fields.Pluck("self", "name", attribute="employer")
- rels = fields.Pluck("self", "name", many=True,
attribute="relatives")
+ emp = fields.Pluck(
+ lambda: MultipleSelfSchema(), "name", attribute="employer"
+ )
+ rels = fields.Pluck(
+ lambda: MultipleSelfSchema(), "name", many=True,
attribute="relatives"
+ )
class Meta:
fields = ("name", "emp", "rels")
@@ -2225,9 +2282,28 @@
relative = data["rels"][0]
assert relative == user.relatives[0].name
- def test_nested_self_many(self):
+ def test_multiple_pluck_self_string(self, user):
+ with pytest.warns(
+ DeprecationWarning, match="Passing 'self' to `Nested` is
deprecated"
+ ):
+
+ class MultipleSelfSchema(Schema):
+ emp = fields.Pluck("self", "name", attribute="employer")
+ rels = fields.Pluck("self", "name", many=True,
attribute="relatives")
+
+ class Meta:
+ fields = ("name", "emp", "rels")
+
+ schema = MultipleSelfSchema()
+ user.relatives = [User(name="Bar", age=12), User(name="Baz", age=34)]
+ data = schema.dump(user)
+ assert len(data["rels"]) == len(user.relatives)
+ relative = data["rels"][0]
+ assert relative == user.relatives[0].name
+
+ def test_nested_self_many_lambda(self):
class SelfManySchema(Schema):
- relatives = fields.Nested("self", many=True)
+ relatives = fields.Nested(lambda: SelfManySchema(), many=True)
class Meta:
additional = ("name", "age")
@@ -2240,15 +2316,53 @@
assert data["relatives"][0]["name"] == person.relatives[0].name
assert data["relatives"][0]["age"] == person.relatives[0].age
+ def test_nested_self_many_string(self):
+ with pytest.warns(
+ DeprecationWarning, match="Passing 'self' to `Nested` is
deprecated"
+ ):
+
+ class SelfManySchema(Schema):
+ relatives = fields.Nested("self", many=True)
+
+ class Meta:
+ additional = ("name", "age")
+
+ person = User(name="Foo")
+ person.relatives = [User(name="Bar", age=12), User(name="Baz", age=34)]
+ data = SelfManySchema().dump(person)
+ assert data["name"] == person.name
+ assert len(data["relatives"]) == len(person.relatives)
+ assert data["relatives"][0]["name"] == person.relatives[0].name
+ assert data["relatives"][0]["age"] == person.relatives[0].age
+
def test_nested_self_list(self):
class SelfListSchema(Schema):
- relatives = fields.List(fields.Nested("self"))
+ relatives = fields.List(fields.Nested(lambda: SelfListSchema()))
class Meta:
additional = ("name", "age")
person = User(name="Foo")
person.relatives = [User(name="Bar", age=12), User(name="Baz", age=34)]
+ data = SelfListSchema().dump(person)
+ assert data["name"] == person.name
+ assert len(data["relatives"]) == len(person.relatives)
+ assert data["relatives"][0]["name"] == person.relatives[0].name
+ assert data["relatives"][0]["age"] == person.relatives[0].age
+
+ def test_nested_self_list_string(self):
+ with pytest.warns(
+ DeprecationWarning, match="Passing 'self' to `Nested` is
deprecated"
+ ):
+
+ class SelfListSchema(Schema):
+ relatives = fields.List(fields.Nested("self"))
+
+ class Meta:
+ additional = ("name", "age")
+
+ person = User(name="Foo")
+ person.relatives = [User(name="Bar", age=12), User(name="Baz", age=34)]
data = SelfListSchema().dump(person)
assert data["name"] == person.name
assert len(data["relatives"]) == len(person.relatives)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/marshmallow-3.2.2/tests/test_validate.py
new/marshmallow-3.5.1/tests/test_validate.py
--- old/marshmallow-3.2.2/tests/test_validate.py 2019-11-04
22:14:53.000000000 +0100
+++ new/marshmallow-3.5.1/tests/test_validate.py 2020-03-05
14:05:11.000000000 +0100
@@ -41,6 +41,7 @@
"http:///example.com/",
"https:///example.com/",
"https://example.org\\",
+ "https://example.org\n",
"ftp:///example.com/",
"ftps:///example.com/",
"http//example.org",
@@ -85,6 +86,7 @@
"invalid_url",
[
"http//example.org",
+ "http://example.org\n",
"suppliers.html",
"../icons/logo.gif",
"icons/logo.gif",
@@ -123,6 +125,7 @@
"invalid_url",
[
"http//example",
+ "http://example\n",
"http://.example.org",
"http:///foo/bar",
"http:// /foo/bar",
@@ -197,6 +200,8 @@
@pytest.mark.parametrize(
"invalid_email",
[
+ "niceandsimple\[email protected]",
+ "[email protected]\n",
'a"b(c)d,e:f;g<h>i[j\\k][email protected]',
'just"not"[email protected]',
'this is"not\[email protected]',