1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 """Utilities for with-statement contexts. See PEP 343."""
36
37 import sys
38
39 __all__ = ["contextmanager", "nested", "closing"]
40
41
42 -class GeneratorContextManager(object):
43 """Helper for @contextmanager decorator."""
44
45 - def __init__(self, gen):
47
48 - def __enter__(self):
49 try:
50 return self.gen.next()
51 except StopIteration:
52 raise RuntimeError("generator didn't yield")
53
54 - def __exit__(self, type, value, tb):
55 if type is None:
56 try:
57 self.gen.next()
58 except StopIteration:
59 return
60 else:
61 raise RuntimeError("generator didn't stop")
62 else:
63 if value is None:
64
65
66 value = type()
67 try:
68 try:
69 self.gen.next()
70 except StopIteration:
71 import traceback
72 traceback.print_exception(type, value, tb)
73 raise value
74 except StopIteration, exc:
75
76
77
78 return exc is not value
79
80
81 -def contextmanager(func):
82 """@contextmanager decorator.
83
84 Typical usage:
85
86 @contextmanager
87 def some_generator(<arguments>):
88 <setup>
89 try:
90 yield <value>
91 finally:
92 <cleanup>
93
94 This makes this:
95
96 with some_generator(<arguments>) as <variable>:
97 <body>
98
99 equivalent to this:
100
101 <setup>
102 try:
103 <variable> = <value>
104 <body>
105 finally:
106 <cleanup>
107
108 """
109
110 def helper(*args, **kwds):
111 return GeneratorContextManager(func(*args, **kwds))
112 try:
113 helper.__name__ = func.__name__
114 helper.__doc__ = func.__doc__
115 helper.__dict__ = func.__dict__
116 except:
117 pass
118 return helper
119
120
121 @contextmanager
122 -def nested(*managers):
123 """Support multiple context managers in a single with-statement.
124
125 Code like this:
126
127 with nested(A, B, C) as (X, Y, Z):
128 <body>
129
130 is equivalent to this:
131
132 with A as X:
133 with B as Y:
134 with C as Z:
135 <body>
136
137 """
138 exits = []
139 vars = []
140 exc = (None, None, None)
141
142
143 undefined = lambda: 42
144 result = undefined
145
146 try:
147 for mgr in managers:
148 exit = mgr.__exit__
149 enter = mgr.__enter__
150 vars.append(enter())
151 exits.append(exit)
152 result = vars
153 except:
154 exc = sys.exc_info()
155
156
157
158 if result != undefined:
159 yield result
160
161 while exits:
162 exit = exits.pop()
163 try:
164 if exit(*exc):
165 exc = (None, None, None)
166 except:
167 exc = sys.exc_info()
168 if exc != (None, None, None):
169
170
171
172 raise exc[0], exc[1], exc[2]
173
176 """Context to automatically close something at the end of a block.
177
178 Code like this:
179
180 with closing(<module>.open(<arguments>)) as f:
181 <block>
182
183 is equivalent to this:
184
185 f = <module>.open(<arguments>)
186 try:
187 <block>
188 finally:
189 f.close()
190
191 """
192
195
198
201