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 2021-03-20 21:26:22
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-proto-plus (Old)
and /work/SRC/openSUSE:Factory/.python-proto-plus.new.2401 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "python-proto-plus"
Sat Mar 20 21:26:22 2021 rev:2 rq:880254 version:1.18.1
Changes:
--------
--- /work/SRC/openSUSE:Factory/python-proto-plus/python-proto-plus.changes
2021-01-06 19:57:29.521216993 +0100
+++
/work/SRC/openSUSE:Factory/.python-proto-plus.new.2401/python-proto-plus.changes
2021-03-20 21:26:46.745233097 +0100
@@ -1,0 +2,37 @@
+Sat Mar 20 12:24:03 UTC 2021 - Matthias Fehring <[email protected]>
+
+- update to 1.18.1
+ * Add arm64 support for PY3.6 (gh#googleapis/proto-plus-python#219)
+- from 1.18.0
+ * add copy_from method for field assignment
+ (gh#googleapis/proto-plus-python#512)
+
+-------------------------------------------------------------------
+Mon Mar 15 17:22:01 UTC 2021 - Matthias Fehring <[email protected]>
+
+- update to 1.17.0
+ * add preserving_proto_field_name to to_json
(gh#googleapis/proto-plus-python#213)
+- from 1.16.0
+ * add preserving_proto_field_name passthrough in MessageMeta.to_dict
+ (gh#googleapis/proto-plus-python#211)
+- from 1.15.0
+ * allow_alias fro enums (gh#googleapis/proto-plus-python#207)
+- from 1.14.3
+ * adding enums to a repeated field does not raise a TypeError
+ (gh#googleapis/proto-plus-python#202)
+- from 1.14.2
+ * use the correct environment for uploading to pypi
+- from 1.14.1
+ * install the wheel dependency
+- from 1.14.0
+ * Features
+ + Pypi publish ghub actions (gh#googleapis/proto-plus-python#189)
+ * Bug Fixes
+ * proper setitem and insert for RepeatedComposite
+ (gh#googleapis/proto-plus-python#178)
+ * proper native marshal for repeated enumeration fields
+ (gh#googleapis/proto-plus-python#180)
+- from 1.13.1
+ * update docstring to match type hint (gh#googleapis/proto-plus-python#172)
+
+-------------------------------------------------------------------
Old:
----
proto-plus-1.13.0.tar.gz
New:
----
proto-plus-1.18.1.tar.gz
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Other differences:
------------------
++++++ python-proto-plus.spec ++++++
--- /var/tmp/diff_new_pack.vGEh1N/_old 2021-03-20 21:26:47.237233673 +0100
+++ /var/tmp/diff_new_pack.vGEh1N/_new 2021-03-20 21:26:47.237233673 +0100
@@ -20,7 +20,7 @@
%define skip_python2 1
%define modname proto-plus
Name: python-proto-plus
-Version: 1.13.0
+Version: 1.18.1
Release: 0
Summary: Pythonic Protocol Buffers
License: Apache-2.0
++++++ proto-plus-1.13.0.tar.gz -> proto-plus-1.18.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/PKG-INFO
new/proto-plus-1.18.1/PKG-INFO
--- old/proto-plus-1.13.0/PKG-INFO 2020-12-07 19:07:38.340301500 +0100
+++ new/proto-plus-1.18.1/PKG-INFO 2021-03-19 23:17:52.886574700 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: proto-plus
-Version: 1.13.0
+Version: 1.18.1
Summary: Beautiful, Pythonic protocol buffers.
Home-page: https://github.com/googleapis/proto-plus-python.git
Author: Google LLC
@@ -9,7 +9,7 @@
Description: Proto Plus for Python
=====================
- |pypi| |release level| |ci| |docs| |codecov|
+ |pypi| |release level| |docs| |codecov|
Beautiful, Pythonic protocol buffers.
@@ -34,8 +34,6 @@
:target: https://cloud.google.com/terms/launch-stages
.. |docs| image::
https://readthedocs.org/projects/proto-plus-python/badge/?version=latest
:target: https://proto-plus-python.readthedocs.io/en/latest/
- .. |ci| image::
https://circleci.com/gh/googleapis/proto-plus-python.svg?style=shield
- :target: https://circleci.com/gh/googleapis/proto-plus-python
.. |codecov| image::
https://codecov.io/gh/googleapis/proto-plus-python/graph/badge.svg
:target: https://codecov.io/gh/googleapis/proto-plus-python
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/README.rst
new/proto-plus-1.18.1/README.rst
--- old/proto-plus-1.13.0/README.rst 2020-12-07 19:07:31.000000000 +0100
+++ new/proto-plus-1.18.1/README.rst 2021-03-19 23:17:44.000000000 +0100
@@ -1,7 +1,7 @@
Proto Plus for Python
=====================
-|pypi| |release level| |ci| |docs| |codecov|
+|pypi| |release level| |docs| |codecov|
Beautiful, Pythonic protocol buffers.
@@ -26,7 +26,5 @@
:target: https://cloud.google.com/terms/launch-stages
.. |docs| image::
https://readthedocs.org/projects/proto-plus-python/badge/?version=latest
:target: https://proto-plus-python.readthedocs.io/en/latest/
-.. |ci| image::
https://circleci.com/gh/googleapis/proto-plus-python.svg?style=shield
- :target: https://circleci.com/gh/googleapis/proto-plus-python
.. |codecov| image::
https://codecov.io/gh/googleapis/proto-plus-python/graph/badge.svg
:target: https://codecov.io/gh/googleapis/proto-plus-python
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/proto/enums.py
new/proto-plus-1.18.1/proto/enums.py
--- old/proto-plus-1.13.0/proto/enums.py 2020-12-07 19:07:31.000000000
+0100
+++ new/proto-plus-1.18.1/proto/enums.py 2021-03-19 23:17:44.000000000
+0100
@@ -47,6 +47,21 @@
filename = _file_info._FileInfo.proto_file_name(
attrs.get("__module__", name.lower())
)
+
+ # Retrieve any enum options.
+ # We expect something that looks like an EnumOptions message,
+ # either an actual instance or a dict-like representation.
+ pb_options = "_pb_options"
+ opts = attrs.pop(pb_options, {})
+ # This is the only portable way to remove the _pb_options name
+ # from the enum attrs.
+ # In 3.7 onwards, we can define an _ignore_ attribute and do some
+ # mucking around with that.
+ if pb_options in attrs._member_names:
+ idx = attrs._member_names.index(pb_options)
+ attrs._member_names.pop(idx)
+
+ # Make the descriptor.
enum_desc = descriptor_pb2.EnumDescriptorProto(
name=name,
# Note: the superclass ctor removes the variants, so get them now.
@@ -60,6 +75,7 @@
),
key=lambda v: v.number,
),
+ options=opts,
)
file_info = _file_info._FileInfo.maybe_add_descriptor(filename,
package)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/proto-plus-1.13.0/proto/marshal/collections/repeated.py
new/proto-plus-1.18.1/proto/marshal/collections/repeated.py
--- old/proto-plus-1.13.0/proto/marshal/collections/repeated.py 2020-12-07
19:07:31.000000000 +0100
+++ new/proto-plus-1.18.1/proto/marshal/collections/repeated.py 2021-03-19
23:17:44.000000000 +0100
@@ -25,7 +25,7 @@
modify the underlying field container directly.
"""
- def __init__(self, sequence, *, marshal):
+ def __init__(self, sequence, *, marshal, proto_type=None):
"""Initialize a wrapper around a protobuf repeated field.
Args:
@@ -35,6 +35,7 @@
"""
self._pb = sequence
self._marshal = marshal
+ self._proto_type = proto_type
def __copy__(self):
"""Copy this object and return the copy."""
@@ -61,7 +62,7 @@
return not self == other
def __repr__(self):
- return repr(self.pb)
+ return repr([*self])
def __setitem__(self, key, value):
self.pb[key] = value
@@ -89,6 +90,11 @@
@cached_property
def _pb_type(self):
"""Return the protocol buffer type for this sequence."""
+ # Provide the marshal-given proto_type, if any.
+ # Used for RepeatedComposite of Enum.
+ if self._proto_type is not None:
+ return self._proto_type
+
# There is no public-interface mechanism to determine the type
# of what should go in the list (and the C implementation seems to
# have no exposed mechanism at all).
@@ -113,22 +119,60 @@
return self._marshal.to_python(self._pb_type, self.pb[key])
def __setitem__(self, key, value):
- pb_value = self._marshal.to_proto(self._pb_type, value, strict=True)
+ # The underlying protocol buffer does not define __setitem__, so we
+ # have to implement all the operations on our own.
- # Protocol buffers does not define a useful __setitem__, so we
- # have to pop everything after this point off the list and reload it.
- after = [pb_value]
- while self.pb[key:]:
- after.append(self.pb.pop(key))
- self.pb.extend(after)
+ # If ``key`` is an integer, as in list[index] = value:
+ if isinstance(key, int):
+ if -len(self) <= key < len(self):
+ self.pop(key) # Delete the old item.
+ self.insert(key, value) # Insert the new item in its place.
+ else:
+ raise IndexError("list assignment index out of range")
+
+ # If ``key`` is a slice object, as in list[start:stop:step] = [values]:
+ elif isinstance(key, slice):
+ start, stop, step = key.indices(len(self))
+
+ if not isinstance(value, collections.abc.Iterable):
+ raise TypeError("can only assign an iterable")
+
+ if step == 1: # Is not an extended slice.
+ # Assign all the new values to the sliced part, replacing the
+ # old values, if any, and unconditionally inserting those
+ # values whose indices already exceed the slice length.
+ for index, item in enumerate(value):
+ if start + index < stop:
+ self.pop(start + index)
+ self.insert(start + index, item)
+
+ # If there are less values than the length of the slice, remove
+ # the remaining elements so that the slice adapts to the
+ # newly provided values.
+ for _ in range(stop - start - len(value)):
+ self.pop(start + len(value))
+
+ else: # Is an extended slice.
+ indices = range(start, stop, step)
+
+ if len(value) != len(indices): # XXX: Use PEP 572 on 3.8+
+ raise ValueError(
+ f"attempt to assign sequence of size "
+ f"{len(value)} to extended slice of size "
+ f"{len(indices)}"
+ )
+
+ # Assign each value to its index, calling this function again
+ # with individual integer indexes that get processed above.
+ for index, item in zip(indices, value):
+ self[index] = item
+
+ else:
+ raise TypeError(
+ f"list indices must be integers or slices, not
{type(key).__name__}"
+ )
def insert(self, index: int, value):
"""Insert ``value`` in the sequence before ``index``."""
- pb_value = self._marshal.to_proto(self._pb_type, value, strict=True)
-
- # Protocol buffers does not define a useful insert, so we have
- # to pop everything after this point off the list and reload it.
- after = [pb_value]
- while self.pb[index:]:
- after.append(self.pb.pop(index))
- self.pb.extend(after)
+ pb_value = self._marshal.to_proto(self._pb_type, value)
+ self.pb.insert(index, pb_value)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/proto/marshal/marshal.py
new/proto-plus-1.18.1/proto/marshal/marshal.py
--- old/proto-plus-1.13.0/proto/marshal/marshal.py 2020-12-07
19:07:31.000000000 +0100
+++ new/proto-plus-1.18.1/proto/marshal/marshal.py 2021-03-19
23:17:44.000000000 +0100
@@ -157,7 +157,10 @@
if value_type in compat.repeated_composite_types:
return RepeatedComposite(value, marshal=self)
if value_type in compat.repeated_scalar_types:
- return Repeated(value, marshal=self)
+ if isinstance(proto_type, type):
+ return RepeatedComposite(value, marshal=self,
proto_type=proto_type)
+ else:
+ return Repeated(value, marshal=self)
# Same thing for maps of messages.
if value_type in compat.map_composite_types:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/proto/message.py
new/proto-plus-1.18.1/proto/message.py
--- old/proto-plus-1.13.0/proto/message.py 2020-12-07 19:07:31.000000000
+0100
+++ new/proto-plus-1.18.1/proto/message.py 2021-03-19 23:17:44.000000000
+0100
@@ -300,7 +300,7 @@
"""
# Optimized fast path.
instance = cls.__new__(cls)
- instance.__dict__["_pb"] = pb
+ super(cls, instance).__setattr__("_pb", pb)
return instance
def serialize(cls, instance) -> bytes:
@@ -332,7 +332,8 @@
instance,
*,
use_integers_for_enums=True,
- including_default_value_fields=True
+ including_default_value_fields=True,
+ preserving_proto_field_name=False,
) -> str:
"""Given a message instance, serialize it to json
@@ -342,6 +343,9 @@
use_integers_for_enums (Optional(bool)): An option that determines
whether enum
values should be represented by strings (False) or integers
(True).
Default is True.
+ preserving_proto_field_name (Optional(bool)): An option that
+ determines whether field name representations preserve
+ proto case (snake_case) or use lowerCamelCase. Default is
False.
Returns:
str: The json string representation of the protocol buffer.
@@ -350,6 +354,7 @@
cls.pb(instance),
use_integers_for_enums=use_integers_for_enums,
including_default_value_fields=including_default_value_fields,
+ preserving_proto_field_name=preserving_proto_field_name,
)
def from_json(cls, payload, *, ignore_unknown_fields=False) -> "Message":
@@ -369,7 +374,9 @@
Parse(payload, instance._pb,
ignore_unknown_fields=ignore_unknown_fields)
return instance
- def to_dict(cls, instance, *, use_integers_for_enums=True) -> "Message":
+ def to_dict(
+ cls, instance, *, use_integers_for_enums=True,
preserving_proto_field_name=True
+ ) -> "Message":
"""Given a message instance, return its representation as a python
dict.
Args:
@@ -378,6 +385,9 @@
use_integers_for_enums (Optional(bool)): An option that determines
whether enum
values should be represented by strings (False) or integers
(True).
Default is True.
+ preserving_proto_field_name (Optional(bool)): An option that
+ determines whether field name representations preserve
+ proto case (snake_case) or use lowerCamelCase. Default is True.
Returns:
dict: A representation of the protocol buffer using pythonic data
structures.
@@ -387,10 +397,40 @@
return MessageToDict(
cls.pb(instance),
including_default_value_fields=True,
- preserving_proto_field_name=True,
+ preserving_proto_field_name=preserving_proto_field_name,
use_integers_for_enums=use_integers_for_enums,
)
+ def copy_from(cls, instance, other):
+ """Equivalent for protobuf.Message.CopyFrom
+
+ Args:
+ instance: An instance of this message type
+ other: (Union[dict, ~.Message):
+ A dictionary or message to reinitialize the values for this
message.
+ """
+ if isinstance(other, cls):
+ # Just want the underlying proto.
+ other = Message.pb(other)
+ elif isinstance(other, cls.pb()):
+ # Don't need to do anything.
+ pass
+ elif isinstance(other, collections.abc.Mapping):
+ # Coerce into a proto
+ other = cls._meta.pb(**other)
+ else:
+ raise TypeError(
+ "invalid argument type to copy to {}: {}".format(
+ cls.__name__, other.__class__.__name__
+ )
+ )
+
+ # Note: we can't just run self.__init__ because this may be a message
field
+ # for a higher order proto; the memory layout for protos is NOT LIKE
the
+ # python memory model. We cannot rely on just setting things by
reference.
+ # Non-trivial complexity is (partially) hidden by the protobuf runtime.
+ cls.pb(instance).CopyFrom(other)
+
class Message(metaclass=MessageMeta):
"""The abstract base class for a message.
@@ -414,7 +454,7 @@
if mapping is None:
if not kwargs:
# Special fast path for empty construction.
- self.__dict__["_pb"] = self._meta.pb()
+ super().__setattr__("_pb", self._meta.pb())
return
mapping = kwargs
@@ -426,11 +466,11 @@
#
# The `wrap` method on the metaclass is the public API for taking
# ownership of the passed in protobuf objet.
- mapping = copy.copy(mapping)
+ mapping = copy.deepcopy(mapping)
if kwargs:
mapping.MergeFrom(self._meta.pb(**kwargs))
- self.__dict__["_pb"] = mapping
+ super().__setattr__("_pb", mapping)
return
elif isinstance(mapping, type(self)):
# Just use the above logic on mapping's underlying pb.
@@ -468,7 +508,7 @@
params[key] = pb_value
# Create the internal protocol buffer.
- self.__dict__["_pb"] = self._meta.pb(**params)
+ super().__setattr__("_pb", self._meta.pb(**params))
def __bool__(self):
"""Return True if any field is truthy, False otherwise."""
@@ -615,7 +655,7 @@
package: str,
full_name: str,
marshal: Marshal,
- options: descriptor_pb2.MessageOptions
+ options: descriptor_pb2.MessageOptions,
) -> None:
self.package = package
self.full_name = full_name
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/proto/modules.py
new/proto-plus-1.18.1/proto/modules.py
--- old/proto-plus-1.13.0/proto/modules.py 2020-12-07 19:07:31.000000000
+0100
+++ new/proto-plus-1.18.1/proto/modules.py 2021-03-19 23:17:44.000000000
+0100
@@ -33,7 +33,7 @@
package (str): The proto package name.
marshal (str): The name of the marshal to use. It is recommended
to use one marshal per Python library (e.g. package on PyPI).
- manifest (Tuple[str]): A tuple of classes to be created. Setting
+ manifest (Set[str]): A set of messages and enums to be created. Setting
this adds a slight efficiency in piecing together proto
descriptors under the hood.
"""
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/proto_plus.egg-info/PKG-INFO
new/proto-plus-1.18.1/proto_plus.egg-info/PKG-INFO
--- old/proto-plus-1.13.0/proto_plus.egg-info/PKG-INFO 2020-12-07
19:07:38.000000000 +0100
+++ new/proto-plus-1.18.1/proto_plus.egg-info/PKG-INFO 2021-03-19
23:17:52.000000000 +0100
@@ -1,6 +1,6 @@
Metadata-Version: 2.1
Name: proto-plus
-Version: 1.13.0
+Version: 1.18.1
Summary: Beautiful, Pythonic protocol buffers.
Home-page: https://github.com/googleapis/proto-plus-python.git
Author: Google LLC
@@ -9,7 +9,7 @@
Description: Proto Plus for Python
=====================
- |pypi| |release level| |ci| |docs| |codecov|
+ |pypi| |release level| |docs| |codecov|
Beautiful, Pythonic protocol buffers.
@@ -34,8 +34,6 @@
:target: https://cloud.google.com/terms/launch-stages
.. |docs| image::
https://readthedocs.org/projects/proto-plus-python/badge/?version=latest
:target: https://proto-plus-python.readthedocs.io/en/latest/
- .. |ci| image::
https://circleci.com/gh/googleapis/proto-plus-python.svg?style=shield
- :target: https://circleci.com/gh/googleapis/proto-plus-python
.. |codecov| image::
https://codecov.io/gh/googleapis/proto-plus-python/graph/badge.svg
:target: https://codecov.io/gh/googleapis/proto-plus-python
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/proto_plus.egg-info/SOURCES.txt
new/proto-plus-1.18.1/proto_plus.egg-info/SOURCES.txt
--- old/proto-plus-1.13.0/proto_plus.egg-info/SOURCES.txt 2020-12-07
19:07:38.000000000 +0100
+++ new/proto-plus-1.18.1/proto_plus.egg-info/SOURCES.txt 2021-03-19
23:17:52.000000000 +0100
@@ -50,6 +50,7 @@
tests/test_file_info_salting_with_manifest.py
tests/test_json.py
tests/test_marshal_register.py
+tests/test_marshal_strict.py
tests/test_marshal_types_dates.py
tests/test_marshal_types_enum.py
tests/test_marshal_types_message.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/setup.py
new/proto-plus-1.18.1/setup.py
--- old/proto-plus-1.13.0/setup.py 2020-12-07 19:07:31.000000000 +0100
+++ new/proto-plus-1.18.1/setup.py 2021-03-19 23:17:44.000000000 +0100
@@ -17,7 +17,7 @@
from setuptools import find_packages, setup
-version = "1.13.0"
+version = "1.18.1"
PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__))
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/tests/test_fields_enum.py
new/proto-plus-1.18.1/tests/test_fields_enum.py
--- old/proto-plus-1.13.0/tests/test_fields_enum.py 2020-12-07
19:07:31.000000000 +0100
+++ new/proto-plus-1.18.1/tests/test_fields_enum.py 2021-03-19
23:17:44.000000000 +0100
@@ -12,7 +12,9 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+import os
import proto
+import pytest
import sys
@@ -353,3 +355,40 @@
t = Task(weekday="TUESDAY")
t2 = Task.deserialize(Task.serialize(t))
assert t == t2
+
+
+if os.environ.get("PROTOCOL_BUFFERS_PYTHON_IMPLEMENTATION", "python") == "cpp":
+ # This test only works, and is only relevant, with the cpp runtime.
+ # Python just doesn't give a care and lets it work anyway.
+ def test_enum_alias_bad():
+ # Certain enums may shadow the different enum monikers with the same
value.
+ # This is generally discouraged, and protobuf will object by default,
+ # but will explicitly allow this behavior if the enum is defined with
+ # the `allow_alias` option set.
+ with pytest.raises(TypeError):
+
+ # The wrapper message is a hack to avoid manifest wrangling to
+ # define the enum.
+ class BadMessage(proto.Message):
+ class BadEnum(proto.Enum):
+ UNKNOWN = 0
+ DEFAULT = 0
+
+ bad_dup_enum = proto.Field(proto.ENUM, number=1, enum=BadEnum)
+
+
+def test_enum_alias_good():
+ # Have to split good and bad enum alias into two tests so that the
generated
+ # file descriptor is properly created.
+ # For the python runtime, aliases are allowed by default, but we want to
+ # make sure that the options don't cause problems.
+ # For the cpp runtime, we need to verify that we can in fact define
aliases.
+ class GoodMessage(proto.Message):
+ class GoodEnum(proto.Enum):
+ _pb_options = {"allow_alias": True}
+ UNKNOWN = 0
+ DEFAULT = 0
+
+ good_dup_enum = proto.Field(proto.ENUM, number=1, enum=GoodEnum)
+
+ assert GoodMessage.GoodEnum.UNKNOWN == GoodMessage.GoodEnum.DEFAULT == 0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore'
old/proto-plus-1.13.0/tests/test_fields_repeated_composite.py
new/proto-plus-1.18.1/tests/test_fields_repeated_composite.py
--- old/proto-plus-1.13.0/tests/test_fields_repeated_composite.py
2020-12-07 19:07:31.000000000 +0100
+++ new/proto-plus-1.18.1/tests/test_fields_repeated_composite.py
2021-03-19 23:17:44.000000000 +0100
@@ -14,6 +14,7 @@
from datetime import datetime
from datetime import timezone
+from enum import Enum
import pytest
@@ -95,6 +96,17 @@
assert foo.timestamps[2].hour == 0
+def test_repeated_composite_enum():
+ class Foo(proto.Message):
+ class Bar(proto.Enum):
+ BAZ = 0
+
+ bars = proto.RepeatedField(Bar, number=1)
+
+ foo = Foo(bars=[Foo.Bar.BAZ])
+ assert isinstance(foo.bars[0], Enum)
+
+
def test_repeated_composite_outer_write():
class Foo(proto.Message):
bar = proto.Field(proto.INT32, number=1)
@@ -153,7 +165,7 @@
assert baz.foos[1].bar == 48
-def test_repeated_composite_set():
+def test_repeated_composite_set_index():
class Foo(proto.Message):
bar = proto.Field(proto.INT32, number=1)
@@ -164,9 +176,101 @@
baz.foos[1] = Foo(bar=55)
assert baz.foos[0].bar == 96
assert baz.foos[1].bar == 55
+ assert len(baz.foos) == 2
+
+
+def test_repeated_composite_set_index_error():
+ class Foo(proto.Message):
+ bar = proto.Field(proto.INT32, number=1)
+
+ class Baz(proto.Message):
+ foos = proto.RepeatedField(proto.MESSAGE, message=Foo, number=1)
+
+ baz = Baz(foos=[])
+ with pytest.raises(IndexError):
+ baz.foos[0] = Foo(bar=55)
+
+
+def test_repeated_composite_set_slice_less():
+ class Foo(proto.Message):
+ bar = proto.Field(proto.INT32, number=1)
+
+ class Baz(proto.Message):
+ foos = proto.RepeatedField(proto.MESSAGE, message=Foo, number=1)
+
+ baz = Baz(foos=[{"bar": 96}, {"bar": 48}, {"bar": 24}])
+ baz.foos[:2] = [{"bar": 12}]
+ assert baz.foos[0].bar == 12
+ assert baz.foos[1].bar == 24
+ assert len(baz.foos) == 2
+
+
+def test_repeated_composite_set_slice_more():
+ class Foo(proto.Message):
+ bar = proto.Field(proto.INT32, number=1)
+
+ class Baz(proto.Message):
+ foos = proto.RepeatedField(proto.MESSAGE, message=Foo, number=1)
+
+ baz = Baz(foos=[{"bar": 12}])
+ baz.foos[:2] = [{"bar": 96}, {"bar": 48}, {"bar": 24}]
+ assert baz.foos[0].bar == 96
+ assert baz.foos[1].bar == 48
+ assert baz.foos[2].bar == 24
+ assert len(baz.foos) == 3
+
+
+def test_repeated_composite_set_slice_not_iterable():
+ class Foo(proto.Message):
+ bar = proto.Field(proto.INT32, number=1)
+
+ class Baz(proto.Message):
+ foos = proto.RepeatedField(proto.MESSAGE, message=Foo, number=1)
+
+ baz = Baz(foos=[])
+ with pytest.raises(TypeError):
+ baz.foos[:1] = None
+
+
+def test_repeated_composite_set_extended_slice():
+ class Foo(proto.Message):
+ bar = proto.Field(proto.INT32, number=1)
+
+ class Baz(proto.Message):
+ foos = proto.RepeatedField(proto.MESSAGE, message=Foo, number=1)
+
+ baz = Baz(foos=[{"bar": 96}, {"bar": 48}])
+ baz.foos[::-1] = [{"bar": 96}, {"bar": 48}]
+ assert baz.foos[0].bar == 48
+ assert baz.foos[1].bar == 96
+ assert len(baz.foos) == 2
+
+
+def test_repeated_composite_set_extended_slice_wrong_length():
+ class Foo(proto.Message):
+ bar = proto.Field(proto.INT32, number=1)
+
+ class Baz(proto.Message):
+ foos = proto.RepeatedField(proto.MESSAGE, message=Foo, number=1)
+
+ baz = Baz(foos=[{"bar": 96}])
+ with pytest.raises(ValueError):
+ baz.foos[::-1] = []
+
+
+def test_repeated_composite_set_wrong_key_type():
+ class Foo(proto.Message):
+ bar = proto.Field(proto.INT32, number=1)
+
+ class Baz(proto.Message):
+ foos = proto.RepeatedField(proto.MESSAGE, message=Foo, number=1)
+
+ baz = Baz(foos=[])
+ with pytest.raises(TypeError):
+ baz.foos[None] = Foo(bar=55)
-def test_repeated_composite_set_wrong_type():
+def test_repeated_composite_set_wrong_value_type():
class Foo(proto.Message):
bar = proto.Field(proto.INT32, number=1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/tests/test_json.py
new/proto-plus-1.18.1/tests/test_json.py
--- old/proto-plus-1.13.0/tests/test_json.py 2020-12-07 19:07:31.000000000
+0100
+++ new/proto-plus-1.18.1/tests/test_json.py 2021-03-19 23:17:44.000000000
+0100
@@ -136,3 +136,15 @@
# Don't permit unknown fields by default
with pytest.raises(ParseError):
o = Octopus.from_json(json_str)
+
+
+def test_json_snake_case():
+ class Squid(proto.Message):
+ mass_kg = proto.Field(proto.INT32, number=1)
+
+ json_str = '{\n "mass_kg": 20\n}'
+ s = Squid.from_json(json_str)
+
+ assert s.mass_kg == 20
+
+ assert Squid.to_json(s, preserving_proto_field_name=True) == json_str
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/tests/test_marshal_strict.py
new/proto-plus-1.18.1/tests/test_marshal_strict.py
--- old/proto-plus-1.13.0/tests/test_marshal_strict.py 1970-01-01
01:00:00.000000000 +0100
+++ new/proto-plus-1.18.1/tests/test_marshal_strict.py 2021-03-19
23:17:44.000000000 +0100
@@ -0,0 +1,24 @@
+# Copyright (C) 2021 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
+#
+# http://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
+from proto.marshal.marshal import BaseMarshal
+import pytest
+
+
+def test_strict_to_proto():
+ m = BaseMarshal()
+
+ with pytest.raises(TypeError):
+ m.to_proto(dict, None, strict=True)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/tests/test_marshal_types_enum.py
new/proto-plus-1.18.1/tests/test_marshal_types_enum.py
--- old/proto-plus-1.13.0/tests/test_marshal_types_enum.py 2020-12-07
19:07:31.000000000 +0100
+++ new/proto-plus-1.18.1/tests/test_marshal_types_enum.py 2021-03-19
23:17:44.000000000 +0100
@@ -58,3 +58,35 @@
with mock.patch.object(warnings, "warn") as warn:
assert enum_rule.to_python(4) == 4
warn.assert_called_once_with("Unrecognized Foo enum value: 4")
+
+
+def test_enum_append():
+ class Bivalve(proto.Enum):
+ CLAM = 0
+ OYSTER = 1
+
+ class MolluscContainer(proto.Message):
+ bivalves = proto.RepeatedField(proto.ENUM, number=1, enum=Bivalve,)
+
+ mc = MolluscContainer()
+ clam = Bivalve.CLAM
+ mc.bivalves.append(clam)
+ mc.bivalves.append(1)
+
+ assert mc.bivalves == [clam, Bivalve.OYSTER]
+
+
+def test_enum_map_insert():
+ class Bivalve(proto.Enum):
+ CLAM = 0
+ OYSTER = 1
+
+ class MolluscContainer(proto.Message):
+ bivalves = proto.MapField(proto.STRING, proto.ENUM, number=1,
enum=Bivalve,)
+
+ mc = MolluscContainer()
+ clam = Bivalve.CLAM
+ mc.bivalves["clam"] = clam
+ mc.bivalves["oyster"] = 1
+
+ assert mc.bivalves == {"clam": clam, "oyster": Bivalve.OYSTER}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn'
'--exclude=.svnignore' old/proto-plus-1.13.0/tests/test_message.py
new/proto-plus-1.18.1/tests/test_message.py
--- old/proto-plus-1.13.0/tests/test_message.py 2020-12-07 19:07:31.000000000
+0100
+++ new/proto-plus-1.18.1/tests/test_message.py 2021-03-19 23:17:44.000000000
+0100
@@ -317,3 +317,27 @@
s = Squid({"mass_kg": 20, "length_cm": 100}, ignore_unknown_fields=True)
assert not hasattr(s, "length_cm")
+
+
+def test_copy_from():
+ class Mollusc(proto.Message):
+ class Squid(proto.Message):
+ mass_kg = proto.Field(proto.INT32, number=1)
+
+ squid = proto.Field(Squid, number=1)
+
+ m = Mollusc()
+ s = Mollusc.Squid(mass_kg=20)
+ Mollusc.Squid.copy_from(m.squid, s)
+ assert m.squid is not s
+ assert m.squid == s
+
+ s.mass_kg = 30
+ Mollusc.Squid.copy_from(m.squid, Mollusc.Squid.pb(s))
+ assert m.squid == s
+
+ Mollusc.Squid.copy_from(m.squid, {"mass_kg": 10})
+ assert m.squid.mass_kg == 10
+
+ with pytest.raises(TypeError):
+ Mollusc.Squid.copy_from(m.squid, (("mass_kg", 20)))