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-09-09 18:28:18
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/python-proto-plus (Old)
 and      /work/SRC/openSUSE:Factory/.python-proto-plus.new.2083 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "python-proto-plus"

Fri Sep  9 18:28:18 2022 rev:7 rq:1002311 version:1.22.1

Changes:
--------
--- /work/SRC/openSUSE:Factory/python-proto-plus/python-proto-plus.changes      
2022-04-30 00:47:00.811029532 +0200
+++ 
/work/SRC/openSUSE:Factory/.python-proto-plus.new.2083/python-proto-plus.changes
    2022-09-09 18:29:59.685339965 +0200
@@ -1,0 +2,21 @@
+Fri Sep  9 12:39:29 UTC 2022 - John Paul Adrian Glaubitz 
<adrian.glaub...@suse.com>
+
+- Update to 1.22.1
+  * Add no-pretty print option (#336)
+- from version 1.22.0
+  * Add support for protobuf v4 (#327)
+  * Fix Timestamp, Duration and FieldMask marshaling
+    in REST transport (a2e7300)
+  * fixes bug in the test. (#332)
+- from version 1.20.6
+  * **deps:** allow protobuf < 5.0.0 (#324)
+  * fix changelog header to consistent size (#319)
+- from version 1.20.5
+  * **deps:** require google-api-core[grpc] >= 1.31.5 (1d13c41)
+  * **deps:** require protobuf>= 3.15.0, <4.0.0dev (#315)
+- from version 1.20.4
+  * default proto package name is the module name, not "" (#309)
+  * lookup attribute instead of performing a deepcopy (#226)
+- Update BuildRequires and Requires from setup.py
+
+-------------------------------------------------------------------

Old:
----
  proto-plus-1.20.3.tar.gz

New:
----
  proto-plus-1.22.1.tar.gz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ python-proto-plus.spec ++++++
--- /var/tmp/diff_new_pack.li6SYj/_old  2022-09-09 18:30:00.065340940 +0200
+++ /var/tmp/diff_new_pack.li6SYj/_new  2022-09-09 18:30:00.073340961 +0200
@@ -28,7 +28,7 @@
 %define skip_python2 1
 %define modname proto-plus
 Name:           python-proto-plus%{psuffix}
-Version:        1.20.3
+Version:        1.22.1
 Release:        0
 Summary:        Pythonic Protocol Buffers
 License:        Apache-2.0
@@ -38,19 +38,19 @@
 # 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 protobuf >= 3.19.0}
 BuildRequires:  %{python_module setuptools}
 BuildRequires:  %{python_module wheel}
 BuildRequires:  python-rpm-macros
 # SECTION test requirements
 %if %{with test}
-BuildRequires:  %{python_module google-api-core >= 1.22.2}
+BuildRequires:  %{python_module google-api-core >= 1.31.5}
 BuildRequires:  %{python_module proto-plus}
 BuildRequires:  %{python_module pytest}
 %endif
 # /SECTION
 BuildRequires:  fdupes
-Requires:       python-protobuf >= 3.12.0
+Requires:       python-protobuf >= 3.19.0
 BuildArch:      noarch
 %python_subpackages
 

++++++ proto-plus-1.20.3.tar.gz -> proto-plus-1.22.1.tar.gz ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/PKG-INFO 
new/proto-plus-1.22.1/PKG-INFO
--- old/proto-plus-1.20.3/PKG-INFO      2022-02-18 04:21:25.574449800 +0100
+++ new/proto-plus-1.22.1/PKG-INFO      2022-08-30 15:37:55.717580600 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: proto-plus
-Version: 1.20.3
+Version: 1.22.1
 Summary: Beautiful, Pythonic protocol buffers.
 Home-page: https://github.com/googleapis/proto-plus-python.git
 Author: Google LLC
@@ -27,7 +27,7 @@
 Proto Plus for Python
 =====================
 
-|pypi| |release level| |docs| |codecov|
+|pypi| |release level| |docs|
 
     Beautiful, Pythonic protocol buffers.
 
@@ -52,7 +52,3 @@
   :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/
-.. |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.20.3/README.rst 
new/proto-plus-1.22.1/README.rst
--- old/proto-plus-1.20.3/README.rst    2022-02-18 04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/README.rst    2022-08-30 15:37:47.000000000 +0200
@@ -1,7 +1,7 @@
 Proto Plus for Python
 =====================
 
-|pypi| |release level| |docs| |codecov|
+|pypi| |release level| |docs|
 
     Beautiful, Pythonic protocol buffers.
 
@@ -26,5 +26,3 @@
   :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/
-.. |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.20.3/proto/_file_info.py 
new/proto-plus-1.22.1/proto/_file_info.py
--- old/proto-plus-1.20.3/proto/_file_info.py   2022-02-18 04:21:16.000000000 
+0100
+++ new/proto-plus-1.22.1/proto/_file_info.py   2022-08-30 15:37:47.000000000 
+0200
@@ -40,7 +40,9 @@
         if not descriptor:
             descriptor = cls.registry[filename] = cls(
                 descriptor=descriptor_pb2.FileDescriptorProto(
-                    name=filename, package=package, syntax="proto3",
+                    name=filename,
+                    package=package,
+                    syntax="proto3",
                 ),
                 enums=collections.OrderedDict(),
                 messages=collections.OrderedDict(),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/_package_info.py 
new/proto-plus-1.22.1/proto/_package_info.py
--- old/proto-plus-1.20.3/proto/_package_info.py        2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/proto/_package_info.py        2022-08-30 
15:37:47.000000000 +0200
@@ -33,10 +33,17 @@
     # Pull a reference to the module where this class is being
     # declared.
     module = sys.modules.get(attrs.get("__module__"))
+    module_name = module.__name__ if hasattr(module, __name__) else ""
     proto_module = getattr(module, "__protobuf__", object())
 
     # A package should be present; get the marshal from there.
-    package = getattr(proto_module, "package", "")
+    # TODO: Revert to empty string as a package value after protobuf fix.
+    # When package is empty, upb based protobuf fails with an
+    # "TypeError: Couldn't build proto file into descriptor pool: invalid 
name: empty part ()' means"
+    # during an attempt to add to descriptor pool.
+    package = getattr(
+        proto_module, "package", module_name if module_name else 
"_default_package"
+    )
     marshal = Marshal(name=getattr(proto_module, "marshal", package))
 
     # Done; return the data.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/datetime_helpers.py 
new/proto-plus-1.22.1/proto/datetime_helpers.py
--- old/proto-plus-1.20.3/proto/datetime_helpers.py     2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/proto/datetime_helpers.py     2022-08-30 
15:37:47.000000000 +0200
@@ -171,7 +171,7 @@
             nanos = 0
         else:
             scale = 9 - len(fraction)
-            nanos = int(fraction) * (10 ** scale)
+            nanos = int(fraction) * (10**scale)
         return cls(
             bare.year,
             bare.month,
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/fields.py 
new/proto-plus-1.22.1/proto/fields.py
--- old/proto-plus-1.20.3/proto/fields.py       2022-02-18 04:21:16.000000000 
+0100
+++ new/proto-plus-1.22.1/proto/fields.py       2022-08-30 15:37:47.000000000 
+0200
@@ -78,7 +78,8 @@
             if isinstance(self.message, str):
                 if not self.message.startswith(self.package):
                     self.message = "{package}.{name}".format(
-                        package=self.package, name=self.message,
+                        package=self.package,
+                        name=self.message,
                     )
                 type_name = self.message
             elif self.message:
@@ -90,7 +91,8 @@
             elif isinstance(self.enum, str):
                 if not self.enum.startswith(self.package):
                     self.enum = "{package}.{name}".format(
-                        package=self.package, name=self.enum,
+                        package=self.package,
+                        name=self.enum,
                     )
                 type_name = self.enum
             elif self.enum:
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/marshal/collections/maps.py 
new/proto-plus-1.22.1/proto/marshal/collections/maps.py
--- old/proto-plus-1.20.3/proto/marshal/collections/maps.py     2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/proto/marshal/collections/maps.py     2022-08-30 
15:37:47.000000000 +0200
@@ -15,6 +15,7 @@
 import collections
 
 from proto.utils import cached_property
+from google.protobuf.message import Message
 
 
 class MapComposite(collections.abc.MutableMapping):
@@ -58,7 +59,6 @@
 
     def __setitem__(self, key, value):
         pb_value = self._marshal.to_proto(self._pb_type, value, strict=True)
-
         # Directly setting a key is not allowed; however, protocol buffers
         # is so permissive that querying for the existence of a key will in
         # of itself create it.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/proto-plus-1.20.3/proto/marshal/collections/repeated.py 
new/proto-plus-1.22.1/proto/marshal/collections/repeated.py
--- old/proto-plus-1.20.3/proto/marshal/collections/repeated.py 2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/proto/marshal/collections/repeated.py 2022-08-30 
15:37:47.000000000 +0200
@@ -104,7 +104,13 @@
         if len(self.pb) > 0:
             return type(self.pb[0])
 
-        # We have no members in the list.
+        # We have no members in the list, so we get the type from the 
attributes.
+        if hasattr(self.pb, "_message_descriptor") and hasattr(
+            self.pb._message_descriptor, "_concrete_class"
+        ):
+            return self.pb._message_descriptor._concrete_class
+
+        # Fallback logic in case attributes are not available
         # In order to get the type, we create a throw-away copy and add a
         # blank member to it.
         canary = copy.deepcopy(self.pb).add()
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/marshal/compat.py 
new/proto-plus-1.22.1/proto/marshal/compat.py
--- old/proto-plus-1.20.3/proto/marshal/compat.py       2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/proto/marshal/compat.py       2022-08-30 
15:37:47.000000000 +0200
@@ -20,14 +20,23 @@
 
 from google.protobuf.internal import containers
 
+# Import protobuf 4.xx first and fallback to earlier version
+# if not present.
 try:
-    from google.protobuf.pyext import _message
+    from google._upb import _message
 except ImportError:
     _message = None
 
+if not _message:
+    try:
+        from google.protobuf.pyext import _message
+    except ImportError:
+        _message = None
+
 repeated_composite_types = (containers.RepeatedCompositeFieldContainer,)
 repeated_scalar_types = (containers.RepeatedScalarFieldContainer,)
 map_composite_types = (containers.MessageMap,)
+
 if _message:
     repeated_composite_types += (_message.RepeatedCompositeContainer,)
     repeated_scalar_types += (_message.RepeatedScalarContainer,)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/marshal/marshal.py 
new/proto-plus-1.22.1/proto/marshal/marshal.py
--- old/proto-plus-1.20.3/proto/marshal/marshal.py      2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/proto/marshal/marshal.py      2022-08-30 
15:37:47.000000000 +0200
@@ -18,6 +18,7 @@
 from google.protobuf import message
 from google.protobuf import duration_pb2
 from google.protobuf import timestamp_pb2
+from google.protobuf import field_mask_pb2
 from google.protobuf import struct_pb2
 from google.protobuf import wrappers_pb2
 
@@ -25,11 +26,13 @@
 from proto.marshal.collections import MapComposite
 from proto.marshal.collections import Repeated
 from proto.marshal.collections import RepeatedComposite
+
 from proto.marshal.rules import bytes as pb_bytes
 from proto.marshal.rules import stringy_numbers
 from proto.marshal.rules import dates
 from proto.marshal.rules import struct
 from proto.marshal.rules import wrappers
+from proto.marshal.rules import field_mask
 from proto.primitives import ProtoType
 
 
@@ -125,6 +128,9 @@
         self.register(timestamp_pb2.Timestamp, dates.TimestampRule())
         self.register(duration_pb2.Duration, dates.DurationRule())
 
+        # Register FieldMask wrappers.
+        self.register(field_mask_pb2.FieldMask, field_mask.FieldMaskRule())
+
         # Register nullable primitive wrappers.
         self.register(wrappers_pb2.BoolValue, wrappers.BoolValueRule())
         self.register(wrappers_pb2.BytesValue, wrappers.BytesValueRule())
@@ -215,10 +221,10 @@
             raise TypeError(
                 "Parameter must be instance of the same class; "
                 "expected {expected}, got {got}".format(
-                    expected=proto_type.__name__, 
got=pb_value.__class__.__name__,
+                    expected=proto_type.__name__,
+                    got=pb_value.__class__.__name__,
                 ),
             )
-
         # Return the final value.
         return pb_value
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/marshal/rules/dates.py 
new/proto-plus-1.22.1/proto/marshal/rules/dates.py
--- old/proto-plus-1.20.3/proto/marshal/rules/dates.py  2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/proto/marshal/rules/dates.py  2022-08-30 
15:37:47.000000000 +0200
@@ -44,8 +44,13 @@
             return value.timestamp_pb()
         if isinstance(value, datetime):
             return timestamp_pb2.Timestamp(
-                seconds=int(value.timestamp()), nanos=value.microsecond * 1000,
+                seconds=int(value.timestamp()),
+                nanos=value.microsecond * 1000,
             )
+        if isinstance(value, str):
+            timestamp_value = timestamp_pb2.Timestamp()
+            timestamp_value.FromJsonString(value=value)
+            return timestamp_value
         return value
 
 
@@ -73,4 +78,8 @@
                 seconds=value.days * 86400 + value.seconds,
                 nanos=value.microseconds * 1000,
             )
+        if isinstance(value, str):
+            duration_value = duration_pb2.Duration()
+            duration_value.FromJsonString(value=value)
+            return duration_value
         return value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/marshal/rules/enums.py 
new/proto-plus-1.22.1/proto/marshal/rules/enums.py
--- old/proto-plus-1.20.3/proto/marshal/rules/enums.py  2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/proto/marshal/rules/enums.py  2022-08-30 
15:37:47.000000000 +0200
@@ -36,7 +36,8 @@
                 # the user realizes that an unexpected value came along.
                 warnings.warn(
                     "Unrecognized {name} enum value: {value}".format(
-                        name=self._enum.__name__, value=value,
+                        name=self._enum.__name__,
+                        value=value,
                     )
                 )
         return value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/marshal/rules/field_mask.py 
new/proto-plus-1.22.1/proto/marshal/rules/field_mask.py
--- old/proto-plus-1.20.3/proto/marshal/rules/field_mask.py     1970-01-01 
01:00:00.000000000 +0100
+++ new/proto-plus-1.22.1/proto/marshal/rules/field_mask.py     2022-08-30 
15:37:47.000000000 +0200
@@ -0,0 +1,36 @@
+# 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.
+
+from google.protobuf import field_mask_pb2
+
+
+class FieldMaskRule:
+    """A marshal between FieldMask and strings.
+
+    See https://github.com/googleapis/proto-plus-python/issues/333
+    and
+    https://developers.google.com/protocol-buffers/docs/proto3#json
+    for more details.
+    """
+
+    def to_python(self, value, *, absent: bool = None):
+        return value
+
+    def to_proto(self, value):
+        if isinstance(value, str):
+            field_mask_value = field_mask_pb2.FieldMask()
+            field_mask_value.FromJsonString(value=value)
+            return field_mask_value
+
+        return value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/marshal/rules/struct.py 
new/proto-plus-1.22.1/proto/marshal/rules/struct.py
--- old/proto-plus-1.20.3/proto/marshal/rules/struct.py 2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/proto/marshal/rules/struct.py 2022-08-30 
15:37:47.000000000 +0200
@@ -47,11 +47,15 @@
             return str(value.string_value)
         if kind == "struct_value":
             return self._marshal.to_python(
-                struct_pb2.Struct, value.struct_value, absent=False,
+                struct_pb2.Struct,
+                value.struct_value,
+                absent=False,
             )
         if kind == "list_value":
             return self._marshal.to_python(
-                struct_pb2.ListValue, value.list_value, absent=False,
+                struct_pb2.ListValue,
+                value.list_value,
+                absent=False,
             )
         # If more variants are ever added, we want to fail loudly
         # instead of tacitly returning None.
@@ -126,7 +130,9 @@
         if isinstance(value, struct_pb2.Struct):
             return value
         if isinstance(value, maps.MapComposite):
-            return struct_pb2.Struct(fields={k: v for k, v in 
value.pb.items()},)
+            return struct_pb2.Struct(
+                fields={k: v for k, v in value.pb.items()},
+            )
 
         # We got a dict (or something dict-like); convert it.
         answer = struct_pb2.Struct(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/message.py 
new/proto-plus-1.22.1/proto/message.py
--- old/proto-plus-1.20.3/proto/message.py      2022-02-18 04:21:16.000000000 
+0100
+++ new/proto-plus-1.22.1/proto/message.py      2022-08-30 15:37:47.000000000 
+0200
@@ -29,6 +29,10 @@
 from proto.fields import RepeatedField
 from proto.marshal import Marshal
 from proto.primitives import ProtoType
+from proto.utils import has_upb
+
+
+_upb = has_upb()  # Important to cache result here.
 
 
 class MessageMeta(type):
@@ -67,7 +71,9 @@
             # Determine the name of the entry message.
             msg_name = "{pascal_key}Entry".format(
                 pascal_key=re.sub(
-                    r"_\w", lambda m: m.group()[1:].upper(), key,
+                    r"_\w",
+                    lambda m: m.group()[1:].upper(),
+                    key,
                 ).replace(key[0], key[0].upper(), 1),
             )
 
@@ -83,20 +89,26 @@
                 {
                     "__module__": attrs.get("__module__", None),
                     "__qualname__": "{prefix}.{name}".format(
-                        prefix=attrs.get("__qualname__", name), name=msg_name,
+                        prefix=attrs.get("__qualname__", name),
+                        name=msg_name,
                     ),
                     "_pb_options": {"map_entry": True},
                 }
             )
             entry_attrs["key"] = Field(field.map_key_type, number=1)
             entry_attrs["value"] = Field(
-                field.proto_type, number=2, enum=field.enum, 
message=field.message,
+                field.proto_type,
+                number=2,
+                enum=field.enum,
+                message=field.message,
             )
             map_fields[msg_name] = MessageMeta(msg_name, (Message,), 
entry_attrs)
 
             # Create the repeated field for the entry message.
             map_fields[key] = RepeatedField(
-                ProtoType.MESSAGE, number=field.number, 
message=map_fields[msg_name],
+                ProtoType.MESSAGE,
+                number=field.number,
+                message=map_fields[msg_name],
             )
 
         # Add the new entries to the attrs
@@ -312,7 +324,13 @@
             if coerce:
                 obj = cls(obj)
             else:
-                raise TypeError("%r is not an instance of %s" % (obj, 
cls.__name__,))
+                raise TypeError(
+                    "%r is not an instance of %s"
+                    % (
+                        obj,
+                        cls.__name__,
+                    )
+                )
         return obj._pb
 
     def wrap(cls, pb):
@@ -358,6 +376,7 @@
         use_integers_for_enums=True,
         including_default_value_fields=True,
         preserving_proto_field_name=False,
+        indent=2,
     ) -> str:
         """Given a message instance, serialize it to json
 
@@ -370,6 +389,9 @@
             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.
+            indent: The JSON object will be pretty-printed with this indent 
level.
+                An indent level of 0 or negative will only insert newlines.
+                Pass None for the most compact representation without newlines.
 
         Returns:
             str: The json string representation of the protocol buffer.
@@ -379,6 +401,7 @@
             use_integers_for_enums=use_integers_for_enums,
             including_default_value_fields=including_default_value_fields,
             preserving_proto_field_name=preserving_proto_field_name,
+            indent=indent,
         )
 
     def from_json(cls, payload, *, ignore_unknown_fields=False) -> "Message":
@@ -478,7 +501,11 @@
     """
 
     def __init__(
-        self, mapping=None, *, ignore_unknown_fields=False, **kwargs,
+        self,
+        mapping=None,
+        *,
+        ignore_unknown_fields=False,
+        **kwargs,
     ):
         # We accept several things for `mapping`:
         #   * An instance of this class.
@@ -519,7 +546,10 @@
             # Sanity check: Did we get something not a map? Error if so.
             raise TypeError(
                 "Invalid constructor input for %s: %r"
-                % (self.__class__.__name__, mapping,)
+                % (
+                    self.__class__.__name__,
+                    mapping,
+                )
             )
 
         params = {}
@@ -547,11 +577,21 @@
                 # 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}_")
-                    ]
+                    if _upb:
+                        # In UPB, pb_type is MessageMeta which doesn't expose 
attrs like it used to in Python/CPP.
+                        keys_to_update = [
+                            item
+                            for item in value
+                            if item not in pb_type.DESCRIPTOR.fields_by_name
+                            and f"{item}_" in pb_type.DESCRIPTOR.fields_by_name
+                        ]
+                    else:
+                        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)
 
@@ -564,7 +604,7 @@
         super().__setattr__("_pb", self._meta.pb(**params))
 
     def _get_pb_type_from_key(self, key):
-        """Given a key, return the corresponding pb_type. 
+        """Given a key, return the corresponding pb_type.
 
         Args:
             key(str): The name of the field.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/modules.py 
new/proto-plus-1.22.1/proto/modules.py
--- old/proto-plus-1.20.3/proto/modules.py      2022-02-18 04:21:16.000000000 
+0100
+++ new/proto-plus-1.22.1/proto/modules.py      2022-08-30 15:37:47.000000000 
+0200
@@ -17,7 +17,8 @@
 
 
 _ProtoModule = collections.namedtuple(
-    "ProtoModule", ["package", "marshal", "manifest"],
+    "ProtoModule",
+    ["package", "marshal", "manifest"],
 )
 
 
@@ -39,7 +40,11 @@
     """
     if not marshal:
         marshal = package
-    return _ProtoModule(package=package, marshal=marshal, 
manifest=frozenset(manifest),)
+    return _ProtoModule(
+        package=package,
+        marshal=marshal,
+        manifest=frozenset(manifest),
+    )
 
 
 __all__ = ("define_module",)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto/utils.py 
new/proto-plus-1.22.1/proto/utils.py
--- old/proto-plus-1.20.3/proto/utils.py        2022-02-18 04:21:16.000000000 
+0100
+++ new/proto-plus-1.22.1/proto/utils.py        2022-08-30 15:37:47.000000000 
+0200
@@ -15,6 +15,16 @@
 import functools
 
 
+def has_upb():
+    try:
+        from google._upb import _message  # pylint: disable=unused-import
+
+        has_upb = True
+    except ImportError:
+        has_upb = False
+    return has_upb
+
+
 def cached_property(fx):
     """Make the callable into a cached property.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto_plus.egg-info/PKG-INFO 
new/proto-plus-1.22.1/proto_plus.egg-info/PKG-INFO
--- old/proto-plus-1.20.3/proto_plus.egg-info/PKG-INFO  2022-02-18 
04:21:25.000000000 +0100
+++ new/proto-plus-1.22.1/proto_plus.egg-info/PKG-INFO  2022-08-30 
15:37:55.000000000 +0200
@@ -1,6 +1,6 @@
 Metadata-Version: 2.1
 Name: proto-plus
-Version: 1.20.3
+Version: 1.22.1
 Summary: Beautiful, Pythonic protocol buffers.
 Home-page: https://github.com/googleapis/proto-plus-python.git
 Author: Google LLC
@@ -27,7 +27,7 @@
 Proto Plus for Python
 =====================
 
-|pypi| |release level| |docs| |codecov|
+|pypi| |release level| |docs|
 
     Beautiful, Pythonic protocol buffers.
 
@@ -52,7 +52,3 @@
   :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/
-.. |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.20.3/proto_plus.egg-info/SOURCES.txt 
new/proto-plus-1.22.1/proto_plus.egg-info/SOURCES.txt
--- old/proto-plus-1.20.3/proto_plus.egg-info/SOURCES.txt       2022-02-18 
04:21:25.000000000 +0100
+++ new/proto-plus-1.22.1/proto_plus.egg-info/SOURCES.txt       2022-08-30 
15:37:55.000000000 +0200
@@ -22,6 +22,7 @@
 proto/marshal/rules/bytes.py
 proto/marshal/rules/dates.py
 proto/marshal/rules/enums.py
+proto/marshal/rules/field_mask.py
 proto/marshal/rules/message.py
 proto/marshal/rules/stringy_numbers.py
 proto/marshal/rules/struct.py
@@ -54,6 +55,7 @@
 tests/test_file_info_salting.py
 tests/test_file_info_salting_with_manifest.py
 tests/test_json.py
+tests/test_marshal_field_mask.py
 tests/test_marshal_register.py
 tests/test_marshal_strict.py
 tests/test_marshal_stringy_numbers.py
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/proto_plus.egg-info/requires.txt 
new/proto-plus-1.22.1/proto_plus.egg-info/requires.txt
--- old/proto-plus-1.20.3/proto_plus.egg-info/requires.txt      2022-02-18 
04:21:25.000000000 +0100
+++ new/proto-plus-1.22.1/proto_plus.egg-info/requires.txt      2022-08-30 
15:37:55.000000000 +0200
@@ -1,4 +1,4 @@
-protobuf>=3.19.0
+protobuf<5.0.0dev,>=3.19.0
 
 [testing]
-google-api-core[grpc]>=1.22.2
+google-api-core[grpc]>=1.31.5
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/setup.py 
new/proto-plus-1.22.1/setup.py
--- old/proto-plus-1.20.3/setup.py      2022-02-18 04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/setup.py      2022-08-30 15:37:47.000000000 +0200
@@ -17,7 +17,7 @@
 
 from setuptools import find_packages, setup
 
-version = "1.20.3"
+version = "1.22.1"
 
 PACKAGE_ROOT = os.path.abspath(os.path.dirname(__file__))
 
@@ -36,8 +36,12 @@
     long_description=README,
     platforms="Posix; MacOS X",
     include_package_data=True,
-    install_requires=("protobuf >= 3.19.0",),
-    extras_require={"testing": ["google-api-core[grpc] >= 1.22.2",],},
+    install_requires=("protobuf >= 3.19.0, <5.0.0dev",),
+    extras_require={
+        "testing": [
+            "google-api-core[grpc] >= 1.31.5",
+        ],
+    },
     python_requires=">=3.6",
     classifiers=[
         "Development Status :: 5 - Production/Stable",
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/clam.py 
new/proto-plus-1.22.1/tests/clam.py
--- old/proto-plus-1.20.3/tests/clam.py 2022-02-18 04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/clam.py 2022-08-30 15:37:47.000000000 +0200
@@ -14,7 +14,13 @@
 
 import proto
 
-__protobuf__ = proto.module(package="ocean.clam.v1", manifest={"Clam", 
"Species",},)
+__protobuf__ = proto.module(
+    package="ocean.clam.v1",
+    manifest={
+        "Clam",
+        "Species",
+    },
+)
 
 
 class Species(proto.Enum):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/conftest.py 
new/proto-plus-1.22.1/tests/conftest.py
--- old/proto-plus-1.20.3/tests/conftest.py     2022-02-18 04:21:16.000000000 
+0100
+++ new/proto-plus-1.22.1/tests/conftest.py     2022-08-30 15:37:47.000000000 
+0200
@@ -23,6 +23,7 @@
 from proto._file_info import _FileInfo
 from proto.marshal import Marshal
 from proto.marshal import rules
+from proto.utils import has_upb
 
 
 def pytest_runtest_setup(item):
@@ -37,10 +38,14 @@
         mock.patch.object(symbol_database, "Default", return_value=sym_db),
     ]
     if descriptor_pool._USE_C_DESCRIPTORS:
-        from google.protobuf.pyext import _message
 
         item._mocks.append(
-            mock.patch("google.protobuf.pyext._message.default_pool", pool)
+            mock.patch(
+                "google._upb._message.default_pool"
+                if has_upb()
+                else "google.protobuf.pyext._message.default_pool",
+                pool,
+            )
         )
 
     [i.start() for i in item._mocks]
@@ -92,7 +97,9 @@
     """Create and register messages from the file descriptor."""
     for name, descriptor in iterable.items():
         new_msg = reflection.GeneratedProtocolMessageType(
-            name, (message.Message,), {"DESCRIPTOR": descriptor, "__module__": 
None},
+            name,
+            (message.Message,),
+            {"DESCRIPTOR": descriptor, "__module__": None},
         )
         sym_db.RegisterMessage(new_msg)
         setattr(scope, name, new_msg)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/enums_test.py 
new/proto-plus-1.22.1/tests/enums_test.py
--- old/proto-plus-1.20.3/tests/enums_test.py   2022-02-18 04:21:16.000000000 
+0100
+++ new/proto-plus-1.22.1/tests/enums_test.py   2022-08-30 15:37:47.000000000 
+0200
@@ -14,7 +14,12 @@
 
 import proto
 
-__protobuf__ = proto.module(package="test.proto", manifest={"Enums",},)
+__protobuf__ = proto.module(
+    package="test.proto",
+    manifest={
+        "Enums",
+    },
+)
 
 
 class OneEnum(proto.Enum):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/mollusc.py 
new/proto-plus-1.22.1/tests/mollusc.py
--- old/proto-plus-1.20.3/tests/mollusc.py      2022-02-18 04:21:16.000000000 
+0100
+++ new/proto-plus-1.22.1/tests/mollusc.py      2022-08-30 15:37:47.000000000 
+0200
@@ -15,7 +15,12 @@
 import proto
 import zone
 
-__protobuf__ = proto.module(package="ocean.mollusc.v1", manifest={"Mollusc",},)
+__protobuf__ = proto.module(
+    package="ocean.mollusc.v1",
+    manifest={
+        "Mollusc",
+    },
+)
 
 
 class Mollusc(proto.Message):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/test_fields_int.py 
new/proto-plus-1.22.1/tests/test_fields_int.py
--- old/proto-plus-1.20.3/tests/test_fields_int.py      2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_fields_int.py      2022-08-30 
15:37:47.000000000 +0200
@@ -65,12 +65,12 @@
         big = proto.Field(proto.INT64, number=2)
 
     foo = Foo()
-    foo.big = 2 ** 40
-    assert foo.big == 2 ** 40
+    foo.big = 2**40
+    assert foo.big == 2**40
     with pytest.raises(ValueError):
-        foo.small = 2 ** 40
+        foo.small = 2**40
     with pytest.raises(ValueError):
-        Foo(small=2 ** 40)
+        Foo(small=2**40)
 
 
 def test_int_unsigned():
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/test_fields_map_composite.py 
new/proto-plus-1.22.1/tests/test_fields_map_composite.py
--- old/proto-plus-1.20.3/tests/test_fields_map_composite.py    2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_fields_map_composite.py    2022-08-30 
15:37:47.000000000 +0200
@@ -22,7 +22,12 @@
         bar = proto.Field(proto.INT32, number=1)
 
     class Baz(proto.Message):
-        foos = proto.MapField(proto.STRING, proto.MESSAGE, number=1, 
message=Foo,)
+        foos = proto.MapField(
+            proto.STRING,
+            proto.MESSAGE,
+            number=1,
+            message=Foo,
+        )
 
     baz = Baz(foos={"i": Foo(bar=42), "j": Foo(bar=24)})
     assert len(baz.foos) == 2
@@ -36,7 +41,12 @@
         bar = proto.Field(proto.INT32, number=1)
 
     class Baz(proto.Message):
-        foos = proto.MapField(proto.STRING, proto.MESSAGE, number=1, 
message=Foo,)
+        foos = proto.MapField(
+            proto.STRING,
+            proto.MESSAGE,
+            number=1,
+            message=Foo,
+        )
 
     baz = Baz(foos={"i": {"bar": 42}, "j": {"bar": 24}})
     assert len(baz.foos) == 2
@@ -52,7 +62,12 @@
         bar = proto.Field(proto.INT32, number=1)
 
     class Baz(proto.Message):
-        foos = proto.MapField(proto.STRING, proto.MESSAGE, number=1, 
message=Foo,)
+        foos = proto.MapField(
+            proto.STRING,
+            proto.MESSAGE,
+            number=1,
+            message=Foo,
+        )
 
     baz = Baz()
     baz.foos["i"] = Foo(bar=42)
@@ -68,7 +83,12 @@
         bar = proto.Field(proto.INT32, number=1)
 
     class Baz(proto.Message):
-        foos = proto.MapField(proto.STRING, proto.MESSAGE, number=1, 
message=Foo,)
+        foos = proto.MapField(
+            proto.STRING,
+            proto.MESSAGE,
+            number=1,
+            message=Foo,
+        )
 
     baz = Baz()
     baz.foos["i"] = Foo()
@@ -82,7 +102,12 @@
         bar = proto.Field(proto.INT32, number=1)
 
     class Baz(proto.Message):
-        foos = proto.MapField(proto.STRING, proto.MESSAGE, number=1, 
message=Foo,)
+        foos = proto.MapField(
+            proto.STRING,
+            proto.MESSAGE,
+            number=1,
+            message=Foo,
+        )
 
     baz = Baz()
     baz.foos["i"] = Foo(bar=42)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/proto-plus-1.20.3/tests/test_fields_repeated_composite.py 
new/proto-plus-1.22.1/tests/test_fields_repeated_composite.py
--- old/proto-plus-1.20.3/tests/test_fields_repeated_composite.py       
2022-02-18 04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_fields_repeated_composite.py       
2022-08-30 15:37:47.000000000 +0200
@@ -35,6 +35,7 @@
     assert len(baz.foos) == 1
     assert baz.foos == baz.foos
     assert baz.foos[0].bar == 42
+    assert isinstance(baz.foos[0], Foo)
 
 
 def test_repeated_composite_equality():
@@ -75,7 +76,9 @@
 def test_repeated_composite_marshaled():
     class Foo(proto.Message):
         timestamps = proto.RepeatedField(
-            proto.MESSAGE, message=timestamp_pb2.Timestamp, number=1,
+            proto.MESSAGE,
+            message=timestamp_pb2.Timestamp,
+            number=1,
         )
 
     foo = Foo(
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/test_file_info_salting.py 
new/proto-plus-1.22.1/tests/test_file_info_salting.py
--- old/proto-plus-1.20.3/tests/test_file_info_salting.py       2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_file_info_salting.py       2022-08-30 
15:37:47.000000000 +0200
@@ -34,7 +34,9 @@
         filename,
         _file_info._FileInfo(
             descriptor=descriptor_pb2.FileDescriptorProto(
-                name=filename, package=package, syntax="proto3",
+                name=filename,
+                package=package,
+                syntax="proto3",
             ),
             enums=collections.OrderedDict(),
             messages=collections.OrderedDict(),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/proto-plus-1.20.3/tests/test_file_info_salting_with_manifest.py 
new/proto-plus-1.22.1/tests/test_file_info_salting_with_manifest.py
--- old/proto-plus-1.20.3/tests/test_file_info_salting_with_manifest.py 
2022-02-18 04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_file_info_salting_with_manifest.py 
2022-08-30 15:37:47.000000000 +0200
@@ -21,7 +21,10 @@
 from proto import _file_info, _package_info
 
 PACKAGE = "a.test.package.salting.with.manifest"
-__protobuf__ = proto.module(package=PACKAGE, manifest={"This", "That"},)
+__protobuf__ = proto.module(
+    package=PACKAGE,
+    manifest={"This", "That"},
+)
 
 
 class This(proto.Message):
@@ -49,7 +52,9 @@
         filename,
         _file_info._FileInfo(
             descriptor=descriptor_pb2.FileDescriptorProto(
-                name=filename, package=package, syntax="proto3",
+                name=filename,
+                package=package,
+                syntax="proto3",
             ),
             enums=collections.OrderedDict(),
             messages=collections.OrderedDict(),
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/test_json.py 
new/proto-plus-1.22.1/tests/test_json.py
--- old/proto-plus-1.20.3/tests/test_json.py    2022-02-18 04:21:16.000000000 
+0100
+++ new/proto-plus-1.22.1/tests/test_json.py    2022-08-30 15:37:47.000000000 
+0200
@@ -28,6 +28,16 @@
     assert json == '{"massKg":100}'
 
 
+def test_message_to_json_no_indent():
+    class Squid(proto.Message):
+        mass_kg = proto.Field(proto.INT32, number=1)
+        name = proto.Field(proto.STRING, number=2)
+
+    s = Squid(mass_kg=100, name="no_new_lines_squid")
+    json = Squid.to_json(s, indent=None)
+    assert json == '{"massKg": 100, "name": "no_new_lines_squid"}'
+
+
 def test_message_from_json():
     class Squid(proto.Message):
         mass_kg = proto.Field(proto.INT32, number=1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/test_marshal_field_mask.py 
new/proto-plus-1.22.1/tests/test_marshal_field_mask.py
--- old/proto-plus-1.20.3/tests/test_marshal_field_mask.py      1970-01-01 
01:00:00.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_marshal_field_mask.py      2022-08-30 
15:37:47.000000000 +0200
@@ -0,0 +1,100 @@
+# 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.
+
+from google.protobuf import field_mask_pb2
+
+import proto
+from proto.marshal.marshal import BaseMarshal
+
+
+def test_field_mask_read():
+    class Foo(proto.Message):
+        mask = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=field_mask_pb2.FieldMask,
+        )
+
+    foo = Foo(mask=field_mask_pb2.FieldMask(paths=["f.b.d", "f.c"]))
+
+    assert isinstance(foo.mask, field_mask_pb2.FieldMask)
+    assert foo.mask.paths == ["f.b.d", "f.c"]
+
+
+def test_field_mask_write_string():
+    class Foo(proto.Message):
+        mask = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=field_mask_pb2.FieldMask,
+        )
+
+    foo = Foo()
+    foo.mask = "f.b.d,f.c"
+
+    assert isinstance(foo.mask, field_mask_pb2.FieldMask)
+    assert foo.mask.paths == ["f.b.d", "f.c"]
+
+
+def test_field_mask_write_pb2():
+    class Foo(proto.Message):
+        mask = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=field_mask_pb2.FieldMask,
+        )
+
+    foo = Foo()
+    foo.mask = field_mask_pb2.FieldMask(paths=["f.b.d", "f.c"])
+
+    assert isinstance(foo.mask, field_mask_pb2.FieldMask)
+    assert foo.mask.paths == ["f.b.d", "f.c"]
+
+
+def test_field_mask_absence():
+    class Foo(proto.Message):
+        mask = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=field_mask_pb2.FieldMask,
+        )
+
+    foo = Foo()
+    assert not foo.mask.paths
+
+
+def test_timestamp_del():
+    class Foo(proto.Message):
+        mask = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=field_mask_pb2.FieldMask,
+        )
+
+    foo = Foo()
+    foo.mask = field_mask_pb2.FieldMask(paths=["f.b.d", "f.c"])
+
+    del foo.mask
+    assert not foo.mask.paths
+
+
+def test_timestamp_to_python_idempotent():
+    # This path can never run in the current configuration because proto
+    # values are the only thing ever saved, and `to_python` is a read method.
+    #
+    # However, we test idempotency for consistency with `to_proto` and
+    # general resiliency.
+    marshal = BaseMarshal()
+    py_value = "f.b.d,f.c"
+    assert marshal.to_python(field_mask_pb2.FieldMask, py_value) is py_value
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/test_marshal_types_dates.py 
new/proto-plus-1.22.1/tests/test_marshal_types_dates.py
--- old/proto-plus-1.20.3/tests/test_marshal_types_dates.py     2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_marshal_types_dates.py     2022-08-30 
15:37:47.000000000 +0200
@@ -28,7 +28,9 @@
 def test_timestamp_read():
     class Foo(proto.Message):
         event_time = proto.Field(
-            proto.MESSAGE, number=1, message=timestamp_pb2.Timestamp,
+            proto.MESSAGE,
+            number=1,
+            message=timestamp_pb2.Timestamp,
         )
 
     foo = Foo(event_time=timestamp_pb2.Timestamp(seconds=1335020400))
@@ -45,7 +47,9 @@
 def test_timestamp_write_init():
     class Foo(proto.Message):
         event_time = proto.Field(
-            proto.MESSAGE, number=1, message=timestamp_pb2.Timestamp,
+            proto.MESSAGE,
+            number=1,
+            message=timestamp_pb2.Timestamp,
         )
 
     foo = Foo(event_time=DatetimeWithNanoseconds(2012, 4, 21, 15, 
tzinfo=timezone.utc))
@@ -60,7 +64,9 @@
 def test_timestamp_write():
     class Foo(proto.Message):
         event_time = proto.Field(
-            proto.MESSAGE, number=1, message=timestamp_pb2.Timestamp,
+            proto.MESSAGE,
+            number=1,
+            message=timestamp_pb2.Timestamp,
         )
 
     foo = Foo()
@@ -77,7 +83,9 @@
 def test_timestamp_write_pb2():
     class Foo(proto.Message):
         event_time = proto.Field(
-            proto.MESSAGE, number=1, message=timestamp_pb2.Timestamp,
+            proto.MESSAGE,
+            number=1,
+            message=timestamp_pb2.Timestamp,
         )
 
     foo = Foo()
@@ -90,10 +98,30 @@
     assert Foo.pb(foo).event_time.seconds == 1335020400
 
 
+def test_timestamp_write_string():
+    class Foo(proto.Message):
+        event_time = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=timestamp_pb2.Timestamp,
+        )
+
+    foo = Foo()
+    foo.event_time = "2012-04-21T15:00:00Z"
+    assert isinstance(foo.event_time, DatetimeWithNanoseconds)
+    assert isinstance(Foo.pb(foo).event_time, timestamp_pb2.Timestamp)
+    assert foo.event_time.year == 2012
+    assert foo.event_time.month == 4
+    assert foo.event_time.hour == 15
+    assert Foo.pb(foo).event_time.seconds == 1335020400
+
+
 def test_timestamp_rmw_nanos():
     class Foo(proto.Message):
         event_time = proto.Field(
-            proto.MESSAGE, number=1, message=timestamp_pb2.Timestamp,
+            proto.MESSAGE,
+            number=1,
+            message=timestamp_pb2.Timestamp,
         )
 
     foo = Foo()
@@ -110,7 +138,9 @@
 def test_timestamp_absence():
     class Foo(proto.Message):
         event_time = proto.Field(
-            proto.MESSAGE, number=1, message=timestamp_pb2.Timestamp,
+            proto.MESSAGE,
+            number=1,
+            message=timestamp_pb2.Timestamp,
         )
 
     foo = Foo()
@@ -120,7 +150,9 @@
 def test_timestamp_del():
     class Foo(proto.Message):
         event_time = proto.Field(
-            proto.MESSAGE, number=1, message=timestamp_pb2.Timestamp,
+            proto.MESSAGE,
+            number=1,
+            message=timestamp_pb2.Timestamp,
         )
 
     foo = Foo(event_time=DatetimeWithNanoseconds(2012, 4, 21, 15, 
tzinfo=timezone.utc))
@@ -130,7 +162,11 @@
 
 def test_duration_read():
     class Foo(proto.Message):
-        ttl = proto.Field(proto.MESSAGE, number=1, 
message=duration_pb2.Duration,)
+        ttl = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=duration_pb2.Duration,
+        )
 
     foo = Foo(ttl=duration_pb2.Duration(seconds=60, nanos=1000))
     assert isinstance(foo.ttl, timedelta)
@@ -142,7 +178,11 @@
 
 def test_duration_write_init():
     class Foo(proto.Message):
-        ttl = proto.Field(proto.MESSAGE, number=1, 
message=duration_pb2.Duration,)
+        ttl = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=duration_pb2.Duration,
+        )
 
     foo = Foo(ttl=timedelta(days=2))
     assert isinstance(foo.ttl, timedelta)
@@ -155,7 +195,11 @@
 
 def test_duration_write():
     class Foo(proto.Message):
-        ttl = proto.Field(proto.MESSAGE, number=1, 
message=duration_pb2.Duration,)
+        ttl = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=duration_pb2.Duration,
+        )
 
     foo = Foo()
     foo.ttl = timedelta(seconds=120)
@@ -167,7 +211,11 @@
 
 def test_duration_write_pb2():
     class Foo(proto.Message):
-        ttl = proto.Field(proto.MESSAGE, number=1, 
message=duration_pb2.Duration,)
+        ttl = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=duration_pb2.Duration,
+        )
 
     foo = Foo()
     foo.ttl = duration_pb2.Duration(seconds=120)
@@ -177,9 +225,29 @@
     assert Foo.pb(foo).ttl.seconds == 120
 
 
+def test_duration_write_string():
+    class Foo(proto.Message):
+        ttl = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=duration_pb2.Duration,
+        )
+
+    foo = Foo()
+    foo.ttl = "120s"
+    assert isinstance(foo.ttl, timedelta)
+    assert isinstance(Foo.pb(foo).ttl, duration_pb2.Duration)
+    assert foo.ttl.seconds == 120
+    assert Foo.pb(foo).ttl.seconds == 120
+
+
 def test_duration_del():
     class Foo(proto.Message):
-        ttl = proto.Field(proto.MESSAGE, number=1, 
message=duration_pb2.Duration,)
+        ttl = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=duration_pb2.Duration,
+        )
 
     foo = Foo(ttl=timedelta(seconds=900))
     del foo.ttl
@@ -191,7 +259,11 @@
 
 def test_duration_nanos_rmw():
     class Foo(proto.Message):
-        ttl = proto.Field(proto.MESSAGE, number=1, 
message=duration_pb2.Duration,)
+        ttl = proto.Field(
+            proto.MESSAGE,
+            number=1,
+            message=duration_pb2.Duration,
+        )
 
     foo = Foo(ttl=timedelta(microseconds=50))
     assert foo.ttl.microseconds == 50
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/test_marshal_types_enum.py 
new/proto-plus-1.22.1/tests/test_marshal_types_enum.py
--- old/proto-plus-1.20.3/tests/test_marshal_types_enum.py      2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_marshal_types_enum.py      2022-08-30 
15:37:47.000000000 +0200
@@ -66,7 +66,11 @@
         OYSTER = 1
 
     class MolluscContainer(proto.Message):
