Reputation: 51
I'm trying to use the new contextvars library (https://docs.python.org/3/library/contextvars.html) to make certain values available across modules in an async context, similar to ContextVars across modules, and was wondering if there was a way of fetching context variables by name or identifier from within a given execution context without importing the context variable directly.
Ideally, I would like to do something like the following:
from _contextvars import ContextVar
language = ContextVar('language')
language.set('en-US')
And in a separate module, which may serve a web request or fetch a translation based on the language that was set:
from _contextvars import copy_context
ctx = copy_context()
if 'language' in ctx:
lang_context_var = ctx.get('language') # get the context variable
lang_value = lang_context_var.get() # get the value
I realise the API for the contextvars library has a mapping between a ContextVar object and value and not string to value so this lookup can't be done, but I find that needing to do a from module_with_context_var import language
a bit messy and prone to being spread across a codebase rather than a single wrapper for the current context , which seems like what copy_context() should be.
Any pointers in a good way to structure context variable fetching and setting in a central location which also works with co-routines/async programming would be much appreciated!
Upvotes: 5
Views: 603
Reputation: 150081
If you don't want to import anything from the module where vars are declared, you could just do a linear search on the context mapping, e.g.:
from contextvars import ContextVar, copy_context
def get_var_by_name(var_name: str) -> ContextVar | None:
ctx = copy_context()
return next((var for var in ctx if var.name == var_name), None)
lang_context_var = get_var_by_name('language')
if lang_context_var is not None:
print(f"Language set to {lang_context_var.get()}")
Alternatively, you could put the context vars in a dictionary keyed by name and import that:
CONTEXT_VARS: dict[str, ContextVar] = {
"language": ContextVar('language'),
"country": ContextVar('country'),
# etc
}
# in another module
from context_vars import CONTEXT_VARS
if "language" in CONTEXT_VARS:
language = CONTEXT_VARS["language"].get(None)
if language is not None:
print(f"Language set to {language}")
Of course, in this case you should set values for the variables via the dictionary as well.
Upvotes: 1