Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-marshmallow for openSUSE:Factory checked in at 2022-11-01 13:42:18 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-marshmallow (Old) and /work/SRC/openSUSE:Factory/.python-marshmallow.new.2275 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-marshmallow" Tue Nov 1 13:42:18 2022 rev:18 rq:1032503 version:3.18.0 Changes: -------- --- /work/SRC/openSUSE:Factory/python-marshmallow/python-marshmallow.changes 2022-09-30 17:58:05.401286521 +0200 +++ /work/SRC/openSUSE:Factory/.python-marshmallow.new.2275/python-marshmallow.changes 2022-11-01 13:42:29.399871111 +0100 @@ -2 +2 @@ -Thu Sep 29 15:53:34 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> +Fri Oct 28 18:21:19 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> @@ -8,0 +9,3 @@ + +------------------------------------------------------------------- +Thu Sep 29 15:53:34 UTC 2022 - Yogalakshmi Arunachalam <yarunacha...@suse.com> Old: ---- marshmallow-3.17.1.tar.gz New: ---- marshmallow-3.18.0.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-marshmallow.spec ++++++ --- /var/tmp/diff_new_pack.GQCtsu/_old 2022-11-01 13:42:29.799873240 +0100 +++ /var/tmp/diff_new_pack.GQCtsu/_new 2022-11-01 13:42:29.807873282 +0100 @@ -19,7 +19,7 @@ %{?!python_module:%define python_module() python-%{**} python3-%{**}} %define skip_python2 1 Name: python-marshmallow -Version: 3.17.1 +Version: 3.18.0 Release: 0 Summary: ORM/ODM/framework-agnostic library to convert datatypes from/to Python types License: BSD-3-Clause AND MIT ++++++ marshmallow-3.17.1.tar.gz -> marshmallow-3.18.0.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/marshmallow-3.17.1/CHANGELOG.rst new/marshmallow-3.18.0/CHANGELOG.rst --- old/marshmallow-3.17.1/CHANGELOG.rst 2022-08-22 21:36:43.000000000 +0200 +++ new/marshmallow-3.18.0/CHANGELOG.rst 2022-09-15 22:26:57.000000000 +0200 @@ -1,12 +1,23 @@ Changelog --------- +3.18.0 (2022-09-15) +******************* + +Features: + +- Add ``Enum`` field (:pr:`2017`) and (:pr:`2044`). + +Bug fixes: + +- Fix typing in ``Field._serialize`` signature (:pr:`2046`). + 3.17.1 (2022-08-22) ******************* Bug fixes: -- Add return type to `fields.Email.__init__` (:pr:`2018`). +- Add return type to ``fields.Email.__init__`` (:pr:`2018`). Thanks :user:`kkirsche` for the PR. - Add missing type hint to IPInterface __init__ (:pr:`2036`). diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/marshmallow-3.17.1/PKG-INFO new/marshmallow-3.18.0/PKG-INFO --- old/marshmallow-3.17.1/PKG-INFO 2022-08-22 21:36:55.306264200 +0200 +++ new/marshmallow-3.18.0/PKG-INFO 2022-09-15 22:27:10.895295400 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: marshmallow -Version: 3.17.1 +Version: 3.18.0 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 @@ -173,12 +173,6 @@ :target: https://tidelift.com/subscription/pkg/pypi-marshmallow?utm_source=pypi-marshmallow&utm_medium=readme :alt: Get supported marshmallow with Tidelift -Security Contact Information -============================ - -To report a security vulnerability, please use the -`Tidelift security contact <https://tidelift.com/security>`_. -Tidelift will coordinate the fix and disclosure. Project Links ============= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/marshmallow-3.17.1/README.rst new/marshmallow-3.18.0/README.rst --- old/marshmallow-3.17.1/README.rst 2022-08-22 21:36:43.000000000 +0200 +++ new/marshmallow-3.18.0/README.rst 2022-09-15 22:26:57.000000000 +0200 @@ -145,12 +145,6 @@ :target: https://tidelift.com/subscription/pkg/pypi-marshmallow?utm_source=pypi-marshmallow&utm_medium=readme :alt: Get supported marshmallow with Tidelift -Security Contact Information -============================ - -To report a security vulnerability, please use the -`Tidelift security contact <https://tidelift.com/security>`_. -Tidelift will coordinate the fix and disclosure. Project Links ============= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/marshmallow-3.17.1/setup.py new/marshmallow-3.18.0/setup.py --- old/marshmallow-3.17.1/setup.py 2022-08-22 21:36:43.000000000 +0200 +++ new/marshmallow-3.18.0/setup.py 2022-09-15 22:26:57.000000000 +0200 @@ -6,7 +6,7 @@ "lint": [ "mypy==0.971", "flake8==5.0.4", - "flake8-bugbear==22.8.22", + "flake8-bugbear==22.9.11", "pre-commit~=2.4", ], "docs": [ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/marshmallow-3.17.1/src/marshmallow/__init__.py new/marshmallow-3.18.0/src/marshmallow/__init__.py --- old/marshmallow-3.17.1/src/marshmallow/__init__.py 2022-08-22 21:36:43.000000000 +0200 +++ new/marshmallow-3.18.0/src/marshmallow/__init__.py 2022-09-15 22:26:57.000000000 +0200 @@ -16,7 +16,7 @@ from . import fields -__version__ = "3.17.1" +__version__ = "3.18.0" __parsed_version__ = Version(__version__) __version_info__: tuple[int, int, int] | tuple[ int, int, int, str, int diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/marshmallow-3.17.1/src/marshmallow/fields.py new/marshmallow-3.18.0/src/marshmallow/fields.py --- old/marshmallow-3.17.1/src/marshmallow/fields.py 2022-08-22 21:36:43.000000000 +0200 +++ new/marshmallow-3.18.0/src/marshmallow/fields.py 2022-09-15 22:26:57.000000000 +0200 @@ -11,6 +11,7 @@ import math import typing import warnings +from enum import Enum as EnumType from collections.abc import Mapping as _Mapping from marshmallow import validate, utils, class_registry, types @@ -59,6 +60,7 @@ "IPInterface", "IPv4Interface", "IPv6Interface", + "Enum", "Method", "Function", "Str", @@ -384,7 +386,9 @@ self.parent.root if isinstance(self.parent, FieldABC) else self.parent ) - def _serialize(self, value: typing.Any, attr: str, obj: typing.Any, **kwargs): + def _serialize( + self, value: typing.Any, attr: str | None, obj: typing.Any, **kwargs + ): """Serializes ``value`` to a basic Python datatype. Noop by default. Concrete :class:`Field` classes should implement this method. @@ -995,11 +999,7 @@ # override Number def _validated(self, value): - if self.strict: - if isinstance(value, numbers.Number) and isinstance( - value, numbers.Integral - ): - return super()._validated(value) + if self.strict and not isinstance(value, numbers.Integral): raise self.make_error("invalid", input=value) return super()._validated(value) @@ -1855,6 +1855,79 @@ DESERIALIZATION_CLASS = ipaddress.IPv6Interface +class Enum(Field): + """An Enum field (de)serializing enum members by symbol (name) or by value. + + :param enum Enum: Enum class + :param boolean|Schema|Field by_value: Whether to (de)serialize by value or by name, + or Field class or instance to use to (de)serialize by value. Defaults to False. + + If `by_value` is `False` (default), enum members are (de)serialized by symbol (name). + If it is `True`, they are (de)serialized by value using :class:`Field`. + If it is a field instance or class, they are (de)serialized by value using this field. + + .. versionadded:: 3.18.0 + """ + + default_error_messages = { + "unknown": "Must be one of: {choices}.", + } + + def __init__( + self, + enum: type[EnumType], + *, + by_value: bool | Field | type = False, + **kwargs, + ): + super().__init__(**kwargs) + self.enum = enum + self.by_value = by_value + + # Serialization by name + if by_value is False: + self.field: Field = String() + self.choices_text = ", ".join( + str(self.field._serialize(m, None, None)) for m in enum.__members__ + ) + # Serialization by value + else: + if by_value is True: + self.field = Field() + else: + try: + self.field = resolve_field_instance(by_value) + except FieldInstanceResolutionError as error: + raise ValueError( + '"by_value" must be either a bool or a subclass or instance of ' + "marshmallow.base.FieldABC." + ) from error + self.choices_text = ", ".join( + str(self.field._serialize(m.value, None, None)) for m in enum + ) + + def _serialize(self, value, attr, obj, **kwargs): + if value is None: + return None + if self.by_value: + val = value.value + else: + val = value.name + return self.field._serialize(val, attr, obj, **kwargs) + + def _deserialize(self, value, attr, data, **kwargs): + val = self.field._deserialize(value, attr, data, **kwargs) + if self.by_value: + try: + return self.enum(val) + except ValueError as error: + raise self.make_error("unknown", choices=self.choices_text) from error + try: + return getattr(self.enum, val) + except AttributeError as error: + raise self.make_error("unknown", choices=self.choices_text) from error + + class Method(Field): """A field that takes the value returned by a `Schema` method. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/marshmallow-3.17.1/src/marshmallow.egg-info/PKG-INFO new/marshmallow-3.18.0/src/marshmallow.egg-info/PKG-INFO --- old/marshmallow-3.17.1/src/marshmallow.egg-info/PKG-INFO 2022-08-22 21:36:55.000000000 +0200 +++ new/marshmallow-3.18.0/src/marshmallow.egg-info/PKG-INFO 2022-09-15 22:27:10.000000000 +0200 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: marshmallow -Version: 3.17.1 +Version: 3.18.0 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 @@ -173,12 +173,6 @@ :target: https://tidelift.com/subscription/pkg/pypi-marshmallow?utm_source=pypi-marshmallow&utm_medium=readme :alt: Get supported marshmallow with Tidelift -Security Contact Information -============================ - -To report a security vulnerability, please use the -`Tidelift security contact <https://tidelift.com/security>`_. -Tidelift will coordinate the fix and disclosure. Project Links ============= diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/marshmallow-3.17.1/src/marshmallow.egg-info/requires.txt new/marshmallow-3.18.0/src/marshmallow.egg-info/requires.txt --- old/marshmallow-3.17.1/src/marshmallow.egg-info/requires.txt 2022-08-22 21:36:55.000000000 +0200 +++ new/marshmallow-3.18.0/src/marshmallow.egg-info/requires.txt 2022-09-15 22:27:10.000000000 +0200 @@ -6,7 +6,7 @@ simplejson mypy==0.971 flake8==5.0.4 -flake8-bugbear==22.8.22 +flake8-bugbear==22.9.11 pre-commit~=2.4 tox @@ -20,7 +20,7 @@ [lint] mypy==0.971 flake8==5.0.4 -flake8-bugbear==22.8.22 +flake8-bugbear==22.9.11 pre-commit~=2.4 [tests] diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/marshmallow-3.17.1/tests/base.py new/marshmallow-3.18.0/tests/base.py --- old/marshmallow-3.17.1/tests/base.py 2022-08-22 21:36:43.000000000 +0200 +++ new/marshmallow-3.18.0/tests/base.py 2022-09-15 22:26:57.000000000 +0200 @@ -1,6 +1,8 @@ """Test utilities and fixtures.""" +import functools import datetime as dt import uuid +from enum import Enum, IntEnum import simplejson @@ -12,6 +14,25 @@ central = pytz.timezone("US/Central") +class GenderEnum(IntEnum): + male = 1 + female = 2 + non_binary = 3 + + +class HairColorEnum(Enum): + black = "black hair" + brown = "brown hair" + blond = "blond hair" + red = "red hair" + + +class DateEnum(Enum): + date_1 = dt.date(2004, 2, 29) + date_2 = dt.date(2008, 2, 29) + date_3 = dt.date(2012, 2, 29) + + ALL_FIELDS = [ fields.String, fields.Integer, @@ -33,8 +54,12 @@ fields.IPInterface, fields.IPv4Interface, fields.IPv6Interface, + functools.partial(fields.Enum, GenderEnum), + functools.partial(fields.Enum, HairColorEnum, by_value=fields.String), + functools.partial(fields.Enum, GenderEnum, by_value=fields.Integer), ] + ##### Custom asserts ##### @@ -69,7 +94,8 @@ birthdate=None, birthtime=None, balance=100, - sex="male", + sex=GenderEnum.male, + hair_color=HairColorEnum.black, employer=None, various_data=None, ): @@ -86,8 +112,8 @@ self.email = email self.balance = balance self.registered = registered - self.hair_colors = ["black", "brown", "blond", "redhead"] - self.sex_choices = ("male", "female") + self.hair_colors = list(HairColorEnum.__members__) + self.sex_choices = list(GenderEnum.__members__) self.finger_count = 10 self.uid = uuid.uuid1() self.time_registered = time_registered or dt.time(1, 23, 45, 6789) @@ -95,6 +121,7 @@ self.birthtime = birthtime or dt.time(0, 1, 2, 3333) self.activation_date = dt.date(2013, 12, 11) self.sex = sex + self.hair_color = hair_color self.employer = employer self.relatives = [] self.various_data = various_data or { @@ -180,7 +207,7 @@ birthtime = fields.Time() activation_date = fields.Date() since_created = fields.TimeDelta() - sex = fields.Str(validate=validate.OneOf(["male", "female"])) + sex = fields.Str(validate=validate.OneOf(list(GenderEnum.__members__))) various_data = fields.Dict() class Meta: diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/marshmallow-3.17.1/tests/test_deserialization.py new/marshmallow-3.18.0/tests/test_deserialization.py --- old/marshmallow-3.17.1/tests/test_deserialization.py 2022-08-22 21:36:43.000000000 +0200 +++ new/marshmallow-3.18.0/tests/test_deserialization.py 2022-09-15 22:26:57.000000000 +0200 @@ -10,7 +10,15 @@ from marshmallow.exceptions import ValidationError from marshmallow.validate import Equal -from tests.base import assert_date_equal, assert_time_equal, central, ALL_FIELDS +from tests.base import ( + assert_date_equal, + assert_time_equal, + central, + ALL_FIELDS, + GenderEnum, + HairColorEnum, + DateEnum, +) class TestDeserializingNone: @@ -1089,6 +1097,85 @@ assert excinfo.value.args[0] == "Not a valid IPv6 interface." + def test_enum_field_by_symbol_deserialization(self): + field = fields.Enum(GenderEnum) + assert field.deserialize("male") == GenderEnum.male + + def test_enum_field_by_symbol_invalid_value(self): + field = fields.Enum(GenderEnum) + with pytest.raises( + ValidationError, match="Must be one of: male, female, non_binary." + ): + field.deserialize("dummy") + + def test_enum_field_by_symbol_not_string(self): + field = fields.Enum(GenderEnum) + with pytest.raises(ValidationError, match="Not a valid string."): + field.deserialize(12) + + def test_enum_field_by_value_true_deserialization(self): + field = fields.Enum(HairColorEnum, by_value=True) + assert field.deserialize("black hair") == HairColorEnum.black + field = fields.Enum(GenderEnum, by_value=True) + assert field.deserialize(1) == GenderEnum.male + + def test_enum_field_by_value_field_deserialization(self): + field = fields.Enum(HairColorEnum, by_value=fields.String) + assert field.deserialize("black hair") == HairColorEnum.black + field = fields.Enum(GenderEnum, by_value=fields.Integer) + assert field.deserialize(1) == GenderEnum.male + field = fields.Enum(DateEnum, by_value=fields.Date(format="%d/%m/%Y")) + assert field.deserialize("29/02/2004") == DateEnum.date_1 + + def test_enum_field_by_value_true_invalid_value(self): + field = fields.Enum(HairColorEnum, by_value=True) + with pytest.raises( + ValidationError, + match="Must be one of: black hair, brown hair, blond hair, red hair.", + ): + field.deserialize("dummy") + field = fields.Enum(GenderEnum, by_value=True) + with pytest.raises(ValidationError, match="Must be one of: 1, 2, 3."): + field.deserialize(12) + + def test_enum_field_by_value_field_invalid_value(self): + field = fields.Enum(HairColorEnum, by_value=fields.String) + with pytest.raises( + ValidationError, + match="Must be one of: black hair, brown hair, blond hair, red hair.", + ): + field.deserialize("dummy") + field = fields.Enum(GenderEnum, by_value=fields.Integer) + with pytest.raises(ValidationError, match="Must be one of: 1, 2, 3."): + field.deserialize(12) + field = fields.Enum(DateEnum, by_value=fields.Date(format="%d/%m/%Y")) + with pytest.raises( + ValidationError, match="Must be one of: 29/02/2004, 29/02/2008, 29/02/2012." + ): + field.deserialize("28/02/2004") + + def test_enum_field_by_value_true_wrong_type(self): + field = fields.Enum(HairColorEnum, by_value=True) + with pytest.raises( + ValidationError, + match="Must be one of: black hair, brown hair, blond hair, red hair.", + ): + field.deserialize("dummy") + field = fields.Enum(GenderEnum, by_value=True) + with pytest.raises(ValidationError, match="Must be one of: 1, 2, 3."): + field.deserialize(12) + + def test_enum_field_by_value_field_wrong_type(self): + field = fields.Enum(HairColorEnum, by_value=fields.String) + with pytest.raises(ValidationError, match="Not a valid string."): + field.deserialize(12) + field = fields.Enum(GenderEnum, by_value=fields.Integer) + with pytest.raises(ValidationError, match="Not a valid integer."): + field.deserialize("dummy") + field = fields.Enum(DateEnum, by_value=fields.Date(format="%d/%m/%Y")) + with pytest.raises(ValidationError, match="Not a valid date."): + field.deserialize("30/02/2004") + def test_deserialization_function_must_be_callable(self): with pytest.raises(TypeError): fields.Function(lambda x: None, deserialize="notvalid") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/marshmallow-3.17.1/tests/test_serialization.py new/marshmallow-3.18.0/tests/test_serialization.py --- old/marshmallow-3.17.1/tests/test_serialization.py 2022-08-22 21:36:43.000000000 +0200 +++ new/marshmallow-3.18.0/tests/test_serialization.py 2022-09-15 22:26:57.000000000 +0200 @@ -11,7 +11,7 @@ from marshmallow import Schema, fields, missing as missing_ -from tests.base import User, ALL_FIELDS, central +from tests.base import User, ALL_FIELDS, central, GenderEnum, HairColorEnum, DateEnum class DateTimeList: @@ -255,6 +255,31 @@ == ipv6interface_exploded_string ) + def test_enum_field_by_symbol_serialization(self, user): + user.sex = GenderEnum.male + field = fields.Enum(GenderEnum) + assert field.serialize("sex", user) == "male" + + def test_enum_field_by_value_true_serialization(self, user): + user.hair_color = HairColorEnum.black + field = fields.Enum(HairColorEnum, by_value=True) + assert field.serialize("hair_color", user) == "black hair" + user.sex = GenderEnum.male + field = fields.Enum(GenderEnum, by_value=True) + assert field.serialize("sex", user) == 1 + user.some_date = DateEnum.date_1 + + def test_enum_field_by_value_field_serialization(self, user): + user.hair_color = HairColorEnum.black + field = fields.Enum(HairColorEnum, by_value=fields.String) + assert field.serialize("hair_color", user) == "black hair" + user.sex = GenderEnum.male + field = fields.Enum(GenderEnum, by_value=fields.Integer) + assert field.serialize("sex", user) == 1 + user.some_date = DateEnum.date_1 + field = fields.Enum(DateEnum, by_value=fields.Date(format="%d/%m/%Y")) + assert field.serialize("some_date", user) == "29/02/2004" + def test_decimal_field(self, user): user.m1 = 12 user.m2 = "12.355"