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

Unified Diff: Doc/library/contextlib.rst

Issue 14843: support define_macros / undef_macros in setup.cfg
Patch Set: Created 11 months, 2 weeks ago
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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Doc/library/bz2.rst ('k') | Doc/library/datetime.rst » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
--- a/Doc/library/contextlib.rst Sat Jun 09 17:31:59 2012 +0100
+++ b/Doc/library/contextlib.rst Mon May 21 23:01:17 2012 -0400
@@ -12,11 +12,8 @@
statement. For more information see also :ref:`typecontextmanager` and
:ref:`context-managers`.
+Functions provided:
-Utilities
----------
-
-Functions and classes provided:
.. decorator:: contextmanager
@@ -171,348 +168,6 @@
.. versionadded:: 3.2
-.. class:: ExitStack()
-
- A context manager that is designed to make it easy to programmatically
- combine other context managers and cleanup functions, especially those
- that are optional or otherwise driven by input data.
-
- For example, a set of files may easily be handled in a single with
- statement as follows::
-
- with ExitStack() as stack:
- files = [stack.enter_context(open(fname)) for fname in filenames]
- # All opened files will automatically be closed at the end of
- # the with statement, even if attempts to open files later
- # in the list throw an exception
-
- Each instance maintains a stack of registered callbacks that are called in
- reverse order when the instance is closed (either explicitly or implicitly
- at the end of a :keyword:`with` statement). Note that callbacks are *not*
- invoked implicitly when the context stack instance is garbage collected.
-
- This stack model is used so that context managers that acquire their
- resources in their ``__init__`` method (such as file objects) can be
- handled correctly.
-
- Since registered callbacks are invoked in the reverse order of
- registration, this ends up behaving as if multiple nested :keyword:`with`
- statements had been used with the registered set of callbacks. This even
- extends to exception handling - if an inner callback suppresses or replaces
- an exception, then outer callbacks will be passed arguments based on that
- updated state.
-
- This is a relatively low level API that takes care of the details of
- correctly unwinding the stack of exit callbacks. It provides a suitable
- foundation for higher level context managers that manipulate the exit
- stack in application specific ways.
-
- .. versionadded:: 3.3
-
- .. method:: enter_context(cm)
-
- Enters a new context manager and adds its :meth:`__exit__` method to
- the callback stack. The return value is the result of the context
- manager's own :meth:`__enter__` method.
-
- These context managers may suppress exceptions just as they normally
- would if used directly as part of a :keyword:`with` statement.
-
- .. method:: push(exit)
-
- Adds a context manager's :meth:`__exit__` method to the callback stack.
-
- As ``__enter__`` is *not* invoked, this method can be used to cover
- part of an :meth:`__enter__` implementation with a context manager's own
- :meth:`__exit__` method.
-
- If passed an object that is not a context manager, this method assumes
- it is a callback with the same signature as a context manager's
- :meth:`__exit__` method and adds it directly to the callback stack.
-
- By returning true values, these callbacks can suppress exceptions the
- same way context manager :meth:`__exit__` methods can.
-
- The passed in object is returned from the function, allowing this
- method to be used as a function decorator.
-
- .. method:: callback(callback, *args, **kwds)
-
- Accepts an arbitrary callback function and arguments and adds it to
- the callback stack.
-
- Unlike the other methods, callbacks added this way cannot suppress
- exceptions (as they are never passed the exception details).
-
- The passed in callback is returned from the function, allowing this
- method to be used as a function decorator.
-
- .. method:: pop_all()
-
- Transfers the callback stack to a fresh :class:`ExitStack` instance
- and returns it. No callbacks are invoked by this operation - instead,
- they will now be invoked when the new stack is closed (either
- explicitly or implicitly at the end of a :keyword:`with` statement).
-
- For example, a group of files can be opened as an "all or nothing"
- operation as follows::
-
- with ExitStack() as stack:
- files = [stack.enter_context(open(fname)) for fname in filenames]
- close_files = stack.pop_all().close
- # If opening any file fails, all previously opened files will be
- # closed automatically. If all files are opened successfully,
- # they will remain open even after the with statement ends.
- # close_files() can then be invoked explicitly to close them all
-
- .. method:: close()
-
- Immediately unwinds the callback stack, invoking callbacks in the
- reverse order of registration. For any context managers and exit
- callbacks registered, the arguments passed in will indicate that no
- exception occurred.
-
-
-Examples and Recipes
---------------------
-
-This section describes some examples and recipes for making effective use of
-the tools provided by :mod:`contextlib`.
-
-
-Supporting a variable number of context managers
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-The primary use case for :class:`ExitStack` is the one given in the class
-documentation: supporting a variable number of context managers and other
-cleanup operations in a single :keyword:`with` statement. The variability
-may come from the number of context managers needed being driven by user
-input (such as opening a user specified collection of files), or from
-some of the context managers being optional::
-
- with ExitStack() as stack:
- for resource in resources:
- stack.enter_context(resource)
- if need_special resource:
- special = acquire_special_resource()
- stack.callback(release_special_resource, special)
- # Perform operations that use the acquired resources
-
-As shown, :class:`ExitStack` also makes it quite easy to use :keyword:`with`
-statements to manage arbitrary resources that don't natively support the
-context management protocol.
-
-
-Simplifying support for single optional context managers
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-In the specific case of a single optional context manager, :class:`ExitStack`
-instances can be used as a "do nothing" context manager, allowing a context
-manager to easily be omitted without affecting the overall structure of
-the source code::
-
- def debug_trace(details):
- if __debug__:
- return TraceContext(details)
- # Don't do anything special with the context in release mode
- return ExitStack()
-
- with debug_trace():
- # Suite is traced in debug mode, but runs normally otherwise
-
-
-Catching exceptions from ``__enter__`` methods
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-It is occasionally desirable to catch exceptions from an ``__enter__``
-method implementation, *without* inadvertently catching exceptions from
-the :keyword:`with` statement body or the context manager's ``__exit__``
-method. By using :class:`ExitStack` the steps in the context management
-protocol can be separated slightly in order to allow this::
-
- stack = ExitStack()
- try:
- x = stack.enter_context(cm)
- except Exception:
- # handle __enter__ exception
- else:
- with stack:
- # Handle normal case
-
-Actually needing to do this is likely to indicate that the underlying API
-should be providing a direct resource management interface for use with
-:keyword:`try`/:keyword:`except`/:keyword:`finally` statements, but not
-all APIs are well designed in that regard. When a context manager is the
-only resource management API provided, then :class:`ExitStack` can make it
-easier to handle various situations that can't be handled directly in a
-:keyword:`with` statement.
-
-
-Cleaning up in an ``__enter__`` implementation
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-As noted in the documentation of :meth:`ExitStack.push`, this
-method can be useful in cleaning up an already allocated resource if later
-steps in the :meth:`__enter__` implementation fail.
-
-Here's an example of doing this for a context manager that accepts resource
-acquisition and release functions, along with an optional validation function,
-and maps them to the context management protocol::
-
- from contextlib import contextmanager, ExitStack
-
- class ResourceManager(object):
-
- def __init__(self, acquire_resource, release_resource, check_resource_ok=None):
- self.acquire_resource = acquire_resource
- self.release_resource = release_resource
- if check_resource_ok is None:
- def check_resource_ok(resource):
- return True
- self.check_resource_ok = check_resource_ok
-
- @contextmanager
- def _cleanup_on_error(self):
- with ExitStack() as stack:
- stack.push(self)
- yield
- # The validation check passed and didn't raise an exception
- # Accordingly, we want to keep the resource, and pass it
- # back to our caller
- stack.pop_all()
-
- def __enter__(self):
- resource = self.acquire_resource()
- with self._cleanup_on_error():
- if not self.check_resource_ok(resource):
- msg = "Failed validation for {!r}"
- raise RuntimeError(msg.format(resource))
- return resource
-
- def __exit__(self, *exc_details):
- # We don't need to duplicate any of our resource release logic
- self.release_resource()
-
-
-Replacing any use of ``try-finally`` and flag variables
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-A pattern you will sometimes see is a ``try-finally`` statement with a flag
-variable to indicate whether or not the body of the ``finally`` clause should
-be executed. In its simplest form (that can't already be handled just by
-using an ``except`` clause instead), it looks something like this::
-
- cleanup_needed = True
- try:
- result = perform_operation()
- if result:
- cleanup_needed = False
- finally:
- if cleanup_needed:
- cleanup_resources()
-
-As with any ``try`` statement based code, this can cause problems for
-development and review, because the setup code and the cleanup code can end
-up being separated by arbitrarily long sections of code.
-
-:class:`ExitStack` makes it possible to instead register a callback for
-execution at the end of a ``with`` statement, and then later decide to skip
-executing that callback::
-
- from contextlib import ExitStack
-
- with ExitStack() as stack:
- stack.callback(cleanup_resources)
- result = perform_operation()
- if result:
- stack.pop_all()
-
-This allows the intended cleanup up behaviour to be made explicit up front,
-rather than requiring a separate flag variable.
-
-If a particular application uses this pattern a lot, it can be simplified
-even further by means of a small helper class::
-
- from contextlib import ExitStack
-
- class Callback(ExitStack):
- def __init__(self, callback, *args, **kwds):
- super(Callback, self).__init__()
- self.callback(callback, *args, **kwds)
-
- def cancel(self):
- self.pop_all()
-
- with Callback(cleanup_resources) as cb:
- result = perform_operation()
- if result:
- cb.cancel()
-
-If the resource cleanup isn't already neatly bundled into a standalone
-function, then it is still possible to use the decorator form of
-:meth:`ExitStack.callback` to declare the resource cleanup in
-advance::
-
- from contextlib import ExitStack
-
- with ExitStack() as stack:
- @stack.callback
- def cleanup_resources():
- ...
- result = perform_operation()
- if result:
- stack.pop_all()
-
-Due to the way the decorator protocol works, a callback function
-declared this way cannot take any parameters. Instead, any resources to
-be released must be accessed as closure variables
-
-
-Using a context manager as a function decorator
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-:class:`ContextDecorator` makes it possible to use a context manager in
-both an ordinary ``with`` statement and also as a function decorator.
-
-For example, it is sometimes useful to wrap functions or groups of statements
-with a logger that can track the time of entry and time of exit. Rather than
-writing both a function decorator and a context manager for the task,
-inheriting from :class:`ContextDecorator` provides both capabilities in a
-single definition::
-
- from contextlib import ContextDecorator
- import logging
-
- logging.basicConfig(level=logging.INFO)
-
- class track_entry_and_exit(ContextDecorator):
- def __init__(self, name):
- self.name = name
-
- def __enter__(self):
- logging.info('Entering: {}'.format(name))
-
- def __exit__(self, exc_type, exc, exc_tb):
- logging.info('Exiting: {}'.format(name))
-
-Instances of this class can be used as both a context manager::
-
- with track_entry_and_exit('widget loader'):
- print('Some time consuming activity goes here')
- load_widget()
-
-And also as a function decorator::
-
- @track_entry_and_exit('widget loader')
- def activity():
- print('Some time consuming activity goes here')
- load_widget()
-
-Note that there is one additional limitation when using context managers
-as function decorators: there's no way to access the return value of
-:meth:`__enter__`. If that value is needed, then it is still necessary to use
-an explicit ``with`` statement.
-
.. seealso::
:pep:`0343` - The "with" statement
« no previous file with comments | « Doc/library/bz2.rst ('k') | Doc/library/datetime.rst » ('j') | no next file with comments »

RSS Feeds Recent Issues | This issue
This is Rietveld cbc36f91f3f7