Skip to main content

Vinod

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

Why Vinod?

  • 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 vinod

Quick Start

from vinod import Vinod, Response, login_required

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

@app.route("/")
def home(req):
    return Response.html("<h1>Hello from Vinod</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 = Vinod(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.0

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.0
File Size Uploaded
bwsgi-0.1.0.tar.gz 12.8 kB Details

Built distribution (wheel)

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

Total release size: 24.4 kB

Release files / bwsgi-0.1.0.tar.gz

Download URL bwsgi-0.1.0.tar.gz
Size 12.8 kB
Tags Source
SHA-256 checksum
How to use checksums
e0286b55af71b2a615cc7a2eef57604e465f00dc6b40a58ad9f581e398a8ecd8
BLAKE2b-256 checksum
How to use checksums
b52a2d44c6e0ab7dd4106b14b52fd4f300f66fb3f33d29cced935ee45b3064dd
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.0-py3-none-any.whl

Download URL bwsgi-0.1.0-py3-none-any.whl
Size 11.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
b82fffc37e25bf14222569ddd5f3b49e5da537bb715eb435e57c03c93cc051a7
BLAKE2b-256 checksum
How to use checksums
99863458f43e4d16e6ec587ae94f8156180ac06847c97ee3ea08028475b038ef
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

0.1.1

2 release files

This release

0.1.0 This release

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