I defined two enum (AnsType
and ErrorType
) in a single .proto file and I used both of them in a message. However, the client can not parse both enum. Why does it happen and how can I solve it?
The definition of the proto file is helloworld.proto
:
syntax = "proto3";
option java_multiple_files = true;
option java_package = "io.grpc.examples.helloworld";
option java_outer_classname = "HelloWorldProto";
option objc_class_prefix = "HLW";
package helloworld;
enum AnsType {
OTHER = 0;
YES = 1;
NO = 2;
}
enum ErrorType {
UNDEFINED = 0;
OOM = 1;
}
// The greeting service definition.
service Greeter {
// Sends a greeting
rpc SayHello (HelloRequest) returns (HelloReply) {}
rpc SayHelloStreamReply (HelloRequest) returns (stream HelloReply) {}
}
// The request message containing the user's name.
message HelloRequest {
string name = 1;
}
// The response message containing the greetings
message HelloReply {
string message = 1;
AnsType status = 2;
ErrorType error = 3;
}
Server side python code greeter_server.py
:
from concurrent import futures
import logging
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
class Greeter(helloworld_pb2_grpc.GreeterServicer):
def SayHello(self, request, context):
print(f'Receive {request}')
return helloworld_pb2.HelloReply(
message='Hello, %s!' % request.name,
status=helloworld_pb2.AnsType.YES,
error=helloworld_pb2.ErrorType.UNDEFINED,
)
def serve():
port = '50051'
server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
helloworld_pb2_grpc.add_GreeterServicer_to_server(Greeter(), server)
server.add_insecure_port('[::]:' + port)
server.start()
print("Server started, listening on " + port)
server.wait_for_termination()
if __name__ == '__main__':
logging.basicConfig()
serve()
Client side python code greeter_client.py
:
from __future__ import print_function
import sys
import logging
import grpc
import helloworld_pb2
import helloworld_pb2_grpc
def run():
# NOTE(gRPC Python Team): .close() is possible on a channel and should be
# used in circumstances in which the with statement does not fit the needs
# of the code.
print("Will try to greet world ...")
with grpc.insecure_channel('localhost:50051') as channel:
stub = helloworld_pb2_grpc.GreeterStub(channel)
response = stub.SayHello(helloworld_pb2.HelloRequest(name='you'))
print(response)
print("Greeter client received: " + response.message)
if __name__ == '__main__':
logging.basicConfig()
run()
The above code derives from a tutorial (https://grpc.io/docs/languages/python/quickstart/).
The output from the client side is:
Will try to greet world ...
message: "Hello, you!"
Greeter client received: Hello, you!
However, what I expected output is
Will try to greet world ...
message: "Hello, you!"
status: OTHER
error: UNDEFINED
Greeter client received: Hello, you!
Thank you in advance.
Your code works.
You may be unfamiliar with Protobuf use of default values.
In Python, Protobuf enums are integers with a default value of zero.
Protobuf doesn't serialize default valued fields and so, AnsType.OTHER
(==0) and ErrorType.UNDEFINED
(==0) won't be present in the message received by the client.
However, you can e.g. assert response.error == helloworld_pb2.Error.UNDEFINED
or helloworld_pb2.Error.Value("UNDEFINED")
See Default Values