Asynchronous pure Python gRPC client and server implementation supporting asyncio, uvloop, curio and trio (achieved with anyio compatibility layer).
- CPython >= 3.5
- PyPy >= 3.5
Latest PyPI version:
pip install purerpc
Latest development version:
pip install git+https://github.com/standy66/purerpc.git
By default purerpc uses asyncio event loop, if you want to use uvloop, curio or trio, please install them manually.
purerpc adds protoc-gen-purerpc
plugin for protoc
to your PATH
enviroment variable
so you can use it to generate service definition and stubs:
protoc --purerpc_out=. --python_out=. -I. greeter.proto
or, if you installed grpcio_tools
Python package:
python -m grpc_tools.protoc --purerpc_out=. --python_out=. -I. greeter.proto
NOTE: greeter_grpc
module is generated by purerpc's protoc-gen-purerpc
plugin.
Below are the examples for Python 3.6 and above which introduced asynchronous generators as a language concept.
For Python 3.5, where native asynchronous generators are not supported, you can use async_generator library for this purpose.
Just mark yielding coroutines with @async_generator
decorator and use await yield_(value)
and await yield_from_(async_iterable)
instead of yield
.
from greeter_pb2 import HelloRequest, HelloReply
from greeter_grpc import GreeterServicer
from purerpc import Server
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}")
server = Server(50055)
server.add_service(Greeter().service)
server.serve(backend="asyncio") # backend can also be one of: "uvloop", "curio", "trio"
import anyio
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 main():
async with purerpc.insecure_channel("localhost", 50055) as channel:
stub = GreeterStub(channel)
reply = await stub.SayHello(HelloRequest(name="World"))
print(reply.message)
async for reply in stub.SayHelloToMany(gen()):
print(reply.message)
if __name__ == "__main__":
anyio.run(main, backend="asyncio") # backend can also be one of: "uvloop", "curio", "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