I had a similar recent need, with a bit more on top of it, and solved it
with this slightly insane library. (Alas, I haven't figured out a good way
to make it act as a true subtype of UnderlyingType yet)
import contextvars
from typing import Any, Generic, TypeVar
UnderlyingType = TypeVar('UnderlyingType')
class DuckTypeContextVar(Generic[UnderlyingType]):
"""A DuckTypeContextVar takes contextvars.ContextVar to the next level:
It duck-type emulates
the underlying variable. This means you can do something like
sys.stdout = DuckTypeContextVar('stdout', sys.stdout)
token = sys.stdout.setLocalValue(myFile)
....
sys.stdout.resetLocalValue(token)
"""
def __init__(self, name: str, value: UnderlyingType) -> None:
self._value = contextvars.ContextVar(name, default=value)
def getLocalValue(self) -> UnderlyingType:
return self._value.get()
def setLocalValue(self, value: UnderlyingType) -> contextvars.Token:
return self._value.set(value)
def resetLocalValue(self, token: contextvars.Token) -> None:
self._value.reset(token)
def __getattr__(self, attr: str) -> Any:
return getattr(self._value, attr)
On Wed, Jun 5, 2019 at 6:14 PM Yury Selivanov <[email protected]>
wrote:
> On Wed, Jun 5, 2019 at 6:22 PM Christoph Groth <[email protected]>
> wrote:
> [..]
> > I'm aware of this possibility, however it is not suitable for the use
> > case that I have in mind (configuration variables), because it requires
> > too much code for each variable.
> >
> > Of course one could wrap your example inside a factory function, but
> > that's unwieldy as well, since it requires keeping track of one context
> > manager for each context variable:
>
> I suggest you to open an issue on bugs.python.org to implement support
> for context manager protocol for contextvars.Token. I'm not opposed
> to the idea. Keep in mind that Python 3.8 is already in a feature
> freeze mode, so the earliest we can get this is Python 3.9.
>
> > By the way, contexts being implemented as immutable dictionaries implies
> > one copy of a dictionary per call to the set method. That in turn means
> > that using hundreds of context variables (a large library could easily
> > have that many configuration variables) might not be a good idea. Is
> > this correct?
>
> The contextvars module uses a special dictionary implementation (read
> more on that in PEP 567/550) with its ".set()" operation only slightly
> slower than updating a standard Python dict. Setting/resetting N
> context variables is about 1.5x slower than mutating a Python dict N
> times. In short, it's a fast operation by Python standards.
>
> >
> > A final, unrelated comment: I find the use of the word "context" in the
> > standard library for both context managers and context variables (and
> > related to them "contexts") needlessly confusing. I suggest clearly
> > explaining their independence at the top of the documentation of either
> > module.
>
> Pull requests to improve the docs are always welcome!
>
> Yury
> Python-Ideas mailing list -- python-dev(a)python.org
> To unsubscribe send an email to python-ideas-leave(a)python.org
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
>
Python-Ideas mailing list -- python-dev(a)python.org
To unsubscribe send an email to python-ideas-leave(a)python.org
https://mail.python.org/mailman3/lists/python-ideas.python.org/