Contexts & Global Proxies
In this project, contexts and global proxies provide a mechanism for accessing application and request state without explicitly passing objects through every function call. This design choice simplifies the API for view functions, blueprints, and utility modules by providing thread-safe and task-safe access to the current execution state.
The Unified Context Model
As of version 3.2, the project has moved to a unified context model where AppContext serves as the single source of truth for both application-level and request-level data. Previously, these were managed by separate AppContext and RequestContext objects. In src/flask/ctx.py, AppContext is defined to hold references to the application instance, the current request, the session, and the g object.
class AppContext:
def __init__(
self,
app: Flask,
*,
request: Request | None = None,
session: SessionMixin | None = None,
) -> None:
self.app = app
self.g: _AppCtxGlobals = app.app_ctx_globals_class()
self._request = request
self._session = session
# ...
The context is pushed to a stack-like structure managed by contextvars.ContextVar (specifically _cv_app in src/flask/globals.py). This ensures that even in asynchronous or multi-threaded environments, each execution flow sees its own isolated context.
Global Proxies
To access the data inside the active AppContext, the project uses "Global Proxies." These are instances of werkzeug.local.LocalProxy that redirect all operations to the object currently bound to the active context.
The four primary proxies defined in src/flask/globals.py are:
current_app: Points to theFlaskapplication instance handling the current context.request: Points to theRequestobject. Accessing this outside of an HTTP request context raises aRuntimeError.session: Points to the current user session.g: A general-purpose namespace for storing data during a single context lifecycle.
These proxies allow code in separate modules to interact with the "current" state. For example, a database utility can access configuration via current_app.config without needing the app object passed to it:
# examples/tutorial/flaskr/db.py
from flask import current_app, g
def get_db():
if "db" not in g:
g.db = sqlite3.connect(
current_app.config["DATABASE"],
detect_types=sqlite3.PARSE_DECLTYPES
)
return g.db
The g Object and Resource Management
The g object (an instance of _AppCtxGlobals) is specifically designed for storing resources that should persist for the duration of a context but be cleaned up afterward. It supports attribute access and dictionary-like methods such as get(), pop(), and setdefault().
A common pattern in this codebase is using g to cache database connections. By registering a teardown function with app.teardown_appcontext, the project ensures that resources stored in g are properly released when the context is popped, regardless of whether the request succeeded or raised an exception.
# examples/tutorial/flaskr/db.py
def close_db(e=None):
db = g.pop("db", None)
if db is not None:
db.close()
def init_app(app):
app.teardown_appcontext(close_db)
Context Lifecycle and Manual Management
Flask automatically manages the lifecycle of contexts during the standard request-response cycle and CLI command execution. When a request starts, an AppContext (with request data) is pushed; when the request ends, it is popped.
However, there are scenarios where a context must be managed manually, such as during unit tests or when running standalone scripts. The app.app_context() method returns a context manager that handles the push() and pop() operations:
# tests/test_appctx.py
def test_basic_url_generation(app):
app.config["SERVER_NAME"] = "localhost"
with app.app_context():
# Inside this block, current_app and url_for work
rv = flask.url_for("index")
assert rv == "https://localhost/"
Tradeoffs and Constraints
While the proxy pattern provides a clean API, it introduces specific constraints:
- Context Requirement: Accessing a proxy like
requestoutside of an active context will result in aRuntimeError. The proxies insrc/flask/globals.pyinclude descriptiveunbound_messagestrings to help developers diagnose these issues. - Teardown Guarantees: The implementation of
AppContext.popinsrc/flask/ctx.pyis designed to be robust. On Python 3.11+, it usesExceptionGroupto ensure that all registered teardown functions run, even if one of them raises an error. - Background Tasks: Because contexts are bound to the current execution flow (via
ContextVar), background threads or tasks do not automatically inherit the context. Thecopy_current_request_contextdecorator insrc/flask/ctx.pyis provided to manually propagate the context to other threads, though the documentation warns that passing data explicitly is often safer.