From 9c4d0edd645764844b53fc634fb11a9bf4683e87 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Wed, 1 Jul 2009 01:32:12 +0000 Subject: Removed contextlib.nested() --- Doc/library/contextlib.rst | 49 ------------------ Lib/contextlib.py | 45 ---------------- Lib/test/test_contextlib.py | 122 -------------------------------------------- 3 files changed, 216 deletions(-) diff --git a/Doc/library/contextlib.rst b/Doc/library/contextlib.rst index ca37f0f..2ee9e8d 100644 --- a/Doc/library/contextlib.rst +++ b/Doc/library/contextlib.rst @@ -52,55 +52,6 @@ Functions provided: 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) Return a context manager that closes *thing* upon completion of the block. This diff --git a/Lib/contextlib.py b/Lib/contextlib.py index bffa0c4..d14c07b 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -85,51 +85,6 @@ def contextmanager(func): 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): """Context to automatically close something at the end of a block. diff --git a/Lib/test/test_contextlib.py b/Lib/test/test_contextlib.py index 015a0c5..bdf4776 100644 --- a/Lib/test/test_contextlib.py +++ b/Lib/test/test_contextlib.py @@ -101,128 +101,6 @@ class ContextManagerTestCase(unittest.TestCase): self.assertEqual(baz.foo, 'bar') 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): # XXX This needs more work -- cgit v0.12