Skip to main content

Easy gRPC-web client in python

Project description

pyease-grpc

Lint Release PyPI version Python version GitHub License Downloads

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 found
  • requests.exceptions.InvalidHeader: If the header of expected length is not found
  • requests.exceptions.ContentDecodingError: If the data of expected length is not found
  • NotImplementedError: If compression is enabled in the response headers
  • grpc.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 found
  • grpc.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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pyease_grpc-1.7.4.tar.gz (16.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

pyease_grpc-1.7.4-py3-none-any.whl (19.6 kB view details)

Uploaded Python 3

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

Hashes for pyease_grpc-1.7.4.tar.gz
Algorithm Hash digest
SHA256 f06449b79ae8247cc48bc94972ded026ff74cd76437cbfc460dfa596a274da1c
MD5 92564993e82cd0f9ae10452365819cab
BLAKE2b-256 86a18c8ac98ef57c895c5c6e9535a9b7128b4765a09cea15aec3a5f77e8795ff

See more details on using hashes here.

Provenance

The following attestation bundles were made for pyease_grpc-1.7.4.tar.gz:

Publisher: release.yml on dipu-bd/pyease-grpc

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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

Hashes for pyease_grpc-1.7.4-py3-none-any.whl
Algorithm Hash digest
SHA256 6945900d622686b539b9431df8727ab906a05bcf2538651c8da8cca5a3bad216
MD5 e56188c8dde4a02624ce6e433c3d9e89
BLAKE2b-256 e295df53896e871c2a8e019bd4a7c9523748860844ac4276620816a72e1f49da

See more details on using hashes here.

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

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page