From d8d8253dea866f7681ac8094778f982c0983ed16 Mon Sep 17 00:00:00 2001 From: Amaury Forgeot d'Arc Date: Wed, 10 Dec 2008 23:55:09 +0000 Subject: [PATCH] Merged revisions 67689 via svnmerge from svn+ssh://pythondev@svn.python.org/python/branches/py3k MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit ................ r67689 | amaury.forgeotdarc | 2008-12-11 00:49:33 +0100 (jeu., 11 déc. 2008) | 13 lines Merged revisions 67688 via svnmerge from 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 | 30 ++++++++++++++++++++++++++++++ Misc/NEWS | 3 +++ Python/ceval.c | 13 +++++++++++-- 3 files changed, 44 insertions(+), 2 deletions(-) diff --git a/Lib/test/test_with.py b/Lib/test/test_with.py index 43f327122854..b192429cf719 100644 --- a/Lib/test/test_with.py +++ b/Lib/test/test_with.py @@ -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): diff --git a/Misc/NEWS b/Misc/NEWS index 61e2263cbafd..3dbd1eea2bf9 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -12,6 +12,9 @@ What's New in Python 3.0.1? 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 #4533: File read operation was dreadfully slow due to a slowly growing read buffer. Fixed by using the same growth rate algorithm as Python 2.x. diff --git a/Python/ceval.c b/Python/ceval.c index dc4276b1bb64..f58a55d7baf4 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -2181,7 +2181,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)); @@ -2189,7 +2199,6 @@ PyEval_EvalFrameEx(PyFrameObject *f, int throwflag) Py_DECREF(v); Py_DECREF(w); } - Py_DECREF(x); PREDICT(END_FINALLY); break; } -- 2.47.3