[Python-modules-commits] [contextlib2] 01/05: Import contextlib2_0.5.1.orig.tar.gz

Tristan Seligmann mithrandi at moszumanska.debian.org
Tue Jan 19 17:55:02 UTC 2016


This is an automated email from the git hooks/post-receive script.

mithrandi pushed a commit to branch master
in repository contextlib2.

commit bc6a82f45d8d19ce24f1eaca8228e178bb43c28e
Author: Tristan Seligmann <mithrandi at debian.org>
Date:   Tue Jan 19 19:47:01 2016 +0200

    Import contextlib2_0.5.1.orig.tar.gz
---
 NEWS.rst            |  21 ++
 PKG-INFO            |  53 +++++-
 README.rst          |  42 ++++
 README.txt          |   3 -
 VERSION.txt         |   2 +-
 contextlib2.py      | 245 +++++++++++++++++++-----
 docs/index.rst      | 432 ++++++++++++++++++++++++++++++-----------
 setup.py            |  23 ++-
 test_contextlib2.py | 538 +++++++++++++++++++++++++++++++++++++++-------------
 9 files changed, 1058 insertions(+), 301 deletions(-)

diff --git a/NEWS.rst b/NEWS.rst
index 55b9783..1eb2c0f 100644
--- a/NEWS.rst
+++ b/NEWS.rst
@@ -1,6 +1,27 @@
 Release History
 ---------------
 
+0.5.1 (2016-01-13)
+~~~~~~~~~~~~~~~~~~
+
+* Python 2.6 compatilibity restored (although 2.6 is still missing from the
+  current CI configuration)
+
+* README converted back to reStructured Text formatting
+
+0.5.0 (2016-01-12)
+~~~~~~~~~~~~~~~~~~
+
+* Updated to include all features from the Python 3.4 and 3.5 releases of
+  contextlib (also includes some ``ExitStack`` enhancements made following
+  the integration into the standard library for Python 3.3)
+
+* The legacy ``ContextStack`` and ``ContextDecorator.refresh_cm`` APIs are
+  no longer documented and emit ``DeprecationWarning`` when used
+
+* Python 2.6, 3.2 and 3.3 have been dropped from compatibility testing
+
+
 0.4.0 (2012-05-05)
 ~~~~~~~~~~~~~~~~~~
 
diff --git a/PKG-INFO b/PKG-INFO
index 11f0640..7b735ff 100644
--- a/PKG-INFO
+++ b/PKG-INFO
@@ -1,13 +1,58 @@
-Metadata-Version: 1.0
+Metadata-Version: 1.1
 Name: contextlib2
-Version: 0.4.0
+Version: 0.5.1
 Summary: Backports and enhancements for the contextlib module
 Home-page: http://contextlib2.readthedocs.org
 Author: Nick Coghlan
 Author-email: ncoghlan at gmail.com
 License: PSF License
-Description: contextlib2 is a backport of the standard library's contextlib module to earlier Python versions.
+Description: .. image:: https://readthedocs.org/projects/contextlib2/badge/?version=latest
+            :target: https://contextlib2.readthedocs.org/
+            :alt: Latest Docs
         
-        It also serves as a real world proving ground for possible future enhancements to the standard library version.
+        .. image:: https://codeship.com/projects/884e9500-3d1a-0133-3eb0-1abe7f570a4c/status?branch=default
+            :target: https://codeship.com/projects/102388
         
+        .. image:: https://codecov.io/bitbucket/ncoghlan/contextlib2/coverage.svg?branch=default
+            :target: https://codecov.io/bitbucket/ncoghlan/contextlib2?branch=default
+        
+        contextlib2 is a backport of the `standard library's contextlib
+        module <https://docs.python.org/3.5/library/contextlib.html>`_ to
+        earlier Python versions.
+        
+        It also serves as a real world proving ground for possible future
+        enhancements to the standard library version.
+        
+        Development
+        -----------
+        
+        contextlib2 currently has no dependencies.
+        
+        Local testing is currently just a matter of running ``python test_contextlib2.py``.
+        
+        You can test against multiple versions of Python with `tox <http://tox.testrun.org/>`_::
+        
+            pip install tox
+            tox
+        
+        Versions currently tested in tox are:
+        
+        * CPython 2.7 (also tested in Codeship)
+        * CPython 3.4 (also tested in Codeship)
+        * CPython 3.5
+        * PyPy
+        * PyPy3
+        
+        To install all the relevant runtimes on Fedora 23::
+        
+            sudo dnf install python python3 pypy pypy3
+            sudo dnf copr enable -y mstuchli/Python3.5
+            sudo dnf install python35-python3
 Platform: UNKNOWN
+Classifier: Development Status :: 5 - Production/Stable
+Classifier: License :: OSI Approved :: Python Software Foundation License
+Classifier: Programming Language :: Python :: 2
+Classifier: Programming Language :: Python :: 2.7
+Classifier: Programming Language :: Python :: 3
+Classifier: Programming Language :: Python :: 3.4
+Classifier: Programming Language :: Python :: 3.5
diff --git a/README.rst b/README.rst
new file mode 100644
index 0000000..74b1136
--- /dev/null
+++ b/README.rst
@@ -0,0 +1,42 @@
+.. image:: https://readthedocs.org/projects/contextlib2/badge/?version=latest
+    :target: https://contextlib2.readthedocs.org/
+    :alt: Latest Docs
+
+.. image:: https://codeship.com/projects/884e9500-3d1a-0133-3eb0-1abe7f570a4c/status?branch=default
+    :target: https://codeship.com/projects/102388
+
+.. image:: https://codecov.io/bitbucket/ncoghlan/contextlib2/coverage.svg?branch=default
+    :target: https://codecov.io/bitbucket/ncoghlan/contextlib2?branch=default
+
+contextlib2 is a backport of the `standard library's contextlib
+module <https://docs.python.org/3.5/library/contextlib.html>`_ to
+earlier Python versions.
+
+It also serves as a real world proving ground for possible future
+enhancements to the standard library version.
+
+Development
+-----------
+
+contextlib2 currently has no dependencies.
+
+Local testing is currently just a matter of running ``python test_contextlib2.py``.
+
+You can test against multiple versions of Python with `tox <http://tox.testrun.org/>`_::
+
+    pip install tox
+    tox
+
+Versions currently tested in tox are:
+
+* CPython 2.7 (also tested in Codeship)
+* CPython 3.4 (also tested in Codeship)
+* CPython 3.5
+* PyPy
+* PyPy3
+
+To install all the relevant runtimes on Fedora 23::
+
+    sudo dnf install python python3 pypy pypy3
+    sudo dnf copr enable -y mstuchli/Python3.5
+    sudo dnf install python35-python3
\ No newline at end of file
diff --git a/README.txt b/README.txt
deleted file mode 100644
index 3bf4588..0000000
--- a/README.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-contextlib2 is a backport of the standard library's contextlib module to earlier Python versions.
-
-It also serves as a real world proving ground for possible future enhancements to the standard library version.
diff --git a/VERSION.txt b/VERSION.txt
index 60a2d3e..4b9fcbe 100644
--- a/VERSION.txt
+++ b/VERSION.txt
@@ -1 +1 @@
-0.4.0
\ No newline at end of file
+0.5.1
diff --git a/contextlib2.py b/contextlib2.py
index 1fe5bc2..2b80384 100644
--- a/contextlib2.py
+++ b/contextlib2.py
@@ -1,12 +1,15 @@
 """contextlib2 - backports and enhancements to the contextlib module"""
 
 import sys
+import warnings
 from collections import deque
 from functools import wraps
 
