Fix a problem with @contextmanager not detecting a broken generator

that yields after a throw().  Make @contextmanager not reraise
exceptions, but return a false value in that case instead.  Add test
cases for both behaviors.
This commit is contained in:
Phillip J. Eby 2006-03-25 00:28:24 +00:00
parent bee0712214
commit 6edd258608
2 changed files with 26 additions and 1 deletions

View File

@ -30,9 +30,12 @@ class GeneratorContextManager(object):
else:
try:
self.gen.throw(type, value, traceback)
return True
raise RuntimeError("generator didn't stop after throw()")
except StopIteration:
return True
except:
if sys.exc_info()[1] is not value:
raise
def contextmanager(func):

View File

@ -45,6 +45,28 @@ class ContextManagerTestCase(unittest.TestCase):
self.fail("Expected ZeroDivisionError")
self.assertEqual(state, [1, 42, 999])
def test_contextmanager_no_reraise(self):
@contextmanager
def whee():
yield
ctx = whee().__context__()
ctx.__enter__()
# Calling __exit__ should not result in an exception
self.failIf(ctx.__exit__(TypeError, TypeError("foo"), None))
def test_contextmanager_trap_yield_after_throw(self):
@contextmanager
def whoo():
try:
yield
except:
yield
ctx = whoo().__context__()
ctx.__enter__()
self.assertRaises(
RuntimeError, ctx.__exit__, TypeError, TypeError("foo"), None
)
def test_contextmanager_except(self):
state = []
@contextmanager