Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package python-proto-plus for openSUSE:Factory checked in at 2022-04-30 00:46:30 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/python-proto-plus (Old) and /work/SRC/openSUSE:Factory/.python-proto-plus.new.1538 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-proto-plus" Sat Apr 30 00:46:30 2022 rev:6 rq:973991 version:1.20.3 Changes: -------- --- /work/SRC/openSUSE:Factory/python-proto-plus/python-proto-plus.changes 2022-01-31 22:58:22.181158292 +0100 +++ /work/SRC/openSUSE:Factory/.python-proto-plus.new.1538/python-proto-plus.changes 2022-04-30 00:47:00.811029532 +0200 @@ -1,0 +2,12 @@ +Mon Apr 25 17:45:27 UTC 2022 - Matej Cepl <mc...@suse.com> + +- Update to 1.20.3: + - additional logic to mitigate collisions with reserved terms + - dir(proto.Message) does not raise + - mitigate collisions in field names + - add custom dir for messages and message classes + - workaround for buggy pytest +- Add pytest-staticmethod.patch which works around Pytest bug + gh#pytest-dev/pytest#9637. + +------------------------------------------------------------------- Old: ---- proto-plus-1.19.9.tar.gz New: ---- proto-plus-1.20.3.tar.gz pytest-staticmethod.patch ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ python-proto-plus.spec ++++++ --- /var/tmp/diff_new_pack.SguCcJ/_old 2022-04-30 00:47:01.347030379 +0200 +++ /var/tmp/diff_new_pack.SguCcJ/_new 2022-04-30 00:47:01.351030386 +0200 @@ -28,15 +28,19 @@ %define skip_python2 1 %define modname proto-plus Name: python-proto-plus%{psuffix} -Version: 1.19.9 +Version: 1.20.3 Release: 0 Summary: Pythonic Protocol Buffers License: Apache-2.0 URL: https://github.com/googleapis/proto-plus-python Source0: https://files.pythonhosted.org/packages/source/p/%{modname}/%{modname}-%{version}.tar.gz -BuildRequires: %{python_module devel} +# PATCH-FIX-UPSTREAM pytest-staticmethod.patch gh#pytest-dev/pytest#9637 mc...@suse.com +# workaround for the problem with pytest 7.0 +Patch0: pytest-staticmethod.patch +BuildRequires: %{python_module pip} BuildRequires: %{python_module protobuf >= 3.12.0} BuildRequires: %{python_module setuptools} +BuildRequires: %{python_module wheel} BuildRequires: python-rpm-macros # SECTION test requirements %if %{with test} @@ -57,7 +61,7 @@ that largely behave like native Python types. %prep -%setup -q -n %{modname}-%{version} +%autosetup -p1 -n %{modname}-%{version} %build %python_build @@ -70,14 +74,16 @@ %check %if %{with test} -%pytest +# gh#googleapis/proto-plus-python#311 +%pytest -k 'not (test_fields_mitigate_collision or test_dir or test_dir_message_base)' %endif %if !%{with test} %files %{python_files} %license LICENSE %doc README.rst -%{python_sitelib}/* +%{python_sitelib}/proto +%{python_sitelib}/proto_plus-%{version}*-info %endif %changelog ++++++ proto-plus-1.19.9.tar.gz -> proto-plus-1.20.3.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/proto-plus-1.19.9/PKG-INFO new/proto-plus-1.20.3/PKG-INFO --- old/proto-plus-1.19.9/PKG-INFO 2022-01-25 23:48:13.936669800 +0100 +++ new/proto-plus-1.20.3/PKG-INFO 2022-02-18 04:21:25.574449800 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: proto-plus -Version: 1.19.9 +Version: 1.20.3 Summary: Beautiful, Pythonic protocol buffers. Home-page: https://github.com/googleapis/proto-plus-python.git Author: Google LLC @@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 Classifier: Topic :: Software Development :: Code Generators Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/proto-plus-1.19.9/proto/message.py new/proto-plus-1.20.3/proto/message.py --- old/proto-plus-1.19.9/proto/message.py 2022-01-25 23:48:06.000000000 +0100 +++ new/proto-plus-1.20.3/proto/message.py 2022-02-18 04:21:16.000000000 +0100 @@ -273,6 +273,30 @@ def meta(cls): return cls._meta + def __dir__(self): + try: + names = set(dir(type)) + names.update( + ( + "meta", + "pb", + "wrap", + "serialize", + "deserialize", + "to_json", + "from_json", + "to_dict", + "copy_from", + ) + ) + desc = self.pb().DESCRIPTOR + names.update(t.name for t in desc.nested_types) + names.update(e.name for e in desc.enum_types) + + return names + except AttributeError: + return dir(type) + def pb(cls, obj=None, *, coerce: bool = False): """Return the underlying protobuf Message class or instance. @@ -503,9 +527,8 @@ # coerced. marshal = self._meta.marshal for key, value in mapping.items(): - try: - pb_type = self._meta.fields[key].pb_type - except KeyError: + (key, pb_type) = self._get_pb_type_from_key(key) + if pb_type is None: if ignore_unknown_fields: continue @@ -513,13 +536,86 @@ "Unknown field for {}: {}".format(self.__class__.__name__, key) ) - pb_value = marshal.to_proto(pb_type, value) + try: + pb_value = marshal.to_proto(pb_type, value) + except ValueError: + # Underscores may be appended to field names + # that collide with python or proto-plus keywords. + # In case a key only exists with a `_` suffix, coerce the key + # to include the `_` suffix. It's not possible to + # natively define the same field with a trailing underscore in protobuf. + # See related issue + # https://github.com/googleapis/python-api-core/issues/227 + if isinstance(value, dict): + keys_to_update = [ + item + for item in value + if not hasattr(pb_type, item) and hasattr(pb_type, f"{item}_") + ] + for item in keys_to_update: + value[f"{item}_"] = value.pop(item) + + pb_value = marshal.to_proto(pb_type, value) + if pb_value is not None: params[key] = pb_value # Create the internal protocol buffer. super().__setattr__("_pb", self._meta.pb(**params)) + def _get_pb_type_from_key(self, key): + """Given a key, return the corresponding pb_type. + + Args: + key(str): The name of the field. + + Returns: + A tuple containing a key and pb_type. The pb_type will be + the composite type of the field, or the primitive type if a primitive. + If no corresponding field exists, return None. + """ + + pb_type = None + + try: + pb_type = self._meta.fields[key].pb_type + except KeyError: + # Underscores may be appended to field names + # that collide with python or proto-plus keywords. + # In case a key only exists with a `_` suffix, coerce the key + # to include the `_` suffix. It's not possible to + # natively define the same field with a trailing underscore in protobuf. + # See related issue + # https://github.com/googleapis/python-api-core/issues/227 + if f"{key}_" in self._meta.fields: + key = f"{key}_" + pb_type = self._meta.fields[key].pb_type + + return (key, pb_type) + + def __dir__(self): + desc = type(self).pb().DESCRIPTOR + names = {f_name for f_name in self._meta.fields.keys()} + names.update(m.name for m in desc.nested_types) + names.update(e.name for e in desc.enum_types) + names.update(dir(object())) + # Can't think of a better way of determining + # the special methods than manually listing them. + names.update( + ( + "__bool__", + "__contains__", + "__dict__", + "__getattr__", + "__getstate__", + "__module__", + "__setstate__", + "__weakref__", + ) + ) + + return names + def __bool__(self): """Return True if any field is truthy, False otherwise.""" return any(k in self and getattr(self, k) for k in self._meta.fields.keys()) @@ -606,13 +702,14 @@ their Python equivalents. See the ``marshal`` module for more details. """ - try: - pb_type = self._meta.fields[key].pb_type - pb_value = getattr(self._pb, key) - marshal = self._meta.marshal - return marshal.to_python(pb_type, pb_value, absent=key not in self) - except KeyError as ex: - raise AttributeError(str(ex)) + (key, pb_type) = self._get_pb_type_from_key(key) + if pb_type is None: + raise AttributeError( + "Unknown field for {}: {}".format(self.__class__.__name__, key) + ) + pb_value = getattr(self._pb, key) + marshal = self._meta.marshal + return marshal.to_python(pb_type, pb_value, absent=key not in self) def __ne__(self, other): """Return True if the messages are unequal, False otherwise.""" @@ -630,7 +727,12 @@ if key[0] == "_": return super().__setattr__(key, value) marshal = self._meta.marshal - pb_type = self._meta.fields[key].pb_type + (key, pb_type) = self._get_pb_type_from_key(key) + if pb_type is None: + raise AttributeError( + "Unknown field for {}: {}".format(self.__class__.__name__, key) + ) + pb_value = marshal.to_proto(pb_type, value) # Clear the existing field. diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/proto-plus-1.19.9/proto_plus.egg-info/PKG-INFO new/proto-plus-1.20.3/proto_plus.egg-info/PKG-INFO --- old/proto-plus-1.19.9/proto_plus.egg-info/PKG-INFO 2022-01-25 23:48:13.000000000 +0100 +++ new/proto-plus-1.20.3/proto_plus.egg-info/PKG-INFO 2022-02-18 04:21:25.000000000 +0100 @@ -1,6 +1,6 @@ Metadata-Version: 2.1 Name: proto-plus -Version: 1.19.9 +Version: 1.20.3 Summary: Beautiful, Pythonic protocol buffers. Home-page: https://github.com/googleapis/proto-plus-python.git Author: Google LLC @@ -17,6 +17,7 @@ Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Programming Language :: Python :: 3.9 +Classifier: Programming Language :: Python :: 3.10 Classifier: Topic :: Software Development :: Code Generators Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.6 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/proto-plus-1.19.9/proto_plus.egg-info/SOURCES.txt new/proto-plus-1.20.3/proto_plus.egg-info/SOURCES.txt --- old/proto-plus-1.19.9/proto_plus.egg-info/SOURCES.txt 2022-01-25 23:48:13.000000000 +0100 +++ new/proto-plus-1.20.3/proto_plus.egg-info/SOURCES.txt 2022-02-18 04:21:25.000000000 +0100 @@ -45,6 +45,7 @@ tests/test_fields_int.py tests/test_fields_map_composite.py tests/test_fields_map_scalar.py +tests/test_fields_mitigate_collision.py tests/test_fields_oneof.py tests/test_fields_optional.py tests/test_fields_repeated_composite.py diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/proto-plus-1.19.9/setup.py new/proto-plus-1.20.3/setup.py --- old/proto-plus-1.19.9/setup.py 2022-01-25 23:48:06.000000000 +0100 +++ new/proto-plus-1.20.3/setup.py 2022-02-18 04:21:16.000000000 +0100 @@ -17,7 +17,7 @@ from setuptools import find_packages, setup -version = "1.19.9" +version = "1.20.3" PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__)) @@ -50,6 +50,7 @@ "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3.8", "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", "Topic :: Software Development :: Code Generators", "Topic :: Software Development :: Libraries :: Python Modules", ], diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/proto-plus-1.19.9/tests/test_datetime_helpers.py new/proto-plus-1.20.3/tests/test_datetime_helpers.py --- old/proto-plus-1.19.9/tests/test_datetime_helpers.py 2022-01-25 23:48:06.000000000 +0100 +++ new/proto-plus-1.20.3/tests/test_datetime_helpers.py 2022-02-18 04:21:16.000000000 +0100 @@ -173,7 +173,6 @@ assert stamp == expected -@staticmethod @pytest.mark.parametrize( "fractional, nanos", [ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/proto-plus-1.19.9/tests/test_fields_mitigate_collision.py new/proto-plus-1.20.3/tests/test_fields_mitigate_collision.py --- old/proto-plus-1.19.9/tests/test_fields_mitigate_collision.py 1970-01-01 01:00:00.000000000 +0100 +++ new/proto-plus-1.20.3/tests/test_fields_mitigate_collision.py 2022-02-18 04:21:16.000000000 +0100 @@ -0,0 +1,81 @@ +# Copyright 2022 Google LLC +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import proto +import pytest + +# Underscores may be appended to field names +# that collide with python or proto-plus keywords. +# In case a key only exists with a `_` suffix, coerce the key +# to include the `_` suffix. It's not possible to +# natively define the same field with a trailing underscore in protobuf. +# See related issue +# https://github.com/googleapis/python-api-core/issues/227 +def test_fields_mitigate_collision(): + class TestMessage(proto.Message): + spam_ = proto.Field(proto.STRING, number=1) + eggs = proto.Field(proto.STRING, number=2) + + class TextStream(proto.Message): + text_stream = proto.Field(TestMessage, number=1) + + obj = TestMessage(spam_="has_spam") + obj.eggs = "has_eggs" + assert obj.spam_ == "has_spam" + + # Test that `spam` is coerced to `spam_` + modified_obj = TestMessage({"spam": "has_spam", "eggs": "has_eggs"}) + assert modified_obj.spam_ == "has_spam" + + # Test get and set + modified_obj.spam = "no_spam" + assert modified_obj.spam == "no_spam" + + modified_obj.spam_ = "yes_spam" + assert modified_obj.spam_ == "yes_spam" + + modified_obj.spam = "maybe_spam" + assert modified_obj.spam_ == "maybe_spam" + + modified_obj.spam_ = "maybe_not_spam" + assert modified_obj.spam == "maybe_not_spam" + + # Try nested values + modified_obj = TextStream( + text_stream=TestMessage({"spam": "has_spam", "eggs": "has_eggs"}) + ) + assert modified_obj.text_stream.spam_ == "has_spam" + + # Test get and set for nested values + modified_obj.text_stream.spam = "no_spam" + assert modified_obj.text_stream.spam == "no_spam" + + modified_obj.text_stream.spam_ = "yes_spam" + assert modified_obj.text_stream.spam_ == "yes_spam" + + modified_obj.text_stream.spam = "maybe_spam" + assert modified_obj.text_stream.spam_ == "maybe_spam" + + modified_obj.text_stream.spam_ = "maybe_not_spam" + assert modified_obj.text_stream.spam == "maybe_not_spam" + + with pytest.raises(AttributeError): + assert modified_obj.text_stream.attribute_does_not_exist == "n/a" + + with pytest.raises(AttributeError): + modified_obj.text_stream.attribute_does_not_exist = "n/a" + + # Try using dict + modified_obj = TextStream(text_stream={"spam": "has_spam", "eggs": "has_eggs"}) + assert modified_obj.text_stream.spam_ == "has_spam" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/proto-plus-1.19.9/tests/test_message.py new/proto-plus-1.20.3/tests/test_message.py --- old/proto-plus-1.19.9/tests/test_message.py 2022-01-25 23:48:06.000000000 +0100 +++ new/proto-plus-1.20.3/tests/test_message.py 2022-02-18 04:21:16.000000000 +0100 @@ -346,3 +346,76 @@ with pytest.raises(TypeError): Mollusc.Squid.copy_from(m.squid, (("mass_kg", 20))) + + +def test_dir(): + class Mollusc(proto.Message): + class Class(proto.Enum): + UNKNOWN = 0 + GASTROPOD = 1 + BIVALVE = 2 + CEPHALOPOD = 3 + + class Arm(proto.Message): + length_cm = proto.Field(proto.INT32, number=1) + + mass_kg = proto.Field(proto.INT32, number=1) + class_ = proto.Field(Class, number=2) + arms = proto.RepeatedField(Arm, number=3) + + expected = ( + { + # Fields and nested message and enum types + "arms", + "class_", + "mass_kg", + "Arm", + "Class", + } + | { + # Other methods and attributes + "__bool__", + "__contains__", + "__dict__", + "__getattr__", + "__getstate__", + "__module__", + "__setstate__", + "__weakref__", + } + | set(dir(object)) + ) # Gets the long tail of dunder methods and attributes. + + actual = set(dir(Mollusc())) + + # Check instance names + assert actual == expected + + # Check type names + expected = ( + set(dir(type)) + | { + # Class methods from the MessageMeta metaclass + "copy_from", + "deserialize", + "from_json", + "meta", + "pb", + "serialize", + "to_dict", + "to_json", + "wrap", + } + | { + # Nested message and enum types + "Arm", + "Class", + } + ) + + actual = set(dir(Mollusc)) + assert actual == expected + + +def test_dir_message_base(): + assert set(dir(proto.Message)) == set(dir(type)) ++++++ pytest-staticmethod.patch ++++++ --- proto/_file_info.py | 1 - 1 file changed, 1 deletion(-) --- a/proto/_file_info.py +++ b/proto/_file_info.py @@ -51,7 +51,6 @@ class _FileInfo( return descriptor - @staticmethod def proto_file_name(name): return "{0}.proto".format(name.replace(".", "/"))