From 20a88004bae8ead66a205a125e1fe979376fc3ea Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 29 Jun 2021 11:27:04 +0300 Subject: bpo-12022: Change error type for bad objects in "with" and "async with" (GH-26809) A TypeError is now raised instead of an AttributeError in "with" and "async with" statements for objects which do not support the context manager or asynchronous context manager protocols correspondingly. --- Python/ceval.c | 48 ++++++++++++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 18 deletions(-) (limited to 'Python/ceval.c') diff --git a/Python/ceval.c b/Python/ceval.c index 3f961f60c0..2ae36b3d28 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -82,7 +82,6 @@ static void format_exc_check_arg(PyThreadState *, PyObject *, const char *, PyOb static void format_exc_unbound(PyThreadState *tstate, PyCodeObject *co, int oparg); static PyObject * unicode_concatenate(PyThreadState *, PyObject *, PyObject *, PyFrameObject *, const _Py_CODEUNIT *); -static PyObject * special_lookup(PyThreadState *, PyObject *, _Py_Identifier *); static int check_args_iterable(PyThreadState *, PyObject *func, PyObject *vararg); static void format_kwargs_error(PyThreadState *, PyObject *func, PyObject *kwargs); static void format_awaitable_error(PyThreadState *, PyTypeObject *, int, int); @@ -3844,13 +3843,26 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) _Py_IDENTIFIER(__aenter__); _Py_IDENTIFIER(__aexit__); PyObject *mgr = TOP(); - PyObject *enter = special_lookup(tstate, mgr, &PyId___aenter__); PyObject *res; + PyObject *enter = _PyObject_LookupSpecial(mgr, &PyId___aenter__); if (enter == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object does not support the " + "asynchronous context manager protocol", + Py_TYPE(mgr)->tp_name); + } goto error; } - PyObject *exit = special_lookup(tstate, mgr, &PyId___aexit__); + PyObject *exit = _PyObject_LookupSpecial(mgr, &PyId___aexit__); if (exit == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object does not support the " + "asynchronous context manager protocol " + "(missed __aexit__ method)", + Py_TYPE(mgr)->tp_name); + } Py_DECREF(enter); goto error; } @@ -3869,13 +3881,26 @@ _PyEval_EvalFrameDefault(PyThreadState *tstate, PyFrameObject *f, int throwflag) _Py_IDENTIFIER(__enter__); _Py_IDENTIFIER(__exit__); PyObject *mgr = TOP(); - PyObject *enter = special_lookup(tstate, mgr, &PyId___enter__); PyObject *res; + PyObject *enter = _PyObject_LookupSpecial(mgr, &PyId___enter__); if (enter == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object does not support the " + "context manager protocol", + Py_TYPE(mgr)->tp_name); + } goto error; } - PyObject *exit = special_lookup(tstate, mgr, &PyId___exit__); + PyObject *exit = _PyObject_LookupSpecial(mgr, &PyId___exit__); if (exit == NULL) { + if (!_PyErr_Occurred(tstate)) { + _PyErr_Format(tstate, PyExc_TypeError, + "'%.200s' object does not support the " + "context manager protocol " + "(missed __exit__ method)", + Py_TYPE(mgr)->tp_name); + } Py_DECREF(enter); goto error; } @@ -5110,19 +5135,6 @@ fail: } -static PyObject * -special_lookup(PyThreadState *tstate, PyObject *o, _Py_Identifier *id) -{ - PyObject *res; - res = _PyObject_LookupSpecial(o, id); - if (res == NULL && !_PyErr_Occurred(tstate)) { - _PyErr_SetObject(tstate, PyExc_AttributeError, _PyUnicode_FromId(id)); - return NULL; - } - return res; -} - - /* Logic for the raise statement (too complicated for inlining). This *consumes* a reference count to each of its arguments. */ static int -- cgit v1.2.1