Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(55626)

Side by Side Diff: Lib/contextlib.py

Issue 13585: Add contextlib.CleanupManager
Patch Set: Created 7 years, 6 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 """Utilities for with-statement contexts. See PEP 343.""" 1 """Utilities for with-statement contexts. See PEP 343."""
2 2
3 import sys 3 import sys
4 from functools import wraps 4 from functools import wraps
5 5
6 __all__ = ["contextmanager", "closing", "ContextDecorator"] 6 __all__ = ["contextmanager", "closing", "ContextDecorator"]
7 7
8 8
9 class ContextDecorator(object): 9 class ContextDecorator(object):
10 "A base class or mixin that enables context managers to work as decorators." 10 "A base class or mixin that enables context managers to work as decorators."
(...skipping 120 matching lines...) Expand 10 before | Expand all | Expand 10 after
131 finally: 131 finally:
132 f.close() 132 f.close()
133 133
134 """ 134 """
135 def __init__(self, thing): 135 def __init__(self, thing):
136 self.thing = thing 136 self.thing = thing
137 def __enter__(self): 137 def __enter__(self):
138 return self.thing 138 return self.thing
139 def __exit__(self, *exc_info): 139 def __exit__(self, *exc_info):
140 self.thing.close() 140 self.thing.close()
141
142
143 class CleanupManager(object):
144 '''Context manager to automatically call registered "cleanup"
145 functions at the end of a block.
146
147 This context manager is typically used to manage resources that
148 need to be explicitly freed but don't come with their own context
149 manager. It also avoids deeply nested with try..finally blocks if
150 several resources need to be managed.
151
152 Example 1:
153
154 with CleanupManager() as mngr:
155 tmpdir = tempfile.mkdtemp()
156 mngr.register(shutil.rmtree, tmpdir)
157 <block>
158
159 is equivalent to
160
161 try:
162 tmpdir = tempfile.mkdtemp()
163 <block>
164 finally:
165 shutil.rmtree(tmpdir)
166
167 Example 2:
168
169 allocate_res1()
170 try:
171 # do stuff
172 allocate_res2()
173 try:
174 # do stuff
175 allocate_res3()
176 try:
177 # do stuff
178 finally:
179 cleanup_res3()
180 finally:
181 cleanup_res2()
182 finally:
183 cleanup_res1()
184
185 can also be written as:
186
187 with CleanupManager() as mngr:
188 allocate_res1()
189 mngr.register(cleanup_res1)
190 # do stuff
191 allocate_res2()
192 mngr.register(cleanup_res2)
193 # do stuff
194 allocate_res3()
195 mngr.register(cleanup_res3)
196 # do stuff
197 '''
198
199 def __init__(self):
200 self.cleanup_callbacks = list()
201
202 def register(self, callback, *args, **kwargs):
203 '''Register *callback* as a cleanup function
204
205 This method instructs the `CleanupManager` instance to add
206 *callback* to the list of functions to be called when control
207 leaves the managed block. The function will be called with
208 arguments *args* and keywords arguments *kwargs*.
209 '''
210
211 self.cleanup_callbacks.append((callback, args, kwargs))
212
213 def unregister(self, callback, *args, **kwargs):
214 '''Remove *callback* from the list of cleanup functions
215
216 This method instructs the `CleanupManager` instance to remove
217 *callback* from the list of functions to be called when control
218 leaves the managed block.
219
220 This method removes all calls to *callback* with the specified
221 arguments. To remove all calls to *callback* disregarding the
222 arguments, use the `unregister_all` functions.
223 '''
224
225 self._cleanup_callbacks = [ el for el in self._cleanup_callbacks
226 if el != (callback, args, kwargs) ]
227
228 def unregister_all(self, callback):
229 '''Remove *callback* from the list of cleanup functions
230
231 This method instructs the `CleanupManager` instance to remove
232 *callback* from the list of functions to be called when control
233 leaves the managed block.
234
235 This method removes all calls to *callback*, disregarding the
236 arguments passed to `register`.
237 '''
238
239 self._cleanup_callbacks = [ el for el in self._cleanup_callbacks
240 if el[0] != callback ]
241
242 def __enter__(self):
243 return self
244
245 def __exit__(self, exc_type, exc, tb):
246 self._next_callback()
247
248 def _next_callback(self):
249 if self.cleanup_callbacks:
250 (callback, args, kwargs) = self.cleanup_callbacks.pop()
251 try:
252 callback(*args, **kwargs)
253 finally:
254 self._next_callback()
255
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld 894c83f36cb7+