mirror of
https://github.com/python/cpython.git
synced 2025-09-27 10:50:04 +00:00
Removed contextlib.nested()
This commit is contained in:
parent
6e5b0a1140
commit
9c4d0edd64
3 changed files with 0 additions and 216 deletions
|
@ -52,55 +52,6 @@ Functions provided:
|
||||||
immediately following the :keyword:`with` statement.
|
immediately following the :keyword:`with` statement.
|
||||||
|
|
||||||
|
|
||||||
.. 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).
|
|
||||||
|
|
||||||
|
|
||||||
.. function:: closing(thing)
|
.. function:: closing(thing)
|
||||||
|
|
||||||
Return a context manager that closes *thing* upon completion of the block. This
|
Return a context manager that closes *thing* upon completion of the block. This
|
||||||
|
|
|
@ -85,51 +85,6 @@ def contextmanager(func):
|
||||||
return helper
|
return helper
|
||||||
|
|
||||||
|
|
||||||
@contextmanager
|
|
||||||
def nested(*managers):
|
|
||||||
"""Combine multiple context managers into a single nested context manager.
|
|
||||||
|
|
||||||
This function has been deprecated in favour of the multiple manager form
|
|
||||||
of the with statement.
|
|
||||||
|
|
||||||
The one advantage of this function over the multiple manager form of the
|
|
||||||
with statement is that argument unpacking allows it to be
|
|
||||||
used with a variable number of context managers as follows:
|
|
||||||
|
|
||||||
with nested(*managers):
|
|
||||||
do_something()
|
|
||||||
|
|
||||||
"""
|
|
||||||
warn("With-statements now directly support multiple context managers",
|
|
||||||
DeprecationWarning, 3)
|
|
||||||
exits = []
|
|
||||||
vars = []
|
|
||||||
exc = (None, None, None)
|
|
||||||
try:
|
|
||||||
for mgr in managers:
|
|
||||||
exit = mgr.__exit__
|
|
||||||
enter = mgr.__enter__
|
|
||||||
vars.append(enter())
|
|
||||||
exits.append(exit)
|
|
||||||
yield vars
|
|
||||||
except:
|
|
||||||
exc = sys.exc_info()
|
|
||||||
finally:
|
|
||||||
while exits:
|
|
||||||
exit = exits.pop()
|
|
||||||
try:
|
|
||||||
if exit(*exc):
|
|
||||||
exc = (None, None, None)
|
|
||||||
except:
|
|
||||||
exc = sys.exc_info()
|
|
||||||
if exc != (None, None, None):
|
|
||||||
# Don't rely on sys.exc_info() still containing
|
|
||||||
# the right information. Another exception may
|
|
||||||
# have been raised and caught by an exit method
|
|
||||||
# exc[1] already has the __traceback__ attribute populated
|
|
||||||
raise exc[1]
|
|
||||||
|
|
||||||
|
|
||||||
class closing(object):
|
class closing(object):
|
||||||
"""Context to automatically close something at the end of a block.
|
"""Context to automatically close something at the end of a block.
|
||||||
|
|
||||||
|
|
|
@ -101,128 +101,6 @@ class ContextManagerTestCase(unittest.TestCase):
|
||||||
self.assertEqual(baz.foo, 'bar')
|
self.assertEqual(baz.foo, 'bar')
|
||||||
self.assertEqual(baz.__doc__, "Whee!")
|
self.assertEqual(baz.__doc__, "Whee!")
|
||||||
|
|
||||||
class NestedTestCase(unittest.TestCase):
|
|
||||||
|
|
||||||
# XXX This needs more work
|
|
||||||
|
|
||||||
def test_nested(self):
|
|
||||||
@contextmanager
|
|
||||||
def a():
|
|
||||||
yield 1
|
|
||||||
@contextmanager
|
|
||||||
def b():
|
|
||||||
yield 2
|
|
||||||
@contextmanager
|
|
||||||
def c():
|
|
||||||
yield 3
|
|
||||||
with nested(a(), b(), c()) as (x, y, z):
|
|
||||||
self.assertEqual(x, 1)
|
|
||||||
self.assertEqual(y, 2)
|
|
||||||
self.assertEqual(z, 3)
|
|
||||||
|
|
||||||
def test_nested_cleanup(self):
|
|
||||||
state = []
|
|
||||||
@contextmanager
|
|
||||||
def a():
|
|
||||||
state.append(1)
|
|
||||||
try:
|
|
||||||
yield 2
|
|
||||||
finally:
|
|
||||||
state.append(3)
|
|
||||||
@contextmanager
|
|
||||||
def b():
|
|
||||||
state.append(4)
|
|
||||||
try:
|
|
||||||
yield 5
|
|
||||||
finally:
|
|
||||||
state.append(6)
|
|
||||||
try:
|
|
||||||
with nested(a(), b()) as (x, y):
|
|
||||||
state.append(x)
|
|
||||||
state.append(y)
|
|
||||||
1/0
|
|
||||||
except ZeroDivisionError:
|
|
||||||
self.assertEqual(state, [1, 4, 2, 5, 6, 3])
|
|
||||||
else:
|
|
||||||
self.fail("Didn't raise ZeroDivisionError")
|
|
||||||
|
|
||||||
def test_nested_right_exception(self):
|
|
||||||
state = []
|
|
||||||
@contextmanager
|
|
||||||
def a():
|
|
||||||
yield 1
|
|
||||||
class b(object):
|
|
||||||
def __enter__(self):
|
|
||||||
return 2
|
|
||||||
def __exit__(self, *exc_info):
|
|
||||||
try:
|
|
||||||
raise Exception()
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
with nested(a(), b()) as (x, y):
|
|
||||||
1/0
|
|
||||||
except ZeroDivisionError:
|
|
||||||
self.assertEqual((x, y), (1, 2))
|
|
||||||
except Exception:
|
|
||||||
self.fail("Reraised wrong exception")
|
|
||||||
else:
|
|
||||||
self.fail("Didn't raise ZeroDivisionError")
|
|
||||||
|
|
||||||
def test_nested_b_swallows(self):
|
|
||||||
@contextmanager
|
|
||||||
def a():
|
|
||||||
yield
|
|
||||||
@contextmanager
|
|
||||||
def b():
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
except:
|
|
||||||
# Swallow the exception
|
|
||||||
pass
|
|
||||||
try:
|
|
||||||
with nested(a(), b()):
|
|
||||||
1/0
|
|
||||||
except ZeroDivisionError:
|
|
||||||
self.fail("Didn't swallow ZeroDivisionError")
|
|
||||||
|
|
||||||
def test_nested_break(self):
|
|
||||||
@contextmanager
|
|
||||||
def a():
|
|
||||||
yield
|
|
||||||
state = 0
|
|
||||||
while True:
|
|
||||||
state += 1
|
|
||||||
with nested(a(), a()):
|
|
||||||
break
|
|
||||||
state += 10
|
|
||||||
self.assertEqual(state, 1)
|
|
||||||
|
|
||||||
def test_nested_continue(self):
|
|
||||||
@contextmanager
|
|
||||||
def a():
|
|
||||||
yield
|
|
||||||
state = 0
|
|
||||||
while state < 3:
|
|
||||||
state += 1
|
|
||||||
with nested(a(), a()):
|
|
||||||
continue
|
|
||||||
state += 10
|
|
||||||
self.assertEqual(state, 3)
|
|
||||||
|
|
||||||
def test_nested_return(self):
|
|
||||||
@contextmanager
|
|
||||||
def a():
|
|
||||||
try:
|
|
||||||
yield
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
def foo():
|
|
||||||
with nested(a(), a()):
|
|
||||||
return 1
|
|
||||||
return 10
|
|
||||||
self.assertEqual(foo(), 1)
|
|
||||||
|
|
||||||
class ClosingTestCase(unittest.TestCase):
|
class ClosingTestCase(unittest.TestCase):
|
||||||
|
|
||||||
# XXX This needs more work
|
# XXX This needs more work
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue