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
):
13 def __context__(self
):
18 return self
.gen
.next()
20 raise RuntimeError("generator didn't yield")
22 def __exit__(self
, type, value
, traceback
):
29 raise RuntimeError("generator didn't stop")
32 self
.gen
.throw(type, value
, traceback
)
33 raise RuntimeError("generator didn't stop after throw()")
35 # Suppress the exception *unless* it's the same exception that
36 # was passed to throw(). This prevents a StopIteration
37 # raised inside the "with" statement from being suppressed
38 return sys
.exc_info()[1] is not value
40 # only re-raise if it's *not* the exception that was
41 # passed to throw(), because __exit__() must not raise
42 # an exception unless __exit__() itself failed. But throw()
43 # has to raise the exception to signal propagation, so this
44 # fixes the impedance mismatch between the throw() protocol
45 # and the __exit__() protocol.
47 if sys
.exc_info()[1] is not value
:
51 def contextmanager(func
):
52 """@contextmanager decorator.
57 def some_generator(<arguments>):
66 with some_generator(<arguments>) as <variable>:
79 def helper(*args
, **kwds
):
80 return GeneratorContextManager(func(*args
, **kwds
))
82 helper
.__name
__ = func
.__name
__
83 helper
.__doc
__ = func
.__doc
__
84 helper
.__dict
__ = func
.__dict
__
91 def nested(*contexts
):
92 """Support multiple context managers in a single with-statement.
96 with nested(A, B, C) as (X, Y, Z):
99 is equivalent to this:
109 exc
= (None, None, None)
112 for context
in contexts
:
113 mgr
= context
.__context
__()
115 enter
= mgr
.__enter
__
126 exc
= (None, None, None)
129 if exc
!= (None, None, None):
135 """Context manager to automatically close something at the end of a block.
139 with closing(<module>.open(<arguments>)) as f:
142 is equivalent to this:
144 f = <module>.open(<arguments>)