{"id":31622842,"url":"https://github.com/connectrpc/connect-python","last_synced_at":"2026-05-29T04:01:25.921Z","repository":{"id":316152139,"uuid":"1062161604","full_name":"connectrpc/connect-python","owner":"connectrpc","description":"The Python implementation of Connect: Protobuf RPC that works.","archived":false,"fork":false,"pushed_at":"2026-05-25T09:25:36.000Z","size":2588,"stargazers_count":114,"open_issues_count":2,"forks_count":11,"subscribers_count":4,"default_branch":"main","last_synced_at":"2026-05-25T11:19:38.924Z","etag":null,"topics":["connectrpc","grpc","protobuf","python"],"latest_commit_sha":null,"homepage":"https://connectrpc.com","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/connectrpc.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":"MAINTAINERS.md","copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2025-09-22T22:23:34.000Z","updated_at":"2026-05-25T09:25:38.000Z","dependencies_parsed_at":"2025-09-23T02:30:29.626Z","dependency_job_id":"894ef835-b931-4aa8-a667-4b69d72edd7a","html_url":"https://github.com/connectrpc/connect-python","commit_stats":null,"previous_names":["connectrpc/connect-python"],"tags_count":12,"template":false,"template_full_name":null,"purl":"pkg:github/connectrpc/connect-python","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/connectrpc%2Fconnect-python","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/connectrpc%2Fconnect-python/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/connectrpc%2Fconnect-python/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/connectrpc%2Fconnect-python/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/connectrpc","download_url":"https://codeload.github.com/connectrpc/connect-python/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/connectrpc%2Fconnect-python/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33635961,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"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":["connectrpc","grpc","protobuf","python"],"created_at":"2025-10-06T17:35:59.065Z","updated_at":"2026-05-29T04:01:25.914Z","avatar_url":"https://github.com/connectrpc.png","language":"Python","funding_links":[],"categories":["Python"],"sub_categories":[],"readme":"# connect-python\n\n[![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)](https://opensource.org/licenses/Apache-2.0)\n[![CI](https://github.com/connectrpc/connect-python/actions/workflows/ci.yaml/badge.svg)](https://github.com/connectrpc/connect-python/actions/workflows/ci.yaml)\n[![codecov](https://codecov.io/github/connectrpc/connect-python/graph/badge.svg)](https://codecov.io/github/connectrpc/connect-python)\n[![PyPI version](https://img.shields.io/pypi/v/connect-python)](https://pypi.org/project/connect-python)\n[![API Docs](https://img.shields.io/badge/API_Docs-connectrpc.github.io-blue)](https://connectrpc.github.io/connect-python/api/)\n\nA Python implementation of [Connect](https://connectrpc.com/): Protobuf RPC that works.\n\nThis repo provides a Python implementation of Connect, including both client and server support. It includes a protoc plugin that generates typed client stubs and server interfaces from your `.proto` files, along with runtime libraries for both synchronous and asynchronous code.\n\n## Features\n\n- **Clients**: Both synchronous and asynchronous clients backed by [pyqwest](https://pyqwest.dev/)\n- **Servers**: WSGI and ASGI server implementations for use with any Python app server\n- **Type Safety**: Fully type-annotated, including the generated code\n- **Compression**: Built-in support for gzip, brotli, and zstd compression\n- **Interceptors**: Server-side and client-side interceptors for cross-cutting concerns\n- **Streaming**: Full support for server, client, and bidirectional streaming\n- **Standards Compliant**: Verified implementation using the official\n  [Connect conformance](https://github.com/connectrpc/conformance) test\n  suite\n\n## Installation\n\n### Install the runtime library\n\n```bash\npip install connectrpc\n```\n\nOr with your preferred package manager:\n\n```bash\n# Using uv\nuv add connectrpc\n\n# Using poetry\npoetry add connectrpc\n```\n\n### Install the code generator\n\nWith a protobuf definition in hand, you can generate stub code. This is\neasiest using buf, but you can also use protoc if you're feeling\nmasochistic.\n\nA reasonable `buf.gen.yaml`:\n\n```yaml\nversion: v2\nplugins:\n  - remote: buf.build/protocolbuffers/python\n    out: .\n  - remote: buf.build/protocolbuffers/pyi\n    out: .\n  - remote: buf.build/connectrpc/python\n    out: .\n```\n\nOr, you can install the compiler (e.g. `pip install protoc-gen-connectrpc`), and\nit can be referenced as `protoc-gen-connectrpc`.\nThen, you can use `protoc-gen-connectrpc` as a local plugin:\n\n```yaml\n- local: .venv/bin/protoc-gen-connectrpc\n  out: .\n```\n\nAlternatively, download a precompiled binary from the\n[releases](https://github.com/connectrpc/connect-python/releases).\n\n`protoc-gen-connectrpc` is only needed for code generation. Your actual\napplication should include `connectrpc` as a dependency for the runtime\ncomponent.\n\n### Basic Client Usage\n\n```python\nfrom your_service_pb2 import HelloRequest, HelloResponse\nfrom your_service_connect import HelloServiceClient\n\n# Create async client\nasync def main():\n    async with HelloServiceClient(\"https://api.example.com\") as client:\n        # Make a unary RPC call\n        response = await client.say_hello(HelloRequest(name=\"World\"))\n        print(response.message)  # \"Hello, World!\"\n```\n\n### Basic Server Usage\n\n```python\nfrom connectrpc.request import RequestContext\nfrom your_service_pb2 import HelloRequest, HelloResponse\nfrom your_service_connect import HelloService, HelloServiceASGIApplication\n\nclass MyHelloService(HelloService):\n    async def say_hello(self, request: HelloRequest, ctx: RequestContext) -\u003e HelloResponse:\n        return HelloResponse(message=f\"Hello, {request.name}!\")\n\n# Create ASGI app\napp = HelloServiceASGIApplication(MyHelloService())\n\n# Run with any ASGI server like uvicorn and hypercorn:\n# uvicorn server:app --port 8080\n```\n\n### Basic Client Usage (Synchronous)\n\n```python\nfrom your_service_pb2 import HelloRequest\nfrom your_service_connect import HelloServiceClientSync\n\n# Create sync client\ndef main():\n    with HelloServiceClientSync(\"https://api.example.com\") as client:\n        # Make a unary RPC call\n        response = client.say_hello(HelloRequest(name=\"World\"))\n        print(response.message)  # \"Hello, World!\"\n\nif __name__ == \"__main__\":\n    main()\n```\n\nCheck out [the docs](https://connectrpc.com/docs/python/getting-started) for more detailed usage including [streaming](https://connectrpc.com/docs/python/streaming), [interceptors](https://connectrpc.com/docs/python/interceptors), and other advanced features.\n\n## Streaming Support\n\nconnect-python supports all RPC streaming types:\n\n- **Unary**: Single request, single response\n- **Server Streaming**: Single request, multiple responses\n- **Client Streaming**: Multiple requests, single response\n- **Bidirectional Streaming**: Multiple requests, multiple responses\n\n### Server Streaming\n\nSingle request, multiple responses:\n\n```python\n# Server implementation\nasync def make_hats(self, req: Size, ctx: RequestContext) -\u003e AsyncIterator[Hat]:\n    for i in range(3):\n        yield Hat(size=req.inches + i, color=[\"red\", \"green\", \"blue\"][i])\n\n# Client usage\nasync for hat in client.make_hats(Size(inches=12)):\n    print(f\"Received: {hat}\")\n```\n\n### Client Streaming\n\nMultiple requests, single response:\n\n```python\n# Server implementation\nasync def collect_sizes(self, reqs: AsyncIterator[Size], ctx: RequestContext) -\u003e Summary:\n    total = 0\n    count = 0\n    async for size in reqs:\n        total += size.inches\n        count += 1\n    return Summary(total=total, average=total/count if count else 0)\n\n# Client usage\nasync def send_sizes():\n    for i in range(5):\n        yield Size(inches=i * 2)\n\nsummary = await client.collect_sizes(send_sizes())\n```\n\n### Bidirectional Streaming\n\nMultiple requests and responses:\n\n```python\n# Server implementation (like the Eliza chatbot)\nasync def converse(self, reqs: AsyncIterator[ConverseRequest], ctx: RequestContext) -\u003e AsyncIterator[ConverseResponse]:\n    async for req in reqs:\n        # Process and respond to each message\n        reply = process_message(req.sentence)\n        yield ConverseResponse(sentence=reply)\n\n# Client usage\nasync def chat():\n    yield ConverseRequest(sentence=\"Hello\")\n    yield ConverseRequest(sentence=\"How are you?\")\n\nasync for response in client.converse(chat()):\n    print(f\"Response: {response.sentence}\")\n```\n\n### Streaming Notes\n\n- **HTTP/2 ASGI servers** (Hypercorn, Daphne): Support all streaming types including full-duplex bidirectional\n- **HTTP/1.1 servers**: Support half-duplex bidirectional streaming only\n- **WSGI servers**: Support streaming but not full-duplex bidirectional due to protocol limitations\n\n- **Clients**: Support half-duplex bidirectional streaming only\n\n## Examples\n\nThe `example/` directory contains complete working examples demonstrating all features:\n\n- **Eliza Chatbot**: A Connect implementation of the classic ELIZA psychotherapist chatbot\n  - `eliza_service.py` - Async ASGI server implementation\n  - `eliza_service_sync.py` - Synchronous WSGI server implementation\n  - `eliza_client.py` - Async client example\n  - `eliza_client_sync.py` - Synchronous client example\n- **All streaming patterns**: Unary, server streaming, client streaming, and bidirectional\n- **Integration examples**: Starlette, Flask, and other frameworks\n\nRun the Eliza example:\n\n```bash\n# Start the server\ncd example\nuvicorn example.eliza_service:app --port 8080\n\n# In another terminal, run the client\npython -m example.eliza_client\n```\n\n## Supported Protocols\n\n- ✅ Connect Protocol over HTTP/1.1 and HTTP/2\n- ✅ gRPC Protocol support\n- 🚧 gRPC-Web Protocol support is not available\n\n## Server Runtime Options\n\nFor ASGI servers:\n\n- [Uvicorn](https://www.uvicorn.org/) - Lightning-fast ASGI server\n- [Daphne](https://github.com/django/daphne) - Django Channels' ASGI server with HTTP/2 support\n- [Hypercorn](https://gitlab.com/pgjones/hypercorn) - ASGI server with HTTP/2 and HTTP/3 support\n\nFor WSGI servers:\n\n- [Gunicorn](https://gunicorn.org/) - Python WSGI HTTP Server\n- [uWSGI](https://uwsgi-docs.readthedocs.io/) - Full-featured application server\n- Any WSGI-compliant server\n\nFor testing, you'll need the [buf CLI](https://buf.build/docs/installation) for running conformance tests.\n\n## WSGI Support\n\nconnect-python provides full WSGI support via `ConnectWSGIApplication` for synchronous Python applications. This enables integration with traditional WSGI servers like Gunicorn and uWSGI.\n\n```python\nfrom connectrpc.request import RequestContext\nfrom connectrpc.server import ConnectWSGIApplication\nfrom your_service_pb2 import Request, Response\nfrom your_service_connect import YourService, YourServiceWSGIApplication\n\nclass YourServiceImpl(YourService):\n    def your_method(self, request: Request, ctx: RequestContext) -\u003e Response:\n        # Synchronous implementation\n        return Response(message=\"Hello from WSGI\")\n\n    # WSGI also supports streaming (except full-duplex bidirectional)\n    def stream_data(self, request: Request, ctx: RequestContext) -\u003e Iterator[Response]:\n        for i in range(3):\n            yield Response(message=f\"Message {i}\")\n\n# Create WSGI application\napp = YourServiceWSGIApplication(YourServiceImpl())\n\n# Run with gunicorn: gunicorn server:app\n```\n\n## Compression Support\n\nconnect-python supports multiple compression algorithms:\n\n- **gzip**: Built-in support, always available\n- **brotli**: Available when `brotli` package is installed\n- **zstd**: Available when `zstandard` package is installed\n\nCompression is automatically negotiated between client and server based on the `Accept-Encoding` and `Content-Encoding` headers.\n\n## Interceptors\n\n### Server-Side Interceptors\n\nInterceptors allow you to add cross-cutting concerns like authentication, logging, and metrics:\n\n```python\nfrom connectrpc.interceptor import MetadataInterceptor\nfrom connectrpc.request import RequestContext\n\nclass LoggingInterceptor:\n    \"\"\"Implements the MetadataInterceptor protocol.\"\"\"\n\n    async def on_start(self, ctx: RequestContext) -\u003e None:\n        print(f\"Handling {ctx.method().name} request\")\n\n    async def on_end(self, token: None, ctx: RequestContext, error: Exception | None) -\u003e None:\n        if error:\n            print(f\"Failed {ctx.method().name}: {error}\")\n        else:\n            print(f\"Completed {ctx.method().name} request\")\n\n# Add to your application\napp = HelloServiceASGIApplication(\n    MyHelloService(),\n    interceptors=[LoggingInterceptor()]\n)\n```\n\n### Client-Side Interceptors\n\nClients also support interceptors for request/response processing:\n\n```python\nclient = HelloServiceClient(\n    \"https://api.example.com\",\n    interceptors=[AuthInterceptor(), RetryInterceptor()]\n)\n```\n\n## Advanced Features\n\n### Connect GET Support\n\nconnect-python automatically enables GET request support for methods marked with `idempotency_level = NO_SIDE_EFFECTS` in your proto files:\n\n```proto\nservice YourService {\n  // This method will support both GET and POST requests\n  rpc GetData(Request) returns (Response) {\n    option idempotency_level = NO_SIDE_EFFECTS;\n  }\n}\n```\n\nClients can use GET requests automatically:\n\n```python\n# The client will use GET for idempotent methods\nresponse = await client.get_data(request)\n```\n\n### CORS Support\n\nconnect-python works with any ASGI CORS middleware. For example, using Starlette:\n\n```python\nfrom starlette.middleware.cors import CORSMiddleware\nfrom starlette.applications import Starlette\n\napp = Starlette()\napp.add_middleware(\n    CORSMiddleware,\n    allow_origins=[\"*\"],\n    allow_methods=[\"GET\", \"POST\"],\n    allow_headers=[\"*\"],\n)\n# Mount your Connect application\n```\n\n### Message Size Limits\n\nProtect against resource exhaustion by limiting message sizes:\n\n```python\n# ASGI application with 1MB limit\napp = YourServiceASGIApplication(\n    service,\n    read_max_bytes=1024 * 1024  # 1MB\n)\n\n# Client with message size limit\nclient = YourServiceClient(\n    \"https://api.example.com\",\n    read_max_bytes=1024 * 1024\n)\n```\n\nWhen exceeded, returns `RESOURCE_EXHAUSTED` error.\n\n### Proto Editions Support\n\n`protoc-gen-connectrpc` supports up to [Protobuf Editions](https://protobuf.dev/editions/overview/) 2024:\n\n```proto\nedition = \"2024\";\n\npackage your.service;\n\nservice YourService {\n  rpc YourMethod(Request) returns (Response);\n}\n```\n\n## Development\n\nWe use `ruff` for linting and formatting, `ty` for type checking, and `tombi` for TOML linting and formatting.\n\nWe rely on the conformance test suit (in\n[./conformance](./conformance)) to verify behavior.\n\nSet up a virtual env:\n\n```sh\nuv sync\n```\n\nThen, use `uv run poe check` to do development checks, or check out `uv run poe` for other targets.\n\n## Status\n\nThis project is in beta and is being actively developed.\n1.0 will include a new Protobuf implementation built from scratch by Buf, which may introduce breaking changes.\nJoin us on [Slack][] if you have questions or feedback.\n\n## Legal\n\nOffered under the [Apache 2 license](/LICENSE).\n\n[slack]: https://buf.build/links/slack\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconnectrpc%2Fconnect-python","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fconnectrpc%2Fconnect-python","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fconnectrpc%2Fconnect-python/lists"}