-        bivalves = proto.RepeatedField(proto.ENUM, number=1, enum=Bivalve,)
+        bivalves = proto.RepeatedField(
+            proto.ENUM,
+            number=1,
+            enum=Bivalve,
+        )
 
     mc = MolluscContainer()
     clam = Bivalve.CLAM
@@ -82,11 +86,15 @@
         OYSTER = 1
 
     class MolluscContainer(proto.Message):
-        bivalves = proto.MapField(proto.STRING, proto.ENUM, number=1, 
enum=Bivalve,)
+        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}
+    assert dict(mc.bivalves) == {"clam": clam, "oyster": Bivalve.OYSTER}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/proto-plus-1.20.3/tests/test_marshal_types_wrappers_bool.py 
new/proto-plus-1.22.1/tests/test_marshal_types_wrappers_bool.py
--- old/proto-plus-1.20.3/tests/test_marshal_types_wrappers_bool.py     
2022-02-18 04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_marshal_types_wrappers_bool.py     
2022-08-30 15:37:47.000000000 +0200
@@ -20,7 +20,11 @@
 
 def test_bool_value_init():
     class Foo(proto.Message):
-        bar = proto.Field(proto.MESSAGE, message=wrappers_pb2.BoolValue, 
number=1,)
+        bar = proto.Field(
+            proto.MESSAGE,
+            message=wrappers_pb2.BoolValue,
+            number=1,
+        )
 
     assert Foo(bar=True).bar is True
     assert Foo(bar=False).bar is False
@@ -29,7 +33,11 @@
 
 def test_bool_value_init_dict():
     class Foo(proto.Message):
-        bar = proto.Field(proto.MESSAGE, message=wrappers_pb2.BoolValue, 
number=1,)
+        bar = proto.Field(
+            proto.MESSAGE,
+            message=wrappers_pb2.BoolValue,
+            number=1,
+        )
 
     assert Foo({"bar": True}).bar is True
     assert Foo({"bar": False}).bar is False
@@ -38,7 +46,11 @@
 
 def test_bool_value_distinction_from_bool():
     class Foo(proto.Message):
-        bar = proto.Field(proto.MESSAGE, message=wrappers_pb2.BoolValue, 
number=1,)
+        bar = proto.Field(
+            proto.MESSAGE,
+            message=wrappers_pb2.BoolValue,
+            number=1,
+        )
         baz = proto.Field(proto.BOOL, number=2)
 
     assert Foo().bar is None
@@ -63,7 +75,11 @@
 
 def test_bool_value_write_bool_value():
     class Foo(proto.Message):
-        bar = proto.Field(proto.MESSAGE, message=wrappers_pb2.BoolValue, 
number=1,)
+        bar = proto.Field(
+            proto.MESSAGE,
+            message=wrappers_pb2.BoolValue,
+            number=1,
+        )
 
     foo = Foo(bar=True)
     foo.bar = wrappers_pb2.BoolValue()
@@ -72,7 +88,11 @@
 
 def test_bool_value_del():
     class Foo(proto.Message):
-        bar = proto.Field(proto.MESSAGE, message=wrappers_pb2.BoolValue, 
number=1,)
+        bar = proto.Field(
+            proto.MESSAGE,
+            message=wrappers_pb2.BoolValue,
+            number=1,
+        )
 
     foo = Foo(bar=False)
     assert foo.bar is False
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/test_message_filename.py 
new/proto-plus-1.22.1/tests/test_message_filename.py
--- old/proto-plus-1.20.3/tests/test_message_filename.py        2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_message_filename.py        2022-08-30 
15:37:47.000000000 +0200
@@ -20,4 +20,7 @@
     class Foo(proto.Message):
         bar = proto.Field(proto.INT32, number=1)
 
-    assert Foo.pb(Foo()).DESCRIPTOR.file.name == 
"test_message_filename_foo.proto"
+    assert (
+        Foo.pb(Foo()).DESCRIPTOR.file.name
+        == "test_message_filename__default_package.foo.proto"
+    )
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/proto-plus-1.20.3/tests/test_message_filename_with_and_without_manifest.py 
new/proto-plus-1.22.1/tests/test_message_filename_with_and_without_manifest.py
--- 
old/proto-plus-1.20.3/tests/test_message_filename_with_and_without_manifest.py  
    2022-02-18 04:21:16.000000000 +0100
