bpo-29692: contextlib.contextmanager may incorrectly unchain RuntimeError (GH-949)

contextlib._GeneratorContextManager.__exit__ includes a special case to deal with
PEP 479 RuntimeErrors created when `StopIteration` is thrown into the context
manager body.

Previously this check was too permissive, and undid one level of chaining on *all*
RuntimeError instances, not just those that wrapped a StopIteration instance.
This commit is contained in:
svelankar 2017-04-11 05:11:13 -04:00 committed by Nick Coghlan
parent 6fab78e902
commit 00c75e9a45
3 changed files with 32 additions and 6 deletions

View file

@ -88,7 +88,7 @@ class _GeneratorContextManager(ContextDecorator, AbstractContextManager):
try:
next(self.gen)
except StopIteration:
return
return False
else:
raise RuntimeError("generator didn't stop")
else:
@ -110,7 +110,7 @@ class _GeneratorContextManager(ContextDecorator, AbstractContextManager):
# Likewise, avoid suppressing if a StopIteration exception
# was passed to throw() and later wrapped into a RuntimeError
# (see PEP 479).
if exc.__cause__ is value:
if type is StopIteration and exc.__cause__ is value:
return False
raise
except:
@ -121,10 +121,10 @@ class _GeneratorContextManager(ContextDecorator, AbstractContextManager):
# fixes the impedance mismatch between the throw() protocol
# and the __exit__() protocol.
#
if sys.exc_info()[1] is not value:
raise
else:
raise RuntimeError("generator didn't stop after throw()")
if sys.exc_info()[1] is value:
return False
raise
raise RuntimeError("generator didn't stop after throw()")
def contextmanager(func):