A hybrid Python web framework with a Rust core.
FastAPI gets you /docs in minutes, then you assemble Jinja, forms, a CLI, and an admin yourself. Pyron is that whole path: HTML form, JSON API, and optional /admin on the same model, from pyron init.
Docs: website · docs/index.md · local: mkdocs serve → http://127.0.0.1:8001
20–30% Rust 70–80% Python
routing · validation handlers · Pydantic · Jinja2
JSON · OpenAPI assemble admin panel · CLI · SQLModel · Granian
- Pydantic bodies → validation and automatic OpenAPI (
/docs,/redoc) - Jinja2 pages +
Form()+ flash (redirect("/", message="Saved.")) — no extra packages - Optional Vite for React / Vue / Svelte
- Optional admin panel at
/admin(Django-style): Site (Pages + Settings) and Data (your tables); Markdown pages with preview; public header/footer from settings - Same
request.useron API and the panel;@permission_required("book.delete"); staff cannot delete by default - Admin panel UI: English / Español / Português / Français, light / dark / system (system is the default)
- Enable the panel later with
pyron enable admin— does not rewrite your API handlers pyron startapp+app.include_app(...)for Django-shaped packages- Typer CLI, SQLModel + Alembic, optional Mongo documents + Redis cache, Granian (Uvicorn fallback)
BackgroundTasks,app.url_for, production checks:pyron check --deploy
cd pyron
python -m pip install maturin
maturin build --release
python -m pip install (Get-ChildItem target\wheels\pyron-*.whl).FullName
python -m pip install ".[standard,db]"
pyron versionPowerShell does not expand pyron-*.whl for pip; use Get-ChildItem or the exact wheel name. Full steps: docs/install.md.
pyron init app # asks name + what it is about; 10 starter records
cd <folder>
pyron devOpen http://127.0.0.1:8000 — add an item in the form. Same row appears in /docs and /admin. Pages become /p/about. Settings is the shop name, phone, and hours.
from pydantic import BaseModel, Field
from pyron import Pyron
app = Pyron(title="Harbor API")
class BookIn(BaseModel):
title: str = Field(min_length=1)
price: float = Field(ge=0)
@app.get("/health")
async def health() -> dict[str, str]:
return {"status": "ok"}
@app.post("/books", status_code=201)
async def create_book(book: BookIn) -> BookIn:
return bookpyron init shop --template api # JSON only; add the panel later with `pyron enable admin`
pyron dev --app app.main:apppyron enable admin
pyron createsuperuserOr in code: app.enable("admin", engine=engine). Details: docs/enable.md · docs/admin.md.
PYRON_ENV=production plus pyron check. Passwords are PBKDF2; logins are throttled; admin panel POSTs are CSRF-protected. See docs/security.md.
examples/bookstore — catalog SSR, /api/books, admin panel at /admin.
cd examples/bookstore
pyron dev --app app.main:appMeasured on CPython 3.12, Windows x86_64, release wheel (re-run python benchmarks/bench.py before quoting):
| Task | Pyron Rust core | Baseline | Ratio |
|---|---|---|---|
| Route match, 200 templates | 719 ns | 24.7 µs linear Python | 34× |
| Validate small JSON | 2.67 µs | 2.13 µs Pydantic v2 | 0.80× |
| Dump small dict | 1.09 µs | 2.57 µs stdlib | 2.4× |
| Route + validate + dump | 4.28 µs | Pydantic JSON + stdlib | 1.2× |
Pydantic v2 is already Rust. Pyron does not claim a validation blowout; routing and dumps are the clear wins. Method: benchmarks/results.md. Comparison in words: docs/comparison.md.
The markdown in docs/ is also a publishable site (MkDocs Material, Pyron colors).
python -m pip install mkdocs-material
mkdocs serveOpens http://127.0.0.1:8001 (8000 is reserved for the app). Push to main with GitHub Pages (Actions) enabled; .github/workflows/docs.yml publishes to https://nezbit.github.io/pyron/.
pytest
cargo test --libv0.10.0. Alpha. MIT. See CHANGELOG.md · docs.