diff options
author | Nick Coghlan <ncoghlan@gmail.com> | 2012-06-01 12:48:32 (GMT) |
---|---|---|
committer | Nick Coghlan <ncoghlan@gmail.com> | 2012-06-01 12:48:32 (GMT) |
commit | 77452fc12121a333397ea262a3d29bdb8cbc7a57 (patch) | |
tree | 4327efa4d00f3b8a80ccc3b31f466626f4e1a322 /Lib/contextlib.py | |
parent | c4b78a3e15dcc627a06ba3a0fc92358aade2b7ea (diff) | |
download | cpython-77452fc12121a333397ea262a3d29bdb8cbc7a57.zip cpython-77452fc12121a333397ea262a3d29bdb8cbc7a57.tar.gz cpython-77452fc12121a333397ea262a3d29bdb8cbc7a57.tar.bz2 |
Close #14969: Improve the handling of exception chaining in contextlib.ExitStack
Diffstat (limited to 'Lib/contextlib.py')
-rw-r--r-- | Lib/contextlib.py | 16 |
1 files changed, 13 insertions, 3 deletions
diff --git a/Lib/contextlib.py b/Lib/contextlib.py index f5232b6..bde2feb 100644 --- a/Lib/contextlib.py +++ b/Lib/contextlib.py @@ -225,6 +225,17 @@ class ExitStack(object): return self def __exit__(self, *exc_details): + # We manipulate the exception state so it behaves as though + # we were actually nesting multiple with statements + frame_exc = sys.exc_info()[1] + def _fix_exception_context(new_exc, old_exc): + while 1: + exc_context = new_exc.__context__ + if exc_context in (None, frame_exc): + break + new_exc = exc_context + new_exc.__context__ = old_exc + # Callbacks are invoked in LIFO order to match the behaviour of # nested context managers suppressed_exc = False @@ -236,9 +247,8 @@ class ExitStack(object): exc_details = (None, None, None) except: new_exc_details = sys.exc_info() - if exc_details != (None, None, None): - # simulate the stack of exceptions by setting the context - new_exc_details[1].__context__ = exc_details[1] + # simulate the stack of exceptions by setting the context + _fix_exception_context(new_exc_details[1], exc_details[1]) if not self._exit_callbacks: raise exc_details = new_exc_details |