Context Locals

You may find that you have some data during each request that you want to use across functions. Instead of passing these as arguments between every function, you may want to access them as global data. However, using global variables in Python web applications is not thread safe; different workers might interfere with each others’ data.

Instead of storing common data during a request using global variables, you must use context-local variables instead. A context local is defined/imported globally, but the data it contains is specific to the current thread, asyncio task, or greenlet. You won’t accidentally get or overwrite another worker’s data.

The current approach for storing per-context data in Python is the contextvars module. Context vars store data per thread, async task, or greenlet. This replaces the older threading.local which only handled threads.

Werkzeug provides wrappers around ContextVar to make it easier to work with.

Proxy Objects

LocalProxy allows treating a context var as an object directly instead of needing to use and check ContextVar.get(). If the context var is set, the local proxy will look and behave like the object the var is set to. If it’s not set, a RuntimeError is raised for most operations.

from contextvars import ContextVar
from werkzeug.local import LocalProxy

_request_var = ContextVar("request")
request = LocalProxy(_request_var)

from werkzeug.wrappers import Request

@Request.application
def app(r):
    _request_var.set(r)
    check_auth()
    ...

from werkzeug.exceptions import Unauthorized

def check_auth():
    if request.form["username"] != "admin":
        raise Unauthorized()

Accessing request will point to the specific request that each server worker is handling. You can treat request just like an actual Request object.

bool(proxy) will always return False if the var is not set. If you need access to the object directly instead of the proxy, you can get it with the _get_current_object() method.

class werkzeug.local.LocalProxy(local, name=None, *, unbound_message=None)

A proxy to the object bound to a context-local object. All operations on the proxy are forwarded to the bound object. If no object is bound, a RuntimeError is raised.

Parameters:
  • local – The context-local object that provides the proxied object.

  • name – Proxy this attribute from the proxied object.

  • unbound_message – The error message to show if the context-local object is unbound.

Proxy a ContextVar to make it easier to access. Pass a name to proxy that attribute.

_request_var = ContextVar("request")
request = LocalProxy(_request_var)
session = LocalProxy(_request_var, "session")

Proxy an attribute on a Local namespace by calling the local with the attribute name:

data = Local()
user = data("user")

Proxy the top item on a LocalStack by calling the local. Pass a name to proxy that attribute.

app_stack = LocalStack()
current_app = app_stack()
g = app_stack("g")

Pass a function to proxy the return value from that function. This was previously used to access attributes of local objects before that was supported directly.

session = LocalProxy(lambda: request.session)

__repr__ and __class__ are proxied, so repr(x) and isinstance(x, cls) will look like the proxied object. Use issubclass(type(x), LocalProxy) to check if an object is a proxy.

repr(user)  # <User admin>
isinstance(user, User)  # True
issubclass(type(user), LocalProxy)  # True

Changed in version 2.2.2: __wrapped__ is set when wrapping an object, not only when wrapping a function, to prevent doctest from failing.

Changed in version 2.2: Can proxy a ContextVar or LocalStack directly.

Changed in version 2.2: The name parameter can be used with any proxied object, not only Local.

Changed in version 2.2: Added the unbound_message parameter.

Changelog

Changed in version 2.0: Updated proxied attributes and methods to reflect the current data model.

Changed in version 0.6.1: The class can be instantiated with a callable.

_get_current_object: Callable[[], T]

Return the current object this proxy is bound to. If the proxy is unbound, this raises a RuntimeError.

This should be used if you need to pass the object to something that doesn’t understand the proxy. It can also be useful for performance if you are accessing the object multiple times in a function, rather than going through the proxy multiple times.

Stacks and Namespaces

ContextVar stores one value at a time. You may find that you need to store a stack of items, or a namespace with multiple attributes. A list or dict can be used for these, but using them as context var values requires some extra care. Werkzeug provides LocalStack which wraps a list, and Local which wraps a dict.

There is some amount of performance penalty associated with these objects. Because lists and dicts are mutable, LocalStack and Local need to do extra work to ensure data isn’t shared between nested contexts. If possible, design your application to use LocalProxy around a context var directly.

class werkzeug.local.LocalStack(context_var=None)

Create a stack of context-local data. This wraps a ContextVar containing a list value.

This may incur a performance penalty compared to using individual context vars, as it has to copy data to avoid mutating the list between nested contexts.

Parameters:

context_var (Optional[ContextVar[List[T]]]) – The ContextVar to use as storage for this local. If not given, one will be created. Context vars not created at the global scope may interfere with garbage collection.

Changelog

Changed in version 2.0: Uses ContextVar instead of a custom storage implementation.

New in version 0.6.1.

__call__(name=None, *, unbound_message=None)

Create a LocalProxy that accesses the top of this local stack.

Parameters:
  • name (Optional[str]) – If given, the proxy access this attribute of the top item, rather than the item itself.

  • unbound_message (Optional[str]) – The error message that the proxy will show if the stack is empty.

Return type:

LocalProxy

pop()

Remove the top item from the stack and return it. If the stack is empty, return None.

Return type:

Optional[T]

push(obj)

Add a new item to the top of the stack.

Parameters:

obj (T) –

Return type:

List[T]

property top: Optional[T]

The topmost item on the stack. If the stack is empty, None is returned.

class werkzeug.local.Local(context_var=None)

Create a namespace of context-local data. This wraps a ContextVar containing a dict value.

This may incur a performance penalty compared to using individual context vars, as it has to copy data to avoid mutating the dict between nested contexts.

Parameters:

context_var (Optional[ContextVar[Dict[str, Any]]]) – The ContextVar to use as storage for this local. If not given, one will be created. Context vars not created at the global scope may interfere with garbage collection.

Changelog

Changed in version 2.0: Uses ContextVar instead of a custom storage implementation.

__call__(name, *, unbound_message=None)

Create a LocalProxy that access an attribute on this local namespace.

Parameters:
  • name (str) – Proxy this attribute.

  • unbound_message (Optional[str]) – The error message that the proxy will show if the attribute isn’t set.

Return type:

LocalProxy

Releasing Data

A previous implementation of Local used internal data structures which could not be cleaned up automatically when each context ended. Instead, the following utilities could be used to release the data.

Warning

This should not be needed with the modern implementation, as the data in context vars is automatically managed by Python. It is kept for compatibility for now, but may be removed in the future.

class werkzeug.local.LocalManager(locals=None)

Manage releasing the data for the current context in one or more Local and LocalStack objects.

This should not be needed for modern use cases, and may be removed in the future.

Parameters:

locals (Optional[Union[Local, LocalStack, Iterable[Union[Local, LocalStack]]]]) – A local or list of locals to manage.

Changelog

Changed in version 2.0: ident_func is deprecated and will be removed in Werkzeug 2.1.

Changed in version 0.7: The ident_func parameter was added.

Changed in version 0.6.1: The release_local() function can be used instead of a manager.

cleanup()

Release the data in the locals for this context. Call this at the end of each request or use make_middleware().

Return type:

None

make_middleware(app)

Wrap a WSGI application so that local data is released automatically after the response has been sent for a request.

Parameters:

app (WSGIApplication) –

Return type:

WSGIApplication

middleware(func)

Like make_middleware() but used as a decorator on the WSGI application function.

@manager.middleware
def application(environ, start_response):
    ...
Parameters:

func (WSGIApplication) –

Return type:

WSGIApplication

werkzeug.local.release_local(local)

Release the data for the current context in a Local or LocalStack without using a LocalManager.

This should not be needed for modern use cases, and may be removed in the future.

Changelog

New in version 0.6.1.

Parameters:

local (Union[Local, LocalStack]) –

Return type:

None