Skip to main content

Bwsgi

Ultra-lightweight, zero-dependency Python WSGI framework. Flask-style routing. Django-style auth. Built on the Python Standard Library.

Why Bwsgi?

  • Zero dependencies — pure Python stdlib
  • ~5-8 MB idle RAM — runs happily on 512MB hosts like Serv00
  • Flask-style routing — decorator-based, familiar syntax
  • Secure auth built in — PBKDF2 password hashing + DB-backed sessions
  • WSGI native — works with Passenger, Gunicorn, uWSGI

Install

pip install bwsgi

Quick Start

from bwsgi import Bwsgi, Response, login_required

app = Bwsgi(db_path="app.db")

@app.route("/")
def home(req):
    return Response.html("<h1>Hello from Bwsgi</h1>")

@app.route("/dashboard")
@login_required
def dashboard(req):
    return Response.html(f"<h1>Hi {req.user['username']}</h1>")

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

Routing and responses

Routes accept named path parameters and one or more HTTP methods:

@app.route("/users/<username>", methods=("GET",))
def user(req, username):
    return Response.json({"username": username})

profile_url = app.url_for("user", username="Jane Doe")

Path values generated by url_for are URL-encoded. Requests to a known path with an unsupported method receive 405 Method Not Allowed and an Allow header. Static files are served from static/ at /static/; files are streamed in chunks and paths are checked against the configured static root.

Request provides query, headers, cookies, body, form(), and json(). Malformed JSON request bodies receive 400 Bad Request. Response provides text(), html(), json(), redirect(), and file().

JSON request validation

Use Request.validate_json() to require a JSON object with specific required fields and Python types. Malformed JSON and invalid values return a JSON 400 Bad Request response:

@app.route("/api/items", methods=("POST",))
def create_item(req):
    item = req.validate_json({"name": str, "quantity": int})
    return Response.json(item, "201 Created")

Sessions and CSRF

req.session is a server-side dictionary persisted in SQLite and identified by a signed, HTTP-only cookie. Set a stable secret key when creating the app so session cookies survive process restarts:

app = Bwsgi(db_path="app.db", secret_key="load-this-from-your-environment")

Protect state-changing routes with @csrf_protect. Render req.csrf_token() into a hidden form field named _csrf_token, or send it in the X-Csrf-Token header for JSON requests:

@app.route("/submit", methods=("POST",))
@csrf_protect
def submit(req):
    req.session["submitted"] = True
    return Response.json({"ok": True})

Safe methods (GET, HEAD, OPTIONS, and TRACE) do not require a token. Keep state-changing actions on non-safe methods and use CSRF protection for browser-session routes.

Templates, middleware, and errors

Templates are UTF-8 files under templates/ by default. {{ name }} values are HTML-escaped automatically; this intentionally supports variable substitution only, not template logic:

<h1>Hello, {{ username }}</h1>
return app.render_template("hello.html", username="Ada")

Register standard WSGI middleware with a factory that accepts and returns a WSGI callable:

def request_id_middleware(next_app):
    def middleware(environ, start_response):
        environ["HTTP_X_REQUEST_ID"] = "example"
        return next_app(environ, start_response)
    return middleware

app.add_middleware(request_id_middleware)

Error handlers may be registered for HTTP status codes or exception classes:

@app.errorhandler(ValueError)
def invalid_value(req):
    return Response.json({"error": "invalid value"}, "400 Bad Request")

License

MIT

Metadata

Release files for bwsgi 0.1.1

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for bwsgi 0.1.1
File Size Uploaded
bwsgi-0.1.1.tar.gz 14.9 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for bwsgi 0.1.1
File Interpreter ABI Platform
bwsgi-0.1.1-py3-none-any.whl Python 3 none any Details

Total release size: 26.5 kB

Release files / bwsgi-0.1.1.tar.gz

Download URL bwsgi-0.1.1.tar.gz
Size 14.9 kB
Tags Source
SHA-256 checksum
How to use checksums
07b036e8629d2f2d2685ff268c7b252ee1d780fbeefd6e7c5889a7b81640673a
BLAKE2b-256 checksum
How to use checksums
88692278f6f80297c7cb699b5a778fef4d9b60c7315d0c49636291046333d471
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / bwsgi-0.1.1-py3-none-any.whl

Download URL bwsgi-0.1.1-py3-none-any.whl
Size 11.5 kB
Tags Python 3
SHA-256 checksum
How to use checksums
76312541205332873d9b6de8f6545cb25da8e8076c4fbe9efacc9748004e504b
BLAKE2b-256 checksum
How to use checksums
ca39a48a75e4712a9b6af52a4a6ec7337cd6572d097ead2d5ae945647148d4be
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.12.5 {"installer":{"name":"uv","version":"0.12.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release history Release notifications | RSS feed

This release

0.1.1 This release

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page