diff --git a/IPython/core/interactiveshell.py b/IPython/core/interactiveshell.py index 7ac7937..b59516b 100644 --- a/IPython/core/interactiveshell.py +++ b/IPython/core/interactiveshell.py @@ -29,7 +29,10 @@ import re import sys import tempfile import types -from contextlib import nested +try: + from contextlib import nested +except: + from IPython.utils.nested_context import nested from IPython.config.configurable import SingletonConfigurable from IPython.core import debugger, oinspect diff --git a/IPython/frontend/terminal/embed.py b/IPython/frontend/terminal/embed.py index febec42..4d26351 100644 --- a/IPython/frontend/terminal/embed.py +++ b/IPython/frontend/terminal/embed.py @@ -26,7 +26,10 @@ from __future__ import with_statement import __main__ import sys -from contextlib import nested +try: + from contextlib import nested +except: + from IPython.utils.nested_context import nested from IPython.core import ultratb from IPython.frontend.terminal.interactiveshell import TerminalInteractiveShell diff --git a/IPython/frontend/terminal/interactiveshell.py b/IPython/frontend/terminal/interactiveshell.py index fe5c48b..abe0328 100644 --- a/IPython/frontend/terminal/interactiveshell.py +++ b/IPython/frontend/terminal/interactiveshell.py @@ -16,11 +16,15 @@ import __builtin__ import bdb -from contextlib import nested import os import re import sys +try: + from contextlib import nested +except: + from IPython.utils.nested_context import nested + from IPython.core.error import TryNext from IPython.core.usage import interactive_usage, default_banner from IPython.core.interactiveshell import InteractiveShell, InteractiveShellABC diff --git a/IPython/utils/nested_context.py b/IPython/utils/nested_context.py new file mode 100644 index 0000000..b47ec9c --- /dev/null +++ b/IPython/utils/nested_context.py @@ -0,0 +1,50 @@ +"""Backwards compatibility - we use contextlib.nested to support Python 2.6, +but it's removed in Python 3.2.""" + +# TODO : Remove this once we drop support for Python 2.6, and use +# "with a, b:" instead. + +from contextlib import contextmanager + +@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 + raise exc[0], exc[1], exc[2]