I have a proto file as below:
message MyMessage
{
optional uint32 field1 = 1 [default = 5];
}
And when I compile it with below command,
protoc -I=. --python_betterproto_out=. my_message.proto
I get below init.py file:
@dataclass(eq=False, repr=False)
class MyMessage(betterproto.Message):
field1: int = betterproto.uint32_field(1)
Finally, I want to get the binary encoded representation of a message object as below, :
meessage = MyMessage()
message.field1 = 0
encoded = bytes(message)
It does not serialize field1. The reason is specified in the __bytes__
function (the link):
# Default (zero) values are not serialized. Two exceptions are
# if this is the selected oneof item or if we know we have to
# serialize an empty message (i.e. zero value was explicitly
# set by the user).
I want to know, why the zero is still the default value, despite of setting it to 5 in `.proto' file? and how can I fix it?
I tried the oneof
solution and it worked. But I don't want to use that.
Here's my repro that demonstrates that betterproto
does not appear to reflect the [default = 5]
while protobuf
does.
python3 -m venv venv
source venv/bin/activate
python3 -m pip "betterproto[compiler]"
python3 -m pip protobuf
Ensure protoc
is in the PATH
:
PATH=${PATH}:/path/to/protoc-22.4-linux-x86_64/bin
Then:
NAME="foo.proto"
protoc \
--proto_path=${PWD} \
--python_betterproto_out=${PWD} \
--python_out=${PWD} \
--pyi_out=${PWD} \
${PWD}/${NAME}
Then:
main.py
:
import foo
import foo_pb2
# betterproto prints default Default (!) of 0
m = foo.MyMessage()
print(m.field1)
# protobuf prints annotated Default of 5
m = foo_pb2.MyMessage()
print(m.field1)
Prints:
0
5
And, protobuf
generates ${NAME}_pb2.py
which includes a serialized copy of the FileDescriptor
which uses FileDescriptorProto
.
We can use protoc
to decode this:
FILE="..." # AddSerializedFile byte string from ${NAME}_pb2.py
printf ${FILE} \
| protoc \
--decode=google.protobuf.FileDescriptorProto \
--proto_path=path/to/descriptor.proto
Which yields:
name: "{NAME}"
package: "{PACKAGE}"
message_type {
name: "MyMessage"
field {
name: "field1"
number: 1
label: LABEL_OPTIONAL
type: TYPE_UINT32
default_value: "5"
}
}