Skip to main content

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 the Flask application instance handling the current context.
  • request: Points to the Request object. Accessing this outside of an HTTP request context raises a RuntimeError.
  • 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:

  1. Context Requirement: Accessing a proxy like request outside of an active context will result in a RuntimeError. The proxies in src/flask/globals.py include descriptive unbound_message strings to help developers diagnose these issues.
  2. Teardown Guarantees: The implementation of AppContext.pop in src/flask/ctx.py is designed to be robust. On Python 3.11+, it uses ExceptionGroup to ensure that all registered teardown functions run, even if one of them raises an error.
  3. Background Tasks: Because contexts are bound to the current execution flow (via ContextVar), background threads or tasks do not automatically inherit the context. The copy_current_request_context decorator in src/flask/ctx.py is provided to manually propagate the context to other threads, though the documentation warns that passing data explicitly is often safer.