diff -Nru python-marshmallow-3.6.1/AUTHORS.rst python-marshmallow-3.7.1/AUTHORS.rst --- python-marshmallow-3.6.1/AUTHORS.rst 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/AUTHORS.rst 2020-07-20 13:52:19.000000000 +0000 @@ -148,3 +148,7 @@ - Nathan `@nbanmp `_ - Ronan Murphy `@Resinderate `_ - Laurie Opperman `@EpicWink `_ +- Ram Rachum `@cool-RR `_ +- `@weeix `_ +- Juan Norris `@juannorris `_ +- 장준영 `@jun0jang `_ diff -Nru python-marshmallow-3.6.1/CHANGELOG.rst python-marshmallow-3.7.1/CHANGELOG.rst --- python-marshmallow-3.6.1/CHANGELOG.rst 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/CHANGELOG.rst 2020-07-20 13:52:19.000000000 +0000 @@ -1,6 +1,30 @@ Changelog --------- +3.7.1 (2020-07-20) +****************** + +Bug fixes: + +- ``fields.Boolean`` correctly serializes non-hashable types (:pr:`1633`). + Thanks :user:`jun0jang` for the PR. + +3.7.0 (2020-07-08) +****************** + +Deprecations: + +- `marshmallow.pprint` is deprecated and will be removed in marshmallow 4 (:issue:`1588`). + +Support: + +- Document ``default_error_messages`` on field classes (:pr:`1619`). Thanks :user:`weeix`. + +Bug fixes: + +- Fix passing ``only`` and ``exclude`` to ``Nested`` with an ordered ``Schema`` (:pr:`1627`). + Thanks :user:`juannorris` for the PR. + 3.6.1 (2020-06-02) ****************** diff -Nru python-marshmallow-3.6.1/CONTRIBUTING.rst python-marshmallow-3.7.1/CONTRIBUTING.rst --- python-marshmallow-3.6.1/CONTRIBUTING.rst 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/CONTRIBUTING.rst 2020-07-20 13:52:19.000000000 +0000 @@ -123,7 +123,7 @@ Documentation +++++++++++++ -Contributions to the documentation are welcome. Documentation is written in `reStructured Text`_ (rST). A quick rST reference can be found `here `_. Builds are powered by Sphinx_. +Contributions to the documentation are welcome. Documentation is written in `reStructuredText`_ (rST). A quick rST reference can be found `here `_. Builds are powered by Sphinx_. To build the docs in "watch" mode: :: @@ -141,5 +141,5 @@ .. _Sphinx: https://www.sphinx-doc.org/ -.. _`reStructured Text`: http://docutils.sourceforge.net/rst.html +.. _`reStructuredText`: https://docutils.sourceforge.io/rst.html .. _marshmallow: https://github.com/marshmallow-code/marshmallow diff -Nru python-marshmallow-3.6.1/debian/changelog python-marshmallow-3.7.1/debian/changelog --- python-marshmallow-3.6.1/debian/changelog 2020-06-15 19:47:20.000000000 +0000 +++ python-marshmallow-3.7.1/debian/changelog 2020-07-26 21:47:11.000000000 +0000 @@ -1,3 +1,9 @@ +python-marshmallow (3.7.1-1) unstable; urgency=medium + + * New upstream release + + -- Federico Ceratto Sun, 26 Jul 2020 22:47:11 +0100 + python-marshmallow (3.6.1-1) unstable; urgency=medium * New upstream release diff -Nru python-marshmallow-3.6.1/docs/quickstart.rst python-marshmallow-3.7.1/docs/quickstart.rst --- python-marshmallow-3.6.1/docs/quickstart.rst 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/docs/quickstart.rst 2020-07-20 13:52:19.000000000 +0000 @@ -90,7 +90,7 @@ summary_schema = UserSchema(only=("name", "email")) summary_schema.dump(user) - # {"name": "Monty Python", "email": "monty@python.org"} + # {"name": "Monty", "email": "monty@python.org"} You can also exclude fields by passing in the ``exclude`` parameter. diff -Nru python-marshmallow-3.6.1/examples/package_json_example.py python-marshmallow-3.7.1/examples/package_json_example.py --- python-marshmallow-3.6.1/examples/package_json_example.py 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/examples/package_json_example.py 2020-07-20 13:52:19.000000000 +0000 @@ -12,8 +12,8 @@ def _deserialize(self, value, *args, **kwargs): try: return version.Version(value) - except version.InvalidVersion: - raise ValidationError("Not a valid version.") + except version.InvalidVersion as e: + raise ValidationError("Not a valid version.") from e def _serialize(self, value, *args, **kwargs): return str(value) diff -Nru python-marshmallow-3.6.1/.pre-commit-config.yaml python-marshmallow-3.7.1/.pre-commit-config.yaml --- python-marshmallow-3.6.1/.pre-commit-config.yaml 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/.pre-commit-config.yaml 2020-07-20 13:52:19.000000000 +0000 @@ -1,6 +1,6 @@ repos: - repo: https://github.com/asottile/pyupgrade - rev: v1.26.0 + rev: v2.6.2 hooks: - id: pyupgrade args: ["--py3-plus"] @@ -10,16 +10,16 @@ - id: black language_version: python3 - repo: https://gitlab.com/pycqa/flake8 - rev: 3.7.9 + rev: 3.8.3 hooks: - id: flake8 - additional_dependencies: ['flake8-bugbear==20.1.0'] + additional_dependencies: ['flake8-bugbear==20.1.4'] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.770 + rev: v0.782 hooks: - id: mypy - repo: https://github.com/asottile/blacken-docs - rev: v1.5.0-1 + rev: v1.7.0 hooks: - id: blacken-docs additional_dependencies: [black==19.10b0] diff -Nru python-marshmallow-3.6.1/setup.py python-marshmallow-3.7.1/setup.py --- python-marshmallow-3.6.1/setup.py 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/setup.py 2020-07-20 13:52:19.000000000 +0000 @@ -4,13 +4,13 @@ EXTRAS_REQUIRE = { "tests": ["pytest", "pytz", "simplejson"], "lint": [ - "mypy==0.770", - "flake8==3.8.2", + "mypy==0.782", + "flake8==3.8.3", "flake8-bugbear==20.1.4", "pre-commit~=2.4", ], "docs": [ - "sphinx==3.0.4", + "sphinx==3.1.2", "sphinx-issues==1.2.0", "alabaster==0.7.12", "sphinx-version-warning==1.1.2", @@ -25,7 +25,7 @@ Raises RuntimeError if not found. """ version = "" - with open(fname, "r") as fp: + with open(fname) as fp: reg = re.compile(r'__version__ = [\'"]([^\'"]*)[\'"]') for line in fp: m = reg.match(line) diff -Nru python-marshmallow-3.6.1/src/marshmallow/fields.py python-marshmallow-3.7.1/src/marshmallow/fields.py --- python-marshmallow-3.6.1/src/marshmallow/fields.py 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/src/marshmallow/fields.py 2020-07-20 13:52:19.000000000 +0000 @@ -25,6 +25,7 @@ FieldInstanceResolutionError, ) from marshmallow.validate import Validator, Length +from marshmallow.warnings import RemovedInMarshmallow4Warning __all__ = [ "Field", @@ -269,7 +270,7 @@ '`Field.fail` is deprecated. Use `raise self.make_error("{}", ...)` instead.'.format( key ), - DeprecationWarning, + RemovedInMarshmallow4Warning, ) raise self.make_error(key=key, **kwargs) @@ -451,8 +452,7 @@ # No author = fields.Nested(UserSchema(), only=('id', 'name')) - :param nested: The Schema class or class name (string) - to nest, or ``"self"`` to nest the :class:`Schema` within itself. + :param nested: `Schema` instance, class, class name (string), or callable that returns a `Schema` instance. :param exclude: A list or tuple of fields to exclude. :param only: A list or tuple of fields to marshal. If `None`, all fields are marshalled. This parameter takes precedence over ``exclude``. @@ -462,6 +462,7 @@ :param kwargs: The same keyword arguments that :class:`Field` receives. """ + #: Default error messages. default_error_messages = {"type": "Invalid type."} def __init__( @@ -486,7 +487,7 @@ warnings.warn( "Passing 'self' to `Nested` is deprecated. " "Use `Nested(lambda: MySchema(...))` instead.", - DeprecationWarning, + RemovedInMarshmallow4Warning, ) self.nested = nested self.only = only @@ -521,10 +522,10 @@ original = self._schema.only else: # only=None -> all fields original = self._schema.fields.keys() - self._schema.only = set_class(self.only).intersection(original) + self._schema.only = set_class(self.only) & set_class(original) if self.exclude: original = self._schema.exclude - self._schema.exclude = set_class(self.exclude).union(original) + self._schema.exclude = set_class(self.exclude) | set_class(original) self._schema._init_fields() else: if isinstance(nested, type) and issubclass(nested, SchemaABC): @@ -667,6 +668,7 @@ Does not serialize scalar values to single-item lists. """ + #: Default error messages. default_error_messages = {"invalid": "Not a valid list."} def __init__(self, cls_or_instance: typing.Union[Field, type], **kwargs): @@ -735,6 +737,7 @@ .. versionadded:: 3.0.0rc4 """ + #: Default error messages. default_error_messages = {"invalid": "Not a valid tuple."} def __init__(self, tuple_fields, *args, **kwargs): @@ -804,6 +807,7 @@ :param kwargs: The same keyword arguments that :class:`Field` receives. """ + #: Default error messages. default_error_messages = { "invalid": "Not a valid string.", "invalid_utf8": "Not a valid utf-8 string.", @@ -826,6 +830,7 @@ class UUID(String): """A UUID field.""" + #: Default error messages. default_error_messages = {"invalid_uuid": "Not a valid UUID."} def _validated(self, value) -> typing.Optional[uuid.UUID]: @@ -855,6 +860,7 @@ num_type = float # type: typing.Type + #: Default error messages. default_error_messages = { "invalid": "Not a valid number.", "too_large": "Number too large.", @@ -907,6 +913,8 @@ """ num_type = int + + #: Default error messages. default_error_messages = {"invalid": "Not a valid integer."} def __init__(self, *, strict: bool = False, **kwargs): @@ -934,6 +942,8 @@ """ num_type = float + + #: Default error messages. default_error_messages = { "special": "Special numeric values (nan or infinity) are not permitted." } @@ -989,6 +999,7 @@ num_type = decimal.Decimal + #: Default error messages. default_error_messages = { "special": "Special numeric values (nan or infinity) are not permitted." } @@ -1085,6 +1096,7 @@ False, } + #: Default error messages. default_error_messages = {"invalid": "Not a valid boolean."} def __init__( @@ -1100,10 +1112,14 @@ def _serialize(self, value, attr, obj, **kwargs): if value is None: return None - elif value in self.truthy: - return True - elif value in self.falsy: - return False + + try: + if value in self.truthy: + return True + elif value in self.falsy: + return False + except TypeError: + pass return bool(value) @@ -1154,6 +1170,7 @@ SCHEMA_OPTS_VAR_NAME = "datetimeformat" + #: Default error messages. default_error_messages = { "invalid": "Not a valid {obj_type}.", "invalid_awareness": "Not a valid {awareness} {obj_type}.", @@ -1281,6 +1298,7 @@ :param kwargs: The same keyword arguments that :class:`Field` receives. """ + #: Default error messages. default_error_messages = { "invalid": "Not a valid time.", "format": '"{input}" cannot be formatted as a time.', @@ -1312,6 +1330,7 @@ :param kwargs: The same keyword arguments that :class:`Field` receives. """ + #: Default error messages. default_error_messages = { "invalid": "Not a valid date.", "format": '"{input}" cannot be formatted as a date.', @@ -1355,6 +1374,7 @@ HOURS = "hours" WEEKS = "weeks" + #: Default error messages. default_error_messages = { "invalid": "Not a valid period of time.", "format": "{input!r} cannot be formatted as a timedelta.", @@ -1416,6 +1436,8 @@ """ mapping_type = dict + + #: Default error messages. default_error_messages = {"invalid": "Not a valid mapping type."} def __init__( @@ -1560,6 +1582,7 @@ :param kwargs: The same keyword arguments that :class:`String` receives. """ + #: Default error messages. default_error_messages = {"invalid": "Not a valid URL."} def __init__( @@ -1592,6 +1615,7 @@ :param kwargs: The same keyword arguments that :class:`String` receives. """ + #: Default error messages. default_error_messages = {"invalid": "Not a valid email address."} def __init__(self, *args, **kwargs): diff -Nru python-marshmallow-3.6.1/src/marshmallow/__init__.py python-marshmallow-3.7.1/src/marshmallow/__init__.py --- python-marshmallow-3.6.1/src/marshmallow/__init__.py 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/src/marshmallow/__init__.py 2020-07-20 13:52:19.000000000 +0000 @@ -13,7 +13,7 @@ from marshmallow.exceptions import ValidationError from distutils.version import LooseVersion -__version__ = "3.6.1" +__version__ = "3.7.1" __version_info__ = tuple(LooseVersion(__version__).version) __all__ = [ "EXCLUDE", diff -Nru python-marshmallow-3.6.1/src/marshmallow/schema.py python-marshmallow-3.7.1/src/marshmallow/schema.py --- python-marshmallow-3.6.1/src/marshmallow/schema.py 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/src/marshmallow/schema.py 2020-07-20 13:52:19.000000000 +0000 @@ -34,6 +34,7 @@ is_instance_or_subclass, is_iterable_but_not_string, ) +from marshmallow.warnings import RemovedInMarshmallow4Warning _T = typing.TypeVar("_T") @@ -215,7 +216,7 @@ if hasattr(meta, "json_module"): warnings.warn( "The json_module class Meta option is deprecated. Use render_module instead.", - DeprecationWarning, + RemovedInMarshmallow4Warning, ) render_module = getattr(meta, "json_module", json) else: diff -Nru python-marshmallow-3.6.1/src/marshmallow/utils.py python-marshmallow-3.7.1/src/marshmallow/utils.py --- python-marshmallow-3.6.1/src/marshmallow/utils.py 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/src/marshmallow/utils.py 2020-07-20 13:52:19.000000000 +0000 @@ -6,12 +6,14 @@ import json import re import typing +import warnings from collections.abc import Mapping from email.utils import format_datetime, parsedate_to_datetime from pprint import pprint as py_pprint from marshmallow.base import FieldABC from marshmallow.exceptions import FieldInstanceResolutionError +from marshmallow.warnings import RemovedInMarshmallow4Warning EXCLUDE = "exclude" INCLUDE = "include" @@ -74,6 +76,10 @@ like regular dictionaries. Useful for printing the output of :meth:`marshmallow.Schema.dump`. """ + warnings.warn( + "marshmallow's pprint function is deprecated and will be removed in marshmallow 4.", + RemovedInMarshmallow4Warning, + ) if isinstance(obj, collections.OrderedDict): print(json.dumps(obj, *args, **kwargs)) else: diff -Nru python-marshmallow-3.6.1/src/marshmallow/warnings.py python-marshmallow-3.7.1/src/marshmallow/warnings.py --- python-marshmallow-3.6.1/src/marshmallow/warnings.py 1970-01-01 00:00:00.000000000 +0000 +++ python-marshmallow-3.7.1/src/marshmallow/warnings.py 2020-07-20 13:52:19.000000000 +0000 @@ -0,0 +1,2 @@ +class RemovedInMarshmallow4Warning(DeprecationWarning): + pass diff -Nru python-marshmallow-3.6.1/tests/base.py python-marshmallow-3.7.1/tests/base.py --- python-marshmallow-3.6.1/tests/base.py 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/tests/base.py 2020-07-20 13:52:19.000000000 +0000 @@ -187,7 +187,7 @@ try: return age > 80 except TypeError as te: - raise ValidationError(str(te)) + raise ValidationError(str(te)) from te @post_load def make_user(self, data, **kwargs): @@ -216,7 +216,7 @@ try: return age > 80 except TypeError as te: - raise ValidationError(str(te)) + raise ValidationError(str(te)) from te class Meta: fields = ( diff -Nru python-marshmallow-3.6.1/tests/test_fields.py python-marshmallow-3.7.1/tests/test_fields.py --- python-marshmallow-3.6.1/tests/test_fields.py 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/tests/test_fields.py 2020-07-20 13:52:19.000000000 +0000 @@ -277,6 +277,24 @@ with pytest.raises(ValidationError): MySchema().load({"nested": {"x": 1}}) + @pytest.mark.parametrize( + ("param", "fields_list"), [("only", ["foo"]), ("exclude", ["bar"])] + ) + def test_ordered_instanced_nested_schema_only_and_exclude(self, param, fields_list): + class NestedSchema(Schema): + foo = fields.String() + bar = fields.String() + + class Meta: + ordered = True + + class MySchema(Schema): + nested = fields.Nested(NestedSchema(), **{param: fields_list}) + + assert MySchema().dump({"nested": {"foo": "baz", "bar": "bax"}}) == { + "nested": {"foo": "baz"} + } + class TestListNested: @pytest.mark.parametrize("param", ("only", "exclude", "dump_only", "load_only")) diff -Nru python-marshmallow-3.6.1/tests/test_schema.py python-marshmallow-3.7.1/tests/test_schema.py --- python-marshmallow-3.6.1/tests/test_schema.py 2020-06-02 20:33:52.000000000 +0000 +++ python-marshmallow-3.7.1/tests/test_schema.py 2020-07-20 13:52:19.000000000 +0000 @@ -47,6 +47,7 @@ random.seed(1) + # Run tests with both verbose serializer and 'meta' option serializer @pytest.mark.parametrize("SchemaClass", [UserSchema, UserMetaSchema]) def test_serializing_basic_object(SchemaClass, user): @@ -161,6 +162,16 @@ assert data[0] == s.dump(u1) +@pytest.mark.parametrize("value", [[], {}, [1], {1: 1}]) +def test_boolean_can_dump_unhashable(value): + class MySchema(Schema): + has_items = fields.Boolean() + + schema = MySchema() + data = schema.dump({"has_items": value}) + assert data["has_items"] is bool(value) + + def test_multiple_errors_can_be_stored_for_a_given_index(): class MySchema(Schema): foo = fields.Str(validate=lambda x: len(x) > 3)