1 """Utilities for with-statement contexts. See PEP 343."""
4 from functools
import wraps
5 from warnings
import warn
7 __all__
= ["contextmanager", "nested", "closing"]
9 class GeneratorContextManager(object):
10 """Helper for @contextmanager decorator."""
12 def __init__(self
, gen
):
17 return self
.gen
.next()
19 raise RuntimeError("generator didn't yield")
21 def __exit__(self
, type, value
, traceback
):
28 raise RuntimeError("generator didn't stop")
31 # Need to force instantiation so we can reliably
32 # tell if we get the same exception back
35 self
.gen
.throw(type, value
, traceback
)
36 raise RuntimeError("generator didn't stop after throw()")
37 except StopIteration, exc
:
38 # Suppress the exception *unless* it's the same exception that
39 # was passed to throw(). This prevents a StopIteration
40 # raised inside the "with" statement from being suppressed
41 return exc
is not value
43 # only re-raise if it's *not* the exception that was
44 # passed to throw(), because __exit__() must not raise
45 # an exception unless __exit__() itself failed. But throw()
46 # has to raise the exception to signal propagation, so this
47 # fixes the impedance mismatch between the throw() protocol
48 # and the __exit__() protocol.
50 if sys
.exc_info()[1] is not value
:
54 def contextmanager(func
):
55 """@contextmanager decorator.
60 def some_generator(<arguments>):
69 with some_generator(<arguments>) as <variable>:
83 def helper(*args
, **kwds
):
84 return GeneratorContextManager(func(*args
, **kwds
))
89 def nested(*managers
):
90 """Combine multiple context managers into a single nested context manager.
92 This function has been deprecated in favour of the multiple manager form
93 of the with statement.
95 The one advantage of this function over the multiple manager form of the
96 with statement is that argument unpacking allows it to be
97 used with a variable number of context managers as follows:
99 with nested(*managers):
103 warn("With-statements now directly support multiple context managers",
104 DeprecationWarning, 3)
107 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
):