blob: 8cc71b4f399d7cc9e63d5da030b06942c5c67210 [file] [log] [blame]
Georg Brandl0eaab972009-06-08 08:00:22 +00001:mod:`contextlib` --- Utilities for :keyword:`with`\ -statement contexts
2========================================================================
Georg Brandl116aa622007-08-15 14:28:22 +00003
4.. module:: contextlib
5 :synopsis: Utilities for with-statement contexts.
6
Raymond Hettinger10480942011-01-10 03:26:08 +00007**Source code:** :source:`Lib/contextlib.py`
Georg Brandl116aa622007-08-15 14:28:22 +00008
Raymond Hettinger4f707fd2011-01-10 19:54:11 +00009--------------
10
Georg Brandl116aa622007-08-15 14:28:22 +000011This module provides utilities for common tasks involving the :keyword:`with`
12statement. For more information see also :ref:`typecontextmanager` and
13:ref:`context-managers`.
14
Georg Brandl116aa622007-08-15 14:28:22 +000015
Nick Coghlan3267a302012-05-21 22:54:43 +100016Utilities
17---------
18
19Functions and classes provided:
Georg Brandl116aa622007-08-15 14:28:22 +000020
Georg Brandl8a1caa22010-07-29 16:01:11 +000021.. decorator:: contextmanager
Georg Brandl116aa622007-08-15 14:28:22 +000022
Christian Heimesd8654cf2007-12-02 15:22:16 +000023 This function is a :term:`decorator` that can be used to define a factory
24 function for :keyword:`with` statement context managers, without needing to
25 create a class or separate :meth:`__enter__` and :meth:`__exit__` methods.
Georg Brandl116aa622007-08-15 14:28:22 +000026
27 A simple example (this is not recommended as a real way of generating HTML!)::
28
Georg Brandl116aa622007-08-15 14:28:22 +000029 from contextlib import contextmanager
30
31 @contextmanager
32 def tag(name):
Georg Brandl6911e3c2007-09-04 07:15:32 +000033 print("<%s>" % name)
Georg Brandl116aa622007-08-15 14:28:22 +000034 yield
Georg Brandl6911e3c2007-09-04 07:15:32 +000035 print("</%s>" % name)
Georg Brandl116aa622007-08-15 14:28:22 +000036
37 >>> with tag("h1"):
Georg Brandl6911e3c2007-09-04 07:15:32 +000038 ... print("foo")
Georg Brandl116aa622007-08-15 14:28:22 +000039 ...
40 <h1>
41 foo
42 </h1>
43
Georg Brandl9afde1c2007-11-01 20:32:30 +000044 The function being decorated must return a :term:`generator`-iterator when
45 called. This iterator must yield exactly one value, which will be bound to
46 the targets in the :keyword:`with` statement's :keyword:`as` clause, if any.
Georg Brandl116aa622007-08-15 14:28:22 +000047
48 At the point where the generator yields, the block nested in the :keyword:`with`
49 statement is executed. The generator is then resumed after the block is exited.
50 If an unhandled exception occurs in the block, it is reraised inside the
51 generator at the point where the yield occurred. Thus, you can use a
52 :keyword:`try`...\ :keyword:`except`...\ :keyword:`finally` statement to trap
53 the error (if any), or ensure that some cleanup takes place. If an exception is
54 trapped merely in order to log it or to perform some action (rather than to
55 suppress it entirely), the generator must reraise that exception. Otherwise the
56 generator context manager will indicate to the :keyword:`with` statement that
57 the exception has been handled, and execution will resume with the statement
58 immediately following the :keyword:`with` statement.
59
Nick Coghlan0ded3e32011-05-05 23:49:25 +100060 :func:`contextmanager` uses :class:`ContextDecorator` so the context managers
61 it creates can be used as decorators as well as in :keyword:`with` statements.
62 When used as a decorator, a new generator instance is implicitly created on
63 each function call (this allows the otherwise "one-shot" context managers
64 created by :func:`contextmanager` to meet the requirement that context
65 managers support multiple invocations in order to be used as decorators).
Michael Foordb3a89842010-06-30 12:17:50 +000066
67 .. versionchanged:: 3.2
68 Use of :class:`ContextDecorator`.
Georg Brandl116aa622007-08-15 14:28:22 +000069
Georg Brandl86e78d12010-07-18 13:43:32 +000070
Georg Brandl116aa622007-08-15 14:28:22 +000071.. function:: closing(thing)
72
73 Return a context manager that closes *thing* upon completion of the block. This
74 is basically equivalent to::
75
76 from contextlib import contextmanager
77
78 @contextmanager
79 def closing(thing):
80 try:
81 yield thing
82 finally:
83 thing.close()
84
85 And lets you write code like this::
86
Georg Brandl116aa622007-08-15 14:28:22 +000087 from contextlib import closing
Georg Brandl0f7ede42008-06-23 11:23:31 +000088 from urllib.request import urlopen
Georg Brandl116aa622007-08-15 14:28:22 +000089
Georg Brandl0f7ede42008-06-23 11:23:31 +000090 with closing(urlopen('http://www.python.org')) as page:
Georg Brandl116aa622007-08-15 14:28:22 +000091 for line in page:
Georg Brandl6911e3c2007-09-04 07:15:32 +000092 print(line)
Georg Brandl116aa622007-08-15 14:28:22 +000093
94 without needing to explicitly close ``page``. Even if an error occurs,
95 ``page.close()`` will be called when the :keyword:`with` block is exited.
96
97
Michael Foordb3a89842010-06-30 12:17:50 +000098.. class:: ContextDecorator()
99
100 A base class that enables a context manager to also be used as a decorator.
101
102 Context managers inheriting from ``ContextDecorator`` have to implement
103 ``__enter__`` and ``__exit__`` as normal. ``__exit__`` retains its optional
104 exception handling even when used as a decorator.
105
Georg Brandl86e78d12010-07-18 13:43:32 +0000106 ``ContextDecorator`` is used by :func:`contextmanager`, so you get this
107 functionality automatically.
108
109 Example of ``ContextDecorator``::
Michael Foordb3a89842010-06-30 12:17:50 +0000110
111 from contextlib import ContextDecorator
112
113 class mycontext(ContextDecorator):
Georg Brandl86e78d12010-07-18 13:43:32 +0000114 def __enter__(self):
115 print('Starting')
116 return self
Michael Foordb3a89842010-06-30 12:17:50 +0000117
Georg Brandl86e78d12010-07-18 13:43:32 +0000118 def __exit__(self, *exc):
119 print('Finishing')
120 return False
Michael Foordb3a89842010-06-30 12:17:50 +0000121
122 >>> @mycontext()
123 ... def function():
Georg Brandl86e78d12010-07-18 13:43:32 +0000124 ... print('The bit in the middle')
Michael Foordb3a89842010-06-30 12:17:50 +0000125 ...
126 >>> function()
127 Starting
128 The bit in the middle
129 Finishing
130
131 >>> with mycontext():
Georg Brandl86e78d12010-07-18 13:43:32 +0000132 ... print('The bit in the middle')
Michael Foordb3a89842010-06-30 12:17:50 +0000133 ...
134 Starting
135 The bit in the middle
136 Finishing
137
Georg Brandl86e78d12010-07-18 13:43:32 +0000138 This change is just syntactic sugar for any construct of the following form::
139
140 def f():
141 with cm():
142 # Do stuff
143
144 ``ContextDecorator`` lets you instead write::
145
146 @cm()
147 def f():
148 # Do stuff
149
150 It makes it clear that the ``cm`` applies to the whole function, rather than
151 just a piece of it (and saving an indentation level is nice, too).
152
Michael Foordb3a89842010-06-30 12:17:50 +0000153 Existing context managers that already have a base class can be extended by
154 using ``ContextDecorator`` as a mixin class::
155
156 from contextlib import ContextDecorator
157
158 class mycontext(ContextBaseClass, ContextDecorator):
Georg Brandl86e78d12010-07-18 13:43:32 +0000159 def __enter__(self):
160 return self
Michael Foordb3a89842010-06-30 12:17:50 +0000161
Georg Brandl86e78d12010-07-18 13:43:32 +0000162 def __exit__(self, *exc):
163 return False
Michael Foordb3a89842010-06-30 12:17:50 +0000164
Nick Coghlan0ded3e32011-05-05 23:49:25 +1000165 .. note::
166 As the decorated function must be able to be called multiple times, the
167 underlying context manager must support use in multiple :keyword:`with`
168 statements. If this is not the case, then the original construct with the
169 explicit :keyword:`with` statement inside the function should be used.
170
Michael Foordb3a89842010-06-30 12:17:50 +0000171 .. versionadded:: 3.2
172
173
Nick Coghlan3267a302012-05-21 22:54:43 +1000174.. class:: ExitStack()
175
176 A context manager that is designed to make it easy to programmatically
177 combine other context managers and cleanup functions, especially those
178 that are optional or otherwise driven by input data.
179
180 For example, a set of files may easily be handled in a single with
181 statement as follows::
182
183 with ExitStack() as stack:
184 files = [stack.enter_context(open(fname)) for fname in filenames]
185 # All opened files will automatically be closed at the end of
186 # the with statement, even if attempts to open files later
187 # in the list throw an exception
188
189 Each instance maintains a stack of registered callbacks that are called in
190 reverse order when the instance is closed (either explicitly or implicitly
191 at the end of a ``with`` statement). Note that callbacks are *not* invoked
192 implicitly when the context stack instance is garbage collected.
193
194 This stack model is used so that context managers that acquire their
195 resources in their ``__init__`` method (such as file objects) can be
196 handled correctly.
197
198 Since registered callbacks are invoked in the reverse order of
199 registration, this ends up behaving as if multiple nested ``with``
200 statements had been used with the registered set of callbacks. This even
201 extends to exception handling - if an inner callback suppresses or replaces
202 an exception, then outer callbacks will be passed arguments based on that
203 updated state.
204
205 This is a relatively low level API that takes care of the details of
206 correctly unwinding the stack of exit callbacks. It provides a suitable
207 foundation for higher level context managers that manipulate the exit
208 stack in application specific ways.
209
210 .. method:: enter_context(cm)
211
212 Enters a new context manager and adds its :meth:`__exit__` method to
213 the callback stack. The return value is the result of the context
214 manager's own :meth:`__enter__` method.
215
216 These context managers may suppress exceptions just as they normally
217 would if used directly as part of a ``with`` statement.
218
219 .. method:: push(exit)
220
221 Adds a context manager's :meth:`__exit__` method to the callback stack.
222
223 As ``__enter__`` is *not* invoked, this method can be used to cover
224 part of an :meth:`__enter__` implementation with a context manager's own
225 :meth:`__exit__` method.
226
227 If passed an object that is not a context manager, this method assumes
228 it is a callback with the same signature as a context manager's
229 :meth:`__exit__` method and adds it directly to the callback stack.
230
231 By returning true values, these callbacks can suppress exceptions the
232 same way context manager :meth:`__exit__` methods can.
233
234 The passed in object is returned from the function, allowing this
235 method to be used is a function decorator.
236
237 .. method:: callback(callback, *args, **kwds)
238
239 Accepts an arbitrary callback function and arguments and adds it to
240 the callback stack.
241
242 Unlike the other methods, callbacks added this way cannot suppress
243 exceptions (as they are never passed the exception details).
244
245 The passed in callback is returned from the function, allowing this
246 method to be used is a function decorator.
247
248 .. method:: pop_all()
249
250 Transfers the callback stack to a fresh :class:`ExitStack` instance
251 and returns it. No callbacks are invoked by this operation - instead,
252 they will now be invoked when the new stack is closed (either
253 explicitly or implicitly).
254
255 For example, a group of files can be opened as an "all or nothing"
256 operation as follows::
257
258 with ExitStack() as stack:
259 files = [stack.enter_context(open(fname)) for fname in filenames]
260 close_files = stack.pop_all().close
261 # If opening any file fails, all previously opened files will be
262 # closed automatically. If all files are opened successfully,
263 # they will remain open even after the with statement ends.
264 # close_files() can then be invoked explicitly to close them all
265
266 .. method:: close()
267
268 Immediately unwinds the callback stack, invoking callbacks in the
269 reverse order of registration. For any context managers and exit
270 callbacks registered, the arguments passed in will indicate that no
271 exception occurred.
272
273 .. versionadded:: 3.3
274
275
276Examples and Recipes
277--------------------
278
279This section describes some examples and recipes for making effective use of
280the tools provided by :mod:`contextlib`.
281
282
283Cleaning up in an ``__enter__`` implementation
284^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
285
286As noted in the documentation of :meth:`ExitStack.push`, this
287method can be useful in cleaning up an already allocated resource if later
288steps in the :meth:`__enter__` implementation fail.
289
290Here's an example of doing this for a context manager that accepts resource
291acquisition and release functions, along with an optional validation function,
292and maps them to the context management protocol::
293
294 from contextlib import contextmanager, ExitStack
295
296 class ResourceManager(object):
297
298 def __init__(self, acquire_resource, release_resource, check_resource_ok=None):
299 self.acquire_resource = acquire_resource
300 self.release_resource = release_resource
301 if check_resource_ok is None:
302 def check_resource_ok(resource):
303 return True
304 self.check_resource_ok = check_resource_ok
305
306 @contextmanager
307 def _cleanup_on_error(self):
308 with ExitStack() as stack:
309 stack.push(self)
310 yield
311 # The validation check passed and didn't raise an exception
312 # Accordingly, we want to keep the resource, and pass it
313 # back to our caller
314 stack.pop_all()
315
316 def __enter__(self):
317 resource = self.acquire_resource()
318 with self._cleanup_on_error():
319 if not self.check_resource_ok(resource):
320 msg = "Failed validation for {!r}"
321 raise RuntimeError(msg.format(resource))
322 return resource
323
324 def __exit__(self, *exc_details):
325 # We don't need to duplicate any of our resource release logic
326 self.release_resource()
327
328
329Replacing any use of ``try-finally`` and flag variables
330^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
331
332A pattern you will sometimes see is a ``try-finally`` statement with a flag
333variable to indicate whether or not the body of the ``finally`` clause should
334be executed. In its simplest form (that can't already be handled just by
335using an ``except`` clause instead), it looks something like this::
336
337 cleanup_needed = True
338 try:
339 result = perform_operation()
340 if result:
341 cleanup_needed = False
342 finally:
343 if cleanup_needed:
344 cleanup_resources()
345
346As with any ``try`` statement based code, this can cause problems for
347development and review, because the setup code and the cleanup code can end
348up being separated by arbitrarily long sections of code.
349
350:class:`ExitStack` makes it possible to instead register a callback for
351execution at the end of a ``with`` statement, and then later decide to skip
352executing that callback::
353
354 from contextlib import ExitStack
355
356 with ExitStack() as stack:
357 stack.callback(cleanup_resources)
358 result = perform_operation()
359 if result:
360 stack.pop_all()
361
362This allows the intended cleanup up behaviour to be made explicit up front,
363rather than requiring a separate flag variable.
364
365If a particular application uses this pattern a lot, it can be simplified
366even further by means of a small helper class::
367
368 from contextlib import ExitStack
369
370 class Callback(ExitStack):
371 def __init__(self, callback, *args, **kwds):
372 super(Callback, self).__init__()
373 self.callback(callback, *args, **kwds)
374
375 def cancel(self):
376 self.pop_all()
377
378 with Callback(cleanup_resources) as cb:
379 result = perform_operation()
380 if result:
381 cb.cancel()
382
383If the resource cleanup isn't already neatly bundled into a standalone
384function, then it is still possible to use the decorator form of
385:meth:`ExitStack.callback` to declare the resource cleanup in
386advance::
387
388 from contextlib import ExitStack
389
390 with ExitStack() as stack:
391 @stack.callback
392 def cleanup_resources():
393 ...
394 result = perform_operation()
395 if result:
396 stack.pop_all()
397
398Due to the way the decorator protocol works, a callback function
399declared this way cannot take any parameters. Instead, any resources to
400be released must be accessed as closure variables
401
402
403Using a context manager as a function decorator
404^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
405
406:class:`ContextDecorator` makes it possible to use a context manager in
407both an ordinary ``with`` statement and also as a function decorator.
408
409For example, it is sometimes useful to wrap functions or groups of statements
410with a logger that can track the time of entry and time of exit. Rather than
411writing both a function decorator and a context manager for the task,
412inheriting from :class:`ContextDecorator` provides both capabilities in a
413single definition::
414
415 from contextlib import ContextDecorator
416 import logging
417
418 logging.basicConfig(level=logging.INFO)
419
420 class track_entry_and_exit(ContextDecorator):
421 def __init__(self, name):
422 self.name = name
423
424 def __enter__(self):
425 logging.info('Entering: {}'.format(name))
426
427 def __exit__(self, exc_type, exc, exc_tb):
428 logging.info('Exiting: {}'.format(name))
429
430Instances of this class can be used as both a context manager::
431
432 with track_entry_and_exit('widget loader'):
433 print('Some time consuming activity goes here')
434 load_widget()
435
436And also as a function decorator::
437
438 @track_entry_and_exit('widget loader')
439 def activity():
440 print('Some time consuming activity goes here')
441 load_widget()
442
443Note that there is one additional limitation when using context managers
444as function decorators: there's no way to access the return value of
445:meth:`__enter__`. If that value is needed, then it is still necessary to use
446an explicit ``with`` statement.
447
Georg Brandl116aa622007-08-15 14:28:22 +0000448.. seealso::
449
450 :pep:`0343` - The "with" statement
451 The specification, background, and examples for the Python :keyword:`with`
452 statement.
453