-__all__ = ["contextmanager", "closing", "ContextDecorator",
-           "ContextStack", "ExitStack"]
+__all__ = ["contextmanager", "closing", "ContextDecorator", "ExitStack",
+           "redirect_stdout", "redirect_stderr", "suppress"]
 
+# Backwards compatibility
+__all__ += ["ContextStack"]
 
 class ContextDecorator(object):
     "A base class or mixin that enables context managers to work as decorators."
@@ -14,19 +17,36 @@ class ContextDecorator(object):
     def refresh_cm(self):
         """Returns the context manager used to actually wrap the call to the
         decorated function.
-        
+
         The default implementation just returns *self*.
 
         Overriding this method allows otherwise one-shot context managers
         like _GeneratorContextManager to support use as decorators via
         implicit recreation.
+
+        DEPRECATED: refresh_cm was never added to the standard library's
+                    ContextDecorator API
+        """
+        warnings.warn("refresh_cm was never added to the standard library",
+                      DeprecationWarning)
+        return self._recreate_cm()
+
+    def _recreate_cm(self):
+        """Return a recreated instance of self.
+
+        Allows an otherwise one-shot context manager like
+        _GeneratorContextManager to support use as
+        a decorator via implicit recreation.
+
+        This is a private interface just for _GeneratorContextManager.
+        See issue #11647 for details.
         """
         return self
 
     def __call__(self, func):
         @wraps(func)
         def inner(*args, **kwds):
-            with self.refresh_cm():
+            with self._recreate_cm():
                 return func(*args, **kwds)
         return inner
 
@@ -34,15 +54,25 @@ class ContextDecorator(object):
 class _GeneratorContextManager(ContextDecorator):
     """Helper for @contextmanager decorator."""
 
-    def __init__(self, func, *args, **kwds):
+    def __init__(self, func, args, kwds):
         self.gen = func(*args, **kwds)
         self.func, self.args, self.kwds = func, args, kwds
-
-    def refresh_cm(self):
+        # Issue 19330: ensure context manager instances have good docstrings
+        doc = getattr(func, "__doc__", None)
+        if doc is None:
+            doc = type(self).__doc__
+        self.__doc__ = doc
+        # Unfortunately, this still doesn't provide good help output when
+        # inspecting the created context manager instances, since pydoc
+        # currently bypasses the instance docstring and shows the docstring
+        # for the class instead.
+        # See http://bugs.python.org/issue19404 for more details.
+
+    def _recreate_cm(self):
         # _GCM instances are one-shot context managers, so the
         # CM must be recreated each time a decorated function is
         # called
-        return self.__class__(self.func, *self.args, **self.kwds)
+        return self.__class__(self.func, self.args, self.kwds)
 
     def __enter__(self):
         try:
@@ -67,10 +97,17 @@ class _GeneratorContextManager(ContextDecorator):
                 self.gen.throw(type, value, traceback)
                 raise RuntimeError("generator didn't stop after throw()")
             except StopIteration as exc:
-                # Suppress the exception *unless* it's the same exception that
+                # Suppress StopIteration *unless* it's the same exception that
                 # was passed to throw().  This prevents a StopIteration
-                # raised inside the "with" statement from being suppressed
+                # raised inside the "with" statement from being suppressed.
                 return exc is not value
+            except RuntimeError as exc:
+                # Likewise, avoid suppressing if a StopIteration exception
+                # was passed to throw() and later wrapped into a RuntimeError
+                # (see PEP 479).
+                if _HAVE_EXCEPTION_CHAINING and exc.__cause__ is value:
+                    return False
+                raise
             except:
                 # only re-raise if it's *not* the exception that was
                 # passed to throw(), because __exit__() must not raise
@@ -113,7 +150,7 @@ def contextmanager(func):
     """
     @wraps(func)
     def helper(*args, **kwds):
-        return _GeneratorContextManager(func, *args, **kwds)
+        return _GeneratorContextManager(func, args, kwds)
     return helper
 
 
@@ -142,22 +179,131 @@ class closing(object):
         self.thing.close()
 
 
+class _RedirectStream:
+
+    _stream = None
+
+    def __init__(self, new_target):
+        self._new_target = new_target
+        # We use a list of old targets to make this CM re-entrant
+        self._old_targets = []
+
+    def __enter__(self):
+        self._old_targets.append(getattr(sys, self._stream))
+        setattr(sys, self._stream, self._new_target)
+        return self._new_target
+
+    def __exit__(self, exctype, excinst, exctb):
+        setattr(sys, self._stream, self._old_targets.pop())
+
+
+class redirect_stdout(_RedirectStream):
+    """Context manager for temporarily redirecting stdout to another file.
+
+        # How to send help() to stderr
+        with redirect_stdout(sys.stderr):
+            help(dir)
+
+        # How to write help() to a file
+        with open('help.txt', 'w') as f:
+            with redirect_stdout(f):
+                help(pow)
+    """
+
+    _stream = "stdout"
+
+
+class redirect_stderr(_RedirectStream):
+    """Context manager for temporarily redirecting stderr to another file."""
+
+    _stream = "stderr"
+
+
+class suppress:
+    """Context manager to suppress specified exceptions
+
+    After the exception is suppressed, execution proceeds with the next
+    statement following the with statement.
+
+         with suppress(FileNotFoundError):
+             os.remove(somefile)
+         # Execution still resumes here if the file was already removed
+    """
+
+    def __init__(self, *exceptions):
+        self._exceptions = exceptions
+
+    def __enter__(self):
+        pass
+
+    def __exit__(self, exctype, excinst, exctb):
+        # Unlike isinstance and issubclass, CPython exception handling
+        # currently only looks at the concrete type hierarchy (ignoring
+        # the instance and subclass checking hooks). While Guido considers
+        # that a bug rather than a feature, it's a fairly hard one to fix
+        # due to various internal implementation details. suppress provides
+        # the simpler issubclass based semantics, rather than trying to
+        # exactly reproduce the limitations of the CPython interpreter.
+        #
+        # See http://bugs.python.org/issue12029 for more details
+        return exctype is not None and issubclass(exctype, self._exceptions)
+
+
+# Context manipulation is Python 3 only
+_HAVE_EXCEPTION_CHAINING = sys.version_info[0] >= 3
+if _HAVE_EXCEPTION_CHAINING:
+    def _make_context_fixer(frame_exc):
+        def _fix_exception_context(new_exc, old_exc):
+            # Context may not be correct, so find the end of the chain
+            while 1:
+                exc_context = new_exc.__context__
+                if exc_context is old_exc:
+                    # Context is already set correctly (see issue 20317)
+                    return
+                if exc_context is None or exc_context is frame_exc:
+                    break
+                new_exc = exc_context
+            # Change the end of the chain to point to the exception
+            # we expect it to reference
+            new_exc.__context__ = old_exc
+        return _fix_exception_context
+
+    def _reraise_with_existing_context(exc_details):
+        try:
+            # bare "raise exc_details[1]" replaces our carefully
+            # set-up context
+            fixed_ctx = exc_details[1].__context__
+            raise exc_details[1]
+        except BaseException:
+            exc_details[1].__context__ = fixed_ctx
+            raise
+else:
+    # No exception context in Python 2
+    def _make_context_fixer(frame_exc):
+        return lambda new_exc, old_exc: None
+
+    # Use 3 argument raise in Python 2,
+    # but use exec to avoid SyntaxError in Python 3
+    def _reraise_with_existing_context(exc_details):
+        exc_type, exc_value, exc_tb = exc_details
+        exec ("raise exc_type, exc_value, exc_tb")
+
 # Inspired by discussions on http://bugs.python.org/issue13585
 class ExitStack(object):
     """Context manager for dynamic management of a stack of exit callbacks
-    
+
     For example:
-    
+
         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
-    
+            # in the list raise an exception
+
     """
     def __init__(self):
         self._exit_callbacks = deque()
-        
+
     def pop_all(self):
         """Preserve the context stack by transferring it to a new instance"""
         new_stack = type(self)()
@@ -171,14 +317,14 @@ class ExitStack(object):
             return cm_exit(cm, *exc_details)
         _exit_wrapper.__self__ = cm
         self.push(_exit_wrapper)
-        
+
     def push(self, exit):
         """Registers a callback with the standard __exit__ method signature
 
         Can suppress exceptions the same way __exit__ methods can.
 
-        Also accepts any object with an __exit__ method (registering the
-        method instead of the object itself)
+        Also accepts any object with an __exit__ method (registering a call
+        to the method instead of the object itself)
         """
         # We use an unbound method rather than a bound method to follow
         # the standard lookup behaviour for special methods
@@ -194,7 +340,7 @@ class ExitStack(object):
 
     def callback(self, callback, *args, **kwds):
         """Registers an arbitrary callback and arguments.
-        
+
         Cannot suppress exceptions.
         """
         def _exit_wrapper(exc_type, exc, tb):
@@ -207,7 +353,7 @@ class ExitStack(object):
 
     def enter_context(self, cm):
         """Enters the supplied context manager
-        
+
         If successful, also pushes its __exit__ method as a callback and
         returns the result of the __enter__ method.
         """
@@ -226,40 +372,43 @@ class ExitStack(object):
         return self
 
     def __exit__(self, *exc_details):
-        if not self._exit_callbacks:
-            return
-        # This looks complicated, but it is really just
-        # setting up a chain of try-expect statements to ensure
-        # that outer callbacks still get invoked even if an
-        # inner one throws an exception
-        def _invoke_next_callback(exc_details):
-            # Callbacks are removed from the list in FIFO order
-            # but the recursion means they're invoked in LIFO order
-            cb = self._exit_callbacks.popleft()
-            if not self._exit_callbacks:
-                # Innermost callback is invoked directly
-                return cb(*exc_details)
-            # More callbacks left, so descend another level in the stack
+        received_exc = exc_details[0] is not None
+
+        # We manipulate the exception state so it behaves as though
+        # we were actually nesting multiple with statements
+        frame_exc = sys.exc_info()[1]
+        _fix_exception_context = _make_context_fixer(frame_exc)
+
+        # Callbacks are invoked in LIFO order to match the behaviour of
+        # nested context managers
+        suppressed_exc = False
+        pending_raise = False
+        while self._exit_callbacks:
+            cb = self._exit_callbacks.pop()
             try:
-                suppress_exc = _invoke_next_callback(exc_details)
-            except:
-                suppress_exc = cb(*sys.exc_info())
-                # Check if this cb suppressed the inner exception
-                if not suppress_exc:
-                    raise
-            else:
-                # Check if inner cb suppressed the original exception
-                if suppress_exc:
+                if cb(*exc_details):
+                    suppressed_exc = True
+                    pending_raise = False
                     exc_details = (None, None, None)
-                suppress_exc = cb(*exc_details) or suppress_exc
-            return suppress_exc
-        # Kick off the recursive chain
-        return _invoke_next_callback(exc_details)
+            except:
+                new_exc_details = sys.exc_info()
+                # simulate the stack of exceptions by setting the context
+                _fix_exception_context(new_exc_details[1], exc_details[1])
+                pending_raise = True
+                exc_details = new_exc_details
+        if pending_raise:
+            _reraise_with_existing_context(exc_details)
+        return received_exc and suppressed_exc
 
 # Preserve backwards compatibility
 class ContextStack(ExitStack):
     """Backwards compatibility alias for ExitStack"""
 
+    def __init__(self):
+        warnings.warn("ContextStack has been renamed to ExitStack",
+                      DeprecationWarning)
+        super(ContextStack, self).__init__()
+
     def register_exit(self, callback):
         return self.push(callback)
 
diff --git a/docs/index.rst b/docs/index.rst
index f4ea3ce..cd32393 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -21,22 +21,25 @@ involving the ``with`` statement.
 Additions Relative to the Standard Library
 ------------------------------------------
 
-This module is primarily a backport of the Python 3.2 version of
+This module is primarily a backport of the Python 3.5 version of
 :mod:`contextlib` to earlier releases. However, it is also a proving ground
-for new features not yet part of the standard library. Those new features
-are currently:
+for new features not yet part of the standard library.
 
-* :class:`ExitStack`
-* :meth:`ContextDecorator.refresh_cm`
+There are currently no such features in the module.
+
+Refer to the :mod:`contextlib` documentation for details of which
+versions of Python 3 introduce the various APIs provided in this module.
 
 
 API Reference
 =============
 
-.. function:: contextmanager
+Functions and classes provided:
+
+.. decorator:: contextmanager
 
-   This function is a decorator that can be used to define a factory
-   function for ``with`` statement context managers, without needing to
+   This function is a :term:`decorator` that can be used to define a factory
+   function for :keyword:`with` statement context managers, without needing to
    create a class or separate :meth:`__enter__` and :meth:`__exit__` methods.
 
    A simple example (this is not recommended as a real way of generating HTML!)::
@@ -56,24 +59,24 @@ API Reference
       foo
       </h1>
 
-   The function being decorated must return a generator-iterator when
+   The function being decorated must return a :term:`generator`-iterator when
    called. This iterator must yield exactly one value, which will be bound to
-   the targets in the ``with`` statement's ``as`` clause, if any.
+   the targets in the :keyword:`with` statement's :keyword:`as` clause, if any.
 
-   At the point where the generator yields, the block nested in the ``with``
+   At the point where the generator yields, the block nested in the :keyword:`with`
    statement is executed.  The generator is then resumed after the block is exited.
    If an unhandled exception occurs in the block, it is reraised inside the
    generator at the point where the yield occurred.  Thus, you can use a
-   ``try``...\ ``except``...\ ``finally`` statement to trap
+   :keyword:`try`...\ :keyword:`except`...\ :keyword:`finally` statement to trap
    the error (if any), or ensure that some cleanup takes place. If an exception is
    trapped merely in order to log it or to perform some action (rather than to
    suppress it entirely), the generator must reraise that exception. Otherwise the
-   generator context manager will indicate to the ``with`` statement that
+   generator context manager will indicate to the :keyword:`with` statement that
    the exception has been handled, and execution will resume with the statement
-   immediately following the ``with`` statement.
+   immediately following the :keyword:`with` statement.
 
    :func:`contextmanager` uses :class:`ContextDecorator` so the context managers
-   it creates can be used as decorators as well as in ``with`` statements.
+   it creates can be used as decorators as well as in :keyword:`with` statements.
    When used as a decorator, a new generator instance is implicitly created on
    each function call (this allows the otherwise "one-shot" context managers
    created by :func:`contextmanager` to meet the requirement that context
@@ -104,7 +107,97 @@ API Reference
               print(line)
 
    without needing to explicitly close ``page``.  Even if an error occurs,
-   ``page.close()`` will be called when the ``with`` block is exited.
+   ``page.close()`` will be called when the :keyword:`with` block is exited.
+
+
+.. function:: suppress(*exceptions)
+
+   Return a context manager that suppresses any of the specified exceptions
+   if they occur in the body of a with statement and then resumes execution
+   with the first statement following the end of the with statement.
+
+   As with any other mechanism that completely suppresses exceptions, this
+   context manager should be used only to cover very specific errors where
+   silently continuing with program execution is known to be the right
+   thing to do.
+
+   For example::
+
+       from contextlib import suppress
+
+       with suppress(FileNotFoundError):
+           os.remove('somefile.tmp')
+
+       with suppress(FileNotFoundError):
+           os.remove('someotherfile.tmp')
+
+   This code is equivalent to::
+
+       try:
+           os.remove('somefile.tmp')
+       except FileNotFoundError:
+           pass
+
+       try:
+           os.remove('someotherfile.tmp')
+       except FileNotFoundError:
+           pass
+
+   This context manager is :ref:`reentrant <reentrant-cms>`.
+
+   .. versionadded:: 0.5
+      Part of the standard library in Python 3.4 and later
+
+
+.. function:: redirect_stdout(new_target)
+
+   Context manager for temporarily redirecting :data:`sys.stdout` to
+   another file or file-like object.
+
+   This tool adds flexibility to existing functions or classes whose output
+   is hardwired to stdout.
+
+   For example, the output of :func:`help` normally is sent to *sys.stdout*.
+   You can capture that output in a string by redirecting the output to a
+   :class:`io.StringIO` object::
+
+        f = io.StringIO()
+        with redirect_stdout(f):
+            help(pow)
+        s = f.getvalue()
+
+   To send the output of :func:`help` to a file on disk, redirect the output
+   to a regular file::
+
+        with open('help.txt', 'w') as f:
+            with redirect_stdout(f):
+                help(pow)
+
+   To send the output of :func:`help` to *sys.stderr*::
+
+        with redirect_stdout(sys.stderr):
+            help(pow)
+
+   Note that the global side effect on :data:`sys.stdout` means that this
+   context manager is not suitable for use in library code and most threaded
+   applications. It also has no effect on the output of subprocesses.
+   However, it is still a useful approach for many utility scripts.
+
+   This context manager is :ref:`reentrant <reentrant-cms>`.
+
+   .. versionadded:: 0.5
+      Part of the standard library in Python 3.4 and later
+
+
+.. function:: redirect_stderr(new_target)
+
+   Similar to :func:`redirect_stdout`, but redirecting :data:`sys.stderr` to
+   another file or file-like object.
+
+   This context manager is :ref:`reentrant <reentrant-cms>`.
+
+   .. versionadded:: 0.5
+      Part of the standard library in Python 3.5 and later
 
 
 .. class:: ContextDecorator()
@@ -112,7 +205,7 @@ API Reference
    A base class that enables a context manager to also be used as a decorator.
 
    Context managers inheriting from ``ContextDecorator`` have to implement
-   :meth:`__enter__` and :meth:`__exit__` as normal. :meth:`__exit__` retains its optional
+   ``__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
@@ -174,22 +267,11 @@ API Reference
           def __exit__(self, *exc):
               return False
 
-   .. method:: refresh_cm()
-
-      This method is invoked each time a call is made to a decorated function.
-      The default implementation just returns *self*.
-
+   .. note::
       As the decorated function must be able to be called multiple times, the
-      underlying context manager must normally support use in multiple
-      ``with`` statements (preferably in a thread-safe manner). If
-      this is not the case, then the context manager must define this method
-      and return a *new* copy of the context manager on each invocation.
-
-      This may involve keeping a copy of the original arguments used to
-      first initialise the context manager.
-
-   .. versionchanged:: 0.1
-      Made the standard library's private :meth:`refresh_cm` API public
+      underlying context manager must support use in multiple :keyword:`with`
+      statements. If this is not the case, then the original construct with the
+      explicit :keyword:`with` statement inside the function should be used.
 
 
 .. class:: ExitStack()
@@ -205,20 +287,32 @@ API Reference
           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
+          # in the list raise 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 ``with`` statement). Note that callbacks are *not* invoked
-   implicitly when the context stack instance is garbage collected.
+   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 ``with``
+   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:: 0.4
+      Part of the standard library in Python 3.3 and later
+
    .. method:: enter_context(cm)
 
       Enters a new context manager and adds its :meth:`__exit__` method to
@@ -226,21 +320,25 @@ API Reference
       manager's own :meth:`__enter__` method.
 
       These context managers may suppress exceptions just as they normally
-      would if used directly as part of a ``with`` statement.
+      would if used directly as part of a :keyword:`with` statement.
 
    .. method:: push(exit)
 
-      Directly accepts a callback with the same signature as a
-      context manager's :meth:`__exit__` method and adds it to the callback
-      stack.
+      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.
 
-      This method also accepts any object with an ``__exit__`` method, and
-      will register that method as the callback. This is mainly useful to
-      cover part of an :meth:`__enter__` implementation with a context
-      manager's own :meth:`__exit__` method.
+      The passed in object is returned from the function, allowing this
+      method to be used as a function decorator.
 
    .. method:: callback(callback, *args, **kwds)
 
@@ -250,22 +348,27 @@ API Reference
       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 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).
+      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]
+             # Hold onto the close method, but don't call it yet.
              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
+             # close_files() can then be invoked explicitly to close them all.
 
    .. method:: close()
 
@@ -274,21 +377,6 @@ API Reference
       callbacks registered, the arguments passed in will indicate that no
       exception occurred.
 
-   .. versionadded:: 0.4
-      New API for :mod:`contextlib2`, not available in standard library
-
-
-.. class:: ContextStack()
-
-   An earlier incarnation of the :class:`ExitStack` interface. This class
-   is deprecated and should no longer be used.
-
-   .. versionchanged:: 0.4
-      Deprecated in favour of :class:`ExitStack`
-
-   .. versionadded:: 0.2
-      New API for :mod:`contextlib2`, not available in standard library
-
 
 Examples and Recipes
 ====================
@@ -299,53 +387,6 @@ the tools provided by :mod:`contextlib2`. Some of them may also work with
 case, it is noted at the end of the example.
 
 
-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. The
-:meth:`ContextDecorator.refresh_cm` method even makes it possible to use
-otherwise single use context managers (such as those created by
-:func:`contextmanager`) that way.
-
-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,
-:func:`contextmanager` provides both capabilities in a single
-definition::
-
-    from contextlib2 import contextmanager
-    import logging
-
-    logging.basicConfig(level=logging.INFO)
-
-    @contextmanager
-    def track_entry_and_exit(name):
-        logging.info('Entering: {}'.format(name))
-        yield
-        logging.info('Exiting: {}'.format(name))
-
-This 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.
-
-This example should also work with :mod:`contextlib` in Python 3.2.1 or later.
-
-
 Cleaning up in an ``__enter__`` implementation
 ----------------------------------------------
 
@@ -384,6 +425,8 @@ and maps them to the context management protocol::
            # We don't need to duplicate any of our resource release logic
            self.release_resource()
 
+This example will also work with :mod:`contextlib` in Python 3.3 or later.
+
 
 Replacing any use of ``try-finally`` and flag variables
 -------------------------------------------------------
@@ -456,7 +499,174 @@ advance::
 
 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
+be released must be accessed as closure variables.
+
+This example will also work with :mod:`contextlib` in Python 3.3 or later.
+
+
+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. The
+:meth:`ContextDecorator.refresh_cm` method even makes it possible to use
+otherwise single use context managers (such as those created by
+:func:`contextmanager`) that way.
+
+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,
+:func:`contextmanager` provides both capabilities in a single
+definition::
+
+    from contextlib2 import contextmanager
+    import logging
+
+    logging.basicConfig(level=logging.INFO)
+
+    @contextmanager
+    def track_entry_and_exit(name):
+        logging.info('Entering: {}'.format(name))
+        yield
+        logging.info('Exiting: {}'.format(name))
+
+This 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.
+
+This example will also work with :mod:`contextlib` in Python 3.2.1 or later.
+
+
+Context Management Concepts
+===========================
+
+.. _single-use-reusable-and-reentrant-cms:
... 796 lines suppressed ...

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/python-modules/packages/contextlib2.git



More information about the Python-modules-commits mailing list