⚠

You are viewing archived documentation for pyrith v0.1.0. The latest version is v0.4.0.

Docs/pyrith/Releases/v0.1.0Initial

pyrith

v0.1.0

Initial release. Core HTTP routing, middleware, HTML DSL, SQLite ORM, session auth, form validation, WebSocket, and CLI.

pip install pyrith==0.1.0GitHub →Upgrade to v0.4.0 →

Overview

pyrith v0.1.0 is the initial release — a minimal but complete Python web framework built entirely from the standard library. No external runtime dependencies: no Flask, no Django, no SQLAlchemy, no Jinja2. Everything — HTTP server, routing, HTML rendering, SQLite ORM, session management, form validation, WebSocket — is implemented from scratch in pure Python.

ℹ

This is the initial release. We recommend upgrading to v0.4.0 (latest) which adds ASGI, OAuth2, MFA, background tasks, payments, AI/LLM streaming, admin panel, telemetry, and 26 new modules — with full backwards compatibility.

Installation

pip install pyrith==0.1.0

# Requires Python 3.9+. No external runtime dependencies.

Quick Start

from pyrith import Pyrith
from pyrith.response import HTMLResponse, JSONResponse

app = Pyrith(__name__)

@app.get('/')
def index(request):
    return HTMLResponse('<h1>Hello from pyrith!</h1>')

@app.get('/api/health')
def health(request):
    return JSONResponse({'status': 'ok', 'version': '0.1.0'})

if __name__ == '__main__':
    app.run(host='127.0.0.1', port=8080, debug=True)

Routing

app = Pyrith(__name__)

# HTTP methods
@app.get('/articles')
def list_articles(request):
    return JSONResponse({'articles': []})

@app.post('/articles')
def create_article(request):
    data = request.json()
    return JSONResponse({'created': True}, status=201)

# Path parameters
@app.get('/articles/{article_id}')
def get_article(request):
    article_id = request.params['article_id']
    return JSONResponse({'id': article_id})

# Delete / put / patch
@app.delete('/articles/{article_id}')
def delete_article(request):
    return JSONResponse({'deleted': True})

# Route groups
from pyrith.router import Router
api = Router(prefix='/api')

@api.get('/users')
def list_users(request):
    return JSONResponse({'users': []})

app.include(api)

Middleware

from pyrith.middleware import CORSMiddleware, LoggingMiddleware, StaticFilesMiddleware, GZipMiddleware

app.use(LoggingMiddleware())
app.use(CORSMiddleware(allow_origins=['*']))
app.use(StaticFilesMiddleware('./public', '/static'))
app.use(GZipMiddleware(min_size=500))

Response

from pyrith.response import HTMLResponse, JSONResponse, RedirectResponse

HTMLResponse('<h1>Hello</h1>')
JSONResponse({'id': 1}, status=201)
RedirectResponse('/login')

# Set headers/cookies
resp = JSONResponse({'ok': True})
resp.set_header('X-Custom', 'value')
resp.set_cookie('session', token, max_age=86400, http_only=True)

HTML DSL

Write HTML as Python function calls. Every HTML5 element is available as a function. Nest them naturally; they stringify to valid HTML.

from pyrith import ui

page = ui.Page(title='My App')
page.body_add(
    ui.div(
        ui.h1('Welcome', class_='title'),
        ui.p('Built with pyrith.'),
        ui.ul(
            ui.li('No HTML templates'),
            ui.li('No Jinja2'),
            ui.li('Pure Python'),
        ),
        ui.a('Learn more', href='/about', class_='link'),
    )
)

return HTMLResponse(page.to_html())

SQLite ORM

ActiveRecord-style ORM backed by SQLite. No migrations in v0.1.0 — table is created on first use.

from pyrith.orm import Model, CharField, IntegerField, BooleanField, DateTimeField

class Article(Model):
    title   = CharField(max_length=200)
    body    = CharField(max_length=10000)
    views   = IntegerField(default=0)
    published = BooleanField(default=False)
    created = DateTimeField(auto_now=True)

# Create
article = Article.create(title='Hello', body='Content here')

# Query
all_articles   = Article.all()
published_ones = Article.filter(published=True)
one            = Article.get(id=1)
recent         = Article.order_by('-created').limit(10).fetch()

# Update / Delete
article.title = 'Updated'
article.save()
article.delete()

Session Auth

from pyrith.auth import login_required
from pyrith.session import SessionStore

app.use(SessionStore(secret='change-me'))

@app.post('/login')
def login(request):
    data = request.json()
    # validate credentials …
    request.session.set('user_id', user.id)
    return JSONResponse({'ok': True})

@app.get('/profile')
@login_required
def profile(request):
    user_id = request.session.get('user_id')
    return JSONResponse({'user_id': user_id})

@app.post('/logout')
def logout(request):
    request.session.clear()
    return RedirectResponse('/login')

Form Validation

from pyrith.forms import Form, CharField, EmailField, IntegerField, BooleanField

class SignupForm(Form):
    username = CharField(min_length=3, max_length=30)
    email    = EmailField()
    age      = IntegerField(min_value=13, required=False)
    agree    = BooleanField(required=True)

@app.post('/signup')
def signup(request):
    form = SignupForm(data=request.json())
    if not form.is_valid():
        return JSONResponse({'errors': form.errors}, status=422)
    # form.cleaned_data is safe to use
    user = User.create(**form.cleaned_data)
    return JSONResponse({'id': user.id}, status=201)

WebSocket

@app.websocket('/ws/chat/{room}')
async def chat(ws, request):
    room = request.params['room']
    await ws.accept()
    try:
        while True:
            msg = await ws.receive()
            # broadcast to same room (pub/sub in v0.1.0 is manual)
            await ws.send(f'Echo: {msg}')
    except Exception:
        await ws.close()

CLI

# Create new project
pyrith new myproject
cd myproject

# Start dev server (auto-reload)
pyrith run --debug

# Show registered routes
pyrith version