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