[Python-Dev] Iterator version of contextlib.nested
Nick Coghlan
ncoghlan at gmail.com
Sat Jun 13 03:01:49 CEST 2009
Hagen Fürstenau wrote:
> I'm proposing to add an iterator version of "nested" to contextlib
> (possibly called "inested"), which takes an iterable of context managers
> instead of a variable number of parameters. The implementation could be
> taken over from the present "nested", only changing "def
> nested(*managers)" to "def inested(managers)".
>
> This has the advantage that an iterator can be passed to "inested", so
> that each context managers is created in the context of all previous
> ones, which was one of the reasons for introducing the multi-with
> statement in the first place. "contextlib.inested" would therefore be
> the generalization of the multi-with statement to a variable number of
> managers (and "contextlib.nested" would stay deprecated).
The semantic change actually needed to make nested() more equivalent to
the multi-with statement is for it to accept zero-argument callables
that create context managers as arguments rather than pre-created
context managers.
Rather than changing the name of the function, this could be done by
inspecting the first argument for an "__enter__" method. If it has one,
use the old semantics (and issue a DeprecationWarning as in 3.1).
Otherwise, use the proposed new semantics.
However, the semantic equivalence still won't be complete as nested()
currently has no way of matching the multi-with behaviour of allowing
outer context managers to suppress exceptions raised by the constructors
or __enter__ methods of inner context managers. Attempting to do so will
result in a RuntimeError as the contextlib.contextmanager wrapper
complains that the generator implementing nested() didn't yield.
The further enhancement needed to address that would be to tweak
nested() to raise a custom exception in that case (e.g. ContextSkipped)
and provide an "allowskip" context manager that just catches and
suppresses that specific exception:
i.e.
@contextmanager
def allowskip():
try:
yield
except ContextSkipped:
pass
with allowskip(), nested(*cm_factories):
# Do something
I suggest putting an RFE on the tracker for this.
Cheers,
Nick.
--
Nick Coghlan | ncoghlan at gmail.com | Brisbane, Australia
---------------------------------------------------------------
More information about the Python-Dev
mailing list