Generated 2026-08-05
Flask is a lightweight WSGI web framework built on Werkzeug and Jinja. The public API (src/flask/__init__.py) is a thin, IO-capable layer — Flask and Blueprint — sitting on top of a larger "sansio" base package that holds most of the actual implementation and is written to be usable by non-Flask, non-WSGI implementations (e.g. Quart) as well.
| Component | Path | Role | Depends on |
|---|---|---|---|
| flask (public API) | src/flask/__init__.py | The entire public surface re-exported in one 39-line file: Flask, Blueprint, current_app/request/g/session, render_template, url_for, redirect, jsonify, signals. Read this before anything else to see what the library actually offers. | — |
| Flask (app.py) | src/flask/app.py | Defines `class Flask(App)` — the object every user instantiates. Adds the IO-touching behavior (the dev server, CLI wiring) on top of the sansio App base class. | sansio.app |
| sansio.app (App base class) | src/flask/sansio/app.py | Defines `class App` — 43 methods, more than Flask's own subclass (38). This is where most of Flask's actual request-handling, config, and routing logic lives, written IO-free so it can be reused by non-WSGI implementations. | sansio.scaffold |
| sansio.scaffold | src/flask/sansio/scaffold.py | Shared base between App and Blueprint — route registration, static/template folder resolution, the `@app.route` decorator machinery. | — |
| Blueprint (app-side + sansio-side) | src/flask/blueprints.py + src/flask/sansio/blueprints.py | Same App/sansio split repeated for Blueprint: a 128-line app-side subclass over a 692-line sansio base. | sansio.scaffold |
| ctx | src/flask/ctx.py | Application/request context push-pop machinery — the part of Flask's design that makes `current_app`/`request`/`g` work as implicit globals during a request. | globals |
| globals | src/flask/globals.py | The context-local proxy objects (current_app, request, g, session) themselves. | — |
| cli | src/flask/cli.py | The `flask` command-line tool (run, shell, routes) — the largest file after app.py, and mostly independent of the request-handling path. | app.py |
| tests | tests/ | 27 test files, roughly one per src/flask/*.py module — the fastest way to see intended behavior confirmed by something that actually runs. | — |
src/flask/__init__.py — 39 lines, every public name re-exported in one place — the fastest possible answer to 'what does this library offer.'src/flask/app.py (class Flask(App), line 109) — The object every Flask app instantiates (`Flask(__name__)`); the natural entry point for reading everything else — but see the gotcha below before assuming its methods live here.src/flask/sansio/app.py (class App) — Defines more methods (43) than Flask's own subclass (38) — a majority of what Flask actually does lives here, not in app.py. Skipping this file means missing most of the implementation.src/flask/ctx.py — The context push/pop machinery behind current_app/request/g — the least obvious part of Flask's design if you've only read route-handler code, and everything that uses `g` or `current_app` depends on it.tests/test_basic.py — The most representative test of the primary use case — a minimal app, routes, and a request/response cycle. Teaches the intended usage faster than reading app.py in isolation, and it's guaranteed accurate since it runs in CI.| Severity | Gotcha | Evidence |
|---|---|---|
| HIGH | Flask the class is a thin subclass — most of its behavior is inherited — class Flask(App) in app.py defines 38 methods; its parent class App in sansio/app.py defines 43. A reader searching app.py for a method like add_url_rule or the route-registration logic won't find it there and needs to know to check the sansio parent. | grep -c ' def ' src/flask/app.py src/flask/sansio/app.py → 38 vs 43; src/flask/app.py:109 `class Flask(App):` |
| MEDIUM | The sansio/ architectural constraint is documented but not enforced — sansio/README.md states code in that package "cannot do any IO, nor be part of a likely IO path" and "cannot use the Flask globals" — but this is a 4-line README, not a lint rule or CI check. A contributor could violate it and nothing would catch it automatically. | src/flask/sansio/README.md (full contents: 4 lines, no enforcement mechanism found in pyproject.toml or CI config checked) |
| MEDIUM | The App/sansio split is repeated for Blueprint, easy to only half-read — Same pattern as Flask/App: blueprints.py (128 lines) is a thin subclass over sansio/blueprints.py (692 lines). Reading only the top-level blueprints.py under-explains Blueprint the same way reading only app.py under-explains Flask. | wc -l src/flask/blueprints.py src/flask/sansio/blueprints.py → 128 vs 692 |
src/flask/app.py) — Add a short comment above `class Flask(App):` in app.py noting that most of Flask's methods are inherited from sansio.app.App, with a pointer to that file. Cheap, and writing it forces you to actually verify the split by diffing the two classes' method lists.src/flask/sansio/README.md) — The README says sansio code "cannot do any IO" but gives no example of what that means in practice (no file opens, no network calls, no touching request-scoped globals). Add one or two concrete examples of allowed vs. disallowed code to make the constraint checkable by a newcomer, not just a contributor who already knows the codebase.