summaryrefslogtreecommitdiffstats
path: root/Doc/library/contextlib.rst
diff options
context:
space:
mode:
Diffstat (limited to 'Doc/library/contextlib.rst')
-rw-r--r--Doc/library/contextlib.rst126
1 files changed, 78 insertions, 48 deletions
diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst
index ca37f0f..a35ea56 100644
--- a/Doc/library/contextlib.rst
+++ b/Doc/library/contextlib.rst
@@ -4,6 +4,9 @@
.. module:: contextlib
:synopsis: Utilities for with-statement contexts.
+**Source code:** :source:`Lib/contextlib.py`
+
+--------------
This module provides utilities for common tasks involving the :keyword:`with`
statement. For more information see also :ref:`typecontextmanager` and
@@ -12,7 +15,7 @@ statement. For more information see also :ref:`typecontextmanager` and
Functions provided:
-.. function:: contextmanager(func)
+.. decorator:: contextmanager
This function is a :term:`decorator` that can be used to define a factory
function for :keyword:`with` statement context managers, without needing to
@@ -51,54 +54,11 @@ Functions provided:
the exception has been handled, and execution will resume with the statement
immediately following the :keyword:`with` statement.
+ contextmanager uses :class:`ContextDecorator` so the context managers it
+ creates can be used as decorators as well as in :keyword:`with` statements.
-.. function:: nested(mgr1[, mgr2[, ...]])
-
- Combine multiple context managers into a single nested context manager.
-
- This function has been deprecated in favour of the multiple manager form
- of the :keyword:`with` statement.
-
- The one advantage of this function over the multiple manager form of the
- :keyword:`with` statement is that argument unpacking allows it to be
- used with a variable number of context managers as follows::
-
- from contextlib import nested
-
- with nested(*managers):
- do_something()
-
- Note that if the :meth:`__exit__` method of one of the nested context managers
- indicates an exception should be suppressed, no exception information will be
- passed to any remaining outer context managers. Similarly, if the
- :meth:`__exit__` method of one of the nested managers raises an exception, any
- previous exception state will be lost; the new exception will be passed to the
- :meth:`__exit__` methods of any remaining outer context managers. In general,
- :meth:`__exit__` methods should avoid raising exceptions, and in particular they
- should not re-raise a passed-in exception.
-
- This function has two major quirks that have led to it being deprecated. Firstly,
- as the context managers are all constructed before the function is invoked, the
- :meth:`__new__` and :meth:`__init__` methods of the inner context managers are
- not actually covered by the scope of the outer context managers. That means, for
- example, that using :func:`nested` to open two files is a programming error as the
- first file will not be closed promptly if an exception is thrown when opening
- the second file.
-
- Secondly, if the :meth:`__enter__` method of one of the inner context managers
- raises an exception that is caught and suppressed by the :meth:`__exit__` method
- of one of the outer context managers, this construct will raise
- :exc:`RuntimeError` rather than skipping the body of the :keyword:`with`
- statement.
-
- Developers that need to support nesting of a variable number of context managers
- can either use the :mod:`warnings` module to suppress the DeprecationWarning
- raised by this function or else use this function as a model for an application
- specific implementation.
-
- .. deprecated:: 3.1
- The with-statement now supports this functionality directly (without the
- confusing error prone quirks).
+ .. versionchanged:: 3.2
+ Use of :class:`ContextDecorator`.
.. function:: closing(thing)
@@ -128,6 +88,76 @@ Functions provided:
``page.close()`` will be called when the :keyword:`with` block is exited.
+.. class:: ContextDecorator()
+
+ A base class that enables a context manager to also be used as a decorator.
+
+ Context managers inheriting from ``ContextDecorator`` have to implement
+ ``__enter__`` and ``__exit__`` as normal. ``__exit__`` retains its optional
+ exception handling even when used as a decorator.
+
+ ``ContextDecorator`` is used by :func:`contextmanager`, so you get this
+ functionality automatically.
+
+ Example of ``ContextDecorator``::
+
+ from contextlib import ContextDecorator
+
+ class mycontext(ContextDecorator):
+ def __enter__(self):
+ print('Starting')
+ return self
+
+ def __exit__(self, *exc):
+ print('Finishing')
+ return False
+
+ >>> @mycontext()
+ ... def function():
+ ... print('The bit in the middle')
+ ...
+ >>> function()
+ Starting
+ The bit in the middle
+ Finishing
+
+ >>> with mycontext():
+ ... print('The bit in the middle')
+ ...
+ Starting
+ The bit in the middle
+ Finishing
+
+ This change is just syntactic sugar for any construct of the following form::
+
+ def f():
+ with cm():
+ # Do stuff
+
+ ``ContextDecorator`` lets you instead write::
+
+ @cm()
+ def f():
+ # Do stuff
+
+ It makes it clear that the ``cm`` applies to the whole function, rather than
+ just a piece of it (and saving an indentation level is nice, too).
+
+ Existing context managers that already have a base class can be extended by
+ using ``ContextDecorator`` as a mixin class::
+
+ from contextlib import ContextDecorator
+
+ class mycontext(ContextBaseClass, ContextDecorator):
+ def __enter__(self):
+ return self
+
+ def __exit__(self, *exc):
+ return False
+
+ .. versionadded:: 3.2
+
+
.. seealso::
:pep:`0343` - The "with" statement