Package: pyease-grpc
pyease-grpcEasy to use gRPC-web client in pythonInstallationInstall the package using:$ pip install pyease-grpcRun the following to check if it has been installed correctly:$ pyease-grpc --versionTutorialBefore you start, you need to have a basic understanding ofhow gRPC works.This package provides arequestslike interface to make calls to native gRPC and gRPC-Web servers.Example ServerAn example server and client can be found in theexamplefolder.> cd example
> docker compose upIt uses two ports:Native gRPC server:localhost:50050gRPC-Web server using envoy:http://localhost:8080You can test the native serve with the client:$ python example/server/client.py
Calling SayHello:
reply: "Hello, world!"

Calling LotsOfReplies:
reply: "Hello, world no. 0!"
reply: "Hello, world no. 1!"
reply: "Hello, world no. 2!"
reply: "Hello, world no. 3!"
reply: "Hello, world no. 4!"

Calling LotsOfGreetings:
reply: "Hello, A, B, C!"

Calling BidiHello:
reply: "Hello, A!"
reply: "Hello, B!"
reply: "Hello, C!"Loading the ProtobufThe proto file is located atexample/server/abc.proto// file: example/server/abc.protosyntax="proto3";packagepyease.sample.v1;serviceGreeter{rpcSayHello(HelloRequest)returns(HelloResponse);rpcLotsOfReplies(HelloRequest)returns(streamHelloResponse);rpcLotsOfGreetings(streamHelloRequest)returns(HelloResponse);rpcBidiHello(streamHelloRequest)returns(streamHelloResponse);}messageHelloRequest{stringname=1;}messageHelloResponse{stringreply=1;}You can directly load this file usingpyease_grpcwithout generating any stubs:frompyease_grpcimportProtobufprotobuf=Protobuf.from_file("example/server/abc.proto")Internally, it converts the proto file intoFileDescriptorSetmessage.It is recommended to use theFileDescriptorSetjson to load theProtobuffaster.To generate theFileDescriptorSetjson from a proto file:$ pyease-grpc -I example/server example/server/abc.proto --output abc_fds.jsonNow you can use this descriptor file directly to create aProtobufinstance.protobuf=Protobuf.restore_file('abc_fds.json')Getting response from gRPC-WebForUnary RPCrequest:frompyease_grpcimportRpcSession,RpcUrisession=RpcSession.from_file("example/server/abc.proto")response=session.request(RpcUri(base_url="http://localhost:8080",package="pyease.sample.v1",service="Greeter",method="SayHello",),{"name":"world"},)response.raise_for_status()print(response.single['reply'])For aServer-side Streaming RPCrequest:frompyease_grpcimportRpcSession,RpcUrisession=RpcSession.from_file("example/server/abc.proto")response=session.request(RpcUri(base_url="http://localhost:8080",package="pyease.sample.v1",service="Greeter",method="LotsOfReplies",),{"name":"world",},)response.raise_for_status()forpayloadinresponse.iter_payloads():print(payload["reply"])gRPC-Web currently supports 2 RPC modes: Unary RPCs, Server-side Streaming RPCs.
Client-side and Bi-directional streaming is not currently supported.Using the native gRPC protocolYou can also directly call a method using the native gRPC protocol.ForUnary RPCrequest:frompyease_grpcimportRpcSession,RpcUrisession=RpcSession.from_file("example/server/abc.proto")response=session.call(RpcUri(base_url="localhost:50050",package="pyease.sample.v1",service="Greeter",method="SayHello",),{"name":"world",})print(response.single["reply"])print(response.payloads)For aServer-side Streaming RPCrequest:frompyease_grpcimportRpcSession,RpcUrisession=RpcSession.from_file("example/server/abc.proto")response=session.call(RpcUri(base_url="localhost:50050",package="pyease.sample.v1",service="Greeter",method="LotsOfReplies",),{"name":"world",},)forpayloadinresponse.iter_payloads():print(payload["reply"])print(response.payloads)For aClient-Side Streaming RPCrequest:frompyease_grpcimportRpcSession,RpcUrisession=RpcSession.from_file("example/server/abc.proto")response=session.call(RpcUri(base_url="localhost:50050",package="pyease.sample.v1",service="Greeter",method="LotsOfGreetings",),iter([{"name":"A"},{"name":"B"},{"name":"C"},]),)print(response.single["reply"])print(response.payloads)For aBidirectional Streaming RPCrequest:frompyease_grpcimportRpcSession,RpcUrisession=RpcSession.from_file("example/server/abc.proto")response=session.call(RpcUri(base_url="localhost:50050",package="pyease.sample.v1",service="Greeter",method="BidiHello",),iter([{"name":"A"},{"name":"B"},{"name":"C"},]),)forpayloadinresponse.iter_payloads():print(payload["reply"])print(response.payloads)Error HandlingErrors are raised as soon as they appear.List of errors that can appear duringrequest:ValueError: If the requested method, service or package is not foundrequests.exceptions.InvalidHeader: If the header of expected length is not foundrequests.exceptions.ContentDecodingError: If the data of expected length is not foundNotImplementedError: If compression is enabled in the response headersgrpc.RpcError: If the grpc-status is non-zeroList of errors that can appear duringcall:ValueError: If the requested method, service or package is not foundgrpc.RpcError: If the grpc-status is non-zeroTo get thegrpc-statusandgrpc-message, you can add a try-catch to your call. e.g.:importgrpcfrompyease_grpcimportRpcSession,RpcUrisession=RpcSession.from_file("example/server/abc.proto")rpc_uri=RpcUri(base_url="localhost:50050",package="pyease.sample.v1",service="Greeter",method="SayHello",)try:response=session.call(rpc_uri,{"name":"error"})print(response.single["reply"])exceptgrpc.RpcErrorase:print('grpc status',e.code())print('grpc message',e.details())