mirror of
https://github.com/python/cpython.git
synced 2025-11-02 14:41:33 +00:00
gh-130821: Add type information to error messages for invalid return type (GH-130835)
This commit is contained in:
parent
c9d7065188
commit
968f6e523a
14 changed files with 76 additions and 76 deletions
|
|
@ -1008,7 +1008,7 @@ async def foo():
|
|||
return (await Awaitable())
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
TypeError, "__await__.*returned non-iterator of type"):
|
||||
TypeError, "__await__.*must return an iterator, not"):
|
||||
|
||||
run_async(foo())
|
||||
|
||||
|
|
@ -1106,7 +1106,7 @@ async def foo():
|
|||
return await Awaitable()
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
TypeError, r"__await__\(\) returned a coroutine"):
|
||||
TypeError, r"__await__\(\) must return an iterator, not coroutine"):
|
||||
run_async(foo())
|
||||
|
||||
c.close()
|
||||
|
|
@ -1120,7 +1120,7 @@ async def foo():
|
|||
return await Awaitable()
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
TypeError, "__await__.*returned non-iterator of type"):
|
||||
TypeError, "__await__.*must return an iterator, not"):
|
||||
|
||||
run_async(foo())
|
||||
|
||||
|
|
@ -2490,7 +2490,7 @@ async def foo():
|
|||
return (await future)
|
||||
|
||||
with self.assertRaisesRegex(
|
||||
TypeError, "__await__.*returned non-iterator of type 'int'"):
|
||||
TypeError, "__await__.*must return an iterator, not int"):
|
||||
self.assertEqual(foo().send(None), 1)
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -309,7 +309,7 @@ def check_annotations(self, f):
|
|||
print(f.__annotations__)
|
||||
|
||||
f.__annotate__ = lambda x: 42
|
||||
with self.assertRaisesRegex(TypeError, r"__annotate__ returned non-dict of type 'int'"):
|
||||
with self.assertRaisesRegex(TypeError, r"__annotate__\(\) must return a dict, not int"):
|
||||
print(f.__annotations__)
|
||||
|
||||
f.__annotate__ = lambda x: {"x": x}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,2 @@
|
|||
Enhance wrong type error messages and make them more consistent. Patch by
|
||||
Semyon Moroz.
|
||||
|
|
@ -132,8 +132,9 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue)
|
|||
return defaultvalue;
|
||||
}
|
||||
if (!PyLong_Check(result)) {
|
||||
PyErr_Format(PyExc_TypeError, "__length_hint__ must be an integer, not %.100s",
|
||||
Py_TYPE(result)->tp_name);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%T.__length_hint__() must return an int, not %T",
|
||||
o, result);
|
||||
Py_DECREF(result);
|
||||
return -1;
|
||||
}
|
||||
|
|
@ -143,7 +144,8 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue)
|
|||
return -1;
|
||||
}
|
||||
if (res < 0) {
|
||||
PyErr_Format(PyExc_ValueError, "__length_hint__() should return >= 0");
|
||||
PyErr_Format(PyExc_ValueError,
|
||||
"%T.__length_hint__() must return a non-negative int", o);
|
||||
return -1;
|
||||
}
|
||||
return res;
|
||||
|
|
@ -887,8 +889,8 @@ PyObject_Format(PyObject *obj, PyObject *format_spec)
|
|||
|
||||
if (result && !PyUnicode_Check(result)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__format__ must return a str, not %.200s",
|
||||
Py_TYPE(result)->tp_name);
|
||||
"%T.__format__() must return a str, not %T",
|
||||
obj, result);
|
||||
Py_SETREF(result, NULL);
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -1421,17 +1423,17 @@ _PyNumber_Index(PyObject *item)
|
|||
|
||||
if (!PyLong_Check(result)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__index__ returned non-int (type %.200s)",
|
||||
Py_TYPE(result)->tp_name);
|
||||
"%T.__index__() must return an int, not %T",
|
||||
item, result);
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
/* Issue #17576: warn if 'result' not of exact type int. */
|
||||
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
||||
"__index__ returned non-int (type %.200s). "
|
||||
"%T.__index__() must return an int, not %T. "
|
||||
"The ability to return an instance of a strict subclass of int "
|
||||
"is deprecated, and may be removed in a future version of Python.",
|
||||
Py_TYPE(result)->tp_name)) {
|
||||
item, result)) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1531,17 +1533,17 @@ PyNumber_Long(PyObject *o)
|
|||
|
||||
if (!PyLong_Check(result)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__int__ returned non-int (type %.200s)",
|
||||
Py_TYPE(result)->tp_name);
|
||||
"%T.__int__() must return an int, not %T",
|
||||
o, result);
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
/* Issue #17576: warn if 'result' not of exact type int. */
|
||||
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
||||
"__int__ returned non-int (type %.200s). "
|
||||
"%T.__int__() must return an int, not %T. "
|
||||
"The ability to return an instance of a strict subclass of int "
|
||||
"is deprecated, and may be removed in a future version of Python.",
|
||||
Py_TYPE(result)->tp_name)) {
|
||||
o, result)) {
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1609,17 +1611,16 @@ PyNumber_Float(PyObject *o)
|
|||
|
||||
if (!PyFloat_Check(res)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.50s.__float__ returned non-float (type %.50s)",
|
||||
Py_TYPE(o)->tp_name, Py_TYPE(res)->tp_name);
|
||||
"%T.__float__() must return a float, not %T", o, res);
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
/* Issue #26983: warn if 'res' not of exact type float. */
|
||||
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
||||
"%.50s.__float__ returned non-float (type %.50s). "
|
||||
"%T.__float__() must return a float, not %T. "
|
||||
"The ability to return an instance of a strict subclass of float "
|
||||
"is deprecated, and may be removed in a future version of Python.",
|
||||
Py_TYPE(o)->tp_name, Py_TYPE(res)->tp_name)) {
|
||||
o, res)) {
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -2435,10 +2436,8 @@ method_output_as_list(PyObject *o, PyObject *meth)
|
|||
PyThreadState *tstate = _PyThreadState_GET();
|
||||
if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"%.200s.%U() returned a non-iterable (type %.200s)",
|
||||
Py_TYPE(o)->tp_name,
|
||||
meth,
|
||||
Py_TYPE(meth_output)->tp_name);
|
||||
"%T.%U() must return an iterable, not %T",
|
||||
o, meth, meth_output);
|
||||
}
|
||||
Py_DECREF(meth_output);
|
||||
return NULL;
|
||||
|
|
@ -2818,9 +2817,8 @@ PyObject_GetIter(PyObject *o)
|
|||
PyObject *res = (*f)(o);
|
||||
if (res != NULL && !PyIter_Check(res)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"iter() returned non-iterator "
|
||||
"of type '%.100s'",
|
||||
Py_TYPE(res)->tp_name);
|
||||
"%T.__iter__() must return an iterator, not %T",
|
||||
o, res);
|
||||
Py_SETREF(res, NULL);
|
||||
}
|
||||
return res;
|
||||
|
|
@ -2839,8 +2837,8 @@ PyObject_GetAIter(PyObject *o) {
|
|||
PyObject *it = (*f)(o);
|
||||
if (it != NULL && !PyAIter_Check(it)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"aiter() returned not an async iterator of type '%.100s'",
|
||||
Py_TYPE(it)->tp_name);
|
||||
"%T.__aiter__() must return an async iterator, not %T",
|
||||
o, it);
|
||||
Py_SETREF(it, NULL);
|
||||
}
|
||||
return it;
|
||||
|
|
|
|||
|
|
@ -566,8 +566,8 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen)
|
|||
return NULL;
|
||||
if (!PyBytes_Check(result)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__bytes__ returned non-bytes (type %.200s)",
|
||||
Py_TYPE(result)->tp_name);
|
||||
"%T.__bytes__() must return a bytes, not %T",
|
||||
v, result);
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -2793,8 +2793,8 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding,
|
|||
return NULL;
|
||||
if (!PyBytes_Check(bytes)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__bytes__ returned non-bytes (type %.200s)",
|
||||
Py_TYPE(bytes)->tp_name);
|
||||
"%T.__bytes__() must return a bytes, not %T",
|
||||
x, bytes);
|
||||
Py_DECREF(bytes);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -515,17 +515,17 @@ try_complex_special_method(PyObject *op)
|
|||
}
|
||||
if (!PyComplex_Check(res)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__complex__ returned non-complex (type %.200s)",
|
||||
Py_TYPE(res)->tp_name);
|
||||
"%T.__complex__() must return a complex, not %T",
|
||||
op, res);
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
/* Issue #29894: warn if 'res' not of exact type complex. */
|
||||
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
||||
"__complex__ returned non-complex (type %.200s). "
|
||||
"%T.__complex__() must return a complex, not %T. "
|
||||
"The ability to return an instance of a strict subclass of complex "
|
||||
"is deprecated, and may be removed in a future version of Python.",
|
||||
Py_TYPE(res)->tp_name)) {
|
||||
op, res)) {
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,9 +68,9 @@ PyFile_GetLine(PyObject *f, int n)
|
|||
}
|
||||
if (result != NULL && !PyBytes_Check(result) &&
|
||||
!PyUnicode_Check(result)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%T.readline() must return a str, not %T", f, result);
|
||||
Py_SETREF(result, NULL);
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"object.readline() returned non-string");
|
||||
}
|
||||
|
||||
if (n < 0 && result != NULL && PyBytes_Check(result)) {
|
||||
|
|
@ -193,8 +193,8 @@ PyObject_AsFileDescriptor(PyObject *o)
|
|||
Py_DECREF(fno);
|
||||
}
|
||||
else {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"fileno() returned a non-integer");
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%T.fileno() must return an int, not %T", o, fno);
|
||||
Py_DECREF(fno);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -288,16 +288,16 @@ PyFloat_AsDouble(PyObject *op)
|
|||
if (!PyFloat_CheckExact(res)) {
|
||||
if (!PyFloat_Check(res)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%.50s.__float__ returned non-float (type %.50s)",
|
||||
Py_TYPE(op)->tp_name, Py_TYPE(res)->tp_name);
|
||||
"%T.__float__() must return a float, not %T",
|
||||
op, res);
|
||||
Py_DECREF(res);
|
||||
return -1;
|
||||
}
|
||||
if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1,
|
||||
"%.50s.__float__ returned non-float (type %.50s). "
|
||||
"%T.__float__() must return a float, not %T. "
|
||||
"The ability to return an instance of a strict subclass of float "
|
||||
"is deprecated, and may be removed in a future version of Python.",
|
||||
Py_TYPE(op)->tp_name, Py_TYPE(res)->tp_name)) {
|
||||
op, res)) {
|
||||
Py_DECREF(res);
|
||||
return -1;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -560,8 +560,9 @@ func_get_annotation_dict(PyFunctionObject *op)
|
|||
return NULL;
|
||||
}
|
||||
if (!PyDict_Check(ann_dict)) {
|
||||
PyErr_Format(PyExc_TypeError, "__annotate__ returned non-dict of type '%.100s'",
|
||||
Py_TYPE(ann_dict)->tp_name);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__annotate__() must return a dict, not %T",
|
||||
ann_dict);
|
||||
Py_DECREF(ann_dict);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1092,14 +1092,14 @@ _PyCoro_GetAwaitableIter(PyObject *o)
|
|||
if (PyCoro_CheckExact(res) || gen_is_coroutine(res)) {
|
||||
/* __await__ must return an *iterator*, not
|
||||
a coroutine or another awaitable (see PEP 492) */
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"__await__() returned a coroutine");
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%T.__await__() must return an iterator, "
|
||||
"not coroutine", o);
|
||||
Py_CLEAR(res);
|
||||
} else if (!PyIter_Check(res)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__await__() returned non-iterator "
|
||||
"of type '%.100s'",
|
||||
Py_TYPE(res)->tp_name);
|
||||
"%T.__await__() must return an iterator, "
|
||||
"not %T", o, res);
|
||||
Py_CLEAR(res);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -357,8 +357,9 @@ anextawaitable_getiter(anextawaitableobject *obj)
|
|||
}
|
||||
Py_SETREF(awaitable, new_awaitable);
|
||||
if (!PyIter_Check(awaitable)) {
|
||||
PyErr_SetString(PyExc_TypeError,
|
||||
"__await__ returned a non-iterable");
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%T.__await__() must return an iterable, not %T",
|
||||
obj, awaitable);
|
||||
Py_DECREF(awaitable);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1329,8 +1329,9 @@ module_get_annotations(PyObject *self, void *Py_UNUSED(ignored))
|
|||
return NULL;
|
||||
}
|
||||
if (!PyDict_Check(annotations)) {
|
||||
PyErr_Format(PyExc_TypeError, "__annotate__ returned non-dict of type '%.100s'",
|
||||
Py_TYPE(annotations)->tp_name);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__annotate__() must return a dict, not %T",
|
||||
annotations);
|
||||
Py_DECREF(annotate);
|
||||
Py_DECREF(annotations);
|
||||
Py_DECREF(dict);
|
||||
|
|
|
|||
|
|
@ -784,8 +784,7 @@ PyObject_Repr(PyObject *v)
|
|||
}
|
||||
if (!PyUnicode_Check(res)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"__repr__ returned non-string (type %.200s)",
|
||||
Py_TYPE(res)->tp_name);
|
||||
"%T.__repr__() must return a str, not %T", v, res);
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -827,8 +826,7 @@ PyObject_Str(PyObject *v)
|
|||
}
|
||||
if (!PyUnicode_Check(res)) {
|
||||
_PyErr_Format(tstate, PyExc_TypeError,
|
||||
"__str__ returned non-string (type %.200s)",
|
||||
Py_TYPE(res)->tp_name);
|
||||
"%T.__str__() must return a str, not %T", v, res);
|
||||
Py_DECREF(res);
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -883,8 +881,8 @@ PyObject_Bytes(PyObject *v)
|
|||
return NULL;
|
||||
if (!PyBytes_Check(result)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__bytes__ returned non-bytes (type %.200s)",
|
||||
Py_TYPE(result)->tp_name);
|
||||
"%T.__bytes__() must return a bytes, not %T",
|
||||
v, result);
|
||||
Py_DECREF(result);
|
||||
return NULL;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2168,8 +2168,9 @@ type_get_annotations(PyObject *tp, void *Py_UNUSED(closure))
|
|||
return NULL;
|
||||
}
|
||||
if (!PyDict_Check(annotations)) {
|
||||
PyErr_Format(PyExc_TypeError, "__annotate__ returned non-dict of type '%.100s'",
|
||||
Py_TYPE(annotations)->tp_name);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__annotate__() must return a dict, not %T",
|
||||
annotations);
|
||||
Py_DECREF(annotations);
|
||||
Py_DECREF(annotate);
|
||||
Py_DECREF(dict);
|
||||
|
|
@ -3510,10 +3511,8 @@ mro_check(PyTypeObject *type, PyObject *mro)
|
|||
for (i = 0; i < n; i++) {
|
||||
PyObject *obj = PyTuple_GET_ITEM(mro, i);
|
||||
if (!PyType_Check(obj)) {
|
||||
PyErr_Format(
|
||||
PyExc_TypeError,
|
||||
"mro() returned a non-class ('%.500s')",
|
||||
Py_TYPE(obj)->tp_name);
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"%N.mro() returned a non-class ('%T')", type, obj);
|
||||
return -1;
|
||||
}
|
||||
PyTypeObject *base = (PyTypeObject*)obj;
|
||||
|
|
@ -3521,8 +3520,8 @@ mro_check(PyTypeObject *type, PyObject *mro)
|
|||
if (!is_subtype_with_mro(lookup_tp_mro(solid), solid, solid_base(base))) {
|
||||
PyErr_Format(
|
||||
PyExc_TypeError,
|
||||
"mro() returned base with unsuitable layout ('%.500s')",
|
||||
base->tp_name);
|
||||
"%N.mro() returned base with unsuitable layout ('%N')",
|
||||
type, base);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
|
@ -10419,9 +10418,8 @@ slot_nb_bool(PyObject *self)
|
|||
}
|
||||
else {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__bool__ should return "
|
||||
"bool, returned %s",
|
||||
Py_TYPE(value)->tp_name);
|
||||
"%T.__bool__() must return a bool, not %T",
|
||||
self, value);
|
||||
result = -1;
|
||||
}
|
||||
Py_DECREF(value);
|
||||
|
|
@ -10901,7 +10899,8 @@ slot_bf_getbuffer(PyObject *self, Py_buffer *buffer, int flags)
|
|||
}
|
||||
if (!PyMemoryView_Check(ret)) {
|
||||
PyErr_Format(PyExc_TypeError,
|
||||
"__buffer__ returned non-memoryview object");
|
||||
"%T.__buffer__() must return a memoryview, not %T",
|
||||
self, ret);
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue