Asynchronous pure python gRPC server and client implementation using curio and hyper-h2.
Project description
purerpc
Asynchronous pure Python gRPC client and server implementation supporting asyncio, curio and trio (achieved with anyio compatibility layer).
Requirements
- CPython >= 3.5
- PyPy >= 3.5
Installation
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 curio or trio, please install them manually.
protoc plugin
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
Usage
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
.
Server
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")
Client
import curio
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__":
curio.run(main) # Or trio.run(main), or run in asyncio event loop
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
Release 0.2.0 (2019-02-10)
Features
- add backend option to Server.serve (5f47f8e)
- add support for Python 3.5 (a681192)
- improved exception handling in test utils (b1df796)
- migrate to anyio (746b1c2)
BREAKING CHANGES
- Server and test now use asyncio event loop by default, this behaviour can be changed with PURERPC_BACKEND environment variable
- purerpc.Channel is removed, migrate to purerpc.insecure_channel async context manager (now supports correct shutdown)
Release 0.1.6
- Allow passing request headers to method handlers in request argument
- Allow passing custom metadata to method stub calls (in metadata optional keyword argument)
Release 0.1.5
- Enforce SO_KEEPALIVE with small timeouts
- Expose PureRPCTestCase in purerpc API for unit testing purerpc services
Release 0.1.4
- Speed up protoc plugin
Release 0.1.3 [PyPI only]
- Fix long description on PyPI
Release 0.1.2
- Fix unit tests on Python 3.7
Release 0.1.0
- Implement immediate mode
Release 0.0.1
- Initial release
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.