Welcome to gRPCAlchemy’s documentation!

gRPCAlchemy

https://img.shields.io/pypi/v/grpcalchemy.svg https://github.com/GuangTianLi/grpcalchemy/workflows/test/badge.svg Documentation Status https://img.shields.io/pypi/pyversions/grpcalchemy.svg https://codecov.io/gh/GuangTianLi/grpcalchemy/branch/master/graph/badge.svg

The Python micro framework for building gPRC application based on official gRPC project.

Installation

$ pipenv install grpcalchemy
✨🍰✨

Only Python 3.6+ is supported.

Example

Server

from grpcalchemy.orm import Message, StringField
from grpcalchemy import Server, Context, grpcmethod

class HelloMessage(Message):
    text: str

class HelloService(Server):
    @grpcmethod
    def Hello(self, request: HelloMessage, context: Context) -> HelloMessage:
        return HelloMessage(text=f'Hello {request.text}')

if __name__ == '__main__':
    HelloService.run()

Then Using gRPC channel to connect the server:

from grpc import insecure_channel

from protos.helloservice_pb2_grpc import HelloServiceStub
from protos.hellomessage_pb2 import HelloMessage

with insecure_channel("localhost:50051") as channel:
    response = HelloServiceStub(channel).Hello(
        HelloMessage(text="world")
    )

Features

  • gPRC Service Support
  • gRPC Message Support
    • Scalar Value Types
    • Message Types
    • Repeated Field
    • Maps
  • Define Message With Type Hint
  • Middleware
  • App Context Manger
  • Error Handler Support
  • Streaming Method Support
  • gRPC-Health Checking and Reflection Support (Alpha)
  • Multiple Processor Support

TODO

  • Test Client Support
  • Async Server Support

Installation

Stable release

To install gRPCAlchemy, run this command in your terminal:

$ pipenv install grpcalchemy
✨🍰✨

This is the preferred method to install gRPCAlchemy, as it will always install the most recent stable release.

If you don’t have pip installed, this Python installation guide can guide you through the process.

From sources

The sources for gRPCAlchemy can be downloaded from the Github repo.

You can either clone the public repository:

$ git clone git://github.com/GuangTianLi/grpcalchemy

Or download the tarball:

$ curl  -OL https://github.com/GuangTianLi/grpcalchemy/tarball/master

Once you have a copy of the source, you can install it with:

$ python setup.py install

Or using pipenv install straightly:

$ pipenv install -e git+https://github.com/GuangTianLi/grpcalchemy#egg=grpcalchemy

Usage

To use gRPCAlchemy in a project:

from grpcalchemy.orm import Message
from grpcalchemy import Server, Context, grpcmethod

class HelloMessage(Message):
    __filename__ = 'hello'
    text: str

class HelloService(Server):
    @grpcmethod
    def Hello(self, request: HelloMessage, context: Context) -> HelloMessage:
        return HelloMessage(text=f'Hello {request.text}')

if __name__ == '__main__':
    HelloService.run()

Defining our Message

Any message which is used in RPC method must have a explicit schema. We can use py files generated by proto files by the grpc_tools straightly. However defining the schemas by our ORM can help to iron out bugs involving incorrect types or missing fields, and also allow us to define utility methods on our message in the same way that traditional ORMs do.

In our Tutorial Application we need to send several different types of message. We will need to have a collection of users, so that we may link posts to an individual. We also need to send our different types of posts (eg: text, image and link) in the RPC method. To aid navigation of our Tutorial Application, posts may have tags associated with them, so that the list of posts shown to the user may be limited to posts that have been assigned a specific tag. Finally, it would be nice if comments could be added to posts. We’ll start with users, as the other document models are slightly more involved.

Users

Just as if we were using a RPC Message with an ORM, we need to define which fields a User may have, and what types of data they might have:

from grpcalchemy.orm import Message
class User(Message):
    email: str
    first_name: str
    last_name: str

Posts, Comments and Tags

Now we’ll think about how to define the rest of the information. To associate the comments with individual posts, We’d also need a link message to provide the many-to-many relationship between posts and tags.

Posts

We can think of Post as a base class, and TextPost, ImagePost and LinkPost as subclasses of Post.

from grpcalchemy.orm import Message
class Post(Message):
    title: str
    author: str

class TextPost(Post):
    content: str

class ImagePost(Post):
    image_path: str

class LinkPost(Post):
    link_url: str

We are storing a reference to the author of the posts using a ReferenceField object. These are equal to use other message types in RPC message.

Tags

Now that we have our Post models figured out, how will we attach tags to them? RPC message allows us to define lists of items natively. So, for both efficiency and simplicity’s sake, we’ll define the tags as strings directly within the post. Let’s take a look at the code of our modified Post class:

from typing import List
from grpcalchemy.orm import Message, Repeated
class Post(Message):
    title: str
    author: User
    tags: Repeated[str]

The ListField object that is used to define a Post’s tags takes a field object as its first argument — this means that you can have lists of any type of field (including lists).

Note

We don’t need to modify the specialized post types as they all inherit from Post.

Comments

A comment is typically associated with one post.utility methods, in exactly the same way we do with regular documents:

from grpcalchemy.orm import Message
class Comment(Message):
    content: str
    name: str

We can then define a list of comment documents in our post message:

from typing import List
from grpcalchemy.orm import Message, Repeated
class Post(Message):
    title: str
    author: User
    tags: Repeated[str]
    comments: Repeated[Comment]

Defining our gRPC Method

grpcmethod is a decorator indicating gRPC methods.

The valid gRPC Method must be with explicit type hint to define the type of request and return value.

Using Iterator to define Stream gRPC Method:

from typing import Iterator

class HelloService(Server):

    @grpcmethod
    def UnaryUnary(self, request: HelloMessage, context: Context) -> HelloMessage:
        return HelloMessage(text=f'Hello {request.text}')

    @grpcmethod
    def UnaryStream(self, request: HelloMessage, context: Context) -> Iterator[HelloMessage]:
        yield HelloMessage(text=f'Hello {request.text}')

    @grpcmethod
    def StreamUnary(self, request: Iterator[HelloMessage], context: Context) -> HelloMessage:
        for r in request:
            pass
        return HelloMessage(text=f'Hello {r.text}')

    @grpcmethod
    def StreamStream(self, request: Iterator[HelloMessage], context: Context) -> Iterator[HelloMessage]:
        for r in request:
            yield HelloMessage(text=f'Hello {r.text}')

The above code is equal to an RPC service with a method:

syntax = "proto3";

service HelloService {
    rpc StreamStream (stream HelloMessage) returns (stream HelloMessage) {}

    rpc StreamUnary (stream HelloMessage) returns (HelloMessage) {}

    rpc UnaryStream (HelloMessage) returns (stream HelloMessage) {}

    rpc UnaryUnary (HelloMessage) returns (HelloMessage) {}
}

Using Blueprint to Build Your Large Application

gRPCAlchemy uses a concept of blueprints for making gRPC services and supporting common patterns within an application or across applications. Blueprint can greatly simplify how large applications work.

from typing import List, Type
from grpcalchemy.orm import Message
from grpcalchemy import Server, Context, Blueprint

class MyService(Server):
    @classmethod
    def get_blueprints(cls) -> List[Type[Blueprint]]:
        return [HelloService]

class HelloMessage(Message):
    __filename__ = 'hello'
    text: str

class HelloService(Blueprint):
    @grpcmethod
    def Hello(self, request: HelloMessage, context: Context) -> HelloMessage:
        return HelloMessage(text=f'Hello {request.text}')


if __name__ == '__main__':
    MyService.run()

Configuration

You can define your custom config by inherit from DefaultConfig which defined a list of configuration available in gRPCAlchemy and their default values.

Note

DefaultConfig is defined by configalchemy - https://configalchemy.readthedocs.io

from grpcalchemy import DefaultConfig

from hello import HelloService

class MyConfig(DefaultConfig):
    ...

config = MyConfig()

HelloService.run(config=config)

Middleware

Middleware is a framework of hooks into gRPCAlchemy’s request/response processing.

Costume middleware can implement by overriding Blueprint.before_request, Blueprint.after_request, Server.process_request and Server.process_response.

grpcalchemy

grpcalchemy package

grpcalchemy.server module

grpcalchemy.blueprint module

grpcalchemy.config module

Contributing

Contributions are welcome, and they are greatly appreciated! Every little bit helps, and credit will always be given.

You can contribute in many ways:

Types of Contributions

Report Bugs

Report bugs at https://github.com/GuangTianLi/grpcalchemy/issues.

If you are reporting a bug, please include:

  • Your operating system name and version.
  • Any details about your local setup that might be helpful in troubleshooting.
  • Detailed steps to reproduce the bug.

Fix Bugs

Look through the GitHub issues for bugs. Anything tagged with “bug” and “help wanted” is open to whoever wants to implement it.

Implement Features

Look through the GitHub issues for features. Anything tagged with “enhancement” and “help wanted” is open to whoever wants to implement it.

Write Documentation

gRPCAlchemy could always use more documentation, whether as part of the official gRPCAlchemy docs, in docstrings, or even on the web in blog posts, articles, and such.

Submit Feedback

The best way to send feedback is to file an issue at https://github.com/GuangTianLi/grpcalchemy/issues.

If you are proposing a feature:

  • Explain in detail how it would work.
  • Keep the scope as narrow as possible, to make it easier to implement.
  • Remember that this is a volunteer-driven project, and that contributions are welcome :)

Get Started!

Ready to contribute? Here’s how to set up grpcalchemy for local development.

  1. Fork the grpcalchemy repo on GitHub.

  2. Clone your fork locally:

    $ git clone git@github.com:your_name_here/grpcalchemy.git
    
  3. Install your local copy into a virtualenv. Assuming you have Pipenv installed, this is how you set up your fork for local development:

    $ cd grpcalchemy/
    $ make init
    $ pipenv shell
    
  4. Create a branch for local development:

    $ git checkout -b name-of-your-bugfix-or-feature
    

    Now you can make your changes locally.

  5. When you’re done making changes, check that your changes pass lint and the tests, including testing other Python versions:

    $ make lint
    $ make test
    
  6. Commit your changes and push your branch to GitHub:

    $ git add .
    $ git commit -m "Your detailed description of your changes."
    $ git push origin name-of-your-bugfix-or-feature
    
  7. Submit a pull request through the GitHub website.

Pull Request Guidelines

Before you submit a pull request, check that it meets these guidelines:

  1. The pull request should include tests.
  2. If the pull request adds functionality, the docs should be updated. Put your new functionality into a function with a docstring, and add the feature to the list in README.rst.
  3. The pull request should work for Python 3.6+. Check https://travis-ci.org/GuangTianLi/grpcalchemy/pull_requests and make sure that the tests pass for all supported Python versions.

Tips

To run a subset of tests:

$ make test

Deploying

A reminder for the maintainers on how to deploy. Make sure all your changes are committed (including an entry in HISTORY.rst). Then run:

$ bumpversion patch # possible: major / minor / patch
$ git push
$ git push --tags

Travis will then deploy to PyPI if tests pass.

Credits

Development Lead

Contributors

None yet. Why not be the first?

History

0.7.*(2021-03-20)

  • Improve initialize function of message
  • Remove default feature in message
  • Refactor composite message Type
  • Support gRPC with xDS
  • Add PROTO_AUTO_GENERATED setting to make runtime proto generation optional

0.6.*(2020-10-27)

  • fix [#36] compatibility in windows
  • fix [#34] compatibility in windows
  • gRPC-Health Checking and Reflection Support (Alpha)
  • Multiple Processor Support

0.5.0(2020-04-27)

  • Support Streaming Method
  • Deprecate request parameter in app context and handle exception

0.4.0(2019-09-24)

  • Support related directory path to generate protocol buffer files
  • Enable use type hint to define message
  • Add error handle to handle Exception
  • Add get_blueprints to get blueprints need to register

0.2.7-10(2019-04-16)

  • Support SSL
  • Improve Implement of Server with grpc.server
  • Support YAML file in Config Module
  • Improve Config Module
  • Add context in current rpc

0.2.5-6(2019-03-06)

  • Implement Rpc Context
  • Improve Config Module

0.2.4(2019-03-01)

  • Implement Globals Variable
  • Implement APP Context

0.2.2-3 (2019-02-26)

  • Improve Config module
  • Improve rpc_call_wrap

0.2.1 (2019-02-14)

  • Implement Own gRPC Server
  • Implement gRPC Server Test Client

0.2.0 (2019-01-30)

  • Change gRPCAlchemy Server register to register_blueprint
  • Make gRPCAlchemy Server inherit from Blueprint
  • Support Json Format
  • Support Inheritance Message

0.1.6 (2019-01-21)

  • Various bug-fixes
  • Improve tests
  • Change Client API
  • Add PreProcess And PostProcess
  • Import Config Object
  • Add Event Listener
  • Change Field Object Into Descriptor

0.1.5 (2018-12-14)

  • Various bug-fixes
  • Improve tests
  • Add client

0.1.4 (2018-12-11)

  • First release on PyPI.

Indices and tables