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 (ContextVar[T] | Local | LocalStack[T] | t.Callable[[], T]) – The context-local object that provides the proxied object.
name (str | None) – Proxy this attribute from the proxied object.
unbound_message (str | None) – 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, sorepr(x)
andisinstance(x, cls)
will look like the proxied object. Useissubclass(type(x), LocalProxy)
to check if an object is a proxy.repr(user) # <User admin> isinstance(user, User) # True issubclass(type(user), LocalProxy) # True
Changelog
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
orLocalStack
directly.Changed in version 2.2: The
name
parameter can be used with any proxied object, not onlyLocal
.Changed in version 2.2: Added the
unbound_message
parameter.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 alist
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 (ContextVar[list[T]] | None) – 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.Added in version 0.6.1.
- pop()¶
Remove the top item from the stack and return it. If the stack is empty, return
None
.- Return type:
T | None
- __call__(name=None, *, unbound_message=None)¶
Create a
LocalProxy
that accesses the top of this local stack.- Parameters:
- Return type:
- class werkzeug.local.Local(context_var=None)¶
Create a namespace of context-local data. This wraps a
ContextVar
containing adict
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 (ContextVar[dict[str, t.Any]] | None) – 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:
- Return type:
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
andLocalStack
objects.This should not be needed for modern use cases, and may be removed in the future.
- Parameters:
locals (None | (Local | LocalStack[t.Any] | t.Iterable[Local | LocalStack[t.Any]])) – A local or list of locals to manage.
Changelog
Changed in version 2.1: The
ident_func
was removed.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
orLocalStack
without using aLocalManager
.This should not be needed for modern use cases, and may be removed in the future.
Changelog
Added in version 0.6.1.
- Parameters:
local (Local | LocalStack[Any])
- Return type:
None