We have code that invokes a variable number of context managers depending on runtime parameters:
from contextlib import nested, contextmanager
@contextmanager
def my_context(arg):
print("entering", arg)
try:
yield arg
finally:
print("exiting", arg)
def my_fn(items):
with nested(*(my_context(arg) for arg in items)) as managers:
print("processing under", managers)
my_fn(range(3))
However, contextlib.nested
is deprecated since Python 2.7:
DeprecationWarning: With-statements now directly support multiple context managers
The answers to Multiple variables in Python 'with' statement indicate that contextlib.nested
has some "confusing error prone quirks", but the suggested alternative of using the multiple-manager with
statement won't work for a variable number of context managers (and also breaks backward compatibility).
Are there any alternatives to contextlib.nested
that aren't deprecated and (preferably) don't have the same bugs?
Or should I continue to use contextlib.nested
and ignore the warning? If so, should I plan for contextlib.nested
to be removed at some time in the future?
It's a little vexing that the python3 maintainers chose to break backwards compatibility, since implementing
nested
in terms ofExitStack
is pretty straightforward:The new Python 3
contextlib.ExitStack
class was added as a replacement forcontextlib.nested()
(see issue 13585).It is coded in such a way you can use it in Python 2 directly:
Use this as your context manager, then add nested context managers at will:
For your example context manager, this prints:
You can also install the
contextlib2
module; it includesExitStack
as a backport.It seems that you are supposed to use the
with
statement with multiple context manager instances.from https://pymotw.com/2/contextlib/: