From a513ee8d95935c8bca53c405e0529c0e9faf3483 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Tue, 4 Mar 2025 18:18:29 +0400 Subject: [PATCH 01/11] Add type information to wrong type error messages --- Objects/abstract.c | 20 ++++++++++---------- Objects/bytesobject.c | 8 ++++---- Objects/complexobject.c | 8 ++++---- Objects/object.c | 12 ++++++------ Objects/typeobject.c | 5 ++--- 5 files changed, 26 insertions(+), 27 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index db7b9263711f68..fc4950862c2fcd 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1418,17 +1418,17 @@ _PyNumber_Index(PyObject *item) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "__index__ returned non-int (type %.200s)", - Py_TYPE(result)->tp_name); + "%.200s.__index__ returned non-int (type %.200s)", + Py_TYPE(item)->tp_name, Py_TYPE(result)->tp_name); 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). " + "%.200s.__index__ returned non-int (type %.200s). " "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)) { + Py_TYPE(item)->tp_name, Py_TYPE(result)->tp_name)) { Py_DECREF(result); return NULL; } @@ -1528,17 +1528,17 @@ PyNumber_Long(PyObject *o) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "__int__ returned non-int (type %.200s)", - Py_TYPE(result)->tp_name); + "%.200s.__int__ returned non-int (type %.200s)", + Py_TYPE(o)->tp_name, Py_TYPE(result)->tp_name); 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). " + "%.200s.__int__ returned non-int (type %.200s). " "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)) { + Py_TYPE(o)->tp_name, Py_TYPE(result)->tp_name)) { Py_DECREF(result); return NULL; } @@ -2815,9 +2815,9 @@ PyObject_GetIter(PyObject *o) PyObject *res = (*f)(o); if (res != NULL && !PyIter_Check(res)) { PyErr_Format(PyExc_TypeError, - "iter() returned non-iterator " + "%.100s.iter() returned non-iterator " "of type '%.100s'", - Py_TYPE(res)->tp_name); + Py_TYPE(o)->tp_name, Py_TYPE(res)->tp_name); Py_SETREF(res, NULL); } return res; diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index b3d1c425ad18b7..63891deb3afbb2 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -567,8 +567,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); + "%.200s.__bytes__ returned non-bytes (type %.200s)", + Py_TYPE(v)->tp_name, Py_TYPE(result)->tp_name); Py_DECREF(result); return NULL; } @@ -2762,8 +2762,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); + "%.200s.__bytes__ returned non-bytes (type %.200s)", + Py_TYPE(x)->tp_name, Py_TYPE(bytes)->tp_name); Py_DECREF(bytes); return NULL; } diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 5d9b3c9f0e3e76..c0668814e0c971 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -499,17 +499,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); + "%.200s.__complex__ returned non-complex (type %.200s)", + Py_TYPE(op)->tp_name, Py_TYPE(res)->tp_name); 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). " + "%.200s.__complex__ returned non-complex (type %.200s). " "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)) { + Py_TYPE(op)->tp_name, Py_TYPE(res)->tp_name)) { Py_DECREF(res); return NULL; } diff --git a/Objects/object.c b/Objects/object.c index b3309bac7afdee..96324a4728f876 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -779,8 +779,8 @@ PyObject_Repr(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "__repr__ returned non-string (type %.200s)", - Py_TYPE(res)->tp_name); + "%.200s.__repr__ returned non-string (type %.200s)", + Py_TYPE(v)->tp_name, Py_TYPE(res)->tp_name); Py_DECREF(res); return NULL; } @@ -822,8 +822,8 @@ PyObject_Str(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "__str__ returned non-string (type %.200s)", - Py_TYPE(res)->tp_name); + "%.200s.__str__ returned non-string (type %.200s)", + Py_TYPE(v)->tp_name, Py_TYPE(res)->tp_name); Py_DECREF(res); return NULL; } @@ -878,8 +878,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); + "%.200s.__bytes__ returned non-bytes (type %.200s)", + Py_TYPE(v)->tp_name, Py_TYPE(result)->tp_name); Py_DECREF(result); return NULL; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index bc840ed51ffe4c..46f1b79edfdcd5 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -9920,9 +9920,8 @@ slot_nb_bool(PyObject *self) } else { PyErr_Format(PyExc_TypeError, - "__bool__ should return " - "bool, returned %s", - Py_TYPE(value)->tp_name); + "%s.__bool__ returned non-bool (type %s)", + Py_TYPE(self)->tp_name, Py_TYPE(value)->tp_name); result = -1; } From 4d792e469e2cdf31e2baa3df96aa7fd744610b46 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Wed, 5 Mar 2025 09:53:36 +0400 Subject: [PATCH 02/11] Use %T to format type names --- Objects/abstract.c | 26 +++++++++++--------------- Objects/bytesobject.c | 8 ++++---- Objects/complexobject.c | 8 ++++---- Objects/object.c | 10 ++++------ Objects/typeobject.c | 3 +-- 5 files changed, 24 insertions(+), 31 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index fc4950862c2fcd..1d1fc64a89004a 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -1418,17 +1418,16 @@ _PyNumber_Index(PyObject *item) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%.200s.__index__ returned non-int (type %.200s)", - Py_TYPE(item)->tp_name, Py_TYPE(result)->tp_name); + "%T.__index__ returned non-int (type %T)", item, result); Py_DECREF(result); return NULL; } /* Issue #17576: warn if 'result' not of exact type int. */ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "%.200s.__index__ returned non-int (type %.200s). " + "%T.__index__ returned non-int (type %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(item)->tp_name, Py_TYPE(result)->tp_name)) { + item, result)) { Py_DECREF(result); return NULL; } @@ -1528,17 +1527,16 @@ PyNumber_Long(PyObject *o) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%.200s.__int__ returned non-int (type %.200s)", - Py_TYPE(o)->tp_name, Py_TYPE(result)->tp_name); + "%T.__int__ returned non-int (type %T)", o, result); Py_DECREF(result); return NULL; } /* Issue #17576: warn if 'result' not of exact type int. */ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "%.200s.__int__ returned non-int (type %.200s). " + "%T.__int__ returned non-int (type %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(o)->tp_name, Py_TYPE(result)->tp_name)) { + o, result)) { Py_DECREF(result); return NULL; } @@ -1606,17 +1604,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__ returned non-float (type %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__ returned non-float (type %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; } @@ -2815,9 +2812,8 @@ PyObject_GetIter(PyObject *o) PyObject *res = (*f)(o); if (res != NULL && !PyIter_Check(res)) { PyErr_Format(PyExc_TypeError, - "%.100s.iter() returned non-iterator " - "of type '%.100s'", - Py_TYPE(o)->tp_name, Py_TYPE(res)->tp_name); + "%T.iter() returned non-iterator of type '%T'", + o, res); Py_SETREF(res, NULL); } return res; diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 63891deb3afbb2..a02e11df976e10 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -567,8 +567,8 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%.200s.__bytes__ returned non-bytes (type %.200s)", - Py_TYPE(v)->tp_name, Py_TYPE(result)->tp_name); + "%T.__bytes__ returned non-bytes (type %T)", + v, result); Py_DECREF(result); return NULL; } @@ -2762,8 +2762,8 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, return NULL; if (!PyBytes_Check(bytes)) { PyErr_Format(PyExc_TypeError, - "%.200s.__bytes__ returned non-bytes (type %.200s)", - Py_TYPE(x)->tp_name, Py_TYPE(bytes)->tp_name); + "%T.__bytes__ returned non-bytes (type %T)", + x, bytes); Py_DECREF(bytes); return NULL; } diff --git a/Objects/complexobject.c b/Objects/complexobject.c index c0668814e0c971..95e91401296019 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -499,17 +499,17 @@ try_complex_special_method(PyObject *op) } if (!PyComplex_Check(res)) { PyErr_Format(PyExc_TypeError, - "%.200s.__complex__ returned non-complex (type %.200s)", - Py_TYPE(op)->tp_name, Py_TYPE(res)->tp_name); + "%T.__complex__ returned non-complex (type %T)", + op, res); Py_DECREF(res); return NULL; } /* Issue #29894: warn if 'res' not of exact type complex. */ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "%.200s.__complex__ returned non-complex (type %.200s). " + "%T.__complex__ returned non-complex (type %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(op)->tp_name, Py_TYPE(res)->tp_name)) { + op, res)) { Py_DECREF(res); return NULL; } diff --git a/Objects/object.c b/Objects/object.c index 96324a4728f876..400587db57d4dc 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -779,8 +779,7 @@ PyObject_Repr(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%.200s.__repr__ returned non-string (type %.200s)", - Py_TYPE(v)->tp_name, Py_TYPE(res)->tp_name); + "%T.__repr__ returned non-string (type %T)", v, res); Py_DECREF(res); return NULL; } @@ -822,8 +821,7 @@ PyObject_Str(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%.200s.__str__ returned non-string (type %.200s)", - Py_TYPE(v)->tp_name, Py_TYPE(res)->tp_name); + "%T.__str__ returned non-string (type %T)", v, res); Py_DECREF(res); return NULL; } @@ -878,8 +876,8 @@ PyObject_Bytes(PyObject *v) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%.200s.__bytes__ returned non-bytes (type %.200s)", - Py_TYPE(v)->tp_name, Py_TYPE(result)->tp_name); + "%T.__bytes__ returned non-bytes (type %T)", + v, result); Py_DECREF(result); return NULL; } diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 46f1b79edfdcd5..51ebbc476d0d04 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -9920,8 +9920,7 @@ slot_nb_bool(PyObject *self) } else { PyErr_Format(PyExc_TypeError, - "%s.__bool__ returned non-bool (type %s)", - Py_TYPE(self)->tp_name, Py_TYPE(value)->tp_name); + "%T.__bool__ returned non-bool (type %T)", self, value); result = -1; } From d97667670f7317a3076686778a0603b6599d5755 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Mon, 28 Apr 2025 05:44:38 +0400 Subject: [PATCH 03/11] Fix error message for methods return type --- Objects/abstract.c | 39 +++++++++++++++++++++------------------ Objects/bytesobject.c | 4 ++-- Objects/complexobject.c | 4 ++-- Objects/fileobject.c | 8 ++++---- Objects/floatobject.c | 8 ++++---- Objects/funcobject.c | 5 +++-- Objects/genobject.c | 10 +++++----- Objects/iterobject.c | 5 +++-- Objects/moduleobject.c | 6 ++++-- Objects/object.c | 6 +++--- Objects/typeobject.c | 16 ++++++++-------- Objects/unicodeobject.c | 22 +++++++++------------- 12 files changed, 68 insertions(+), 65 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index 1d1fc64a89004a..8c25142a5345ff 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -129,8 +129,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 type int (not %T)", + o, result); Py_DECREF(result); return -1; } @@ -140,7 +141,9 @@ 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 positive int (not %T)", + o, result); return -1; } return res; @@ -884,8 +887,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 type str (not %T)", + obj, result); Py_SETREF(result, NULL); goto done; } @@ -1418,13 +1421,14 @@ _PyNumber_Index(PyObject *item) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__index__ returned non-int (type %T)", item, result); + "%T.__index__ must return type 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, - "%T.__index__ returned non-int (type %T). " + "%T.__index__ must return type 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.", item, result)) { @@ -1527,13 +1531,13 @@ PyNumber_Long(PyObject *o) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__int__ returned non-int (type %T)", o, result); + "%T.__int__ must return type 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, - "%T.__int__ returned non-int (type %T). " + "%T.__int__ must return type 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.", o, result)) { @@ -1604,13 +1608,14 @@ PyNumber_Float(PyObject *o) if (!PyFloat_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__float__ returned non-float (type %T)", o, res); + "%T.__float__ must return type 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, - "%T.__float__ returned non-float (type %T). " + "%T.__float__ must return type 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.", o, res)) { @@ -2429,10 +2434,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 type iterable (not %T)", + o, meth, meth_output); } Py_DECREF(meth_output); return NULL; @@ -2812,7 +2815,7 @@ PyObject_GetIter(PyObject *o) PyObject *res = (*f)(o); if (res != NULL && !PyIter_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.iter() returned non-iterator of type '%T'", + "%T.iter() must return type iterator of type '%T'", o, res); Py_SETREF(res, NULL); } @@ -2832,8 +2835,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 type async iterator of type '%T'", + o, it); Py_SETREF(it, NULL); } return it; diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index a02e11df976e10..a81950f41c415c 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -567,7 +567,7 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ returned non-bytes (type %T)", + "%T.__bytes__ must return type bytes (not %T)", v, result); Py_DECREF(result); return NULL; @@ -2762,7 +2762,7 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, return NULL; if (!PyBytes_Check(bytes)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ returned non-bytes (type %T)", + "%T.__bytes__ must return type bytes (not %T)", x, bytes); Py_DECREF(bytes); return NULL; diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 95e91401296019..dd62230bf1f4c9 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -499,14 +499,14 @@ try_complex_special_method(PyObject *op) } if (!PyComplex_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__complex__ returned non-complex (type %T)", + "%T.__complex__ must return type 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, - "%T.__complex__ returned non-complex (type %T). " + "%T.__complex__ must return type 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.", op, res)) { diff --git a/Objects/fileobject.c b/Objects/fileobject.c index 7025b5bcffc1c8..cf565774b33a51 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -66,9 +66,9 @@ PyFile_GetLine(PyObject *f, int n) } if (result != NULL && !PyBytes_Check(result) && !PyUnicode_Check(result)) { + PyErr_Format(PyExc_TypeError, + "%T.readline() must return type 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)) { @@ -191,8 +191,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 type int (not %T)", o, fno); Py_DECREF(fno); return -1; } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 3b72a1e7c37b7f..3d8c34bf0b2e1e 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -315,16 +315,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 type 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 type 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; } diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 169db2048c6a74..3966ddeb7a3051 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -556,8 +556,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 type dict of type '%T'", + ann_dict); Py_DECREF(ann_dict); return NULL; } diff --git a/Objects/genobject.c b/Objects/genobject.c index 79aed8571c35e7..8217c611671e55 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1076,14 +1076,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__ returned a 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 type iterator " + "of type '%T'", + o, res); Py_CLEAR(res); } } diff --git a/Objects/iterobject.c b/Objects/iterobject.c index ebb342ff109222..b461f8e860cecb 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -342,8 +342,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 type iterable (not %T)", + obj, awaitable); Py_DECREF(awaitable); return NULL; } diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 20a2b8ee3221f8..56fe0888e51863 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -1258,8 +1258,10 @@ 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, + "%T.__annotate__ must return type dict " + "of type '%T'", + self, annotations); Py_DECREF(annotate); Py_DECREF(annotations); Py_DECREF(dict); diff --git a/Objects/object.c b/Objects/object.c index 400587db57d4dc..073af6a660ca88 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -779,7 +779,7 @@ PyObject_Repr(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.__repr__ returned non-string (type %T)", v, res); + "%T.__repr__ must return type str (not %T)", v, res); Py_DECREF(res); return NULL; } @@ -821,7 +821,7 @@ PyObject_Str(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.__str__ returned non-string (type %T)", v, res); + "%T.__str__ must return type str (not %T)", v, res); Py_DECREF(res); return NULL; } @@ -876,7 +876,7 @@ PyObject_Bytes(PyObject *v) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ returned non-bytes (type %T)", + "%T.__bytes__ must return type bytes (not %T)", v, result); Py_DECREF(result); return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 51ebbc476d0d04..26a61424bf0068 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2010,8 +2010,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, + "%T.__annotate__ must return type dict of " + "type '%T'", tp, annotations); Py_DECREF(annotations); Py_DECREF(annotate); Py_DECREF(dict); @@ -3238,10 +3239,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, + "%T.mro() must return class (not %T)", type, obj); return -1; } PyTypeObject *base = (PyTypeObject*)obj; @@ -9920,7 +9919,7 @@ slot_nb_bool(PyObject *self) } else { PyErr_Format(PyExc_TypeError, - "%T.__bool__ returned non-bool (type %T)", self, value); + "%T.__bool__ must return type bool (not %T)", self, value); result = -1; } @@ -10445,7 +10444,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 type memoryview (not %T)", + self, ret); goto fail; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 21ccb01f86bc61..84cbf8c6343aa9 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3705,10 +3705,9 @@ PyUnicode_Decode(const char *s, goto onError; if (!PyUnicode_Check(unicode)) { PyErr_Format(PyExc_TypeError, - "'%.400s' decoder returned '%.400s' instead of 'str'; " + "%s decoder must return type str (not %T); " "use codecs.decode() to decode to arbitrary types", - encoding, - Py_TYPE(unicode)->tp_name); + encoding, unicode); Py_DECREF(unicode); goto onError; } @@ -3768,10 +3767,9 @@ PyUnicode_AsDecodedUnicode(PyObject *unicode, goto onError; if (!PyUnicode_Check(v)) { PyErr_Format(PyExc_TypeError, - "'%.400s' decoder returned '%.400s' instead of 'str'; " + "%s decoder must return type str (not %T); " "use codecs.decode() to decode to arbitrary types", - encoding, - Py_TYPE(unicode)->tp_name); + encoding, unicode); Py_DECREF(v); goto onError; } @@ -3981,7 +3979,7 @@ PyUnicode_AsEncodedString(PyObject *unicode, PyObject *b; error = PyErr_WarnFormat(PyExc_RuntimeWarning, 1, - "encoder %s returned bytearray instead of bytes; " + "%s encoder must return type bytes (not bytearray); " "use codecs.encode() to encode to arbitrary types", encoding); if (error) { @@ -3996,10 +3994,9 @@ PyUnicode_AsEncodedString(PyObject *unicode, } PyErr_Format(PyExc_TypeError, - "'%.400s' encoder returned '%.400s' instead of 'bytes'; " + "%s encoder must return type bytes (not %T); " "use codecs.encode() to encode to arbitrary types", - encoding, - Py_TYPE(v)->tp_name); + encoding, v); Py_DECREF(v); return NULL; } @@ -4030,10 +4027,9 @@ PyUnicode_AsEncodedUnicode(PyObject *unicode, goto onError; if (!PyUnicode_Check(v)) { PyErr_Format(PyExc_TypeError, - "'%.400s' encoder returned '%.400s' instead of 'str'; " + "%s encoder must return type str (not %T); " "use codecs.encode() to encode to arbitrary types", - encoding, - Py_TYPE(v)->tp_name); + encoding, v); Py_DECREF(v); goto onError; } From d811b4cb93f3a0e7b8ba7759fcb2e013a6f35276 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Mon, 28 Apr 2025 05:50:00 +0400 Subject: [PATCH 04/11] Revert "Fix error message for methods return type" This reverts commit d97667670f7317a3076686778a0603b6599d5755. --- Objects/abstract.c | 39 ++++++++++++++++++--------------------- Objects/bytesobject.c | 4 ++-- Objects/complexobject.c | 4 ++-- Objects/fileobject.c | 8 ++++---- Objects/floatobject.c | 8 ++++---- Objects/funcobject.c | 5 ++--- Objects/genobject.c | 10 +++++----- Objects/iterobject.c | 5 ++--- Objects/moduleobject.c | 6 ++---- Objects/object.c | 6 +++--- Objects/typeobject.c | 16 ++++++++-------- Objects/unicodeobject.c | 22 +++++++++++++--------- 12 files changed, 65 insertions(+), 68 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index 8c25142a5345ff..1d1fc64a89004a 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -129,9 +129,8 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue) return defaultvalue; } if (!PyLong_Check(result)) { - PyErr_Format(PyExc_TypeError, - "%T.__length_hint__ must return type int (not %T)", - o, result); + PyErr_Format(PyExc_TypeError, "__length_hint__ must be an integer, not %.100s", + Py_TYPE(result)->tp_name); Py_DECREF(result); return -1; } @@ -141,9 +140,7 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue) return -1; } if (res < 0) { - PyErr_Format(PyExc_ValueError, - "%T.__length_hint__ must return positive int (not %T)", - o, result); + PyErr_Format(PyExc_ValueError, "__length_hint__() should return >= 0"); return -1; } return res; @@ -887,8 +884,8 @@ PyObject_Format(PyObject *obj, PyObject *format_spec) if (result && !PyUnicode_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__format__ must return type str (not %T)", - obj, result); + "__format__ must return a str, not %.200s", + Py_TYPE(result)->tp_name); Py_SETREF(result, NULL); goto done; } @@ -1421,14 +1418,13 @@ _PyNumber_Index(PyObject *item) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__index__ must return type int (not %T)", - item, result); + "%T.__index__ returned non-int (type %T)", item, result); Py_DECREF(result); return NULL; } /* Issue #17576: warn if 'result' not of exact type int. */ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "%T.__index__ must return type int (not %T). " + "%T.__index__ returned non-int (type %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.", item, result)) { @@ -1531,13 +1527,13 @@ PyNumber_Long(PyObject *o) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__int__ must return type int (not %T)", o, result); + "%T.__int__ returned non-int (type %T)", o, result); Py_DECREF(result); return NULL; } /* Issue #17576: warn if 'result' not of exact type int. */ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "%T.__int__ must return type int (not %T). " + "%T.__int__ returned non-int (type %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.", o, result)) { @@ -1608,14 +1604,13 @@ PyNumber_Float(PyObject *o) if (!PyFloat_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__float__ must return type float (not %T)", - o, res); + "%T.__float__ returned non-float (type %T)", o, res); Py_DECREF(res); return NULL; } /* Issue #26983: warn if 'res' not of exact type float. */ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "%T.__float__ must return type float (not %T). " + "%T.__float__ returned non-float (type %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.", o, res)) { @@ -2434,8 +2429,10 @@ method_output_as_list(PyObject *o, PyObject *meth) PyThreadState *tstate = _PyThreadState_GET(); if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.%U() must return type iterable (not %T)", - o, meth, meth_output); + "%.200s.%U() returned a non-iterable (type %.200s)", + Py_TYPE(o)->tp_name, + meth, + Py_TYPE(meth_output)->tp_name); } Py_DECREF(meth_output); return NULL; @@ -2815,7 +2812,7 @@ PyObject_GetIter(PyObject *o) PyObject *res = (*f)(o); if (res != NULL && !PyIter_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.iter() must return type iterator of type '%T'", + "%T.iter() returned non-iterator of type '%T'", o, res); Py_SETREF(res, NULL); } @@ -2835,8 +2832,8 @@ PyObject_GetAIter(PyObject *o) { PyObject *it = (*f)(o); if (it != NULL && !PyAIter_Check(it)) { PyErr_Format(PyExc_TypeError, - "%T.aiter() must return type async iterator of type '%T'", - o, it); + "aiter() returned not an async iterator of type '%.100s'", + Py_TYPE(it)->tp_name); Py_SETREF(it, NULL); } return it; diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index a81950f41c415c..a02e11df976e10 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -567,7 +567,7 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ must return type bytes (not %T)", + "%T.__bytes__ returned non-bytes (type %T)", v, result); Py_DECREF(result); return NULL; @@ -2762,7 +2762,7 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, return NULL; if (!PyBytes_Check(bytes)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ must return type bytes (not %T)", + "%T.__bytes__ returned non-bytes (type %T)", x, bytes); Py_DECREF(bytes); return NULL; diff --git a/Objects/complexobject.c b/Objects/complexobject.c index dd62230bf1f4c9..95e91401296019 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -499,14 +499,14 @@ try_complex_special_method(PyObject *op) } if (!PyComplex_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__complex__ must return type complex (not %T)", + "%T.__complex__ returned non-complex (type %T)", op, res); Py_DECREF(res); return NULL; } /* Issue #29894: warn if 'res' not of exact type complex. */ if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "%T.__complex__ must return type complex (not %T). " + "%T.__complex__ returned non-complex (type %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.", op, res)) { diff --git a/Objects/fileobject.c b/Objects/fileobject.c index cf565774b33a51..7025b5bcffc1c8 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -66,9 +66,9 @@ PyFile_GetLine(PyObject *f, int n) } if (result != NULL && !PyBytes_Check(result) && !PyUnicode_Check(result)) { - PyErr_Format(PyExc_TypeError, - "%T.readline() must return type 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)) { @@ -191,8 +191,8 @@ PyObject_AsFileDescriptor(PyObject *o) Py_DECREF(fno); } else { - PyErr_Format(PyExc_TypeError, - "%T.fileno() must return type int (not %T)", o, fno); + PyErr_SetString(PyExc_TypeError, + "fileno() returned a non-integer"); Py_DECREF(fno); return -1; } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 3d8c34bf0b2e1e..3b72a1e7c37b7f 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -315,16 +315,16 @@ PyFloat_AsDouble(PyObject *op) if (!PyFloat_CheckExact(res)) { if (!PyFloat_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__float__ must return type float (not %T)", - op, res); + "%.50s.__float__ returned non-float (type %.50s)", + Py_TYPE(op)->tp_name, Py_TYPE(res)->tp_name); Py_DECREF(res); return -1; } if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "%T.__float__ must return type float (not %T). " + "%.50s.__float__ returned non-float (type %.50s). " "The ability to return an instance of a strict subclass of float " "is deprecated, and may be removed in a future version of Python.", - op, res) { + Py_TYPE(op)->tp_name, Py_TYPE(res)->tp_name)) { Py_DECREF(res); return -1; } diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 3966ddeb7a3051..169db2048c6a74 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -556,9 +556,8 @@ func_get_annotation_dict(PyFunctionObject *op) return NULL; } if (!PyDict_Check(ann_dict)) { - PyErr_Format(PyExc_TypeError, - "__annotate__ must return type dict of type '%T'", - ann_dict); + PyErr_Format(PyExc_TypeError, "__annotate__ returned non-dict of type '%.100s'", + Py_TYPE(ann_dict)->tp_name); Py_DECREF(ann_dict); return NULL; } diff --git a/Objects/genobject.c b/Objects/genobject.c index 8217c611671e55..79aed8571c35e7 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1076,14 +1076,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_Format(PyExc_TypeError, - "%T.__await__ returned a coroutine", o); + PyErr_SetString(PyExc_TypeError, + "__await__() returned a coroutine"); Py_CLEAR(res); } else if (!PyIter_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__await__ must return type iterator " - "of type '%T'", - o, res); + "__await__() returned non-iterator " + "of type '%.100s'", + Py_TYPE(res)->tp_name); Py_CLEAR(res); } } diff --git a/Objects/iterobject.c b/Objects/iterobject.c index b461f8e860cecb..ebb342ff109222 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -342,9 +342,8 @@ anextawaitable_getiter(anextawaitableobject *obj) } Py_SETREF(awaitable, new_awaitable); if (!PyIter_Check(awaitable)) { - PyErr_Format(PyExc_TypeError, - "%T.__await__ must return type iterable (not %T)", - obj, awaitable); + PyErr_SetString(PyExc_TypeError, + "__await__ returned a non-iterable"); Py_DECREF(awaitable); return NULL; } diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 56fe0888e51863..20a2b8ee3221f8 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -1258,10 +1258,8 @@ module_get_annotations(PyObject *self, void *Py_UNUSED(ignored)) return NULL; } if (!PyDict_Check(annotations)) { - PyErr_Format(PyExc_TypeError, - "%T.__annotate__ must return type dict " - "of type '%T'", - self, annotations); + PyErr_Format(PyExc_TypeError, "__annotate__ returned non-dict of type '%.100s'", + Py_TYPE(annotations)->tp_name); Py_DECREF(annotate); Py_DECREF(annotations); Py_DECREF(dict); diff --git a/Objects/object.c b/Objects/object.c index 073af6a660ca88..400587db57d4dc 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -779,7 +779,7 @@ PyObject_Repr(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.__repr__ must return type str (not %T)", v, res); + "%T.__repr__ returned non-string (type %T)", v, res); Py_DECREF(res); return NULL; } @@ -821,7 +821,7 @@ PyObject_Str(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.__str__ must return type str (not %T)", v, res); + "%T.__str__ returned non-string (type %T)", v, res); Py_DECREF(res); return NULL; } @@ -876,7 +876,7 @@ PyObject_Bytes(PyObject *v) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ must return type bytes (not %T)", + "%T.__bytes__ returned non-bytes (type %T)", v, result); Py_DECREF(result); return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 26a61424bf0068..51ebbc476d0d04 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2010,9 +2010,8 @@ type_get_annotations(PyObject *tp, void *Py_UNUSED(closure)) return NULL; } if (!PyDict_Check(annotations)) { - PyErr_Format(PyExc_TypeError, - "%T.__annotate__ must return type dict of " - "type '%T'", tp, annotations); + PyErr_Format(PyExc_TypeError, "__annotate__ returned non-dict of type '%.100s'", + Py_TYPE(annotations)->tp_name); Py_DECREF(annotations); Py_DECREF(annotate); Py_DECREF(dict); @@ -3239,8 +3238,10 @@ 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, - "%T.mro() must return class (not %T)", type, obj); + PyErr_Format( + PyExc_TypeError, + "mro() returned a non-class ('%.500s')", + Py_TYPE(obj)->tp_name); return -1; } PyTypeObject *base = (PyTypeObject*)obj; @@ -9919,7 +9920,7 @@ slot_nb_bool(PyObject *self) } else { PyErr_Format(PyExc_TypeError, - "%T.__bool__ must return type bool (not %T)", self, value); + "%T.__bool__ returned non-bool (type %T)", self, value); result = -1; } @@ -10444,8 +10445,7 @@ slot_bf_getbuffer(PyObject *self, Py_buffer *buffer, int flags) } if (!PyMemoryView_Check(ret)) { PyErr_Format(PyExc_TypeError, - "%T.__buffer__ must return type memoryview (not %T)", - self, ret); + "__buffer__ returned non-memoryview object"); goto fail; } diff --git a/Objects/unicodeobject.c b/Objects/unicodeobject.c index 84cbf8c6343aa9..21ccb01f86bc61 100644 --- a/Objects/unicodeobject.c +++ b/Objects/unicodeobject.c @@ -3705,9 +3705,10 @@ PyUnicode_Decode(const char *s, goto onError; if (!PyUnicode_Check(unicode)) { PyErr_Format(PyExc_TypeError, - "%s decoder must return type str (not %T); " + "'%.400s' decoder returned '%.400s' instead of 'str'; " "use codecs.decode() to decode to arbitrary types", - encoding, unicode); + encoding, + Py_TYPE(unicode)->tp_name); Py_DECREF(unicode); goto onError; } @@ -3767,9 +3768,10 @@ PyUnicode_AsDecodedUnicode(PyObject *unicode, goto onError; if (!PyUnicode_Check(v)) { PyErr_Format(PyExc_TypeError, - "%s decoder must return type str (not %T); " + "'%.400s' decoder returned '%.400s' instead of 'str'; " "use codecs.decode() to decode to arbitrary types", - encoding, unicode); + encoding, + Py_TYPE(unicode)->tp_name); Py_DECREF(v); goto onError; } @@ -3979,7 +3981,7 @@ PyUnicode_AsEncodedString(PyObject *unicode, PyObject *b; error = PyErr_WarnFormat(PyExc_RuntimeWarning, 1, - "%s encoder must return type bytes (not bytearray); " + "encoder %s returned bytearray instead of bytes; " "use codecs.encode() to encode to arbitrary types", encoding); if (error) { @@ -3994,9 +3996,10 @@ PyUnicode_AsEncodedString(PyObject *unicode, } PyErr_Format(PyExc_TypeError, - "%s encoder must return type bytes (not %T); " + "'%.400s' encoder returned '%.400s' instead of 'bytes'; " "use codecs.encode() to encode to arbitrary types", - encoding, v); + encoding, + Py_TYPE(v)->tp_name); Py_DECREF(v); return NULL; } @@ -4027,9 +4030,10 @@ PyUnicode_AsEncodedUnicode(PyObject *unicode, goto onError; if (!PyUnicode_Check(v)) { PyErr_Format(PyExc_TypeError, - "%s encoder must return type str (not %T); " + "'%.400s' encoder returned '%.400s' instead of 'str'; " "use codecs.encode() to encode to arbitrary types", - encoding, v); + encoding, + Py_TYPE(v)->tp_name); Py_DECREF(v); goto onError; } From 70d57c2c565209338a20c94d9accff4918193980 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Mon, 28 Apr 2025 06:01:56 +0400 Subject: [PATCH 05/11] Use new message template --- Objects/abstract.c | 19 ++++++++++--------- Objects/bytesobject.c | 4 ++-- Objects/complexobject.c | 4 ++-- Objects/object.c | 6 +++--- Objects/typeobject.c | 8 +++++--- 5 files changed, 22 insertions(+), 19 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index 1d1fc64a89004a..a447d7ebf977bd 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -884,8 +884,7 @@ 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); + "__format__ must return type str (not %T)", result); Py_SETREF(result, NULL); goto done; } @@ -1418,13 +1417,14 @@ _PyNumber_Index(PyObject *item) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__index__ returned non-int (type %T)", item, result); + "%T.__index__ must return type 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, - "%T.__index__ returned non-int (type %T). " + "%T.__index__ must return type 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.", item, result)) { @@ -1527,13 +1527,14 @@ PyNumber_Long(PyObject *o) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__int__ returned non-int (type %T)", o, result); + "%T.__int__ must return type 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, - "%T.__int__ returned non-int (type %T). " + "%T.__int__ must return type 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.", o, result)) { @@ -1604,13 +1605,13 @@ PyNumber_Float(PyObject *o) if (!PyFloat_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__float__ returned non-float (type %T)", o, res); + "%T.__float__ must return type 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, - "%T.__float__ returned non-float (type %T). " + "%T.__float__ must return type 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.", o, res)) { @@ -2812,7 +2813,7 @@ PyObject_GetIter(PyObject *o) PyObject *res = (*f)(o); if (res != NULL && !PyIter_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.iter() returned non-iterator of type '%T'", + "%T.iter() must return type iterator of type '%T'", o, res); Py_SETREF(res, NULL); } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index a02e11df976e10..a81950f41c415c 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -567,7 +567,7 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ returned non-bytes (type %T)", + "%T.__bytes__ must return type bytes (not %T)", v, result); Py_DECREF(result); return NULL; @@ -2762,7 +2762,7 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, return NULL; if (!PyBytes_Check(bytes)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ returned non-bytes (type %T)", + "%T.__bytes__ must return type bytes (not %T)", x, bytes); Py_DECREF(bytes); return NULL; diff --git a/Objects/complexobject.c b/Objects/complexobject.c index 95e91401296019..dd62230bf1f4c9 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -499,14 +499,14 @@ try_complex_special_method(PyObject *op) } if (!PyComplex_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__complex__ returned non-complex (type %T)", + "%T.__complex__ must return type 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, - "%T.__complex__ returned non-complex (type %T). " + "%T.__complex__ must return type 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.", op, res)) { diff --git a/Objects/object.c b/Objects/object.c index 400587db57d4dc..073af6a660ca88 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -779,7 +779,7 @@ PyObject_Repr(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.__repr__ returned non-string (type %T)", v, res); + "%T.__repr__ must return type str (not %T)", v, res); Py_DECREF(res); return NULL; } @@ -821,7 +821,7 @@ PyObject_Str(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.__str__ returned non-string (type %T)", v, res); + "%T.__str__ must return type str (not %T)", v, res); Py_DECREF(res); return NULL; } @@ -876,7 +876,7 @@ PyObject_Bytes(PyObject *v) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ returned non-bytes (type %T)", + "%T.__bytes__ must return type bytes (not %T)", v, result); Py_DECREF(result); return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 51ebbc476d0d04..32375b568723b1 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2010,8 +2010,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 type dict of type '%T'", + annotations); Py_DECREF(annotations); Py_DECREF(annotate); Py_DECREF(dict); @@ -9920,7 +9921,8 @@ slot_nb_bool(PyObject *self) } else { PyErr_Format(PyExc_TypeError, - "%T.__bool__ returned non-bool (type %T)", self, value); + "%T.__bool__ must return type bool (not %T)", + self, value); result = -1; } From 390f9413d504be1d81c060708136c577365fdd80 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Mon, 28 Apr 2025 17:07:04 +0400 Subject: [PATCH 06/11] Improve message and fix test --- Lib/test/test_type_annotations.py | 2 +- Objects/abstract.c | 15 ++++++++------- Objects/bytesobject.c | 4 ++-- Objects/complexobject.c | 4 ++-- Objects/object.c | 6 +++--- Objects/typeobject.c | 4 ++-- 6 files changed, 18 insertions(+), 17 deletions(-) diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py index fb441976694b34..61ba23dc241910 100644 --- a/Lib/test/test_type_annotations.py +++ b/Lib/test/test_type_annotations.py @@ -301,7 +301,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 type dict of type 'int'"): print(f.__annotations__) f.__annotate__ = lambda x: {"x": x} diff --git a/Objects/abstract.c b/Objects/abstract.c index 62d581689df84b..bea59074637325 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -887,7 +887,8 @@ PyObject_Format(PyObject *obj, PyObject *format_spec) if (result && !PyUnicode_Check(result)) { PyErr_Format(PyExc_TypeError, - "__format__ must return type str (not %T)", result); + "%T.__format__() must return type str (not %T)", + obj, result); Py_SETREF(result, NULL); goto done; } @@ -1420,14 +1421,14 @@ _PyNumber_Index(PyObject *item) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__index__ must return type int (not %T)", + "%T.__index__() must return type 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, - "%T.__index__ must return type int (not %T). " + "%T.__index__() must return type 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.", item, result)) { @@ -1530,14 +1531,14 @@ PyNumber_Long(PyObject *o) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__int__ must return type int (not %T)", + "%T.__int__() must return type 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, - "%T.__int__ must return type int (not %T). " + "%T.__int__() must return type 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.", o, result)) { @@ -1608,13 +1609,13 @@ PyNumber_Float(PyObject *o) if (!PyFloat_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__float__ must return type float (not %T)", o, res); + "%T.__float__() must return type 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, - "%T.__float__ must return type float (not %T). " + "%T.__float__() must return type 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.", o, res)) { diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 8e25f00b7450f0..43bd6206830a18 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -566,7 +566,7 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ must return type bytes (not %T)", + "%T.__bytes__() must return type bytes (not %T)", v, result); Py_DECREF(result); return NULL; @@ -2788,7 +2788,7 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, return NULL; if (!PyBytes_Check(bytes)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ must return type bytes (not %T)", + "%T.__bytes__() must return type bytes (not %T)", x, bytes); Py_DECREF(bytes); return NULL; diff --git a/Objects/complexobject.c b/Objects/complexobject.c index f0f4e980a6638f..fd16a251e93cdd 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -499,14 +499,14 @@ try_complex_special_method(PyObject *op) } if (!PyComplex_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__complex__ must return type complex (not %T)", + "%T.__complex__() must return type 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, - "%T.__complex__ must return type complex (not %T). " + "%T.__complex__() must return type 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.", op, res)) { diff --git a/Objects/object.c b/Objects/object.c index 4cfd2b0f8b75fb..cd075233464e5e 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -781,7 +781,7 @@ PyObject_Repr(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.__repr__ must return type str (not %T)", v, res); + "%T.__repr__() must return type str (not %T)", v, res); Py_DECREF(res); return NULL; } @@ -823,7 +823,7 @@ PyObject_Str(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.__str__ must return type str (not %T)", v, res); + "%T.__str__() must return type str (not %T)", v, res); Py_DECREF(res); return NULL; } @@ -878,7 +878,7 @@ PyObject_Bytes(PyObject *v) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__ must return type bytes (not %T)", + "%T.__bytes__() must return type bytes (not %T)", v, result); Py_DECREF(result); return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 46eb0935c94507..688ad4ad49959d 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2029,7 +2029,7 @@ type_get_annotations(PyObject *tp, void *Py_UNUSED(closure)) } if (!PyDict_Check(annotations)) { PyErr_Format(PyExc_TypeError, - "__annotate__ must return type dict of type '%T'", + "__annotate__() must return type dict of type '%T'", annotations); Py_DECREF(annotations); Py_DECREF(annotate); @@ -10077,7 +10077,7 @@ slot_nb_bool(PyObject *self) } else { PyErr_Format(PyExc_TypeError, - "%T.__bool__ must return type bool (not %T)", + "%T.__bool__() must return type bool (not %T)", self, value); result = -1; } From d2e54e68cd65cafe6ca21a7a2617903cc1792a33 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Mon, 28 Apr 2025 18:17:04 +0400 Subject: [PATCH 07/11] Fix more methods --- Objects/abstract.c | 18 +++++++++--------- Objects/fileobject.c | 8 ++++---- Objects/floatobject.c | 8 ++++---- Objects/funcobject.c | 5 +++-- Objects/genobject.c | 9 ++++----- Objects/iterobject.c | 5 +++-- Objects/moduleobject.c | 5 +++-- Objects/typeobject.c | 14 +++++++------- 8 files changed, 37 insertions(+), 35 deletions(-) diff --git a/Objects/abstract.c b/Objects/abstract.c index bea59074637325..17dfa2030a59c4 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -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 type 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 positive int", o); return -1; } return res; @@ -2434,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 type iterable (not %T)", + o, meth, meth_output); } Py_DECREF(meth_output); return NULL; @@ -2837,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 type async iterator of type '%T'", + o, it); Py_SETREF(it, NULL); } return it; diff --git a/Objects/fileobject.c b/Objects/fileobject.c index e624405bd5f62f..ec6a8c7cde2a25 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -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 type 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 type int (not %T)", o, fno); Py_DECREF(fno); return -1; } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 87a00bf1a458ea..84873fec090853 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -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 type 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 type 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; } diff --git a/Objects/funcobject.c b/Objects/funcobject.c index 6d71dbb5a6affd..c4164c5910b12a 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -557,8 +557,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 type dict of type '%T'", + ann_dict); Py_DECREF(ann_dict); return NULL; } diff --git a/Objects/genobject.c b/Objects/genobject.c index 98b2c5004df8ac..465d7dd7d258b1 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1082,14 +1082,13 @@ _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 type 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 type iterator " + "of type '%T'", o, res); Py_CLEAR(res); } } diff --git a/Objects/iterobject.c b/Objects/iterobject.c index 5712e02ae828ab..00d4a0d39b1167 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -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 type iterable (not %T)", + obj, awaitable); Py_DECREF(awaitable); return NULL; } diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 46dea1534cbcd6..6db8c2bcf81667 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -1261,8 +1261,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 type dict of type '%T'", + annotations); Py_DECREF(annotate); Py_DECREF(annotations); Py_DECREF(dict); diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 688ad4ad49959d..6cad819848f907 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -3384,10 +3384,9 @@ 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, + "%s.mro() must return class (not %T)", + type->tp_name, obj); return -1; } PyTypeObject *base = (PyTypeObject*)obj; @@ -3395,8 +3394,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); + "%s.mro() returned base with unsuitable layout ('%.500s')", + type->tp_name, base->tp_name); return -1; } } @@ -10553,7 +10552,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 type memoryview (not %T)", + self, ret); goto fail; } From 0ac8a1c132a1d9e822ef1749746b8341f84282ec Mon Sep 17 00:00:00 2001 From: donBarbos Date: Mon, 28 Apr 2025 18:29:08 +0400 Subject: [PATCH 08/11] Escape parentheses in regex pattern to fix test match --- Lib/test/test_type_annotations.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py index 61ba23dc241910..da610fd48244a5 100644 --- a/Lib/test/test_type_annotations.py +++ b/Lib/test/test_type_annotations.py @@ -301,7 +301,7 @@ def check_annotations(self, f): print(f.__annotations__) f.__annotate__ = lambda x: 42 - with self.assertRaisesRegex(TypeError, r"__annotate__() must return type dict of type 'int'"): + with self.assertRaisesRegex(TypeError, r"__annotate__\(\) must return type dict of type 'int'"): print(f.__annotations__) f.__annotate__ = lambda x: {"x": x} From 59bca2dad3c0fda90820472a148a0b1f246a5f33 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Mon, 28 Apr 2025 18:41:41 +0400 Subject: [PATCH 09/11] Fix message for coroutine test --- Lib/test/test_coroutines.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 761cb230277bd9..7040645c2afd0b 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1008,7 +1008,7 @@ async def foo(): return (await Awaitable()) with self.assertRaisesRegex( - TypeError, "__await__.*returned non-iterator of type"): + TypeError, "__await__.*must return type iterator of type"): 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 type 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 type iterator of type"): 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 type iterator of type 'int'"): self.assertEqual(foo().send(None), 1) From 51a6c79b93ba049c868901e4875990164357e345 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Mon, 28 Apr 2025 18:59:17 +0400 Subject: [PATCH 10/11] Add News entry --- .../2025-04-28-18-59-11.gh-issue-130821.B11LU1.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-04-28-18-59-11.gh-issue-130821.B11LU1.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-04-28-18-59-11.gh-issue-130821.B11LU1.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-28-18-59-11.gh-issue-130821.B11LU1.rst new file mode 100644 index 00000000000000..09ffaf80a6d535 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-04-28-18-59-11.gh-issue-130821.B11LU1.rst @@ -0,0 +1,2 @@ +Enhance wrong type error messages and make them more consistent. Patch by +Semyon Moroz. From 699b112401ee47939f779c178dc14ea5b4d384a6 Mon Sep 17 00:00:00 2001 From: donBarbos Date: Tue, 29 Apr 2025 00:40:15 +0400 Subject: [PATCH 11/11] Update message template --- Lib/test/test_coroutines.py | 8 ++++---- Lib/test/test_type_annotations.py | 2 +- Objects/abstract.c | 24 ++++++++++++------------ Objects/bytesobject.c | 4 ++-- Objects/complexobject.c | 4 ++-- Objects/fileobject.c | 4 ++-- Objects/floatobject.c | 4 ++-- Objects/funcobject.c | 2 +- Objects/genobject.c | 7 ++++--- Objects/iterobject.c | 2 +- Objects/moduleobject.c | 2 +- Objects/object.c | 6 +++--- Objects/typeobject.c | 8 ++++---- 13 files changed, 39 insertions(+), 38 deletions(-) diff --git a/Lib/test/test_coroutines.py b/Lib/test/test_coroutines.py index 7040645c2afd0b..81c9119337403b 100644 --- a/Lib/test/test_coroutines.py +++ b/Lib/test/test_coroutines.py @@ -1008,7 +1008,7 @@ async def foo(): return (await Awaitable()) with self.assertRaisesRegex( - TypeError, "__await__.*must return type 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__\(\) must return type iterator \(not 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__.*must return type 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__.*must return type iterator of type 'int'"): + TypeError, "__await__.*must return an iterator, not int"): self.assertEqual(foo().send(None), 1) diff --git a/Lib/test/test_type_annotations.py b/Lib/test/test_type_annotations.py index da610fd48244a5..16e9b7c07b6437 100644 --- a/Lib/test/test_type_annotations.py +++ b/Lib/test/test_type_annotations.py @@ -301,7 +301,7 @@ def check_annotations(self, f): print(f.__annotations__) f.__annotate__ = lambda x: 42 - with self.assertRaisesRegex(TypeError, r"__annotate__\(\) must return type 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} diff --git a/Objects/abstract.c b/Objects/abstract.c index 17dfa2030a59c4..50abb16e78cbb6 100644 --- a/Objects/abstract.c +++ b/Objects/abstract.c @@ -133,7 +133,7 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue) } if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__length_hint__() must return type int (not %T)", + "%T.__length_hint__() must return an int, not %T", o, result); Py_DECREF(result); return -1; @@ -145,7 +145,7 @@ PyObject_LengthHint(PyObject *o, Py_ssize_t defaultvalue) } if (res < 0) { PyErr_Format(PyExc_ValueError, - "%T.__length_hint__() must return positive int", o); + "%T.__length_hint__() must return a positive int", o); return -1; } return res; @@ -889,7 +889,7 @@ PyObject_Format(PyObject *obj, PyObject *format_spec) if (result && !PyUnicode_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__format__() must return type str (not %T)", + "%T.__format__() must return a str, not %T", obj, result); Py_SETREF(result, NULL); goto done; @@ -1423,14 +1423,14 @@ _PyNumber_Index(PyObject *item) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__index__() must return type int (not %T)", + "%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, - "%T.__index__() must return type int (not %T). " + "%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.", item, result)) { @@ -1533,14 +1533,14 @@ PyNumber_Long(PyObject *o) if (!PyLong_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__int__() must return type int (not %T)", + "%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, - "%T.__int__() must return type int (not %T). " + "%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.", o, result)) { @@ -1611,13 +1611,13 @@ PyNumber_Float(PyObject *o) if (!PyFloat_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__float__() must return type float (not %T)", o, res); + "%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, - "%T.__float__() must return type float (not %T). " + "%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.", o, res)) { @@ -2436,7 +2436,7 @@ method_output_as_list(PyObject *o, PyObject *meth) PyThreadState *tstate = _PyThreadState_GET(); if (_PyErr_ExceptionMatches(tstate, PyExc_TypeError)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.%U() must return type iterable (not %T)", + "%T.%U() must return an iterable, not %T", o, meth, meth_output); } Py_DECREF(meth_output); @@ -2817,7 +2817,7 @@ PyObject_GetIter(PyObject *o) PyObject *res = (*f)(o); if (res != NULL && !PyIter_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.iter() must return type iterator of type '%T'", + "%T.iter() must return an iterator, not %T", o, res); Py_SETREF(res, NULL); } @@ -2837,7 +2837,7 @@ PyObject_GetAIter(PyObject *o) { PyObject *it = (*f)(o); if (it != NULL && !PyAIter_Check(it)) { PyErr_Format(PyExc_TypeError, - "%T.aiter() must return type async iterator of type '%T'", + "%T.aiter() must return an async iterator, not %T", o, it); Py_SETREF(it, NULL); } diff --git a/Objects/bytesobject.c b/Objects/bytesobject.c index 43bd6206830a18..c8478d50d0f892 100644 --- a/Objects/bytesobject.c +++ b/Objects/bytesobject.c @@ -566,7 +566,7 @@ format_obj(PyObject *v, const char **pbuf, Py_ssize_t *plen) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__() must return type bytes (not %T)", + "%T.__bytes__() must return a bytes, not %T", v, result); Py_DECREF(result); return NULL; @@ -2788,7 +2788,7 @@ bytes_new_impl(PyTypeObject *type, PyObject *x, const char *encoding, return NULL; if (!PyBytes_Check(bytes)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__() must return type bytes (not %T)", + "%T.__bytes__() must return a bytes, not %T", x, bytes); Py_DECREF(bytes); return NULL; diff --git a/Objects/complexobject.c b/Objects/complexobject.c index fd16a251e93cdd..e68dfcd5aba8c9 100644 --- a/Objects/complexobject.c +++ b/Objects/complexobject.c @@ -499,14 +499,14 @@ try_complex_special_method(PyObject *op) } if (!PyComplex_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__complex__() must return type complex (not %T)", + "%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, - "%T.__complex__() must return type complex (not %T). " + "%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.", op, res)) { diff --git a/Objects/fileobject.c b/Objects/fileobject.c index ec6a8c7cde2a25..05c3e75b4642ee 100644 --- a/Objects/fileobject.c +++ b/Objects/fileobject.c @@ -69,7 +69,7 @@ PyFile_GetLine(PyObject *f, int n) if (result != NULL && !PyBytes_Check(result) && !PyUnicode_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.readline() must return type str (not %T)", f, result); + "%T.readline() must return a str, not %T", f, result); Py_SETREF(result, NULL); } @@ -194,7 +194,7 @@ PyObject_AsFileDescriptor(PyObject *o) } else { PyErr_Format(PyExc_TypeError, - "%T.fileno() must return type int (not %T)", o, fno); + "%T.fileno() must return an int, not %T", o, fno); Py_DECREF(fno); return -1; } diff --git a/Objects/floatobject.c b/Objects/floatobject.c index 84873fec090853..963313ba5ba7bb 100644 --- a/Objects/floatobject.c +++ b/Objects/floatobject.c @@ -288,13 +288,13 @@ PyFloat_AsDouble(PyObject *op) if (!PyFloat_CheckExact(res)) { if (!PyFloat_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__float__() must return type float (not %T)", + "%T.__float__() must return a float, not %T", op, res); Py_DECREF(res); return -1; } if (PyErr_WarnFormat(PyExc_DeprecationWarning, 1, - "%T.__float__() must return type float (not %T). " + "%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.", op, res)) { diff --git a/Objects/funcobject.c b/Objects/funcobject.c index c4164c5910b12a..566bfa3c6d5930 100644 --- a/Objects/funcobject.c +++ b/Objects/funcobject.c @@ -558,7 +558,7 @@ func_get_annotation_dict(PyFunctionObject *op) } if (!PyDict_Check(ann_dict)) { PyErr_Format(PyExc_TypeError, - "__annotate__() must return type dict of type '%T'", + "__annotate__() must return a dict, not %T", ann_dict); Py_DECREF(ann_dict); return NULL; diff --git a/Objects/genobject.c b/Objects/genobject.c index 465d7dd7d258b1..710dbbc7497883 100644 --- a/Objects/genobject.c +++ b/Objects/genobject.c @@ -1083,12 +1083,13 @@ _PyCoro_GetAwaitableIter(PyObject *o) /* __await__ must return an *iterator*, not a coroutine or another awaitable (see PEP 492) */ PyErr_Format(PyExc_TypeError, - "%T.__await__() must return type iterator (not coroutine)", o); + "%T.__await__() must return an iterator, " + "not coroutine", o); Py_CLEAR(res); } else if (!PyIter_Check(res)) { PyErr_Format(PyExc_TypeError, - "%T.__await__() must return type iterator " - "of type '%T'", o, res); + "%T.__await__() must return an iterator, " + "not %T", o, res); Py_CLEAR(res); } } diff --git a/Objects/iterobject.c b/Objects/iterobject.c index 00d4a0d39b1167..e323987601d5d4 100644 --- a/Objects/iterobject.c +++ b/Objects/iterobject.c @@ -358,7 +358,7 @@ anextawaitable_getiter(anextawaitableobject *obj) Py_SETREF(awaitable, new_awaitable); if (!PyIter_Check(awaitable)) { PyErr_Format(PyExc_TypeError, - "%T.__await__() must return type iterable (not %T)", + "%T.__await__() must return an iterable, not %T", obj, awaitable); Py_DECREF(awaitable); return NULL; diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 6db8c2bcf81667..653d455c6ad015 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -1262,7 +1262,7 @@ module_get_annotations(PyObject *self, void *Py_UNUSED(ignored)) } if (!PyDict_Check(annotations)) { PyErr_Format(PyExc_TypeError, - "__annotate__() must return type dict of type '%T'", + "__annotate__() must return a dict, not %T", annotations); Py_DECREF(annotate); Py_DECREF(annotations); diff --git a/Objects/object.c b/Objects/object.c index cd075233464e5e..ddcacee04a0938 100644 --- a/Objects/object.c +++ b/Objects/object.c @@ -781,7 +781,7 @@ PyObject_Repr(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.__repr__() must return type str (not %T)", v, res); + "%T.__repr__() must return a str, not %T", v, res); Py_DECREF(res); return NULL; } @@ -823,7 +823,7 @@ PyObject_Str(PyObject *v) } if (!PyUnicode_Check(res)) { _PyErr_Format(tstate, PyExc_TypeError, - "%T.__str__() must return type str (not %T)", v, res); + "%T.__str__() must return a str, not %T", v, res); Py_DECREF(res); return NULL; } @@ -878,7 +878,7 @@ PyObject_Bytes(PyObject *v) return NULL; if (!PyBytes_Check(result)) { PyErr_Format(PyExc_TypeError, - "%T.__bytes__() must return type bytes (not %T)", + "%T.__bytes__() must return a bytes, not %T", v, result); Py_DECREF(result); return NULL; diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 6cad819848f907..4c5edd4fa12420 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -2029,7 +2029,7 @@ type_get_annotations(PyObject *tp, void *Py_UNUSED(closure)) } if (!PyDict_Check(annotations)) { PyErr_Format(PyExc_TypeError, - "__annotate__() must return type dict of type '%T'", + "__annotate__() must return a dict, not %T", annotations); Py_DECREF(annotations); Py_DECREF(annotate); @@ -3385,7 +3385,7 @@ mro_check(PyTypeObject *type, PyObject *mro) PyObject *obj = PyTuple_GET_ITEM(mro, i); if (!PyType_Check(obj)) { PyErr_Format(PyExc_TypeError, - "%s.mro() must return class (not %T)", + "%s.mro() returned a non-class ('%T')", type->tp_name, obj); return -1; } @@ -10076,7 +10076,7 @@ slot_nb_bool(PyObject *self) } else { PyErr_Format(PyExc_TypeError, - "%T.__bool__() must return type bool (not %T)", + "%T.__bool__() must return a bool, not %T", self, value); result = -1; } @@ -10552,7 +10552,7 @@ slot_bf_getbuffer(PyObject *self, Py_buffer *buffer, int flags) } if (!PyMemoryView_Check(ret)) { PyErr_Format(PyExc_TypeError, - "%T.__buffer__() must return type memoryview (not %T)", + "%T.__buffer__() must return a memoryview, not %T", self, ret); goto fail; } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy