Issue #7: Backport fix for CPython issue #27122

Prevents a potential infinite loop on Python 3.5 when handling
``RuntimeError``.

(CPython updates by Gregory P. Smith & Serhiy Storchaka)
This commit is contained in:
Nick Coghlan 2016-07-31 13:31:39 +10:00
parent e4fbea45c6
commit 2f4fd22e2f
2 changed files with 41 additions and 0 deletions

View file

@ -102,6 +102,9 @@ class _GeneratorContextManager(ContextDecorator):
# raised inside the "with" statement from being suppressed.
return exc is not value
except RuntimeError as exc:
# Don't re-raise the passed in exception
if exc is value:
return False
# Likewise, avoid suppressing if a StopIteration exception
# was passed to throw() and later wrapped into a RuntimeError
# (see PEP 479).

View file

@ -739,6 +739,44 @@ class TestExitStack(unittest.TestCase):
pass
def test_dont_reraise_RuntimeError(self):
# https://bugs.python.org/issue27122
class UniqueException(Exception): pass
class UniqueRuntimeError(RuntimeError): pass
@contextmanager
def second():
try:
yield 1
except Exception as exc:
# Py2 compatible explicit exception chaining
new_exc = UniqueException("new exception")
new_exc.__cause__ = exc
raise new_exc
@contextmanager
def first():
try:
yield 1
except Exception as exc:
raise exc
# The UniqueRuntimeError should be caught by second()'s exception
# handler which chain raised a new UniqueException.
with self.assertRaises(UniqueException) as err_ctx:
with ExitStack() as es_ctx:
es_ctx.enter_context(second())
es_ctx.enter_context(first())
raise UniqueRuntimeError("please no infinite loop.")
exc = err_ctx.exception
self.assertIsInstance(exc, UniqueException)
self.assertIsInstance(exc.__cause__, UniqueRuntimeError)
if check_exception_chaining:
self.assertIs(exc.__context__, exc.__cause__)
self.assertIsNone(exc.__cause__.__context__)
self.assertIsNone(exc.__cause__.__cause__)
class TestRedirectStream: