Empty Message in oneof is removed in serialized wire
It seems an empty message in oneof clause, like foo in the following example, is lost after serialization.
syntax = "proto3";
package hello;
message Foo {}
message Greeting {
oneof payload {
Foo foo = 1;
}
}
Detail
I've expected that before and after is equivalent in the following code
from dataclasses import dataclass
import betterproto
@dataclass(eq=False, repr=False)
class Foo(betterproto.Message):
pass
@dataclass(eq=False, repr=False)
class Greeting(betterproto.Message):
foo: Foo = betterproto.message_field(1, group="payload")
def test_which_one_of():
before = Greeting()
before.foo = Foo()
n, v = betterproto.which_one_of(before, "payload")
assert n == "foo"
assert isinstance(v, Foo)
after = Greeting().parse(bytes(before))
n, v = betterproto.which_one_of(after, "payload")
assert n == "foo"
assert isinstance(v, Foo)
but above shows
$ poetry run pytest test.py
========================================= test session starts =========================================
platform darwin -- Python 3.9.0, pytest-6.2.1, py-1.10.0, pluggy-0.13.1
Using --randomly-seed=3216976549
rootdir: /xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx, configfile: pyproject.toml
plugins: cov-2.11.1, asyncio-0.14.0, randomly-3.5.0, icdiff-0.5
collected 1 item
test.py F [100%]
============================================== FAILURES ===============================================
__________________________________________ test_which_one_of __________________________________________
def test_which_one_of():
before = Greeting()
before.foo = Foo()
n, v = betterproto.which_one_of(before, "payload")
assert n == "foo"
assert isinstance(v, Foo)
after = Greeting().parse(bytes(before))
n, v = betterproto.which_one_of(after, "payload")
> assert n == "foo"
E AssertionError: assert equals failed
E '' 'foo'
test.py:25: AssertionError
======================================= short test summary info =======================================
I've noticed that bytes(...) returns b'' on both case
syntax = "proto3";
package hello;
message Foo {}
message Bar {}
message Greeting {
oneof payload {
Foo foo = 1;
Bar bar = 2;
}
}
before = Greeting()
before.foo = Foo()
print(bytes(before))
before = Greeting()
before.bar = Bar()
print(bytes(before))
So there is no way to distinguish and I guess it's a kinda protobuf's spec, right?
No. It seems it's not spec. I've generated code with protobuf and write the following script (ref https://github.com/protocolbuffers/protobuf/issues/5012)
from hello_pb2 import Greeting, Foo, Bar
greeting = Greeting()
print(greeting.SerializeToString())
greeting.foo.CopyFrom(Foo())
print(greeting.SerializeToString())
greeting.bar.CopyFrom(Bar())
print(greeting.SerializeToString())
Above produce the following result.
b''
b'\n\x00'
b'\x12\x00'
Maybe related to https://github.com/danielgtaylor/python-betterproto/issues/179 ?
And maybe fixed by https://github.com/danielgtaylor/python-betterproto/pull/176, right?
Appears to have been fixed by #176