Zero-config async web framework for rapid prototyping
Project description
Quicky — zero-config async web framework
Quicky — асинхронный микрофреймворк на Python 3.12+ для сервисов, которым нужны типобезопасные хендлеры, нативная валидация и «боевой» стек middleware без дополнительной конфигурации. Цели проекта:
- производительность выше типового FastAPI-сервиса за счёт uvloop + httptools + orjson;
- архитектура «type-first» (PEP 695, Annotated, TypedDict,
typing.get_type_hints); - встроенный DI, метрики Prometheus, структурированное логирование и gzip out-of-the-box;
- минимальный код для запуска:
app = Quicky()уже готов принимать трафик.
Возможности
- Декларативная маршрутизация:
@app.get("/items/{item_id}")с поддержкой подстановок и HEAD/OPTIONS по умолчанию. - DSL для параметров:
Path[T],Query[T],Body[T],Header[T]— аннотации превращаются в схему валидации через Pydantic TypeAdapter. - Dependency Injection: контейнер с app/request scope, резолвит зависимости по типам или ключам без классов и метакодирования.
- Zero-config middleware: request-id, gzip, структурное логирование (JSON), latency/throughput-метрики на
/metrics. - Минимум зависимостей: uvicorn, httptools, orjson, pydantic v2.
- CLI и рантайм:
python -m quicky.cli module:app --reloadзапускает uvicorn с httptools и uvloop.
Установка
python -m pip install quicky
Требуется Python 3.12+.
Быстрый старт
from typing import TypedDict
from quicky import Body, Path, Quicky
app = Quicky()
class Item(TypedDict):
id: int
name: str
price: float
@app.get("/items/{item_id}")
async def get_item(item_id: Path[int]) -> Item:
return {"id": item_id, "name": "example", "price": 42.0}
@app.post("/items")
async def create_item(payload: Body[Item]) -> tuple[Item, int]:
return payload, 201
Запуск:
python -m quicky.cli examples.app:app --reload
Архитектура и ключевые модули
quicky/
├── app.py # объект Quicky, роутинг, middleware, /metrics
├── routing.py # сопоставление путей и HTTP-методов
├── types.py # Request/Response + DSL Path/Query/Body/Header
├── handlers.py # анализ сигнатур, построение схем, вызов DI
├── di.py # контейнер зависимостей с app/request scope
├── serializers.py # orjson, tuple/stream ответы, content negotiation
├── middleware.py # request-id, логирование, метрики, gzip
├── metrics.py # in-memory Prometheus registry
├── runtime.py # обёртка над uvicorn (serve/run)
└── cli.py # `quicky run module:app`
Маршрутизация
- соответствие метода и пути хранится в
routing.Router; - паттерны компилируются в сегменты, PEP 634 разрешает match/case поверх HTTP-метода;
- поддерживается автоматическая обработка HEAD → GET.
Типовая система и валидация
Path[T],Query[T],Body[T],Header[T]— этоtyping.AnnotatedсParameterInfo;handlers.build_handler_specвызываетTypeAdapterдля каждой аннотации и кеширует спецификацию;- тело запроса читается один раз, JSON парсится через
orjson, значения прокидываются в адаптер; - отсутствие значения приводит к
422 ValidationErrorс uniform JSON.
Dependency Injection
DependencyContainerрегистрирует фабрики по ключу (тип или произвольный hashable);- scope
appкеширует значение,requestпересоздаёт на каждый запрос; - при отсутствии зависимости фреймворк вернёт 500, либо используйте дефолт в сигнатуре.
Middleware и метрики
- pipeline собирается в
Quicky.middleware, можно добавлять кастомные функции; - дефолтный стек: request-id, Prometheus observer, JSON-логирование, gzip (≥512 B);
/metricsотдаёт текст в формате Prometheus (сумма, count, max, avg).
Сериализация
serializers.normalize_responseпринимаетResponse, tuple(body, status, headers)или любой сериализуемый объект;- для генераторов поддерживается streaming через
Response.stream; orjson.OPT_SERIALIZE_NUMPYвключён по умолчанию.
Runtime и CLI
quicky.runtime.runиserveконфигурируют uvicorn (loop=uvloop, http=httptools);- CLI умеет читать параметры из переменных окружения (
QUICKY_HOST,..._PORT,..._WORKERS).
Пример DI и middleware
from collections.abc import AsyncIterator
from quicky import Quicky, Query, Request
app = Quicky()
async def get_db():
yield {"conn": "stub"} # request scope
app.dependency("db", get_db, scope="request")
@app.get("/ping")
async def ping(q: Query[str], db = "db", request: Request | None = None):
return {"q": q, "db": db["conn"], "rid": request.state["request_id"]}
Roadmap
- v0.1.0 (MVP) — реализовано: маршрутизация, type-first валидация, DI, JSON-сериализация, middleware, gzip, метрики Prometheus.
- v1.0.0 — запланировано: WebSocket API, GraphQL-декоратор, OpenAPI-генерация, rate limiting (
@app.limit), расширенные плагины DI. - Дальше — плагины
quicky-db,quicky-auth,quicky-testing, встроенные клиенты Observability и инструменты бенчмаркинга.
Лицензия
MIT License (см. LICENSE).
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
quicky-0.1.2.tar.gz
(15.0 kB
view details)
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
quicky-0.1.2-py3-none-any.whl
(17.3 kB
view details)
File details
Details for the file quicky-0.1.2.tar.gz.
File metadata
- Download URL: quicky-0.1.2.tar.gz
- Upload date:
- Size: 15.0 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e90eca1ef5ac2712953038023de2661758fd10f56c41793d0eb2714356332f52
|
|
| MD5 |
500fb354afa51b944d80d71fe8827a5c
|
|
| BLAKE2b-256 |
b49f5328a613b852fcc36ff0fc97ea0a580cc63b7a193f889d62e816062fda92
|
File details
Details for the file quicky-0.1.2-py3-none-any.whl.
File metadata
- Download URL: quicky-0.1.2-py3-none-any.whl
- Upload date:
- Size: 17.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3183caa055cbb043532166fbd09c9033a65b99c5b6df585bf4f3be992adfbe2f
|
|
| MD5 |
2ece9beecd615532edd25d67e4bee65c
|
|
| BLAKE2b-256 |
52a80d39eb6eda8b8f262e40e22a94cfd0214eaf207224616dbc3f726241f018
|