# purerpc

[![Build Status](https://travis-ci.org/standy66/purerpc.png?branch=master)](https://travis-ci.org/standy66/purerpc)

Asynchronous pure Python gRPC server and client implementation using
[curio](https://github.com/dabeaz/curio) and [hyper-h2](https://github.com/python-hyper/hyper-h2)

## Requirements

* CPython >= 3.6
* PyPy >= 3.6

## Installation

Latest PyPI version:

```bash
pip install purerpc
```

Latest development version:

```bash
pip install git+https://github.com/standy66/purerpc.git
```

## 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: 

```bash
protoc --purerpc_out=. --python_out=. -I. greeter.proto
```

or, if you installed `grpcio_tools` Python package:

```bash
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

```python
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()
```

### Client

```python
import curio
from greeter_pb2 import HelloRequest, HelloReply
from greeter_grpc import GreeterStub
from purerpc import Channel


async def gen():
    for i in range(5):
        yield HelloRequest(name=str(i))


async def main():
    channel = Channel("localhost", 50055)
    # This is optional, will be run automatically on the first request
    await channel.connect()
    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)
```

You can mix server and client code, for example make a server that requests something using purerpc from another server, etc.

More examples in `misc/` folder