Commit 05778a13 authored by Phillip J. Eby's avatar Phillip J. Eby

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.
parent f154ac95
...@@ -30,9 +30,12 @@ class GeneratorContextManager(object): ...@@ -30,9 +30,12 @@ class GeneratorContextManager(object):
else: else:
try: try:
self.gen.throw(type, value, traceback) self.gen.throw(type, value, traceback)
return True raise RuntimeError("generator didn't stop after throw()")
except StopIteration: except StopIteration:
return True return True
except:
if sys.exc_info()[1] is not value:
raise
def contextmanager(func): def contextmanager(func):
......
...@@ -45,6 +45,28 @@ class ContextManagerTestCase(unittest.TestCase): ...@@ -45,6 +45,28 @@ class ContextManagerTestCase(unittest.TestCase):
self.fail("Expected ZeroDivisionError") self.fail("Expected ZeroDivisionError")
self.assertEqual(state, [1, 42, 999]) 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): def test_contextmanager_except(self):
state = [] state = []
@contextmanager @contextmanager
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment