{ "info": { "author": "IST-SUPSI", "author_email": "geoservice@supsi.ch", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Programming Language :: Python :: 3 :: Only" ], "description": "# Easy GRPC\n\nPython (>=3.7) GRPC service helper library.\n\n## Installation\n\nWe suggest to create a virtual environment.\n\n```bash\npython3.7 -m venv ./venv\nsource venv/bin/activate\npython -m pip install --upgrade pip\n```\n\nInstall the module:\n\n```bash\npip install easy-grpc\n\n```\n\n## Usage example\n\nEasy GRPC helps you to create a GRPC Service in three steps:\n\n1. Define and compile your proto files\n2. Implement the *Actions*\n3. Configure and run the GRPC service\n\n### 1. Define and compile your proto files\n\nIn the example folder there are some files extracted from the [grpclib](https://github.com/vmagamedov/grpclib) repository, which is currently used to run this service. You can find the *helloworld.proto* and the relative compiled python files (*helloworld_pb2.py* and *helloworld_grpc.py*).\n\n```protobuf\nsyntax = \"proto3\";\n\npackage example.helloworld;\n\nmessage HelloRequest {\n string name = 1;\n}\n\nmessage HelloReply {\n string message = 1;\n}\n\nservice Greeter {\n rpc SayHello (HelloRequest) returns (HelloReply) {}\n}\n\n```\n\nTo define the service you have to create the proto files as explained in the official documentations [grpc.io](https://grpc.io/docs/guides/concepts/).\n\nTo compile a proto file by yourself, just execute this command from the root directory.\n\n```bash\npython -m grpc_tools.protoc \\\n --proto_path=. \\\n --python_out=. \\\n --python_grpc_out=. \\\n ./example/helloworld.proto\n```\n\n> **Note:** pay attention to the *python_grpc_out* param. This is not standard in the *grpc_tools.protoc* library, it is [grpclib specific](https://grpclib.readthedocs.io/en/latest/index.html?highlight=python_grpc_out#protoc-plugin).\n\n### 2. Implement the *Actions*\n\nIn the helloworld.proto file there is declared one rpc function (you can declare more). You shall create an action for each rpc, handling the defined input message (HelloRequest) and returning the relative return message (HelloReply).\n\nIn the case of the example the helloworld_action.py is created:\n\n```python\nfrom easygrpc import Action\nfrom .helloworld_pb2 import HelloReply\n\n\nclass Hello(Action):\n async def execute(self, hello_request=None):\n return HelloReply(message=f'Hello {hello_request.name}!')\n\n```\n\nAn *Action* is a Class extending the **easygrpc.action.Action** abstract base class, and must overwrite the execute method.\n\n### 3. Configure and run the GRPC service\n\nFinally to run the service you shall create a config file which is used to configure and run the service.\n\n```ini\n[SERVER]\nserver = example.helloworld_grpc.GreeterBase\nclient = example.client.SendRequest\nhost = 127.0.0.1\nport = 50051\n\n[ACTIONS]\nSayHello = example.helloworld_action.Hello\n\n```\n\nIn the *ACTIONS* section you shall declare one action for each rcp function. Of corse you can declare more then the defined rpc that can be used and exposed.\n\nTo run the service just open a terminal, and:\n\n```bash\nsource venv/bin/activate\npython -m easygrpc.start\n```\n\nTo execute the client, open another teminal, and:\n\n```bash\nsource venv/bin/activate\npython -m easygrpc.start -c\n```\n\nYou should see the response from the service:\n\n```bash\nHello Mr. Easy!\n```\n\n\n## Database interaction\n\nIn every implemented Action you have access to a PostgreSQL Database Client Library ([asyncpg](https://github.com/MagicStack/asyncpg)). In the config file, you define the PostgreSQL connection parameters. And the in the action implementation you can execute SQL commands to interact with the database.\n\ncreate a postgreSQL (versions 9.2 to 10) database named 'easy'.\n\n```bash\nsudo -u postgres createdb -E UTF8 easy\n```\n\nThen create a new table:\n\n```SQL\nCREATE TABLE public.messages\n(\n id serial,\n text character varying,\n PRIMARY KEY (id)\n);\n```\n\nAnd insert a row:\n\n```SQL\nINSERT INTO public.messages(text) VALUES ('Hello PostgreSQL!');\n```\n\nAdd the following configuration section:\n\n```ini\n[POSTGRESQL]\nuser = postgres\npassword = postgres\ndatabase = easy\nhost = localhost\nport = 5432\n\n```\n\nModify the Hello Action (example/helloword_action.py):\n\n```python\nfrom easygrpc import Action\nfrom .helloworld_pb2 import HelloReply\n\n\nclass Hello(Action):\n async def execute(self, hello_request=None):\n rec = await self.conn.fetchval(\"\"\"\n SELECT row_to_json(t)\n FROM (\n SELECT\n text as message\n FROM public.messages\n WHERE\n id = $1\n ) as t\n \"\"\", 1)\n if rec is not None:\n return self.encode(rec, HelloReply)\n return None\n\n```\n\nTo run the service just open a terminal, and:\n\n```bash\nsource venv/bin/activate\npython -m easygrpc.start\n```\n\nTo execute the client, open another teminal, and:\n\n```bash\nsource venv/bin/activate\npython -m easygrpc.start -c\n```\n\n\n## Example with multiple Services\n\nYou can of course declare more then one service and clients in your proto file:\n\n\n```protobuf\nsyntax = \"proto3\";\n\npackage example.helloworld;\n\nmessage HelloRequest {\n string name = 1;\n}\n\nmessage HelloReply {\n string message = 1;\n}\n\nservice Greeter {\n rpc SayHello (HelloRequest) returns (HelloReply) {}\n}\n\nservice GreeterDB {\n rpc SayHello (HelloRequest) returns (HelloReply) {}\n}\n\n```\n\nIn this case the *config.ini* file will be a little bit different:\n\n```ini\n[POSTGRESQL]\nuser = postgres\npassword = postgres\ndatabase = easy\nhost = localhost\nport = 5432\n\n[SERVER]\nserver = example.helloworld_grpc.Greeter,\n example.helloworld_grpc.GreeterDB\nclient = example.client.SendRequest,\n example.client.SendRequestDb\nhost = 127.0.0.1\nport = 50051\n\n[ACTIONS]\nGreeter.SayHello = example.helloworld_action.Hello\nGreeterDB.SayHello = example.helloworld_action.HelloDb\n\n```\n\nPay attention to the *ACTIONS* section. The keys are defined using a dot notation to identify which server is used with the given action.\n\nThe clients can also be more than one (see ./example/client.py):\n\n\n```python\nimport asyncio\n\nfrom grpclib.client import Channel\n\n# generated by protoc\nfrom .helloworld_pb2 import HelloRequest, HelloReply\nfrom .helloworld_grpc import GreeterStub, GreeterDBStub\n\n\nasync def SendRequest(channel):\n greeter = GreeterStub(channel)\n\n reply = await greeter.SayHello(HelloRequest(name='Mr. Easy'))\n print(reply.message)\n\n channel.close()\n\nasync def SendRequestDb(channel):\n greeter = GreeterDBStub(channel)\n\n reply = await greeter.SayHello(HelloRequest(name='Mr. PostgreSQL'))\n print(reply.message)\n\n channel.close()\n```\n\nTo run the service is just same as starting a single service instance:\n\n```bash\nsource venv/bin/activate\npython -m easygrpc.start\n```\n\nTo execute the client, instead, you can chose which client to run:\n\n```bash\nsource venv/bin/activate\npython -m easygrpc.start -c example.client.SendRequestDb\n```\n\n> **Note:** *If the client is not give as a the parameter than the first one is executed*\n\n\n\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://gitlab.com/ist-supsi/istsosm/utils/easygrpc", "keywords": "istsos grpc", "license": "", "maintainer": "", "maintainer_email": "", "name": "easy-grpc", "package_url": "https://pypi.org/project/easy-grpc/", "platform": "", "project_url": "https://pypi.org/project/easy-grpc/", "project_urls": { "Documentation": "https://gitlab.com/ist-supsi/istsosm/utils/easygrpc", "Homepage": "https://gitlab.com/ist-supsi/istsosm/utils/easygrpc", "Source": "https://gitlab.com/ist-supsi/istsosm/utils/easygrpc", "Tracker": "https://gitlab.com/ist-supsi/istsosm/utils/easygrpc/issues" }, "release_url": "https://pypi.org/project/easy-grpc/0.0.1b5/", "requires_dist": [ "googleapis-common-protos", "grpclib", "asyncpg" ], "requires_python": ">=3, <4", "summary": "Helper module to build GRPC service easily", "version": "0.0.1b5" }, "last_serial": 5634462, "releases": { "0.0.1b1": [ { "comment_text": "", "digests": { "md5": "4cc35009559d41b7206e2775beb2d491", "sha256": "025154314662b7c2567d974b818cb55b403a6ddf579e45f47020ddffcf1ddccc" }, "downloads": -1, "filename": "easy_grpc-0.0.1b1-py3-none-any.whl", "has_sig": false, "md5_digest": "4cc35009559d41b7206e2775beb2d491", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3, <4", "size": 9704, "upload_time": "2019-07-24T12:56:42", "url": "https://files.pythonhosted.org/packages/b3/08/c4d045951415d7988671d18b5dfe08e0a4287bf96a8f964eea29f23a4228/easy_grpc-0.0.1b1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8750c4b238315ff8f5bcf0303acb47a7", "sha256": "f567c59b224cad9780ded37798986eb1261484dbc8408e57220a5d07a653bf75" }, "downloads": -1, "filename": "easy-grpc-0.0.1b1.tar.gz", "has_sig": false, "md5_digest": "8750c4b238315ff8f5bcf0303acb47a7", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3, <4", "size": 7722, "upload_time": "2019-07-24T12:56:44", "url": "https://files.pythonhosted.org/packages/35/63/7aa058d41c3c8dd30871c5c36400ca58f5a8aea5eb3323a300f0e600d676/easy-grpc-0.0.1b1.tar.gz" } ], "0.0.1b2": [ { "comment_text": "", "digests": { "md5": "bd28137b150a464aa283cec7492ce9bb", "sha256": "82112c858cf1d850a219991a1db4d4614bac130c8f53977d024bbb68dc84fe3a" }, "downloads": -1, "filename": "easy_grpc-0.0.1b2-py3-none-any.whl", "has_sig": false, "md5_digest": "bd28137b150a464aa283cec7492ce9bb", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3, <4", "size": 10855, "upload_time": "2019-07-29T15:09:40", "url": "https://files.pythonhosted.org/packages/62/5b/a506a947ad483c5614519a44d4a480d703ed4c7c432eb85389b7bd552dcd/easy_grpc-0.0.1b2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "48b6bf01cbcba30d385193f27f4d9834", "sha256": "55873f4e13fce21a80da6184a9994bfc576334633103f469eeeb0aeb85edb28c" }, "downloads": -1, "filename": "easy-grpc-0.0.1b2.tar.gz", "has_sig": false, "md5_digest": "48b6bf01cbcba30d385193f27f4d9834", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3, <4", "size": 8944, "upload_time": "2019-07-29T15:09:41", "url": "https://files.pythonhosted.org/packages/c0/ca/ae3089e62cf24e58547316950d6db6904bd6c0daccd9fe0be899e2d75427/easy-grpc-0.0.1b2.tar.gz" } ], "0.0.1b3": [ { "comment_text": "", "digests": { "md5": "434a7b7b411abb465d62ba3f55d12d20", "sha256": "2946e8fe139286c021d495a47458b8cfbdaa3e977bdde4966f81c44dcfc681a7" }, "downloads": -1, "filename": "easy_grpc-0.0.1b3-py3-none-any.whl", "has_sig": false, "md5_digest": "434a7b7b411abb465d62ba3f55d12d20", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3, <4", "size": 10918, "upload_time": "2019-07-31T13:02:35", "url": "https://files.pythonhosted.org/packages/dd/35/2d4ec3f3aed06539a125b028b318f19f0df9f11085ed0fbde9708047bd27/easy_grpc-0.0.1b3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "f4043d308da7f6dfd9fb5ff337f72fbe", "sha256": "3b431165e106e816aad8e6c91d37de751d3a73e39a9d80a5a59ef85c2b45d3eb" }, "downloads": -1, "filename": "easy-grpc-0.0.1b3.tar.gz", "has_sig": false, "md5_digest": "f4043d308da7f6dfd9fb5ff337f72fbe", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3, <4", "size": 9007, "upload_time": "2019-07-31T13:02:36", "url": "https://files.pythonhosted.org/packages/d5/b0/4d56fd81e041e86816896357ad7fc8d18e493083788464e5360e40b9f295/easy-grpc-0.0.1b3.tar.gz" } ], "0.0.1b4": [ { "comment_text": "", "digests": { "md5": "7959b30aa769a90d55b1574442b88d65", "sha256": "5f7300f2b2069f61317606b1ee01d112b6cbf6d18c783dd0404e808c60153a8f" }, "downloads": -1, "filename": "easy_grpc-0.0.1b4-py2-none-any.whl", "has_sig": false, "md5_digest": "7959b30aa769a90d55b1574442b88d65", "packagetype": "bdist_wheel", "python_version": "py2", "requires_python": ">=3, <4", "size": 10715, "upload_time": "2019-07-31T13:54:10", "url": "https://files.pythonhosted.org/packages/e8/11/d26a2eba3d4d2b33ef5aa9d9bc82d5485e15cbae72323f6fff523360719c/easy_grpc-0.0.1b4-py2-none-any.whl" }, { "comment_text": "", "digests": { "md5": "1c76e8a87f8e95684b71398800944b74", "sha256": "f5e9846120bc8f0d0907dcf5ba164b7b9d4b6e80cdd16ba719419b55aae8de6c" }, "downloads": -1, "filename": "easy-grpc-0.0.1b4.tar.gz", "has_sig": false, "md5_digest": "1c76e8a87f8e95684b71398800944b74", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3, <4", "size": 11075, "upload_time": "2019-07-31T13:54:12", "url": "https://files.pythonhosted.org/packages/1f/ca/cf8d339098326b9e5b809e1b2939aa2f041eec773accbceee2deb1e7529e/easy-grpc-0.0.1b4.tar.gz" } ], "0.0.1b5": [ { "comment_text": "", "digests": { "md5": "75296cd689a09a286b8ad9c9332d0b4e", "sha256": "11e2a110233872a084daa7323931ecb01093c76ab0e604e39fbe7a5b99d2c55b" }, "downloads": -1, "filename": "easy_grpc-0.0.1b5-py3-none-any.whl", "has_sig": false, "md5_digest": "75296cd689a09a286b8ad9c9332d0b4e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3, <4", "size": 12150, "upload_time": "2019-08-05T13:58:56", "url": "https://files.pythonhosted.org/packages/f3/ae/6dee91c81d64295006a95247d7b699b378a95883fa6d855f2976de73572a/easy_grpc-0.0.1b5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "cfbc732d95962d30d6bf2d4c9f87f06a", "sha256": "ad66ec22e87649d4ee6f7e8101159d81579fd7e249a597c757fb2423d22d7c4e" }, "downloads": -1, "filename": "easy-grpc-0.0.1b5.tar.gz", "has_sig": false, "md5_digest": "cfbc732d95962d30d6bf2d4c9f87f06a", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3, <4", "size": 10171, "upload_time": "2019-08-05T13:58:57", "url": "https://files.pythonhosted.org/packages/9c/d6/5eae799612206ee4ce1090ed9f7084d7ee53c02fbf7fa2d72aaf4a4e5a88/easy-grpc-0.0.1b5.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "75296cd689a09a286b8ad9c9332d0b4e", "sha256": "11e2a110233872a084daa7323931ecb01093c76ab0e604e39fbe7a5b99d2c55b" }, "downloads": -1, "filename": "easy_grpc-0.0.1b5-py3-none-any.whl", "has_sig": false, "md5_digest": "75296cd689a09a286b8ad9c9332d0b4e", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3, <4", "size": 12150, "upload_time": "2019-08-05T13:58:56", "url": "https://files.pythonhosted.org/packages/f3/ae/6dee91c81d64295006a95247d7b699b378a95883fa6d855f2976de73572a/easy_grpc-0.0.1b5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "cfbc732d95962d30d6bf2d4c9f87f06a", "sha256": "ad66ec22e87649d4ee6f7e8101159d81579fd7e249a597c757fb2423d22d7c4e" }, "downloads": -1, "filename": "easy-grpc-0.0.1b5.tar.gz", "has_sig": false, "md5_digest": "cfbc732d95962d30d6bf2d4c9f87f06a", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3, <4", "size": 10171, "upload_time": "2019-08-05T13:58:57", "url": "https://files.pythonhosted.org/packages/9c/d6/5eae799612206ee4ce1090ed9f7084d7ee53c02fbf7fa2d72aaf4a4e5a88/easy-grpc-0.0.1b5.tar.gz" } ] }