1 """Utilities for with-statement contexts. See PEP 343."""
4 from functools
import wraps
6 __all__
= ["contextmanager", "nested", "closing"]
8 class GeneratorContextManager(object):
9 """Helper for @contextmanager decorator."""
11 def __init__(self
, gen
):
16 return self
.gen
.next()
18 raise RuntimeError("generator didn't yield")
20 def __exit__(self
, type, value
, traceback
):
27 raise RuntimeError("generator didn't stop")
30 # Need to force instantiation so we can reliably
31 # tell if we get the same exception back
34 self
.gen
.throw(type, value
, traceback
)
35 raise RuntimeError("generator didn't stop after throw()")
36 except StopIteration, exc
:
37 # Suppress the exception *unless* it's the same exception that
38 # was passed to throw(). This prevents a StopIteration
39 # raised inside the "with" statement from being suppressed
40 return exc
is not value
42 # only re-raise if it's *not* the exception that was
43 # passed to throw(), because __exit__() must not raise
44 # an exception unless __exit__() itself failed. But throw()
45 # has to raise the exception to signal propagation, so this
46 # fixes the impedance mismatch between the throw() protocol
47 # and the __exit__() protocol.
49 if sys
.exc_info()[1] is not value
:
53 def contextmanager(func
):
54 """@contextmanager decorator.
59 def some_generator(<arguments>):
68 with some_generator(<arguments>) as <variable>:
82 def helper(*args
, **kwds
):
83 return GeneratorContextManager(func(*args
, **kwds
))
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)
110 enter
= mgr
.__enter
__
121 exc
= (None, None, None)
124 if exc
!= (None, None, None):
125 # Don't rely on sys.exc_info() still containing
126 # the right information. Another exception may
127 # have been raised and caught by an exit method
128 raise exc
[0], exc
[1], exc
[2]
131 class closing(object):
132 """Context to automatically close something at the end of a block.
136 with closing(<module>.open(<arguments>)) as f:
139 is equivalent to this:
141 f = <module>.open(<arguments>)
148 def __init__(self
, thing
):
152 def __exit__(self
, *exc_info
):