{"id":3435,"library":"contextvars","title":"Context Variables","description":"The `contextvars` library is a backport of the standard library `contextvars` module (introduced in Python 3.7 via PEP 567), providing APIs to manage, store, and access context-local state. It enables task-local variables in asynchronous code, ensuring data isolation across different coroutines or threads without explicit argument passing. The current version is 2.4, and it typically releases on demand for bug fixes or dependency updates.","status":"active","version":"2.4","language":"en","source_language":"en","source_url":"http://github.com/MagicStack/contextvars","tags":["async","concurrency","context","asyncio","threading","backport"],"install":[{"cmd":"pip install contextvars","lang":"bash","label":"Install `contextvars`"}],"dependencies":[{"reason":"Provides the underlying Hash Array Mapped Trie (HAMT) data structure for efficient immutable context storage. As of `contextvars` v2.4, `immutables` requires Python >=3.8.0, making this package effectively for Python 3.8+ environments where the standard library module might not be available or suitable.","package":"immutables","optional":false}],"imports":[{"symbol":"ContextVar","correct":"from contextvars import ContextVar"},{"symbol":"copy_context","correct":"from contextvars import copy_context"},{"note":"Used to retrieve the current Context object as a mapping.","symbol":"current_context","correct":"from contextvars import current_context"},{"note":"An opaque object returned by `ContextVar.set()` and required by `ContextVar.reset()` to revert a variable to its previous state.","symbol":"Token","correct":"from contextvars import Token"}],"quickstart":{"code":"import asyncio\nimport contextvars\n\n# Define a context variable\ncurrent_user = contextvars.ContextVar('current_user', default='Guest')\n\nasync def handle_request(user_name):\n    # Set the user for the current task. This returns a Token.\n    token = current_user.set(user_name)\n    try:\n        print(f\"Task for {user_name}: Currently handled by {current_user.get()}\")\n        await asyncio.sleep(0.1) # Simulate async work\n        print(f\"Task for {user_name}: Still handled by {current_user.get()}\")\n    finally:\n        # Reset the context variable to its previous value using the token\n        current_user.reset(token)\n\nasync def main():\n    print(f\"Before tasks: {current_user.get()}\")\n    await asyncio.gather(\n        handle_request(\"Alice\"),\n        handle_request(\"Bob\")\n    )\n    print(f\"After tasks: {current_user.get()}\") # Should revert to default\n\nif __name__ == '__main__':\n    asyncio.run(main())","lang":"python","description":"This example demonstrates how `ContextVar` isolates state in asynchronous tasks. Each `handle_request` coroutine sets a `current_user` value, which remains local to its execution context, preventing state bleeding between concurrent tasks. The `token` returned by `set()` is crucial for `reset()`ing the variable to its previous state, often done in a `try-finally` block for proper cleanup."},"warnings":[{"fix":"Always declare `ContextVar` instances at the module level or as class attributes to ensure a single instance is created per application lifetime.","message":"Creating `ContextVar` instances within closures or functions repeatedly (e.g., inside a loop or request handler) can lead to memory leaks in long-running applications. Each call creates a new `ContextVar` object that may persist in the context graph.","severity":"gotcha","affected_versions":"All"},{"fix":"Ensure `reset(token)` is called in the same `Context` where its corresponding `set()` operation occurred and that each token is used only once. Using `try-finally` blocks or `contextlib.contextmanager` is a common pattern to manage `set`/`reset` pairs safely.","message":"Calling `ContextVar.reset(token)` with a token that was created in a different `Context` will raise a `ValueError`. Additionally, a `RuntimeError` is raised if a token is used to reset a variable more than once.","severity":"gotcha","affected_versions":"All"},{"fix":"Always pair `ContextVar.set()` with `ContextVar.reset(token)` in a `try-finally` block to guarantee the context is restored, even if exceptions occur. Python 3.14+ `Token` objects support the context manager protocol for automatic reset.","message":"Forgetting to `reset()` a `ContextVar` after `set()` in long-running applications (e.g., web servers, background workers) can lead to state bleeding, where subsequent tasks inherit an unexpected context value. This is a common source of hard-to-debug issues.","severity":"gotcha","affected_versions":"All"},{"fix":"Always provide a `default` value when creating a `ContextVar` if a value isn't guaranteed to be set, or wrap `ContextVar.get()` calls in `try-except LookupError` blocks. Alternatively, `ContextVar.get(default_value_for_this_call)` can be used.","message":"Attempting to get the value of a `ContextVar` using `ContextVar.get()` when no value has been set in the current context and no `default` value was provided during `ContextVar` instantiation will raise a `LookupError`.","severity":"gotcha","affected_versions":"All"},{"fix":"Avoid using `contextvars` for sharing state directly between `ProcessPoolExecutor` processes. Instead, use multiprocessing primitives (e.g., `Queue`, `Pipe`, `shared_memory`) for inter-process communication if state needs to be truly shared or synchronized.","message":"Contexts are not automatically propagated across process boundaries. If `contextvars` are used with `multiprocessing.ProcessPoolExecutor`, changes made in a worker process's context will not affect the main process's context or other worker processes, as context variables are copied (pickled) when tasks are assigned.","severity":"gotcha","affected_versions":"All"}],"env_vars":null,"last_verified":"2026-04-11T00:00:00.000Z","next_check":"2026-07-10T00:00:00.000Z"}