Skip to content

Commit a3fec15

Browse files
committed
Issue python#27100: With statement reports missing __enter__ before __exit__. (Contributed by Jonathan Ellington.)
1 parent 4e17e04 commit a3fec15

File tree

3 files changed

+20
-7
lines changed

3 files changed

+20
-7
lines changed

Lib/test/test_with.py

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,24 @@ def fooNotDeclared():
109109
with foo: pass
110110
self.assertRaises(NameError, fooNotDeclared)
111111

112-
def testEnterAttributeError(self):
112+
def testEnterAttributeError1(self):
113113
class LacksEnter(object):
114114
def __exit__(self, type, value, traceback):
115115
pass
116116

117117
def fooLacksEnter():
118118
foo = LacksEnter()
119119
with foo: pass
120-
self.assertRaises(AttributeError, fooLacksEnter)
120+
self.assertRaisesRegexp(AttributeError, '__enter__', fooLacksEnter)
121+
122+
def testEnterAttributeError2(self):
123+
class LacksEnterAndExit(object):
124+
pass
125+
126+
def fooLacksEnterAndExit():
127+
foo = LacksEnterAndExit()
128+
with foo: pass
129+
self.assertRaisesRegexp(AttributeError, '__enter__', fooLacksEnterAndExit)
121130

122131
def testExitAttributeError(self):
123132
class LacksExit(object):
@@ -127,7 +136,7 @@ def __enter__(self):
127136
def fooLacksExit():
128137
foo = LacksExit()
129138
with foo: pass
130-
self.assertRaises(AttributeError, fooLacksExit)
139+
self.assertRaisesRegexp(AttributeError, '__exit__', fooLacksExit)
131140

132141
def assertRaisesSyntaxError(self, codestr):
133142
def shouldRaiseSyntaxError(s):

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,10 @@ Core and Builtins
1212

1313
- Issue #28532: Show sys.version when -V option is supplied twice.
1414

15+
- Issue #27100: The with-statement now checks for __enter__ before it
16+
checks for __exit__. This gives less confusing error messages when
17+
both methods are missing. Patch by Jonathan Ellington.
18+
1519
- Issue #28746: Fix the set_inheritable() file descriptor method on platforms
1620
that do not have the ioctl FIOCLEX and FIONCLEX commands.
1721

Python/ceval.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3133,15 +3133,15 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
31333133
_Py_IDENTIFIER(__exit__);
31343134
_Py_IDENTIFIER(__enter__);
31353135
PyObject *mgr = TOP();
3136-
PyObject *exit = special_lookup(mgr, &PyId___exit__), *enter;
3136+
PyObject *enter = special_lookup(mgr, &PyId___enter__), *exit;
31373137
PyObject *res;
3138+
if (enter == NULL)
3139+
goto error;
3140+
exit = special_lookup(mgr, &PyId___exit__);
31383141
if (exit == NULL)
31393142
goto error;
31403143
SET_TOP(exit);
3141-
enter = special_lookup(mgr, &PyId___enter__);
31423144
Py_DECREF(mgr);
3143-
if (enter == NULL)
3144-
goto error;
31453145
res = PyObject_CallFunctionObjArgs(enter, NULL);
31463146
Py_DECREF(enter);
31473147
if (res == NULL)

0 commit comments

Comments
 (0)