{"id":17289198,"url":"https://github.com/dipu-bd/pyease-grpc","last_synced_at":"2026-03-02T21:07:57.998Z","repository":{"id":47961253,"uuid":"454914040","full_name":"dipu-bd/pyease-grpc","owner":"dipu-bd","description":"Easy to use requests-like gRPC client in python","archived":false,"fork":false,"pushed_at":"2026-02-26T16:13:55.000Z","size":61,"stargazers_count":7,"open_issues_count":0,"forks_count":2,"subscribers_count":1,"default_branch":"master","last_synced_at":"2026-02-26T22:39:30.412Z","etag":null,"topics":["grpc","grpc-client","grpc-web","protobuf","rpc"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dipu-bd.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2022-02-02T19:50:59.000Z","updated_at":"2026-02-26T16:15:28.000Z","dependencies_parsed_at":"2025-04-15T23:54:16.150Z","dependency_job_id":null,"html_url":"https://github.com/dipu-bd/pyease-grpc","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/dipu-bd/pyease-grpc","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dipu-bd%2Fpyease-grpc","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dipu-bd%2Fpyease-grpc/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dipu-bd%2Fpyease-grpc/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dipu-bd%2Fpyease-grpc/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dipu-bd","download_url":"https://codeload.github.com/dipu-bd/pyease-grpc/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dipu-bd%2Fpyease-grpc/sbom","scorecard":{"id":344182,"data":{"date":"2025-08-11","repo":{"name":"github.com/dipu-bd/pyease-grpc","commit":"8a1c9d9137e1f961efd45fcbc72bb4f893a07afc"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.7,"checks":[{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Code-Review","score":1,"reason":"Found 3/29 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: no topLevel permission defined: .github/workflows/commit.yml:1","Warn: no topLevel permission defined: .github/workflows/release.yml:1","Info: no jobLevel write permissions found"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":1,"reason":"2 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE:0","Info: FSF or OSI recognized license: MIT License: LICENSE:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":0,"reason":"Project has not signed or included provenance with any releases.","details":["Warn: release artifact v1.7.1 not signed: https://api.github.com/repos/dipu-bd/pyease-grpc/releases/221944603","Warn: release artifact v1.7.0 not signed: https://api.github.com/repos/dipu-bd/pyease-grpc/releases/169833635","Warn: release artifact v1.6.1 not signed: https://api.github.com/repos/dipu-bd/pyease-grpc/releases/84877650","Warn: release artifact v1.6.0 not signed: https://api.github.com/repos/dipu-bd/pyease-grpc/releases/84877395","Warn: release artifact v1.5.1 not signed: https://api.github.com/repos/dipu-bd/pyease-grpc/releases/84867235","Warn: release artifact v1.7.1 does not have provenance: https://api.github.com/repos/dipu-bd/pyease-grpc/releases/221944603","Warn: release artifact v1.7.0 does not have provenance: https://api.github.com/repos/dipu-bd/pyease-grpc/releases/169833635","Warn: release artifact v1.6.1 does not have provenance: https://api.github.com/repos/dipu-bd/pyease-grpc/releases/84877650","Warn: release artifact v1.6.0 does not have provenance: https://api.github.com/repos/dipu-bd/pyease-grpc/releases/84877395","Warn: release artifact v1.5.1 does not have provenance: https://api.github.com/repos/dipu-bd/pyease-grpc/releases/84867235"],"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Pinned-Dependencies","score":1,"reason":"dependency not pinned by hash detected -- score normalized to 1","details":["Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/commit.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/dipu-bd/pyease-grpc/commit.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/commit.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/dipu-bd/pyease-grpc/commit.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:17: update your workflow using https://app.stepsecurity.io/secureworkflow/dipu-bd/pyease-grpc/release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:19: update your workflow using https://app.stepsecurity.io/secureworkflow/dipu-bd/pyease-grpc/release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:47: update your workflow using https://app.stepsecurity.io/secureworkflow/dipu-bd/pyease-grpc/release.yml/master?enable=pin","Warn: GitHub-owned GitHubAction not pinned by hash: .github/workflows/release.yml:49: update your workflow using https://app.stepsecurity.io/secureworkflow/dipu-bd/pyease-grpc/release.yml/master?enable=pin","Warn: third-party GitHubAction not pinned by hash: .github/workflows/release.yml:62: update your workflow using https://app.stepsecurity.io/secureworkflow/dipu-bd/pyease-grpc/release.yml/master?enable=pin","Warn: containerImage not pinned by hash: example/envoy/Dockerfile:1: pin your Docker image by updating envoyproxy/envoy:v1.15.0 to envoyproxy/envoy:v1.15.0@sha256:f455fd7b45c2fe5d2862e19a3858284bbffc9c72359e0012641b59859d5c68db","Warn: containerImage not pinned by hash: example/server/Dockerfile:1: pin your Docker image by updating python:3.8-alpine to python:3.8-alpine@sha256:3d93b1f77efce339aa77db726656872517b0d67837989aa7c4b35bd5ae7e81ba","Warn: pipCommand not pinned by hash: example/server/Dockerfile:5","Warn: pipCommand not pinned by hash: .github/workflows/commit.yml:25","Warn: pipCommand not pinned by hash: .github/workflows/commit.yml:26","Warn: pipCommand not pinned by hash: .github/workflows/commit.yml:30","Warn: pipCommand not pinned by hash: .github/workflows/release.yml:25","Warn: pipCommand not pinned by hash: .github/workflows/release.yml:26","Warn: pipCommand not pinned by hash: .github/workflows/release.yml:30","Warn: pipCommand not pinned by hash: .github/workflows/release.yml:55","Warn: pipCommand not pinned by hash: .github/workflows/release.yml:56","Info:   0 out of   6 GitHub-owned GitHubAction dependencies pinned","Info:   0 out of   1 third-party GitHubAction dependencies pinned","Info:   0 out of   2 containerImage dependencies pinned","Info:   2 out of  11 pipCommand dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"Vulnerabilities","score":2,"reason":"8 existing vulnerabilities detected","details":["Warn: Project is vulnerable to: PYSEC-2024-48 / GHSA-fj7x-q9j7-g6q6","Warn: Project is vulnerable to: GHSA-8gq9-2x98-w8hf","Warn: Project is vulnerable to: GHSA-8qvm-5x2c-j2w7","Warn: Project is vulnerable to: GHSA-9hjg-9r4m-mvj7","Warn: Project is vulnerable to: GHSA-9wx4-h78v-vm56","Warn: Project is vulnerable to: PYSEC-2023-74 / GHSA-j8r2-6x86-q33q","Warn: Project is vulnerable to: GHSA-496j-2rq6-j6cc","Warn: Project is vulnerable to: PYSEC-2017-101"],"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 4 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-18T06:40:49.184Z","repository_id":47961253,"created_at":"2025-08-18T06:40:49.184Z","updated_at":"2025-08-18T06:40:49.184Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30020288,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-02T20:56:45.032Z","status":"ssl_error","status_checked_at":"2026-03-02T20:51:18.182Z","response_time":60,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["grpc","grpc-client","grpc-web","protobuf","rpc"],"created_at":"2024-10-15T10:33:58.636Z","updated_at":"2026-03-02T21:07:57.977Z","avatar_url":"https://github.com/dipu-bd.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# pyease-grpc\n\n[![Build](https://github.com/dipu-bd/pyease-grpc/actions/workflows/commit.yml/badge.svg)](https://github.com/dipu-bd/pyease-grpc/actions/workflows/commit.yml)\n[![Release](https://github.com/dipu-bd/pyease-grpc/actions/workflows/release.yml/badge.svg)](https://github.com/dipu-bd/pyease-grpc/actions/workflows/release.yml)\n[![PyPI version](https://img.shields.io/pypi/v/pyease-grpc.svg?logo=python)](https://pypi.org/project/pyease-grpc)\n[![Python version](https://img.shields.io/pypi/pyversions/pyease-grpc.svg)](https://pypi.org/project/pyease-grpc)\n[![GitHub License](https://img.shields.io/github/license/dipu-bd/pyease-grpc)](https://github.com/dipu-bd/pyease-grpc/blob/master/LICENSE)\n[![Downloads](https://pepy.tech/badge/pyease-grpc/month)](https://pepy.tech/project/pyease-grpc)\n\nEasy to use gRPC-web client in python\n\n### Installation\n\nInstall the package using:\n\n```\n$ pip install pyease-grpc\n```\n\nRun the following to check if it has been installed correctly:\n\n```\n$ pyease-grpc --version\n```\n\n## Tutorial\n\n\u003e Before you start, you need to have a basic understanding of [how gRPC works](https://grpc.io/docs/what-is-grpc/introduction/).\n\nThis package provides a `requests` like interface to make calls to native gRPC and gRPC-Web servers.\n\n### Example Server\n\nAn example server and client can be found in the `example` folder.\n\n```\n\u003e cd example\n\u003e docker compose up\n```\n\nIt uses two ports:\n\n- Native gRPC server: `localhost:50050`\n- gRPC-Web server using envoy: `http://localhost:8080`\n\nYou can test the native serve with the client:\n\n```\n$ python example/server/client.py\nCalling SayHello:\nreply: \"Hello, world!\"\n\nCalling LotsOfReplies:\nreply: \"Hello, world no. 0!\"\nreply: \"Hello, world no. 1!\"\nreply: \"Hello, world no. 2!\"\nreply: \"Hello, world no. 3!\"\nreply: \"Hello, world no. 4!\"\n\nCalling LotsOfGreetings:\nreply: \"Hello, A, B, C!\"\n\nCalling BidiHello:\nreply: \"Hello, A!\"\nreply: \"Hello, B!\"\nreply: \"Hello, C!\"\n```\n\n### Loading the Protobuf\n\nThe proto file is located at `example/server/abc.proto`\n\n```proto\n// file: example/server/abc.proto\nsyntax = \"proto3\";\n\npackage pyease.sample.v1;\n\nservice Greeter {\n  rpc SayHello (HelloRequest) returns (HelloResponse);\n  rpc LotsOfReplies(HelloRequest) returns (stream HelloResponse);\n  rpc LotsOfGreetings(stream HelloRequest) returns (HelloResponse);\n  rpc BidiHello(stream HelloRequest) returns (stream HelloResponse);\n}\n\nmessage HelloRequest {\n  string name = 1;\n}\n\nmessage HelloResponse {\n  string reply = 1;\n}\n```\n\nYou can directly load this file using `pyease_grpc` without generating any stubs:\n\n```py\nfrom pyease_grpc import Protobuf\n\nprotobuf = Protobuf.from_file(\"example/server/abc.proto\")\n```\n\nInternally, it converts the proto file into `FileDescriptorSet` message.\n\nIt is recommended to use the `FileDescriptorSet` json to load the `Protobuf` faster.\n\nTo generate the `FileDescriptorSet` json from a proto file:\n\n```\n$ pyease-grpc -I example/server example/server/abc.proto --output abc_fds.json\n```\n\nNow you can use this descriptor file directly to create a `Protobuf` instance.\n\n```py\nprotobuf = Protobuf.restore_file('abc_fds.json')\n```\n\n### Getting response from gRPC-Web\n\nFor **Unary RPC** request:\n\n```py\nfrom pyease_grpc import RpcSession, RpcUri\n\nsession = RpcSession.from_file(\"example/server/abc.proto\")\nresponse = session.request(\n    RpcUri(\n      base_url=\"http://localhost:8080\",\n      package=\"pyease.sample.v1\",\n      service=\"Greeter\",\n      method=\"SayHello\",\n    ),\n    {\n      \"name\": \"world\"\n    },\n)\nresponse.raise_for_status()\n\nprint(response.single['reply'])\n```\n\nFor a **Server-side Streaming RPC** request:\n\n```py\nfrom pyease_grpc import RpcSession, RpcUri\n\nsession = RpcSession.from_file(\"example/server/abc.proto\")\nresponse = session.request(\n    RpcUri(\n      base_url=\"http://localhost:8080\",\n      package=\"pyease.sample.v1\",\n      service=\"Greeter\",\n      method=\"LotsOfReplies\",\n    ),\n    {\n      \"name\": \"world\",\n    },\n)\nresponse.raise_for_status()\n\nfor payload in response.iter_payloads():\n    print(payload[\"reply\"])\n```\n\n\u003e gRPC-Web currently supports 2 RPC modes: Unary RPCs, Server-side Streaming RPCs.\n\u003e Client-side and Bi-directional streaming is not currently supported.\n\n### Using the native gRPC protocol\n\nYou can also directly call a method using the native gRPC protocol.\n\nFor **Unary RPC** request:\n\n```py\nfrom pyease_grpc import RpcSession, RpcUri\n\nsession = RpcSession.from_file(\"example/server/abc.proto\")\nresponse = session.call(\n    RpcUri(\n      base_url=\"localhost:50050\",\n      package=\"pyease.sample.v1\",\n      service=\"Greeter\",\n      method=\"SayHello\",\n    ),\n    {\n      \"name\": \"world\",\n    }\n)\n\nprint(response.single[\"reply\"])\nprint(response.payloads)\n```\n\nFor a **Server-side Streaming RPC** request:\n\n```py\nfrom pyease_grpc import RpcSession, RpcUri\n\nsession = RpcSession.from_file(\"example/server/abc.proto\")\nresponse = session.call(\n    RpcUri(\n      base_url=\"localhost:50050\",\n      package=\"pyease.sample.v1\",\n      service=\"Greeter\",\n      method=\"LotsOfReplies\",\n    ),\n    {\n      \"name\": \"world\",\n    },\n)\n\nfor payload in response.iter_payloads():\n    print(payload[\"reply\"])\nprint(response.payloads)\n```\n\nFor a **Client-Side Streaming RPC** request:\n\n```py\nfrom pyease_grpc import RpcSession, RpcUri\n\nsession = RpcSession.from_file(\"example/server/abc.proto\")\nresponse = session.call(\n    RpcUri(\n      base_url=\"localhost:50050\",\n      package=\"pyease.sample.v1\",\n      service=\"Greeter\",\n      method=\"LotsOfGreetings\",\n    ),\n    iter(\n      [\n        {\"name\": \"A\"},\n        {\"name\": \"B\"},\n        {\"name\": \"C\"},\n      ]\n    ),\n)\n\nprint(response.single[\"reply\"])\nprint(response.payloads)\n```\n\nFor a **Bidirectional Streaming RPC** request:\n\n```py\nfrom pyease_grpc import RpcSession, RpcUri\n\nsession = RpcSession.from_file(\"example/server/abc.proto\")\nresponse = session.call(\n    RpcUri(\n      base_url=\"localhost:50050\",\n      package=\"pyease.sample.v1\",\n      service=\"Greeter\",\n      method=\"BidiHello\",\n    ),\n    iter(\n      [\n        {\"name\": \"A\"},\n        {\"name\": \"B\"},\n        {\"name\": \"C\"},\n      ]\n    ),\n)\n\nfor payload in response.iter_payloads():\n    print(payload[\"reply\"])\nprint(response.payloads)\n```\n\n### Error Handling\n\nErrors are raised as soon as they appear.\n\nList of errors that can appear during `request`:\n\n- `ValueError`: If the requested method, service or package is not found\n- `requests.exceptions.InvalidHeader`: If the header of expected length is not found\n- `requests.exceptions.ContentDecodingError`: If the data of expected length is not found\n- `NotImplementedError`: If compression is enabled in the response headers\n- `grpc.RpcError`: If the grpc-status is non-zero\n\nList of errors that can appear during `call`:\n\n- `ValueError`: If the requested method, service or package is not found\n- `grpc.RpcError`: If the grpc-status is non-zero\n\nTo get the `grpc-status` and `grpc-message`, you can add a try-catch to your call. e.g.:\n\n```py\nimport grpc\nfrom pyease_grpc import RpcSession, RpcUri\n\nsession = RpcSession.from_file(\"example/server/abc.proto\")\nrpc_uri = RpcUri(\n  base_url=\"localhost:50050\",\n  package=\"pyease.sample.v1\",\n  service=\"Greeter\",\n  method=\"SayHello\",\n)\ntry:\n  response = session.call(rpc_uri, {\"name\": \"error\"})\n  print(response.single[\"reply\"])\nexcept grpc.RpcError as e:\n  print('grpc status', e.code())\n  print('grpc message', e.details())\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdipu-bd%2Fpyease-grpc","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdipu-bd%2Fpyease-grpc","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdipu-bd%2Fpyease-grpc/lists"}