Skip to main content

oppionated python sse server wrapping granian

Project description

PyPI version

[!WARNING] Under active development — May 2026

py_sse

minimal python sse server

A small framework for building Datastar apps over Server-Sent Events. Runs on Granian via RSGI, talks to SQLite through apsw, and pushes live DOM updates from the database with no client-side polling.

pip install py-sse

Hello

from py_sse import create_app, serve

app = create_app()

@app.get('/')
async def index(req):
    return '<h1>hello</h1>'

if __name__ == '__main__':
    serve(app)

Handlers return one of: str → 200 HTML, dict → 200 JSON, None → 204, (url, status) → redirect/text, or an async generator → raw SSE stream.

Live feed

@app.stream is the core feature: register an SSE endpoint that re-renders every time the database changes. Changes bridges SQLite's update hook to asyncio, so any write() wakes every connected stream.

from py_sse import (create_app, create_db, migrate, query, write,
                    signals, Changes, serve)

db = create_db('chat.db')
migrate(db, "CREATE TABLE IF NOT EXISTS msgs (id INTEGER PRIMARY KEY, txt TEXT)")

def startup(loop):
    global changes
    changes = Changes(db, loop)

app = create_app(on_init=startup, on_del=lambda loop: changes.close())

@app.post('/say')
async def say(req):
    s = await signals(req)
    write(db, lambda c: c.execute("INSERT INTO msgs(txt) VALUES(?)", (s['text'],)))

@app.stream('/feed', on=lambda: changes)
def feed(req):
    rows = query(db, "SELECT txt FROM msgs ORDER BY id DESC LIMIT 50")
    return ''.join(f'<p>{txt}</p>' for (txt,) in rows)

Post to /say from any tab and every tab subscribed to /feed re-renders.

API

Appcreate_app(routes=None, *, on_init=None, on_del=None). Returns a handle with .get/.post/.put/.patch/.delete(path), .mount(prefix, fn), .before(fn, *, methods=None), and .stream(path, *, on). Paths support {name} params. on_init(loop)/on_del(loop) run at startup/shutdown for wiring shared state onto the right loop.

Requestssignals(req) reads Datastar signals (query param on GET, JSON body otherwise). body(req) / body_stream(req) read the raw payload. set_cookie(req, name, value, **opts) queues a Set-Cookie.

SSE eventspatch_elements, patch_signals, remove_signals, execute_script, redirect. @app.stream calls patch_elements for you.

DBcreate_db(path) opens a WAL connection. migrate(conn, sql) applies schema idempotently. query(conn, sql, bindings=(), *, limit=1000) returns rows. write(conn, fn, *args) runs fn in a transaction. Changes(db, loop) fans writes out to streams.

Staticstatic(app, url_prefix, directory) serves a file or directory with HTTP range support and a directory-traversal guard.

Cookiescreate_signer(secret) returns an HMAC-SHA256 signer with .sign(value) / .unsign(signed, max_age=3600).

Servingserve(app, *, host, port, **kwargs) runs in the foreground. serve_background(app, host, port) returns a ServerState you stop with stop_background(state); dev_alive(state) checks the port. Useful for notebooks. start_tunnel(port) / stop_tunnel(t) expose a local server via ngrok (requires ngrok and NGROK_AUTHTOKEN).

License

MIT

License

MIT

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

py_sse-0.12.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.

py_sse-0.12.1-py3-none-any.whl (14.3 kB view details)

Uploaded Python 3

File details

Details for the file py_sse-0.12.1.tar.gz.

File metadata

  • Download URL: py_sse-0.12.1.tar.gz
  • Upload date:
  • Size: 11.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux ARM","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for py_sse-0.12.1.tar.gz
Algorithm Hash digest
SHA256 c9ecc02b3b9c54bce44e1ff6a00b94dd95f872312559c3c6685f3fd27555809c
MD5 1a0a8e5a1473eeb10fae3806e16cf5b9
BLAKE2b-256 1977e019a7b12f6214203dad3cb9e482b6329698dea59190a1342d517cb2265e

See more details on using hashes here.

File details

Details for the file py_sse-0.12.1-py3-none-any.whl.

File metadata

  • Download URL: py_sse-0.12.1-py3-none-any.whl
  • Upload date:
  • Size: 14.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.11.6 {"installer":{"name":"uv","version":"0.11.6","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Arch Linux ARM","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for py_sse-0.12.1-py3-none-any.whl
Algorithm Hash digest
SHA256 d9b66e3322f4004daed454c15c4559ef1fdef47d4c7bf2119a58845a02bed7dc
MD5 28ad44056cbed52a63dcefb475770132
BLAKE2b-256 11b8578f5aa3efa08474435e9c994f02063467cea7ba7eb00831f1fe20930355

See more details on using hashes here.

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