A type-safe RPC bridge between Python and TypeScript. The function signature is the contract.
Project description
dyadpy (Python)
A type-safe RPC bridge between Python and TypeScript.
uv add 'dyadpy==0.1.0a0' # alpha — drop the pin once v0.1.0 ships
This is the Python half of Dyadpy. It ships:
- A thin ASGI framework (
dyadpy.App) that uses your function signatures as the contract — no separate Pydantic models declared above the handler. - A type extractor that walks
inspect.signature+typing.get_type_hints, normalizes throughmsgspec's native JSON Schema export, and produces a canonical IR. - A codegen that turns the IR into a single
client.tsfor your frontend. - A CLI (
dyadpy dev,dyadpy build,dyadpy codegen,dyadpy init) that runs the whole loop in one process.
For the full story, the design rationale, and a side-by-side comparison vs. FastAPI + openapi-typescript / tRPC / Encore.ts / Connect-RPC, see the repo README.
30-second example
from dyadpy import App, stream, raises
from dataclasses import dataclass
import msgspec
app = App()
class CreatePost(msgspec.Struct):
title: str
body: str
class Post(msgspec.Struct):
id: int
title: str
body: str
@dataclass
class PostNotFound(Exception):
post_id: int
@app.post("/posts")
async def create_post(data: CreatePost) -> Post: ...
@app.get("/posts/{post_id}")
@raises(PostNotFound)
async def get_post(post_id: int) -> Post: ...
class Tick(msgspec.Struct, tag="tick"):
seq: int
@app.get("/ticks")
async def ticks(count: int) -> stream[Tick]:
for i in range(count):
yield Tick(seq=i)
Run it:
dyadpy dev server.app:app
The watcher writes frontend/src/lib/dyadpy/client.ts automatically. Then
in your frontend:
import { api } from "@/lib/dyadpy/client";
const post = await api.createPost({ data: { title: "hi", body: "world" } });
for await (const ev of api.ticks({ count: 10 })) {
/* typed */
}
Primitives in this package
| Primitive | Purpose |
|---|---|
App + @app.{get,post,put,patch,delete} |
Route decorators. |
Annotated[T, Body / Query / Path / Header / Cookie / File / Form] |
Parameter location markers. |
Annotated[list[T], Query()] |
Repeated query params (?tag=a&tag=b). |
Bytes |
Raw request / response bodies. Skips the JSON envelope. |
stream[T] |
Typed SSE — client gets AsyncIterable<T>. |
@raises(E1, E2, …) |
Typed error union → Result<T, E1 | E2> on the TS side. |
Context.set_status / set_header / set_cookie / after |
Shape the response without dropping to Starlette. |
Depends(provider) |
DI in the FastAPI shape. |
after(fn, …) |
Run a callback after the response is sent. |
InMemoryBackend + TaskBackend Protocol |
Background jobs. |
dyadpy.otel.instrument(app) |
One OpenTelemetry span per request (dyadpy[otel]). |
dyadpy openapi / swift / kotlin (CLI) |
Emit OpenAPI 3.1, Swift, or Kotlin clients off the same IR. |
Full reference: https://github.com/tamimbinhakim/dyadpy/blob/main/docs/reference.md
Optional extras
uv add 'dyadpy[pydantic]' # Pydantic plugin (model_validate + model_json_schema)
uv add 'dyadpy[otel]' # OpenTelemetry middleware
uv add 'dyadpy[all]' # everything
Scope
Dyadpy ships at the wire level: RPC, typed streaming, typed errors, cancellation, file uploads, dependency injection. It does not ship vertical integrations — no LLM types, no React hooks in core, no chat-bot primitives. Those layers compose on top of the fundamentals and live in their own packages.
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file dyadpy-0.1.1.tar.gz.
File metadata
- Download URL: dyadpy-0.1.1.tar.gz
- Upload date:
- Size: 67.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c4263cea022d74f3e3fe73b45e54eac26a9e033b2a1fa15c53fd4402f2c107e9
|
|
| MD5 |
0f3fd2b093b7a93b4a5313afc7825934
|
|
| BLAKE2b-256 |
1b536d20a6a61cba014f238ae5f0c49589613bbebd907165b8330de9b771cd35
|
Provenance
The following attestation bundles were made for dyadpy-0.1.1.tar.gz:
Publisher:
release.yml on tamimbinhakim/dyadpy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dyadpy-0.1.1.tar.gz -
Subject digest:
c4263cea022d74f3e3fe73b45e54eac26a9e033b2a1fa15c53fd4402f2c107e9 - Sigstore transparency entry: 1561556706
- Sigstore integration time:
-
Permalink:
tamimbinhakim/dyadpy@82f3661ee5152df35ed9d1c5791fe1f2a27fdfd2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/tamimbinhakim
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@82f3661ee5152df35ed9d1c5791fe1f2a27fdfd2 -
Trigger Event:
push
-
Statement type:
File details
Details for the file dyadpy-0.1.1-py3-none-any.whl.
File metadata
- Download URL: dyadpy-0.1.1-py3-none-any.whl
- Upload date:
- Size: 54.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b5fb31e1cfe5a9de4b034a5e9d6bd294cdf62dfb01dd985b3440321cba561adb
|
|
| MD5 |
8dd2f43fc6e6b18bb40e01506a8a4a0c
|
|
| BLAKE2b-256 |
9216d1624dc5290fd692cfa877dfbc4e41ab97fc70ca1d90f8021ce7e495e18b
|
Provenance
The following attestation bundles were made for dyadpy-0.1.1-py3-none-any.whl:
Publisher:
release.yml on tamimbinhakim/dyadpy
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
dyadpy-0.1.1-py3-none-any.whl -
Subject digest:
b5fb31e1cfe5a9de4b034a5e9d6bd294cdf62dfb01dd985b3440321cba561adb - Sigstore transparency entry: 1561556785
- Sigstore integration time:
-
Permalink:
tamimbinhakim/dyadpy@82f3661ee5152df35ed9d1c5791fe1f2a27fdfd2 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/tamimbinhakim
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release.yml@82f3661ee5152df35ed9d1c5791fe1f2a27fdfd2 -
Trigger Event:
push
-
Statement type: