1 """Utilities for with-statement contexts. See PEP 343."""
5 __all__ = ["contextmanager", "nested", "closing"]
7 class GeneratorContextManager(object):
8 """Helper for @contextmanager decorator."""
10 def __init__(self, gen):
15 return self.gen.next()
17 raise RuntimeError("generator didn't yield")
19 def __exit__(self, type, value, traceback):
26 raise RuntimeError("generator didn't stop")
29 self.gen.throw(type, value, traceback)
30 raise RuntimeError("generator didn't stop after throw()")
31 except StopIteration, exc:
32 # Suppress the exception *unless* it's the same exception that
33 # was passed to throw(). This prevents a StopIteration
34 # raised inside the "with" statement from being suppressed
35 return exc is not value
37 # only re-raise if it's *not* the exception that was
38 # passed to throw(), because __exit__() must not raise
39 # an exception unless __exit__() itself failed. But throw()
40 # has to raise the exception to signal propagation, so this
41 # fixes the impedance mismatch between the throw() protocol
42 # and the __exit__() protocol.
44 if sys.exc_info()[1] is not value:
48 def contextmanager(func):
49 """@contextmanager decorator.
54 def some_generator(<arguments>):
63 with some_generator(<arguments>) as <variable>:
76 def helper(*args, **kwds):
77 return GeneratorContextManager(func(*args, **kwds))
79 helper.__name__ = func.__name__
80 helper.__doc__ = func.__doc__
81 helper.__dict__ = func.__dict__
88 def nested(*managers):
89 """Support multiple context managers in a single with-statement.
93 with nested(A, B, C) as (X, Y, Z):
96 is equivalent to this:
106 exc = (None, None, None)
111 enter = mgr.__enter__
122 exc = (None, None, None)
125 if exc != (None, None, None):
126 # Don't rely on sys.exc_info() still containing
127 # the right information. Another exception may
128 # have been raised and caught by an exit method
129 raise exc[0], exc[1], exc[2]
132 class closing(object):
133 """Context to automatically close something at the end of a block.
137 with closing(<module>.open(<arguments>)) as f:
140 is equivalent to this:
142 f = <module>.open(<arguments>)
149 def __init__(self, thing):
153 def __exit__(self, *exc_info):