823 lines
37 KiB
Diff
823 lines
37 KiB
Diff
--- a/setup.py
|
|
+++ b/setup.py
|
|
@@ -42,10 +42,10 @@
|
|
long_description=README,
|
|
platforms="Posix; MacOS X",
|
|
include_package_data=True,
|
|
- install_requires=("protobuf >= 3.19.0, <5.0.0dev",),
|
|
+ install_requires=("protobuf >= 3.19.0, <6.0.0dev",),
|
|
extras_require={
|
|
"testing": [
|
|
- "google-api-core[grpc] >= 1.31.5",
|
|
+ "google-api-core >= 1.31.5",
|
|
],
|
|
},
|
|
python_requires=">=3.6",
|
|
|
|
From 4cedebc7a4d6f9f3ee4b617458cf2bd4c4376e78 Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Tue, 13 Feb 2024 23:14:51 +0000
|
|
Subject: [PATCH 02/16] add compatibility with protobuf 5.x
|
|
|
|
diff --git a/proto/message.py b/proto/message.py
|
|
index 7232d42f..048ca665 100644
|
|
--- a/proto/message.py
|
|
+++ b/proto/message.py
|
|
@@ -18,6 +18,7 @@
|
|
import re
|
|
from typing import List, Type
|
|
|
|
+import google.protobuf
|
|
from google.protobuf import descriptor_pb2
|
|
from google.protobuf import message
|
|
from google.protobuf.json_format import MessageToDict, MessageToJson, Parse
|
|
@@ -32,6 +33,8 @@
|
|
from proto.utils import has_upb
|
|
|
|
|
|
+PROTOBUF_VERSION = google.protobuf.__version__
|
|
+
|
|
_upb = has_upb() # Important to cache result here.
|
|
|
|
|
|
@@ -379,6 +382,7 @@ def to_json(
|
|
sort_keys=False,
|
|
indent=2,
|
|
float_precision=None,
|
|
+ always_print_fields_with_no_presence=True,
|
|
) -> str:
|
|
"""Given a message instance, serialize it to json
|
|
|
|
@@ -398,18 +402,43 @@ def to_json(
|
|
Pass None for the most compact representation without newlines.
|
|
float_precision (Optional(int)): If set, use this to specify float field valid digits.
|
|
Default is None.
|
|
+ always_print_fields_with_no_presence (Optional(bool)): If True, fields without
|
|
+ presence (implicit presence scalars, repeated fields, and map fields) will
|
|
+ always be serialized. Any field that supports presence is not affected by
|
|
+ this option (including singular message fields and oneof fields). If
|
|
+ `including_default_value_fields` is set to False, this option has no effect.
|
|
Returns:
|
|
str: The json string representation of the protocol buffer.
|
|
"""
|
|
- return MessageToJson(
|
|
- 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,
|
|
- sort_keys=sort_keys,
|
|
- indent=indent,
|
|
- float_precision=float_precision,
|
|
- )
|
|
+ # For backwards compatibility of this breaking change in protobuf 5.x which is specific to proto2
|
|
+ # https://github.com/protocolbuffers/protobuf/commit/26995798757fbfef5cf6648610848e389db1fecf
|
|
+ if PROTOBUF_VERSION[0] in ("3", "4"):
|
|
+ return MessageToJson(
|
|
+ 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,
|
|
+ sort_keys=sort_keys,
|
|
+ indent=indent,
|
|
+ float_precision=float_precision,
|
|
+ )
|
|
+ else:
|
|
+ # The `including_default_value_fields` argument was removed from protobuf 5.x
|
|
+ # and replaced with `always_print_fields_with_no_presence` which very similar but has
|
|
+ # consistent handling of optional fields by not affecting them.
|
|
+ # The old flag accidentally had inconsistent behavior between proto2 optional and proto3 optional fields.
|
|
+ return MessageToJson(
|
|
+ cls.pb(instance),
|
|
+ use_integers_for_enums=use_integers_for_enums,
|
|
+ always_print_fields_with_no_presence=(
|
|
+ including_default_value_fields
|
|
+ and always_print_fields_with_no_presence
|
|
+ ),
|
|
+ preserving_proto_field_name=preserving_proto_field_name,
|
|
+ sort_keys=sort_keys,
|
|
+ indent=indent,
|
|
+ float_precision=float_precision,
|
|
+ )
|
|
|
|
def from_json(cls, payload, *, ignore_unknown_fields=False) -> "Message":
|
|
"""Given a json string representing an instance,
|
|
@@ -436,6 +465,7 @@ def to_dict(
|
|
preserving_proto_field_name=True,
|
|
including_default_value_fields=True,
|
|
float_precision=None,
|
|
+ always_print_fields_with_no_presence=True,
|
|
) -> "Message":
|
|
"""Given a message instance, return its representation as a python dict.
|
|
|
|
@@ -448,24 +478,48 @@ def to_dict(
|
|
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.
|
|
- including_default_value_fields (Optional(bool)): An option that
|
|
+ including_default_value_fields (Optional(bool)): Deprecated. Use argument
|
|
+ `always_print_fields_with_no_presence` instead. An option that
|
|
determines whether the default field values should be included in the results.
|
|
Default is True.
|
|
float_precision (Optional(int)): If set, use this to specify float field valid digits.
|
|
Default is None.
|
|
+ always_print_fields_with_no_presence (Optional(bool)): If True, fields without
|
|
+ presence (implicit presence scalars, repeated fields, and map fields) will
|
|
+ always be serialized. Any field that supports presence is not affected by
|
|
+ this option (including singular message fields and oneof fields). If
|
|
+ `including_default_value_fields` is set to False, this option has no effect.
|
|
|
|
Returns:
|
|
dict: A representation of the protocol buffer using pythonic data structures.
|
|
Messages and map fields are represented as dicts,
|
|
repeated fields are represented as lists.
|
|
"""
|
|
- return MessageToDict(
|
|
- cls.pb(instance),
|
|
- including_default_value_fields=including_default_value_fields,
|
|
- preserving_proto_field_name=preserving_proto_field_name,
|
|
- use_integers_for_enums=use_integers_for_enums,
|
|
- float_precision=float_precision,
|
|
- )
|
|
+ # For backwards compatibility of this breaking change in protobuf 5.x which is specific to proto2
|
|
+ # https://github.com/protocolbuffers/protobuf/commit/26995798757fbfef5cf6648610848e389db1fecf
|
|
+ if PROTOBUF_VERSION[0] in ("3", "4"):
|
|
+ return MessageToDict(
|
|
+ cls.pb(instance),
|
|
+ including_default_value_fields=including_default_value_fields,
|
|
+ preserving_proto_field_name=preserving_proto_field_name,
|
|
+ use_integers_for_enums=use_integers_for_enums,
|
|
+ float_precision=float_precision,
|
|
+ )
|
|
+ else:
|
|
+ # The `including_default_value_fields` argument was removed from protobuf 5.x
|
|
+ # and replaced with `always_print_fields_with_no_presence` which very similar but has
|
|
+ # consistent handling of optional fields by not affecting them.
|
|
+ # The old flag accidentally had inconsistent behavior between proto2 optional and proto3 optional fields
|
|
+ return MessageToDict(
|
|
+ cls.pb(instance),
|
|
+ always_print_fields_with_no_presence=(
|
|
+ including_default_value_fields
|
|
+ and always_print_fields_with_no_presence
|
|
+ ),
|
|
+ preserving_proto_field_name=preserving_proto_field_name,
|
|
+ use_integers_for_enums=use_integers_for_enums,
|
|
+ float_precision=float_precision,
|
|
+ )
|
|
|
|
def copy_from(cls, instance, other):
|
|
"""Equivalent for protobuf.Message.CopyFrom
|
|
|
|
From d40dcbb36baebb9f8dbfb9d1220da23e2654e67b Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Wed, 14 Feb 2024 15:07:01 +0000
|
|
Subject: [PATCH 03/16] fix RecursionError: maximum recursion depth exceeded
|
|
while calling a Python object in tests
|
|
|
|
---
|
|
tests/conftest.py | 8 ++++++++
|
|
1 file changed, 8 insertions(+)
|
|
|
|
diff --git a/tests/conftest.py b/tests/conftest.py
|
|
index 765326c6..252ac30c 100644
|
|
--- a/tests/conftest.py
|
|
+++ b/tests/conftest.py
|
|
@@ -67,6 +67,14 @@ def pytest_runtest_setup(item):
|
|
for name in dir(item.module):
|
|
if name.endswith("_pb2") and not name.startswith("test_"):
|
|
module = getattr(item.module, name)
|
|
+
|
|
+ # Exclude `google.protobuf.descriptor_pb2` which causes error
|
|
+ # `RecursionError: maximum recursion depth exceeded while calling a Python object`
|
|
+ # when running the test suite and is not required for tests.
|
|
+ # See https://github.com/googleapis/proto-plus-python/issues/425
|
|
+ if module.__package__ == "google.protobuf" and name == "descriptor_pb2":
|
|
+ continue
|
|
+
|
|
pool.AddSerializedFile(module.DESCRIPTOR.serialized_pb)
|
|
fd = pool.FindFileByName(module.DESCRIPTOR.name)
|
|
|
|
|
|
From fe352b23eabec34e06fa6a83e39d075d33119ddc Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Wed, 14 Feb 2024 15:23:57 +0000
|
|
Subject: [PATCH 05/16] update comments
|
|
|
|
---
|
|
proto/message.py | 8 +++++++-
|
|
1 file changed, 7 insertions(+), 1 deletion(-)
|
|
|
|
diff --git a/proto/message.py b/proto/message.py
|
|
index 048ca665..768f7020 100644
|
|
--- a/proto/message.py
|
|
+++ b/proto/message.py
|
|
@@ -392,6 +392,11 @@ def to_json(
|
|
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.
|
|
+ including_default_value_fields (Optional(bool)): Deprecated. Use argument
|
|
+ `always_print_fields_with_no_presence` instead. An option that
|
|
+ determines whether the default field values should be included in the results.
|
|
+ Default is True. If `always_print_fields_with_no_presence` is set to False, this
|
|
+ option has no effect.
|
|
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.
|
|
@@ -481,7 +486,8 @@ def to_dict(
|
|
including_default_value_fields (Optional(bool)): Deprecated. Use argument
|
|
`always_print_fields_with_no_presence` instead. An option that
|
|
determines whether the default field values should be included in the results.
|
|
- Default is True.
|
|
+ Default is True. If `always_print_fields_with_no_presence` is set to False, this
|
|
+ option has no effect.
|
|
float_precision (Optional(int)): If set, use this to specify float field valid digits.
|
|
Default is None.
|
|
always_print_fields_with_no_presence (Optional(bool)): If True, fields without
|
|
|
|
From fb5f2483fef3bc946630d8e111f3ee64be8cda5d Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Thu, 25 Apr 2024 14:42:39 +0000
|
|
Subject: [PATCH 07/16] See
|
|
https://github.com/protocolbuffers/protobuf/issues/16596;avoid breaking
|
|
change
|
|
|
|
---
|
|
proto/marshal/compat.py | 9 +++++++--
|
|
proto/marshal/marshal.py | 6 +++++-
|
|
2 files changed, 12 insertions(+), 3 deletions(-)
|
|
|
|
diff --git a/proto/marshal/compat.py b/proto/marshal/compat.py
|
|
index e10999bb..0c11d705 100644
|
|
--- a/proto/marshal/compat.py
|
|
+++ b/proto/marshal/compat.py
|
|
@@ -19,6 +19,9 @@
|
|
# not be included.
|
|
|
|
from google.protobuf.internal import containers
|
|
+import google.protobuf
|
|
+
|
|
+PROTOBUF_VERSION = google.protobuf.__version__
|
|
|
|
# Import protobuf 4.xx first and fallback to earlier version
|
|
# if not present.
|
|
@@ -36,15 +39,17 @@
|
|
repeated_composite_types = (containers.RepeatedCompositeFieldContainer,)
|
|
repeated_scalar_types = (containers.RepeatedScalarFieldContainer,)
|
|
map_composite_types = (containers.MessageMap,)
|
|
+map_composite_types_str = ('MessageMapContainer')
|
|
|
|
if _message:
|
|
repeated_composite_types += (_message.RepeatedCompositeContainer,)
|
|
repeated_scalar_types += (_message.RepeatedScalarContainer,)
|
|
- map_composite_types += (_message.MessageMapContainer,)
|
|
-
|
|
+ if PROTOBUF_VERSION[0:2] in ["3.", "4."]:
|
|
+ map_composite_types += (_message.MessageMapContainer,)
|
|
|
|
__all__ = (
|
|
"repeated_composite_types",
|
|
"repeated_scalar_types",
|
|
"map_composite_types",
|
|
+ "map_composite_types_str",
|
|
)
|
|
diff --git a/proto/marshal/marshal.py b/proto/marshal/marshal.py
|
|
index e9fbbb9f..783c8417 100644
|
|
--- a/proto/marshal/marshal.py
|
|
+++ b/proto/marshal/marshal.py
|
|
@@ -188,7 +188,11 @@ def to_python(self, proto_type, value, *, absent: bool = None):
|
|
return Repeated(value, marshal=self)
|
|
|
|
# Same thing for maps of messages.
|
|
- if value_type in compat.map_composite_types:
|
|
+ # See https://github.com/protocolbuffers/protobuf/issues/16596
|
|
+ # We need to look up the name of the type in compat.map_composite_types_str
|
|
+ # as class `MessageMapContainer` is no longer exposed
|
|
+ # This is done to avoid taking a breaking change in proto-plus
|
|
+ if value_type in compat.map_composite_types or value_type.__name__ in compat.map_composite_types_str:
|
|
return MapComposite(value, marshal=self)
|
|
return self.get_rule(proto_type=proto_type).to_python(value, absent=absent)
|
|
|
|
|
|
From 0fff4e5bbc873978650fb432e8d974a3e245fa07 Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Thu, 25 Apr 2024 14:43:25 +0000
|
|
Subject: [PATCH 08/16] lint
|
|
|
|
---
|
|
proto/marshal/compat.py | 2 +-
|
|
proto/marshal/marshal.py | 5 ++++-
|
|
2 files changed, 5 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/proto/marshal/compat.py b/proto/marshal/compat.py
|
|
index 0c11d705..1753629c 100644
|
|
--- a/proto/marshal/compat.py
|
|
+++ b/proto/marshal/compat.py
|
|
@@ -39,7 +39,7 @@
|
|
repeated_composite_types = (containers.RepeatedCompositeFieldContainer,)
|
|
repeated_scalar_types = (containers.RepeatedScalarFieldContainer,)
|
|
map_composite_types = (containers.MessageMap,)
|
|
-map_composite_types_str = ('MessageMapContainer')
|
|
+map_composite_types_str = ("MessageMapContainer",)
|
|
|
|
if _message:
|
|
repeated_composite_types += (_message.RepeatedCompositeContainer,)
|
|
diff --git a/proto/marshal/marshal.py b/proto/marshal/marshal.py
|
|
index 783c8417..8302a795 100644
|
|
--- a/proto/marshal/marshal.py
|
|
+++ b/proto/marshal/marshal.py
|
|
@@ -192,7 +192,10 @@ def to_python(self, proto_type, value, *, absent: bool = None):
|
|
# We need to look up the name of the type in compat.map_composite_types_str
|
|
# as class `MessageMapContainer` is no longer exposed
|
|
# This is done to avoid taking a breaking change in proto-plus
|
|
- if value_type in compat.map_composite_types or value_type.__name__ in compat.map_composite_types_str:
|
|
+ if (
|
|
+ value_type in compat.map_composite_types
|
|
+ or value_type.__name__ in compat.map_composite_types_str
|
|
+ ):
|
|
return MapComposite(value, marshal=self)
|
|
return self.get_rule(proto_type=proto_type).to_python(value, absent=absent)
|
|
|
|
|
|
From ac98abe7e8b5b09973ed71efcc598d1791b0bcf0 Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Thu, 25 Apr 2024 15:28:18 +0000
|
|
Subject: [PATCH 09/16] Address review feedback
|
|
|
|
---
|
|
proto/message.py | 63 ++++++++++++++++++++++++++++++------------------
|
|
1 file changed, 40 insertions(+), 23 deletions(-)
|
|
|
|
diff --git a/proto/message.py b/proto/message.py
|
|
index 768f7020..a148b7fb 100644
|
|
--- a/proto/message.py
|
|
+++ b/proto/message.py
|
|
@@ -377,12 +377,12 @@ def to_json(
|
|
instance,
|
|
*,
|
|
use_integers_for_enums=True,
|
|
- including_default_value_fields=True,
|
|
+ including_default_value_fields=None,
|
|
preserving_proto_field_name=False,
|
|
sort_keys=False,
|
|
indent=2,
|
|
float_precision=None,
|
|
- always_print_fields_with_no_presence=True,
|
|
+ always_print_fields_with_no_presence=None,
|
|
) -> str:
|
|
"""Given a message instance, serialize it to json
|
|
|
|
@@ -395,8 +395,8 @@ def to_json(
|
|
including_default_value_fields (Optional(bool)): Deprecated. Use argument
|
|
`always_print_fields_with_no_presence` instead. An option that
|
|
determines whether the default field values should be included in the results.
|
|
- Default is True. If `always_print_fields_with_no_presence` is set to False, this
|
|
- option has no effect.
|
|
+ This value must match `always_print_fields_with_no_presence`,
|
|
+ if both arguments are explictly set.
|
|
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.
|
|
@@ -410,18 +410,30 @@ def to_json(
|
|
always_print_fields_with_no_presence (Optional(bool)): If True, fields without
|
|
presence (implicit presence scalars, repeated fields, and map fields) will
|
|
always be serialized. Any field that supports presence is not affected by
|
|
- this option (including singular message fields and oneof fields). If
|
|
- `including_default_value_fields` is set to False, this option has no effect.
|
|
+ this option (including singular message fields and oneof fields).
|
|
+ This value must match `including_default_value_fields`,
|
|
+ if both arguments are explictly set.
|
|
Returns:
|
|
str: The json string representation of the protocol buffer.
|
|
"""
|
|
+
|
|
# For backwards compatibility of this breaking change in protobuf 5.x which is specific to proto2
|
|
# https://github.com/protocolbuffers/protobuf/commit/26995798757fbfef5cf6648610848e389db1fecf
|
|
+ if always_print_fields_with_no_presence is not None and including_default_value_fields is not None and always_print_fields_with_no_presence != including_default_value_fields:
|
|
+ raise ValueError("Arguments `always_print_fields_with_no_presence` and `including_default_value_fields` must match")
|
|
+
|
|
+ # By default, fields with no presense will be included in the results
|
|
+ # when both `always_print_fields_with_no_presence` and `including_default_value_fields` are not set
|
|
+ if always_print_fields_with_no_presence is None and including_default_value_fields is None:
|
|
+ print_fields = True
|
|
+ else:
|
|
+ print_fields = always_print_fields_with_no_presence or including_default_value_fields
|
|
+
|
|
if PROTOBUF_VERSION[0] in ("3", "4"):
|
|
return MessageToJson(
|
|
cls.pb(instance),
|
|
use_integers_for_enums=use_integers_for_enums,
|
|
- including_default_value_fields=including_default_value_fields,
|
|
+ including_default_value_fields=print_fields,
|
|
preserving_proto_field_name=preserving_proto_field_name,
|
|
sort_keys=sort_keys,
|
|
indent=indent,
|
|
@@ -435,10 +447,7 @@ def to_json(
|
|
return MessageToJson(
|
|
cls.pb(instance),
|
|
use_integers_for_enums=use_integers_for_enums,
|
|
- always_print_fields_with_no_presence=(
|
|
- including_default_value_fields
|
|
- and always_print_fields_with_no_presence
|
|
- ),
|
|
+ always_print_fields_with_no_presence=print_fields,
|
|
preserving_proto_field_name=preserving_proto_field_name,
|
|
sort_keys=sort_keys,
|
|
indent=indent,
|
|
@@ -468,15 +477,15 @@ def to_dict(
|
|
*,
|
|
use_integers_for_enums=True,
|
|
preserving_proto_field_name=True,
|
|
- including_default_value_fields=True,
|
|
+ including_default_value_fields=None,
|
|
float_precision=None,
|
|
- always_print_fields_with_no_presence=True,
|
|
+ always_print_fields_with_no_presence=None,
|
|
) -> "Message":
|
|
"""Given a message instance, return its representation as a python dict.
|
|
|
|
Args:
|
|
instance: An instance of this message type, or something
|
|
- compatible (accepted by the type's constructor).
|
|
+ compatible (accepted by the type's constructor).
|
|
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.
|
|
@@ -486,27 +495,38 @@ def to_dict(
|
|
including_default_value_fields (Optional(bool)): Deprecated. Use argument
|
|
`always_print_fields_with_no_presence` instead. An option that
|
|
determines whether the default field values should be included in the results.
|
|
- Default is True. If `always_print_fields_with_no_presence` is set to False, this
|
|
- option has no effect.
|
|
+ This value must match `always_print_fields_with_no_presence`,
|
|
+ if both arguments are explictly set.
|
|
float_precision (Optional(int)): If set, use this to specify float field valid digits.
|
|
Default is None.
|
|
always_print_fields_with_no_presence (Optional(bool)): If True, fields without
|
|
presence (implicit presence scalars, repeated fields, and map fields) will
|
|
always be serialized. Any field that supports presence is not affected by
|
|
- this option (including singular message fields and oneof fields). If
|
|
- `including_default_value_fields` is set to False, this option has no effect.
|
|
+ this option (including singular message fields and oneof fields). This value
|
|
+ must match `including_default_value_fields`, if both arguments are explictly set.
|
|
|
|
Returns:
|
|
dict: A representation of the protocol buffer using pythonic data structures.
|
|
Messages and map fields are represented as dicts,
|
|
repeated fields are represented as lists.
|
|
"""
|
|
+
|
|
# For backwards compatibility of this breaking change in protobuf 5.x which is specific to proto2
|
|
# https://github.com/protocolbuffers/protobuf/commit/26995798757fbfef5cf6648610848e389db1fecf
|
|
+ if always_print_fields_with_no_presence is not None and including_default_value_fields is not None and always_print_fields_with_no_presence != including_default_value_fields:
|
|
+ raise ValueError("Arguments `always_print_fields_with_no_presence` and `including_default_value_fields` must match")
|
|
+
|
|
+ # By default, fields with no presense will be included in the results
|
|
+ # when both `always_print_fields_with_no_presence` and `including_default_value_fields` are not set
|
|
+ if always_print_fields_with_no_presence is None and including_default_value_fields is None:
|
|
+ print_fields = True
|
|
+ else:
|
|
+ print_fields = always_print_fields_with_no_presence or including_default_value_fields
|
|
+
|
|
if PROTOBUF_VERSION[0] in ("3", "4"):
|
|
return MessageToDict(
|
|
cls.pb(instance),
|
|
- including_default_value_fields=including_default_value_fields,
|
|
+ including_default_value_fields=print_fields,
|
|
preserving_proto_field_name=preserving_proto_field_name,
|
|
use_integers_for_enums=use_integers_for_enums,
|
|
float_precision=float_precision,
|
|
@@ -518,10 +538,7 @@ def to_dict(
|
|
# The old flag accidentally had inconsistent behavior between proto2 optional and proto3 optional fields
|
|
return MessageToDict(
|
|
cls.pb(instance),
|
|
- always_print_fields_with_no_presence=(
|
|
- including_default_value_fields
|
|
- and always_print_fields_with_no_presence
|
|
- ),
|
|
+ always_print_fields_with_no_presence=print_fields,
|
|
preserving_proto_field_name=preserving_proto_field_name,
|
|
use_integers_for_enums=use_integers_for_enums,
|
|
float_precision=float_precision,
|
|
|
|
From 117907a5060cdf8dd69fcbe2cb717ff8d7a0021d Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Thu, 25 Apr 2024 15:29:49 +0000
|
|
Subject: [PATCH 10/16] lint
|
|
|
|
---
|
|
proto/message.py | 38 +++++++++++++++++++------
|
|
tests/conftest.py | 8 ++++--
|
|
tests/test_fields_mitigate_collision.py | 1 +
|
|
3 files changed, 36 insertions(+), 11 deletions(-)
|
|
|
|
diff --git a/proto/message.py b/proto/message.py
|
|
index a148b7fb..95b3b614 100644
|
|
--- a/proto/message.py
|
|
+++ b/proto/message.py
|
|
@@ -419,15 +419,26 @@ def to_json(
|
|
|
|
# For backwards compatibility of this breaking change in protobuf 5.x which is specific to proto2
|
|
# https://github.com/protocolbuffers/protobuf/commit/26995798757fbfef5cf6648610848e389db1fecf
|
|
- if always_print_fields_with_no_presence is not None and including_default_value_fields is not None and always_print_fields_with_no_presence != including_default_value_fields:
|
|
- raise ValueError("Arguments `always_print_fields_with_no_presence` and `including_default_value_fields` must match")
|
|
+ if (
|
|
+ always_print_fields_with_no_presence is not None
|
|
+ and including_default_value_fields is not None
|
|
+ and always_print_fields_with_no_presence != including_default_value_fields
|
|
+ ):
|
|
+ raise ValueError(
|
|
+ "Arguments `always_print_fields_with_no_presence` and `including_default_value_fields` must match"
|
|
+ )
|
|
|
|
# By default, fields with no presense will be included in the results
|
|
# when both `always_print_fields_with_no_presence` and `including_default_value_fields` are not set
|
|
- if always_print_fields_with_no_presence is None and including_default_value_fields is None:
|
|
+ if (
|
|
+ always_print_fields_with_no_presence is None
|
|
+ and including_default_value_fields is None
|
|
+ ):
|
|
print_fields = True
|
|
else:
|
|
- print_fields = always_print_fields_with_no_presence or including_default_value_fields
|
|
+ print_fields = (
|
|
+ always_print_fields_with_no_presence or including_default_value_fields
|
|
+ )
|
|
|
|
if PROTOBUF_VERSION[0] in ("3", "4"):
|
|
return MessageToJson(
|
|
@@ -513,15 +524,26 @@ def to_dict(
|
|
|
|
# For backwards compatibility of this breaking change in protobuf 5.x which is specific to proto2
|
|
# https://github.com/protocolbuffers/protobuf/commit/26995798757fbfef5cf6648610848e389db1fecf
|
|
- if always_print_fields_with_no_presence is not None and including_default_value_fields is not None and always_print_fields_with_no_presence != including_default_value_fields:
|
|
- raise ValueError("Arguments `always_print_fields_with_no_presence` and `including_default_value_fields` must match")
|
|
+ if (
|
|
+ always_print_fields_with_no_presence is not None
|
|
+ and including_default_value_fields is not None
|
|
+ and always_print_fields_with_no_presence != including_default_value_fields
|
|
+ ):
|
|
+ raise ValueError(
|
|
+ "Arguments `always_print_fields_with_no_presence` and `including_default_value_fields` must match"
|
|
+ )
|
|
|
|
# By default, fields with no presense will be included in the results
|
|
# when both `always_print_fields_with_no_presence` and `including_default_value_fields` are not set
|
|
- if always_print_fields_with_no_presence is None and including_default_value_fields is None:
|
|
+ if (
|
|
+ always_print_fields_with_no_presence is None
|
|
+ and including_default_value_fields is None
|
|
+ ):
|
|
print_fields = True
|
|
else:
|
|
- print_fields = always_print_fields_with_no_presence or including_default_value_fields
|
|
+ print_fields = (
|
|
+ always_print_fields_with_no_presence or including_default_value_fields
|
|
+ )
|
|
|
|
if PROTOBUF_VERSION[0] in ("3", "4"):
|
|
return MessageToDict(
|
|
diff --git a/tests/conftest.py b/tests/conftest.py
|
|
index 252ac30c..9f2f5c95 100644
|
|
--- a/tests/conftest.py
|
|
+++ b/tests/conftest.py
|
|
@@ -41,9 +41,11 @@ def pytest_runtest_setup(item):
|
|
|
|
item._mocks.append(
|
|
mock.patch(
|
|
- "google._upb._message.default_pool"
|
|
- if has_upb()
|
|
- else "google.protobuf.pyext._message.default_pool",
|
|
+ (
|
|
+ "google._upb._message.default_pool"
|
|
+ if has_upb()
|
|
+ else "google.protobuf.pyext._message.default_pool"
|
|
+ ),
|
|
pool,
|
|
)
|
|
)
|
|
diff --git a/tests/test_fields_mitigate_collision.py b/tests/test_fields_mitigate_collision.py
|
|
index 117af48a..07eac5ff 100644
|
|
--- a/tests/test_fields_mitigate_collision.py
|
|
+++ b/tests/test_fields_mitigate_collision.py
|
|
@@ -15,6 +15,7 @@
|
|
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
|
|
|
|
From 09b9bc41f6b2651a3cd4df24c8281ed38fa9dc28 Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Thu, 25 Apr 2024 15:45:09 +0000
|
|
Subject: [PATCH 11/16] add tests
|
|
|
|
---
|
|
tests/test_json.py | 17 +++++++++++++++++
|
|
tests/test_message.py | 14 ++++++++++++++
|
|
2 files changed, 31 insertions(+)
|
|
|
|
diff --git a/tests/test_json.py b/tests/test_json.py
|
|
index e94e935a..e5111751 100644
|
|
--- a/tests/test_json.py
|
|
+++ b/tests/test_json.py
|
|
@@ -121,6 +121,23 @@ class Squid(proto.Message):
|
|
)
|
|
assert json1 == '{"name":"Steve"}'
|
|
|
|
+ json1 = (
|
|
+ Squid.to_json(s, always_print_fields_with_no_presence=False)
|
|
+ .replace(" ", "")
|
|
+ .replace("\n", "")
|
|
+ )
|
|
+ assert json1 == '{"name":"Steve"}'
|
|
+
|
|
+ with pytest.raises(
|
|
+ ValueError,
|
|
+ match="Arguments.*always_print_fields_with_no_presence.*including_default_value_fields.*must match",
|
|
+ ):
|
|
+ Squid.to_json(
|
|
+ s,
|
|
+ including_default_value_fields=True,
|
|
+ always_print_fields_with_no_presence=False,
|
|
+ ).replace(" ", "").replace("\n", "")
|
|
+
|
|
json2 = Squid.to_json(s).replace(" ", "").replace("\n", "")
|
|
assert (
|
|
json2 == '{"name":"Steve","massKg":0}' or json2 == '{"massKg":0,"name":"Steve"}'
|
|
diff --git a/tests/test_message.py b/tests/test_message.py
|
|
index 983cde82..7ba05ab4 100644
|
|
--- a/tests/test_message.py
|
|
+++ b/tests/test_message.py
|
|
@@ -267,6 +267,20 @@ class Color(proto.Enum):
|
|
expected_dict = {"mass_kg": 20}
|
|
assert s_dict_2 == expected_dict
|
|
|
|
+ s_dict_2 = Squid.to_dict(s_new_2, always_print_fields_with_no_presence=False)
|
|
+ expected_dict = {"mass_kg": 20}
|
|
+ assert s_dict_2 == expected_dict
|
|
+
|
|
+ with pytest.raises(
|
|
+ ValueError,
|
|
+ match="Arguments.*always_print_fields_with_no_presence.*including_default_value_fields.*must match",
|
|
+ ):
|
|
+ s_dict_2 = Squid.to_dict(
|
|
+ s_new_2,
|
|
+ including_default_value_fields=True,
|
|
+ always_print_fields_with_no_presence=False,
|
|
+ )
|
|
+
|
|
new_s = Squid(s_dict)
|
|
assert new_s == s
|
|
|
|
|
|
From 6e17595596c9a944248c52f1d964fb66b360dc86 Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Mon, 13 May 2024 12:30:01 -0400
|
|
Subject: [PATCH 12/16] Update tests/test_fields_mitigate_collision.py
|
|
|
|
---
|
|
tests/test_fields_mitigate_collision.py | 1 -
|
|
1 file changed, 1 deletion(-)
|
|
|
|
diff --git a/tests/test_fields_mitigate_collision.py b/tests/test_fields_mitigate_collision.py
|
|
index 07eac5ff..117af48a 100644
|
|
--- a/tests/test_fields_mitigate_collision.py
|
|
+++ b/tests/test_fields_mitigate_collision.py
|
|
@@ -15,7 +15,6 @@
|
|
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
|
|
|
|
From 4d50f04c39753b8e11577e706009deda58e9ae69 Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Wed, 22 May 2024 13:56:48 +0000
|
|
Subject: [PATCH 13/16] add deprecation warning
|
|
|
|
---
|
|
proto/message.py | 19 +++++++++++++++++++
|
|
1 file changed, 19 insertions(+)
|
|
|
|
diff --git a/proto/message.py b/proto/message.py
|
|
index 95b3b614..1da45205 100644
|
|
--- a/proto/message.py
|
|
+++ b/proto/message.py
|
|
@@ -17,6 +17,7 @@
|
|
import copy
|
|
import re
|
|
from typing import List, Type
|
|
+import warnings
|
|
|
|
import google.protobuf
|
|
from google.protobuf import descriptor_pb2
|
|
@@ -417,6 +418,15 @@ def to_json(
|
|
str: The json string representation of the protocol buffer.
|
|
"""
|
|
|
|
+ # Warn Protobuf 5.x users that `including_default_value_fields` is deprecated.
|
|
+ if PROTOBUF_VERSION[0] == "5" and including_default_value_fields is not None:
|
|
+ warnings.warn(
|
|
+ """The argument `including_default_value_fields` is deprecated. Please use
|
|
+ `always_print_fields_with_no_presence` instead.
|
|
+ """,
|
|
+ DeprecationWarning,
|
|
+ )
|
|
+
|
|
# For backwards compatibility of this breaking change in protobuf 5.x which is specific to proto2
|
|
# https://github.com/protocolbuffers/protobuf/commit/26995798757fbfef5cf6648610848e389db1fecf
|
|
if (
|
|
@@ -522,6 +532,15 @@ def to_dict(
|
|
repeated fields are represented as lists.
|
|
"""
|
|
|
|
+ # Warn Protobuf 5.x users that `including_default_value_fields` is deprecated.
|
|
+ if PROTOBUF_VERSION[0] == "5" and including_default_value_fields is not None:
|
|
+ warnings.warn(
|
|
+ """The argument `including_default_value_fields` is deprecated. Please use
|
|
+ `always_print_fields_with_no_presence` instead.
|
|
+ """,
|
|
+ DeprecationWarning,
|
|
+ )
|
|
+
|
|
# For backwards compatibility of this breaking change in protobuf 5.x which is specific to proto2
|
|
# https://github.com/protocolbuffers/protobuf/commit/26995798757fbfef5cf6648610848e389db1fecf
|
|
if (
|
|
|
|
From 70e28ad65a30c520c8579b505333ba5af1818ee2 Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Wed, 22 May 2024 13:58:33 +0000
|
|
Subject: [PATCH 14/16] Cater for protobuf 5.x+
|
|
|
|
---
|
|
proto/message.py | 8 ++++----
|
|
1 file changed, 4 insertions(+), 4 deletions(-)
|
|
|
|
diff --git a/proto/message.py b/proto/message.py
|
|
index 1da45205..b6ad3f68 100644
|
|
--- a/proto/message.py
|
|
+++ b/proto/message.py
|
|
@@ -418,8 +418,8 @@ def to_json(
|
|
str: The json string representation of the protocol buffer.
|
|
"""
|
|
|
|
- # Warn Protobuf 5.x users that `including_default_value_fields` is deprecated.
|
|
- if PROTOBUF_VERSION[0] == "5" and including_default_value_fields is not None:
|
|
+ # Warn Protobuf 5.x+ users that `including_default_value_fields` is deprecated.
|
|
+ if PROTOBUF_VERSION[0] not in ("3", "4") and including_default_value_fields is not None:
|
|
warnings.warn(
|
|
"""The argument `including_default_value_fields` is deprecated. Please use
|
|
`always_print_fields_with_no_presence` instead.
|
|
@@ -532,8 +532,8 @@ def to_dict(
|
|
repeated fields are represented as lists.
|
|
"""
|
|
|
|
- # Warn Protobuf 5.x users that `including_default_value_fields` is deprecated.
|
|
- if PROTOBUF_VERSION[0] == "5" and including_default_value_fields is not None:
|
|
+ # Warn Protobuf 5.x+ users that `including_default_value_fields` is deprecated.
|
|
+ if PROTOBUF_VERSION[0] not in ("3", "4") and including_default_value_fields is not None:
|
|
warnings.warn(
|
|
"""The argument `including_default_value_fields` is deprecated. Please use
|
|
`always_print_fields_with_no_presence` instead.
|
|
|
|
From 5d247e07329515b9e7a60dce173c8d5703671745 Mon Sep 17 00:00:00 2001
|
|
From: Anthonios Partheniou <partheniou@google.com>
|
|
Date: Wed, 22 May 2024 14:00:36 +0000
|
|
Subject: [PATCH 15/16] style
|
|
|
|
---
|
|
proto/message.py | 10 ++++++++--
|
|
1 file changed, 8 insertions(+), 2 deletions(-)
|
|
|
|
diff --git a/proto/message.py b/proto/message.py
|
|
index b6ad3f68..f3d15eb6 100644
|
|
--- a/proto/message.py
|
|
+++ b/proto/message.py
|
|
@@ -419,7 +419,10 @@ def to_json(
|
|
"""
|
|
|
|
# Warn Protobuf 5.x+ users that `including_default_value_fields` is deprecated.
|
|
- if PROTOBUF_VERSION[0] not in ("3", "4") and including_default_value_fields is not None:
|
|
+ if (
|
|
+ PROTOBUF_VERSION[0] not in ("3", "4")
|
|
+ and including_default_value_fields is not None
|
|
+ ):
|
|
warnings.warn(
|
|
"""The argument `including_default_value_fields` is deprecated. Please use
|
|
`always_print_fields_with_no_presence` instead.
|
|
@@ -533,7 +536,10 @@ def to_dict(
|
|
"""
|
|
|
|
# Warn Protobuf 5.x+ users that `including_default_value_fields` is deprecated.
|
|
- if PROTOBUF_VERSION[0] not in ("3", "4") and including_default_value_fields is not None:
|
|
+ if (
|
|
+ PROTOBUF_VERSION[0] not in ("3", "4")
|
|
+ and including_default_value_fields is not None
|
|
+ ):
|
|
warnings.warn(
|
|
"""The argument `including_default_value_fields` is deprecated. Please use
|
|
`always_print_fields_with_no_presence` instead.
|