+++ 
new/proto-plus-1.22.1/tests/test_message_filename_with_and_without_manifest.py  
    2022-08-30 15:37:47.000000000 +0200
@@ -16,7 +16,10 @@
 
 
 PACKAGE = "a.test.package.with.and.without.manifest"
-__protobuf__ = proto.module(package=PACKAGE, manifest={"This", "That"},)
+__protobuf__ = proto.module(
+    package=PACKAGE,
+    manifest={"This", "That"},
+)
 
 
 class This(proto.Message):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' 
old/proto-plus-1.20.3/tests/test_message_filename_with_manifest.py 
new/proto-plus-1.22.1/tests/test_message_filename_with_manifest.py
--- old/proto-plus-1.20.3/tests/test_message_filename_with_manifest.py  
2022-02-18 04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_message_filename_with_manifest.py  
2022-08-30 15:37:47.000000000 +0200
@@ -15,7 +15,10 @@
 import proto
 
 PACKAGE = "a.test.package.with.manifest"
-__protobuf__ = proto.module(package=PACKAGE, manifest={"ThisFoo", "ThisBar"},)
+__protobuf__ = proto.module(
+    package=PACKAGE,
+    manifest={"ThisFoo", "ThisBar"},
+)
 
 
 class ThisFoo(proto.Message):
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/test_message_nested.py 
new/proto-plus-1.22.1/tests/test_message_nested.py
--- old/proto-plus-1.20.3/tests/test_message_nested.py  2022-02-18 
04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/test_message_nested.py  2022-08-30 
15:37:47.000000000 +0200
@@ -56,7 +56,8 @@
         baz = proto.Field(proto.MESSAGE, number=2, message=Baz)
 
     foo = Foo(
-        bar={"spam": "xyz", "eggs": False}, 
baz=Foo.Baz(bacon=Foo.Baz.Bacon(value=42)),
+        bar={"spam": "xyz", "eggs": False},
+        baz=Foo.Baz(bacon=Foo.Baz.Bacon(value=42)),
     )
     assert foo.bar.spam == "xyz"
     assert not foo.bar.eggs
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/test_modules.py 
new/proto-plus-1.22.1/tests/test_modules.py
--- old/proto-plus-1.20.3/tests/test_modules.py 2022-02-18 04:21:16.000000000 
+0100
+++ new/proto-plus-1.22.1/tests/test_modules.py 2022-08-30 15:37:47.000000000 
+0200
@@ -38,7 +38,8 @@
 
 def test_module_package_explicit_marshal():
     sys.modules[__name__].__protobuf__ = proto.module(
-        package="spam.eggs.v1", marshal="foo",
+        package="spam.eggs.v1",
+        marshal="foo",
     )
     try:
 
@@ -54,7 +55,10 @@
 
 
 def test_module_manifest():
-    __protobuf__ = proto.module(manifest={"Foo", "Bar", "Baz"}, 
package="spam.eggs.v1",)
+    __protobuf__ = proto.module(
+        manifest={"Foo", "Bar", "Baz"},
+        package="spam.eggs.v1",
+    )
 
     # We want to fake a module, but modules have attribute access, and
     # `frame.f_locals` is a dictionary. Since we only actually care about
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/proto-plus-1.20.3/tests/zone.py 
new/proto-plus-1.22.1/tests/zone.py
--- old/proto-plus-1.20.3/tests/zone.py 2022-02-18 04:21:16.000000000 +0100
+++ new/proto-plus-1.22.1/tests/zone.py 2022-08-30 15:37:47.000000000 +0200
@@ -16,7 +16,12 @@
 import proto
 
 
-__protobuf__ = proto.module(package="ocean.zone.v1", manifest={"Zone",},)
+__protobuf__ = proto.module(
+    package="ocean.zone.v1",
+    manifest={
+        "Zone",
+    },
+)
 
 
 class Zone(proto.Enum):

Reply via email to