mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-128398: improve error messages when incorrectly using with
and async with
(#132218)
Improve the error message with a suggestion when an object supporting the synchronous (resp. asynchronous) context manager protocol is entered using `async with` (resp. `with`) instead of `with` (resp. `async with`).
This commit is contained in:
parent
95800fe6e7
commit
8a9c6c4d16
10 changed files with 211 additions and 47 deletions
|
@ -545,23 +545,51 @@ const conversion_func _PyEval_ConversionFuncs[4] = {
|
|||
const _Py_SpecialMethod _Py_SpecialMethods[] = {
|
||||
[SPECIAL___ENTER__] = {
|
||||
.name = &_Py_ID(__enter__),
|
||||
.error = "'%.200s' object does not support the "
|
||||
"context manager protocol (missed __enter__ method)",
|
||||
.error = (
|
||||
"'%T' object does not support the context manager protocol "
|
||||
"(missed __enter__ method)"
|
||||
),
|
||||
.error_suggestion = (
|
||||
"'%T' object does not support the context manager protocol "
|
||||
"(missed __enter__ method) but it supports the asynchronous "
|
||||
"context manager protocol. Did you mean to use 'async with'?"
|
||||
)
|
||||
},
|
||||
[SPECIAL___EXIT__] = {
|
||||
.name = &_Py_ID(__exit__),
|
||||
.error = "'%.200s' object does not support the "
|
||||
"context manager protocol (missed __exit__ method)",
|
||||
.error = (
|
||||
"'%T' object does not support the context manager protocol "
|
||||
"(missed __exit__ method)"
|
||||
),
|
||||
.error_suggestion = (
|
||||
"'%T' object does not support the context manager protocol "
|
||||
"(missed __exit__ method) but it supports the asynchronous "
|
||||
"context manager protocol. Did you mean to use 'async with'?"
|
||||
)
|
||||
},
|
||||
[SPECIAL___AENTER__] = {
|
||||
.name = &_Py_ID(__aenter__),
|
||||
.error = "'%.200s' object does not support the asynchronous "
|
||||
"context manager protocol (missed __aenter__ method)",
|
||||
.error = (
|
||||
"'%T' object does not support the asynchronous "
|
||||
"context manager protocol (missed __aenter__ method)"
|
||||
),
|
||||
.error_suggestion = (
|
||||
"'%T' object does not support the asynchronous context manager "
|
||||
"protocol (missed __aenter__ method) but it supports the context "
|
||||
"manager protocol. Did you mean to use 'with'?"
|
||||
)
|
||||
},
|
||||
[SPECIAL___AEXIT__] = {
|
||||
.name = &_Py_ID(__aexit__),
|
||||
.error = "'%.200s' object does not support the asynchronous "
|
||||
"context manager protocol (missed __aexit__ method)",
|
||||
.error = (
|
||||
"'%T' object does not support the asynchronous "
|
||||
"context manager protocol (missed __aexit__ method)"
|
||||
),
|
||||
.error_suggestion = (
|
||||
"'%T' object does not support the asynchronous context manager "
|
||||
"protocol (missed __aexit__ method) but it supports the context "
|
||||
"manager protocol. Did you mean to use 'with'?"
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -3380,3 +3408,33 @@ _PyEval_LoadName(PyThreadState *tstate, _PyInterpreterFrame *frame, PyObject *na
|
|||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
/* Check if a 'cls' provides the given special method. */
|
||||
static inline int
|
||||
type_has_special_method(PyTypeObject *cls, PyObject *name)
|
||||
{
|
||||
// _PyType_Lookup() does not set an exception and returns a borrowed ref
|
||||
assert(!PyErr_Occurred());
|
||||
PyObject *r = _PyType_Lookup(cls, name);
|
||||
return r != NULL && Py_TYPE(r)->tp_descr_get != NULL;
|
||||
}
|
||||
|
||||
int
|
||||
_PyEval_SpecialMethodCanSuggest(PyObject *self, int oparg)
|
||||
{
|
||||
PyTypeObject *type = Py_TYPE(self);
|
||||
switch (oparg) {
|
||||
case SPECIAL___ENTER__:
|
||||
case SPECIAL___EXIT__: {
|
||||
return type_has_special_method(type, &_Py_ID(__aenter__))
|
||||
&& type_has_special_method(type, &_Py_ID(__aexit__));
|
||||
}
|
||||
case SPECIAL___AENTER__:
|
||||
case SPECIAL___AEXIT__: {
|
||||
return type_has_special_method(type, &_Py_ID(__enter__))
|
||||
&& type_has_special_method(type, &_Py_ID(__exit__));
|
||||
}
|
||||
default:
|
||||
Py_FatalError("unsupported special method");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue