Implicit optional is not respected
Summary
When you don't add an explicit optional, fields are not serialized properly if they happen to be set to the default value.
Reproduction Steps
message Sample {
bool foo = 1
}
generates
[
{
"name": "foo",
"type": "BOOLEAN",
"mode": "NULLABLE",
}
]
but the python code generated is
@dataclass(eq=False, repr=False)
class Sample(betterproto.Message):
foo: bool = betterproto.string_field(1)
which implies that the boolean is non-nullable.
Then, if we do
bytes(Sample(foo=False))
it will be serialized to
b''
and actually treated as null.
If we change the proto to
message Sample {
optional bool foo = 1
}
then the correct code is generated and the message is serialized as expected.
Actual Results
The protobuf documentation suggests that not setting optional should be treated in the same way as setting it.
System Information
libprotoc 28.3 Python 3.10.11 betterproto 2.0.0b7
Checklist
- [X] I have searched the issues for duplicates.
- [X] I have shown the entire traceback, if possible.
- [X] I have verified this issue occurs on the latest prelease of betterproto which can be installed using
pip install -U --pre betterproto, if possible.
This should be the correct behavior for proto3, which is the version supported in betterproto. When you decode the message from the empty byte, the field should be set to the right value.
See the following example with Google's implementation (proto-plus):
import proto
class Msg(proto.Message):
field = proto.Field(proto.BOOL, number=1)
print(Msg.serialize(Msg(field=True))) # b'\x08\x01'
print(Msg.serialize(Msg(field=False))) # b''
When you decode the message from the empty byte, the field should be set to the right value.
How do you know whether the empty byte is null or false? If I understand correctly, having no modifier is the same as having the optional modifier, so b'' should be decoded as null but is, in fact, decoded as false.
If the field is not marked as optional, it is not possible for the field to have a null value. If you decode the message from the empty byte, you will see that the field will be actually set to False.
If the field is marked as optional, b'' will make the field have a null value.
Note that this behavior is not valid for messages, which can always have a null value.
You can see this page for more details: https://protobuf.dev/programming-guides/field_presence/