From 182aedaec4a6cfd2465a2c541e5f2485b0aadb58 Mon Sep 17 00:00:00 2001 From: Ollie <69084614+olijeffers0n@users.noreply.github.com> Date: Sat, 24 Jun 2023 20:19:13 +0100 Subject: [PATCH] Handle empty value objects properly (#481) Co-authored-by: James Hilton-Balfe --- src/betterproto/__init__.py | 7 +++++++ .../google_impl_behavior_equivalence.proto | 12 +++++++----- .../test_google_impl_behavior_equivalence.py | 19 +++++++++++++++++-- 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/src/betterproto/__init__.py b/src/betterproto/__init__.py index 40be27f..f22a8f7 100644 --- a/src/betterproto/__init__.py +++ b/src/betterproto/__init__.py @@ -704,6 +704,13 @@ class Message(ABC): return value def __setattr__(self, attr: str, value: Any) -> None: + if ( + isinstance(value, Message) + and hasattr(value, "_betterproto") + and not value._betterproto.meta_by_field_name + ): + value._serialized_on_wire = True + if attr != "_serialized_on_wire": # Track when a field has been set. self.__dict__["_serialized_on_wire"] = True diff --git a/tests/inputs/google_impl_behavior_equivalence/google_impl_behavior_equivalence.proto b/tests/inputs/google_impl_behavior_equivalence/google_impl_behavior_equivalence.proto index 5357a7c..3e9bea9 100644 --- a/tests/inputs/google_impl_behavior_equivalence/google_impl_behavior_equivalence.proto +++ b/tests/inputs/google_impl_behavior_equivalence/google_impl_behavior_equivalence.proto @@ -2,14 +2,16 @@ syntax = "proto3"; package google_impl_behavior_equivalence; -message Foo{ - int64 bar = 1; -} +message Foo { int64 bar = 1; } -message Test{ - oneof group{ +message Test { + oneof group { string string = 1; int64 integer = 2; Foo foo = 3; } } + +message Request { Empty foo = 1; } + +message Empty {} \ No newline at end of file diff --git a/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py b/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py index 0297692..476d20e 100644 --- a/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py +++ b/tests/inputs/google_impl_behavior_equivalence/test_google_impl_behavior_equivalence.py @@ -3,17 +3,20 @@ from google.protobuf import json_format import betterproto from tests.output_betterproto.google_impl_behavior_equivalence import ( + Empty, Foo, + Request, Test, ) from tests.output_reference.google_impl_behavior_equivalence.google_impl_behavior_equivalence_pb2 import ( + Empty as ReferenceEmpty, Foo as ReferenceFoo, + Request as ReferenceRequest, Test as ReferenceTest, ) def test_oneof_serializes_similar_to_google_oneof(): - tests = [ (Test(string="abc"), ReferenceTest(string="abc")), (Test(integer=2), ReferenceTest(integer=2)), @@ -30,7 +33,6 @@ def test_oneof_serializes_similar_to_google_oneof(): def test_bytes_are_the_same_for_oneof(): - message = Test(string="") message_reference = ReferenceTest(string="") @@ -53,3 +55,16 @@ def test_bytes_are_the_same_for_oneof(): assert isinstance(message_reference.foo, ReferenceFoo) assert isinstance(message_reference2.foo, ReferenceFoo) + + +def test_empty_message_field(): + message = Request() + reference_message = ReferenceRequest() + + message.foo = Empty() + reference_message.foo.CopyFrom(ReferenceEmpty()) + + assert betterproto.serialized_on_wire(message.foo) + assert reference_message.HasField("foo") + + assert bytes(message) == reference_message.SerializeToString()