]> granicus.if.org Git - python/commitdiff
Fix a problem with @contextmanager not detecting a broken generator
authorPhillip J. Eby <pje@telecommunity.com>
Sat, 25 Mar 2006 00:28:24 +0000 (00:28 +0000)
committerPhillip J. Eby <pje@telecommunity.com>
Sat, 25 Mar 2006 00:28:24 +0000 (00:28 +0000)
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.

Lib/contextlib.py
Lib/test/test_contextlib.py

index 0a5d608503ab25fa0b64adf1ea80ac2752fa9f39..282fc51004554476d685a264eee131b86c64d297 100644 (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):
index f8db88cc58a78f4e503f7139a763e87c7ad97fd8..7d7f8d281c34908955ca2f01e1a044274f053db1 100644 (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