purerpc
purerpc is a native, async Python gRPC client and server implementation supporting asyncio, uvloop, and trio (achieved with anyio compatibility layer).
This project is in maintenance mode. Updates will primarily be limited to fixing severe bugs, keeping the package usable for actively developed projects, and easing maintenance.
For use cases limited to asyncio, consider the Python package published by the main grpc project instead.
Requirements
- CPython >= 3.7
- PyPy >= 3.7
Installation
Latest PyPI version:
pip install purerpc[grpc]
NOTE: for PyPy, replace "grpc" with "grpc-pypy". Support is tentative, as grpc does not officially support PyPy.
Latest development version:
pip install git+https://github.com/python-trio/purerpc.git[grpc]
These invocations will include dependencies for the grpc runtime and generation of service stubs.
To install extra dependencies for running tests or examples, using the
test_utils
module, etc., apply the [dev]
suffix (e.g.
pip install purerpc[dev]
).
protoc plugin
purerpc adds protoc-gen-purerpc
plugin for protoc
to your PATH
environment variable
so you can use it to generate service definition and stubs:
protoc --purerpc_out=. --python_out=. -I. greeter.proto
or, if you installed the grpcio-tools
Python package:
python -m grpc_tools.protoc --purerpc_out=. --python_out=. -I. greeter.proto
Usage
NOTE: greeter_grpc
module is generated by purerpc's protoc-gen-purerpc
plugin.
Server
from purerpc import Server
from greeter_pb2 import HelloRequest, HelloReply
from greeter_grpc import GreeterServicer
class Greeter(GreeterServicer):
async def SayHello(self, message):
return HelloReply(message="Hello, " + message.name)
async def SayHelloToMany(self, input_messages):
async for message in input_messages:
yield HelloReply(message=f"Hello, {message.name}")
if __name__ == '__main__':
server = Server(50055)
server.add_service(Greeter().service)
# NOTE: if you already have an async loop running, use "await server.serve_async()"
import anyio
anyio.run(server.serve_async) # or set explicit backend="asyncio" or "trio"
Client
import purerpc
from greeter_pb2 import HelloRequest, HelloReply
from greeter_grpc import GreeterStub
async def gen():
for i in range(5):
yield HelloRequest(name=str(i))
async def listen():
async with purerpc.insecure_channel("localhost", 50055) as channel:
stub = GreeterStub(channel)
reply = await stub.SayHello(HelloRequest(name="World"))
print(reply.message)
async with stub.SayHelloToMany(gen()) as stream:
async for reply in stream:
print(reply.message)
if __name__ == '__main__':
# NOTE: if you already have an async loop running, use "await listen()"
import anyio
anyio.run(listen) # or set explicit backend="asyncio" or "trio"
You can mix server and client code, for example make a server that requests something using purerpc from another gRPC server, etc.
More examples in misc/
folder
Project history
purerpc was originally written by Andrew Stepanov and used the curio async event loop. Later it was migrated to the anyio API, supporting asyncio, curio, uvloop, and trio (though curio support has since been dropped from the API).
After going a few years unmaintained, the project was adopted by the python-trio organization with the intent of ensuring a continued gRPC solution for Trio users.