Skip to main content

serp-venom — Venom, Serpentine's FastAPI

A FastAPI drop-in that compiles natively with serp build and dual-runs under CPython. Import name: serp_fastapi (plus serp_uvicorn.run).

from serp_fastapi import FastAPI, HTTPException
from serp_molt import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    price: float


@app.get("/")
def read_root() -> dict[str, str]:
    return {"message": "Hello World"}


@app.get("/items/{item_id}")
def read_item(item_id: int, q: str | None = None) -> PyVal:
    if item_id == 0:
        raise HTTPException(status_code=404, detail="Item not found")
    return {"item_id": item_id, "q": q}


@app.post("/items", status_code=201)
def create_item(item: Item) -> Item:
    return item

Test it with TestClient(app); serve it with serp_uvicorn.run(app, host="127.0.0.1", port=8000) (an event loop: readiness-polled non-blocking sockets, one thread multiplexing every connection). Multi-core: listen(host, port) -> fd, then one serve_async(app, fd) loop per worker thread sharing the listener (spawn(worker, fd)), each worker building its own app.

Covered surface

  • Module-level app = FastAPI(title=..., version=...); @app.get/post/put/delete/patch/head/ options(path, status_code=...) and @app.api_route(path, methods=[...]); add_api_route. Routes match in registration order; {param} segments are percent-decoded; automatic 404 {"detail": "Not Found"} / 405 {"detail": "Method Not Allowed"}.
  • Parameter injection by name and type: {param} path parameters and query parameters as int/str/float/bool (with defaults), T | None optionals, a serp_molt model parameter as the JSON body, or the raw req: Owned[Request]. Bad or missing values produce FastAPI's 422 envelope ({"detail": [{"type": "int_parsing", "loc": ["path", "item_id"], "msg": ..., "input": ...}]}); body validation errors carry pydantic's error list with ["body", ...] locations.
  • Return values: dicts/lists/scalars/PyVal are serialized as JSON (compact separators like FastAPI); a model or list[Model] is model_dump()ed; None sends null (an empty body on 204); a Response passes through. status_code= on the decorator applies to converted returns.
  • Dependencies and routers: param: T = Depends(fn) injects the result of a module-level function whose own parameters are injected the same way (nested Depends work; an HTTPException raised inside a dependency short-circuits). APIRouter(prefix=...) with the same decorators, mounted by a module-level app.include_router(router, prefix=...); module-level app.add_api_route(...) statements are honored too.
  • Request: method, url, path_params, query_params, headers, body, json().
  • Response(content, status_code, headers, media_type) plus JSONResponse, PlainTextResponse, HTMLResponse, RedirectResponse (all accept status_code=, headers=, media_type=).
  • HTTPException(status_code=404, detail="...") → 404 {"detail": "..."} (default detail is the HTTP phrase); any other uncaught handler error → 500 Internal Server Error.
  • TestClient(app) with get/post/put/delete/patch/head/options/request, json=, params=, headers=; responses expose .status_code, .text, .json(), .headers.

How the decorators work

@app.get(...) and the module-level app are lowered at build time (docs/DECISIONS.md D41): the compiler generates a _serp_app_app() factory that constructs the app and registers each route with a synthesized (Request) -> Response endpoint that performs the parameter extraction above, and every use of app in a function becomes a call to that factory. Under CPython the same file runs as ordinary Python — the serpentine.registrar shim wraps FastAPI.get and builds the identical endpoint from the handler's annotations.

Divergences from FastAPI

  • JSONResponse and friends are factory functions returning Response — annotate handlers that return them as -> Response.
  • HTTPException(status_code=, detail=): exc.status_code, exc.detail and str(exc) ("404: detail") work inside except HTTPException as exc:; other attributes (headers) are not carried.
  • app is a build-time factory, not a shared mutable object: configure it at module level (decorators, app.include_router(...), app.add_api_route(...)) — mutating it from inside a function does not persist, and do not rely on identity.
  • No middleware, BackgroundTasks, class/yield dependencies, StreamingResponse, WebSockets, cookies/forms, or automatic /openapi.json (build one by hand from Model.model_json_schema(), see tests/test_molt_body.py).
  • async def handlers are awaited (D45): TestClient/serve_on/serve_async run them to completion inline; to make them concur, serve task-per-connection: conn = await accept_async(fd) then asyncio.create_task(conn_task(conn)) with await serve_conn(app, conn) inside the task (each task references the module-level app, which rebuilds it — route tables never cross tasks). request.json() is synchronous.
  • Handlers run to completion on the event loop; each worker builds its own app — route tables never cross threads.

Metadata

Release files for serp-venom 0.4.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for serp-venom 0.4.0
File Size Uploaded
serp_venom-0.4.0.tar.gz 20.5 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for serp-venom 0.4.0
File Interpreter ABI Platform
serp_venom-0.4.0-py3-none-any.whl Python 3 none any Details

Total release size: 34.2 kB

Release files / serp_venom-0.4.0.tar.gz

Download URL serp_venom-0.4.0.tar.gz
Size 20.5 kB
Tags Source
SHA-256 checksum
How to use checksums
28b6e5115cf4b793dccb471d4174479ce131dbde126f63cc621b228217c3ca63
BLAKE2b-256 checksum
How to use checksums
5a937547f87771046a7beab2fc66aad0b9a0f04788aaf545399f19308e9c22fe
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.

Transparency log

Release files / serp_venom-0.4.0-py3-none-any.whl

Download URL serp_venom-0.4.0-py3-none-any.whl
Size 13.7 kB
Tags Python 3
SHA-256 checksum
How to use checksums
feb63e7b3a65ce3e88c82f429332527e91b5bbce31111cf42fd961d80efa53b7
BLAKE2b-256 checksum
How to use checksums
2e64a49bd2375378aa50de767ef450aab0f207747e73d3ae0cf1d81028bedc72
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 29, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.4.0 This release

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page