]> granicus.if.org Git - python/commitdiff
Merged revisions 67688 via svnmerge from
authorAmaury Forgeot d'Arc <amauryfa@gmail.com>
Wed, 10 Dec 2008 23:49:33 +0000 (23:49 +0000)
committerAmaury Forgeot d'Arc <amauryfa@gmail.com>
Wed, 10 Dec 2008 23:49:33 +0000 (23:49 +0000)
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r67688 | amaury.forgeotdarc | 2008-12-11 00:22:49 +0100 (jeu., 11 déc. 2008) | 6 lines

  #4559: When a context manager's __exit__() method returns an object whose
  conversion to bool raises an exception, 'with' loses that exception.

  Reviewed by Jeffrey Yasskin.
  Already ported to 2.5, will port to 2.6 and 3.0
........

Lib/test/test_with.py
Misc/NEWS
Python/ceval.c

index 43f327122854cd7502c19dfd86ccc66674db3b2a..b192429cf719780988ad842661c419ba1e3c8547 100644 (file)
@@ -505,6 +505,36 @@ class ExceptionalTestCase(ContextmanagerAssertionMixin, unittest.TestCase):
 
         self.assertRaises(GeneratorExit, shouldThrow)
 
+    def testErrorsInBool(self):
+        # issue4589: __exit__ return code may raise an exception
+        # when looking at its truth value.
+
+        class cm(object):
+            def __init__(self, bool_conversion):
+                class Bool:
+                    def __bool__(self):
+                        return bool_conversion()
+                self.exit_result = Bool()
+            def __enter__(self):
+                return 3
+            def __exit__(self, a, b, c):
+                return self.exit_result
+
+        def trueAsBool():
+            with cm(lambda: True):
+                self.fail("Should NOT see this")
+        trueAsBool()
+
+        def falseAsBool():
+            with cm(lambda: False):
+                self.fail("Should raise")
+        self.assertRaises(AssertionError, falseAsBool)
+
+        def failAsBool():
+            with cm(lambda: 1//0):
+                self.fail("Should NOT see this")
+        self.assertRaises(ZeroDivisionError, failAsBool)
+
 
 class NonLocalFlowControlTestCase(unittest.TestCase):
 
index cb2cf4383c50bf4e10b25a0408527a1288d00efd..01a592792d5953490ac4eb70c74f7f334d978b6d 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,9 @@ What's New in Python 3.1 alpha 0
 Core and Builtins
 -----------------
 
+- Issue #4597: Fixed exception handling when the __exit__ function of a
+  context manager returns a value that cannot be converted to a bool.
+
 - Issue #4445: Replace "sizeof(PyBytesObject)" with
   "offsetof(PyBytesObject, ob_sval) + 1" when allocating memory for
   bytes instances.  On a typical machine this saves 3 bytes of memory
index c3945540003c731864051dd2992fdbd63518075c..84d18b3a3cb10011633b549c141a3fe9c4458ed2 100644 (file)
@@ -2189,7 +2189,17 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
                        Py_DECREF(exit_func);
                        if (x == NULL)
                                break; /* Go to error exit */
-                       if (u != Py_None && PyObject_IsTrue(x)) {
+
+                       if (u != Py_None)
+                               err = PyObject_IsTrue(x);
+                       else
+                               err = 0;
+                       Py_DECREF(x);
+
+                       if (err < 0)
+                               break; /* Go to error exit */
+                       else if (err > 0) {
+                               err = 0;
                                /* There was an exception and a True return */
                                STACKADJ(-2);
                                SET_TOP(PyLong_FromLong((long) WHY_SILENCED));
@@ -2197,7 +2207,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag)
                                Py_DECREF(v);
                                Py_DECREF(w);
                        }
-                       Py_DECREF(x);
                        PREDICT(END_FINALLY);
                        break;
                }