◐ Shell
reader mode source ↗
Skip to content
Merged
Show file tree
Changes from all commits
File filter
Conversations
Jump to
Diff view
Apply and reload
Show whitespace
Diff view
Apply and reload
30 changes: 30 additions & 0 deletions Doc/library/contextlib.rst
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,36 @@ Functions and classes provided:
Use of :class:`ContextDecorator`.


.. function:: closing(thing)

Return a context manager that closes *thing* upon completion of the block. This
Expand Down
2 changes: 2 additions & 0 deletions Doc/reference/datamodel.rst
Original file line number Diff line number Diff line change
Expand Up @@ -2575,6 +2575,8 @@ An example of an asynchronous iterable object::
result in a :exc:`RuntimeError`.


Asynchronous Context Managers
-----------------------------

Expand Down
6 changes: 6 additions & 0 deletions Doc/whatsnew/3.7.rst
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,12 @@ New Modules
Improved Modules
================

distutils
---------

Expand Down
99 changes: 93 additions & 6 deletions Lib/contextlib.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
from collections import deque
from functools import wraps

__all__ = ["contextmanager", "closing", "AbstractContextManager",
"ContextDecorator", "ExitStack", "redirect_stdout",
"redirect_stderr", "suppress"]


class AbstractContextManager(abc.ABC):
Expand Down Expand Up @@ -54,8 +54,8 @@ def inner(*args, **kwds):
return inner


class _GeneratorContextManager(ContextDecorator, AbstractContextManager):
"""Helper for @contextmanager decorator."""

def __init__(self, func, args, kwds):
self.gen = func(*args, **kwds)
Expand All @@ -71,6 +71,12 @@ def __init__(self, func, args, kwds):
# 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
Expand Down Expand Up @@ -121,12 +127,61 @@ def __exit__(self, type, value, traceback):
# fixes the impedance mismatch between the throw() protocol
# and the __exit__() protocol.
#
if sys.exc_info()[1] is value:
return False
raise
raise RuntimeError("generator didn't stop after throw()")


def contextmanager(func):
"""@contextmanager decorator.

Expand All @@ -153,14 +208,46 @@ def some_generator(<arguments>):
<body>
finally:
<cleanup>

"""
@wraps(func)
def helper(*args, **kwds):
return _GeneratorContextManager(func, args, kwds)
return helper


class closing(AbstractContextManager):
"""Context to automatically close something at the end of a block.

Expand Down
Loading
Toggle all file notes Toggle all file annotations