]> granicus.if.org Git - python/commitdiff
Issue #27100: With statement reports missing __enter__ before __exit__. (Contribute...
authorRaymond Hettinger <python@rcn.com>
Tue, 22 Nov 2016 01:24:23 +0000 (17:24 -0800)
committerRaymond Hettinger <python@rcn.com>
Tue, 22 Nov 2016 01:24:23 +0000 (17:24 -0800)
Lib/test/test_with.py
Misc/NEWS
Python/ceval.c

index e247ff6a6171e3044f364900c15b9170e58e0cf1..cbb85da1541df51c1b5347bcc1063bf9990e278e 100644 (file)
@@ -109,7 +109,7 @@ class FailureTestCase(unittest.TestCase):
             with foo: pass
         self.assertRaises(NameError, fooNotDeclared)
 
-    def testEnterAttributeError(self):
+    def testEnterAttributeError1(self):
         class LacksEnter(object):
             def __exit__(self, type, value, traceback):
                 pass
@@ -117,7 +117,16 @@ class FailureTestCase(unittest.TestCase):
         def fooLacksEnter():
             foo = LacksEnter()
             with foo: pass
-        self.assertRaises(AttributeError, fooLacksEnter)
+        self.assertRaisesRegexp(AttributeError, '__enter__', fooLacksEnter)
+
+    def testEnterAttributeError2(self):
+        class LacksEnterAndExit(object):
+            pass
+
+        def fooLacksEnterAndExit():
+            foo = LacksEnterAndExit()
+            with foo: pass
+        self.assertRaisesRegexp(AttributeError, '__enter__', fooLacksEnterAndExit)
 
     def testExitAttributeError(self):
         class LacksExit(object):
@@ -127,7 +136,7 @@ class FailureTestCase(unittest.TestCase):
         def fooLacksExit():
             foo = LacksExit()
             with foo: pass
-        self.assertRaises(AttributeError, fooLacksExit)
+        self.assertRaisesRegexp(AttributeError, '__exit__', fooLacksExit)
 
     def assertRaisesSyntaxError(self, codestr):
         def shouldRaiseSyntaxError(s):
index de614eee4c6ca46ad5baed575d528fef97abc055..cc421b03e2af167007bf3b436620e2f58ed24f75 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -12,6 +12,10 @@ Core and Builtins
 
 - Issue #28532: Show sys.version when -V option is supplied twice.
 
+- Issue #27100: The with-statement now checks for __enter__ before it
+  checks for __exit__.  This gives less confusing error messages when
+  both methods are missing. Patch by Jonathan Ellington.
+
 - Issue #28746: Fix the set_inheritable() file descriptor method on platforms
   that do not have the ioctl FIOCLEX and FIONCLEX commands.
 
index a9d7c2f6d3d030eb2c211408379f02f4c6993492..ebf073a87fb6b91f763dc435ca64c0c23bf096d2 100644 (file)
@@ -3133,15 +3133,15 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
             _Py_IDENTIFIER(__exit__);
             _Py_IDENTIFIER(__enter__);
             PyObject *mgr = TOP();
-            PyObject *exit = special_lookup(mgr, &PyId___exit__), *enter;
+            PyObject *enter = special_lookup(mgr, &PyId___enter__), *exit;
             PyObject *res;
+            if (enter == NULL)
+                goto error;
+            exit = special_lookup(mgr, &PyId___exit__);
             if (exit == NULL)
                 goto error;
             SET_TOP(exit);
-            enter = special_lookup(mgr, &PyId___enter__);
             Py_DECREF(mgr);
-            if (enter == NULL)
-                goto error;
             res = PyObject_CallFunctionObjArgs(enter, NULL);
             Py_DECREF(enter);
             if (res == NULL)