Skip to main content

Typed-first Python web framework for fast, stable APIs.

Project description

thrustly

CI PyPI version codecov Python 3.12+ uv Ruff ty License: Apache-2.0

Typed-first Python web framework for fast, stable APIs. Built on Granian and Pydantic.

Alpha -- Thrustly is under active development. APIs may change between releases. Not recommended for production use yet.

Quick Start

uv add thrustly
from thrustly import Thrustly, Request, JSONResponse

app = Thrustly()

@app.get("/")
async def index(request: Request) -> JSONResponse:
    return JSONResponse({"message": "hello, world"})

@app.get("/users/{user_id:int}")
async def get_user(request: Request, user_id: int) -> JSONResponse:
    return JSONResponse({"id": user_id})

if __name__ == "__main__":
    app.run()

Features

  • Typed path parameters -- {id:int}, {slug:str}, {amount:float}, {uid:uuid}, {filepath:path}
  • Pydantic serialization -- return Pydantic models directly from JSONResponse
  • Sync and async handlers -- sync handlers run in a thread executor automatically
  • Strict mode -- validates handler return type annotations at registration time
  • Middleware -- standard ASGI middleware wrapping
  • Granian server -- built-in app.run() for development, or use Granian directly in production

Handlers

Handlers receive a Request object and any matched path parameters as keyword arguments:

@app.post("/items")
async def create_item(request: Request) -> JSONResponse:
    data = await request.json()
    return JSONResponse(data, status_code=201)

Sync handlers work too -- they're offloaded to a thread pool so they don't block the event loop:

@app.get("/sync")
def health(request: Request) -> JSONResponse:
    return JSONResponse({"status": "ok"})

Return dicts or lists directly and they'll be serialized as JSON:

@app.get("/simple")
async def simple(request: Request) -> dict:
    return {"works": True}

Strict Mode

Catch handler signature mistakes at import time instead of at request time:

app = Thrustly(strict=True)

@app.get("/x")
def bad(request: Request) -> dict:  # TypeError -- must return Response or subclass
    return {}

Middleware

Standard ASGI middleware pattern -- a function that takes an app and returns an app:

def add_cors(inner_app):
    async def middleware(scope, receive, send):
        async def custom_send(message):
            if message["type"] == "http.response.start":
                headers = list(message.get("headers", []))
                headers.append((b"access-control-allow-origin", b"*"))
                message = {**message, "headers": headers}
            await send(message)
        await inner_app(scope, receive, custom_send)
    return middleware

app.add_middleware(add_cors)

Development

Prerequisites

  • Python 3.12+
  • uv for package management

Setup

git clone https://github.com/ritwiktiwari/thrustly.git
cd thrustly
make install

Running Tests

make test

# With coverage
make test-cov

# Across all Python versions
make test-matrix

Code Quality

# Run all checks (lint, format, type-check)
make verify

# Auto-fix lint and format issues
make fix

Documentation

make docs-serve

License

This project is licensed under the Apache-2.0 License - see the LICENSE file for details.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

thrustly-0.1.1.tar.gz (11.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

thrustly-0.1.1-py3-none-any.whl (12.8 kB view details)

Uploaded Python 3

File details

Details for the file thrustly-0.1.1.tar.gz.

File metadata

  • Download URL: thrustly-0.1.1.tar.gz
  • Upload date:
  • Size: 11.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for thrustly-0.1.1.tar.gz
Algorithm Hash digest
SHA256 78d25060009a3e67c0980857016d9538f7574e7bb8d2d3b77beba534a0a7d4d6
MD5 ef3ddb7c012ff03dbbf43a376b6a1348
BLAKE2b-256 5b1a2f7b99d855c448eb5687c43bdb44fcc3651d110515526befdbc3e2fed3db

See more details on using hashes here.

Provenance

The following attestation bundles were made for thrustly-0.1.1.tar.gz:

Publisher: release.yml on ritwiktiwari/thrustly

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file thrustly-0.1.1-py3-none-any.whl.

File metadata

  • Download URL: thrustly-0.1.1-py3-none-any.whl
  • Upload date:
  • Size: 12.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for thrustly-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0f46f1da0614692978448601f92d5fd3a2c0f75f4e0f5b7e1e96366eb75eb8e4
MD5 d45c6d8b6123a0f48bcbfb1745612a33
BLAKE2b-256 5262a465a51c84e17b73e467cce0ac9c593419f3451d37c93f03416fd712ddb1

See more details on using hashes here.

Provenance

The following attestation bundles were made for thrustly-0.1.1-py3-none-any.whl:

Publisher: release.yml on ritwiktiwari/thrustly

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page