Easy gRPC-web client in python
Project description
pyease-grpc
Easy to use gRPC-web client in python
Installation
Install the package using pip or uv:
$ pip install pyease-grpc
$ uv pip install pyease-grpc
Development
From a clone of this repository, create a virtual environment and install the package with dev tools:
$ uv sync --all-groups
Lint and format (same as CI) with uv run ruff check pyease_grpc and uv run ruff format --check pyease_grpc. Apply formatting with uv run ruff format pyease_grpc. Run the CLI with uv run pyease-grpc --version. Build wheels with uv build.
Run the following to check if the published package has been installed correctly:
$ pyease-grpc --version
Tutorial
Before you start, you need to have a basic understanding of how gRPC works.
This package provides a requests like interface to make calls to native gRPC and gRPC-Web servers.
Example Server
An example server and client can be found in the example folder.
> cd example
> docker compose up
It uses two ports:
- Native gRPC server:
localhost:50050 - gRPC-Web server using envoy:
http://localhost:8080
You 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 Protobuf
The proto file is located at example/server/abc.proto
// file: example/server/abc.proto
syntax = "proto3";
package pyease.sample.v1;
service Greeter {
rpc SayHello (HelloRequest) returns (HelloResponse);
rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);
rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);
rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);
}
message HelloRequest {
string name = 1;
}
message HelloResponse {
string reply = 1;
}
You can directly load this file using pyease_grpc without generating any stubs:
from pyease_grpc import Protobuf
protobuf = Protobuf.from_file("example/server/abc.proto")
Internally, it converts the proto file into FileDescriptorSet message.
It is recommended to use the FileDescriptorSet json to load the Protobuf faster.
To generate the FileDescriptorSet json from a proto file:
$ pyease-grpc -I example/server example/server/abc.proto --output abc_fds.json
Now you can use this descriptor file directly to create a Protobuf instance.
protobuf = Protobuf.restore_file('abc_fds.json')
Getting response from gRPC-Web
For Unary RPC request:
from pyease_grpc import RpcSession, RpcUri
session = 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 a Server-side Streaming RPC request:
from pyease_grpc import RpcSession, RpcUri
session = 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()
for payload in response.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 protocol
You can also directly call a method using the native gRPC protocol.
For Unary RPC request:
from pyease_grpc import RpcSession, RpcUri
session = 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 a Server-side Streaming RPC request:
from pyease_grpc import RpcSession, RpcUri
session = 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",
},
)
for payload in response.iter_payloads():
print(payload["reply"])
print(response.payloads)
For a Client-Side Streaming RPC request:
from pyease_grpc import RpcSession, RpcUri
session = 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 a Bidirectional Streaming RPC request:
from pyease_grpc import RpcSession, RpcUri
session = 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"},
]
),
)
for payload in response.iter_payloads():
print(payload["reply"])
print(response.payloads)
Error Handling
Errors are raised as soon as they appear.
List of errors that can appear during request:
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-zero
List of errors that can appear during call:
ValueError: If the requested method, service or package is not foundgrpc.RpcError: If the grpc-status is non-zero
To get the grpc-status and grpc-message, you can add a try-catch to your call. e.g.:
import grpc
from pyease_grpc import RpcSession, RpcUri
session = 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"])
except grpc.RpcError as e:
print('grpc status', e.code())
print('grpc message', e.details())
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file pyease_grpc-1.7.4.tar.gz.
File metadata
- Download URL: pyease_grpc-1.7.4.tar.gz
- Upload date:
- Size: 16.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f06449b79ae8247cc48bc94972ded026ff74cd76437cbfc460dfa596a274da1c
|
|
| MD5 |
92564993e82cd0f9ae10452365819cab
|
|
| BLAKE2b-256 |
86a18c8ac98ef57c895c5c6e9535a9b7128b4765a09cea15aec3a5f77e8795ff
|
Provenance
The following attestation bundles were made for pyease_grpc-1.7.4.tar.gz:
Publisher:
release.yml on dipu-bd/pyease-grpc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyease_grpc-1.7.4.tar.gz -
Subject digest:
f06449b79ae8247cc48bc94972ded026ff74cd76437cbfc460dfa596a274da1c - Sigstore transparency entry: 1214597512
- Sigstore integration time:
-
Permalink:
dipu-bd/pyease-grpc@724431fcaedd7c16e420afb5a38989372984a865 -
Branch / Tag:
refs/tags/v1.7.4 - Owner: https://github.com/dipu-bd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@724431fcaedd7c16e420afb5a38989372984a865 -
Trigger Event:
push
-
Statement type:
File details
Details for the file pyease_grpc-1.7.4-py3-none-any.whl.
File metadata
- Download URL: pyease_grpc-1.7.4-py3-none-any.whl
- Upload date:
- Size: 19.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6945900d622686b539b9431df8727ab906a05bcf2538651c8da8cca5a3bad216
|
|
| MD5 |
e56188c8dde4a02624ce6e433c3d9e89
|
|
| BLAKE2b-256 |
e295df53896e871c2a8e019bd4a7c9523748860844ac4276620816a72e1f49da
|
Provenance
The following attestation bundles were made for pyease_grpc-1.7.4-py3-none-any.whl:
Publisher:
release.yml on dipu-bd/pyease-grpc
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
pyease_grpc-1.7.4-py3-none-any.whl -
Subject digest:
6945900d622686b539b9431df8727ab906a05bcf2538651c8da8cca5a3bad216 - Sigstore transparency entry: 1214597597
- Sigstore integration time:
-
Permalink:
dipu-bd/pyease-grpc@724431fcaedd7c16e420afb5a38989372984a865 -
Branch / Tag:
refs/tags/v1.7.4 - Owner: https://github.com/dipu-bd
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@724431fcaedd7c16e420afb5a38989372984a865 -
Trigger Event:
push
-
Statement type: