Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

gh-130821: Add type information to wrong type error messages#130835

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
donBarbos wants to merge13 commits intopython:main
base:main
Choose a base branch
Loading
fromdonBarbos:issue-130821
Open
Show file tree
Hide file tree
Changes fromall commits
Commits
Show all changes
13 commits
Select commitHold shift + click to select a range
a513ee8
Add type information to wrong type error messages
donBarbosMar 4, 2025
4d792e4
Use %T to format type names
donBarbosMar 5, 2025
d976676
Fix error message for methods return type
donBarbosApr 28, 2025
d811b4c
Revert "Fix error message for methods return type"
donBarbosApr 28, 2025
70d57c2
Use new message template
donBarbosApr 28, 2025
b6f75e4
Merge branch 'main' into issue-130821
donBarbosApr 28, 2025
390f941
Improve message and fix test
donBarbosApr 28, 2025
d2e54e6
Fix more methods
donBarbosApr 28, 2025
0ac8a1c
Escape parentheses in regex pattern to fix test match
donBarbosApr 28, 2025
59bca2d
Fix message for coroutine test
donBarbosApr 28, 2025
51a6c79
Add News entry
donBarbosApr 28, 2025
699b112
Update message template
donBarbosApr 28, 2025
06606e4
Merge branch 'main' into issue-130821
donBarbosMay 6, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletionsLib/test/test_coroutines.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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())

Expand DownExpand Up@@ -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()
Expand All@@ -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())

Expand DownExpand Up@@ -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, notint"):
self.assertEqual(foo().send(None), 1)


Expand Down
2 changes: 1 addition & 1 deletionLib/test/test_type_annotations.py
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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, notint"):
print(f.__annotations__)

f.__annotate__ = lambda x: {"x": x}
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
Enhance wrong type error messages and make them more consistent. Patch by
Semyon Moroz.
50 changes: 24 additions & 26 deletionsObjects/abstract.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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;
}
Expand All@@ -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 positive int", o);
return -1;
}
return res;
Expand DownExpand Up@@ -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;
}
Expand DownExpand Up@@ -1421,17 +1423,17 @@ _PyNumber_Index(PyObject *item)

if (!PyLong_Check(result)) {
PyErr_Format(PyExc_TypeError,
"__index__ returned non-int (type %.200s)",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I don't see much reason to change this error message either.

Copy link
ContributorAuthor

@donBarbosdonBarbosApr 29, 2025
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

I changed it to the more common way as you recommended elsewhere:__method__() must return an int, not ...
and added type info before method name, like for other methods

Py_TYPE(result)->tp_name);
"%T.__index__() must return anint, 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 anint, 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;
}
Expand DownExpand Up@@ -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 anint, 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 anint, 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;
}
Expand DownExpand Up@@ -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 afloat, 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;
}
Expand DownExpand Up@@ -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)",

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

Here I strongly prefer the old message. Iterable is not a type, it's a category of types.

Copy link
ContributorAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

what do you think about new message:"%T.%U() must return an iterable, not %T"

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;
Expand DownExpand Up@@ -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;
Expand All@@ -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;
Expand Down
8 changes: 4 additions & 4 deletionsObjects/bytesobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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 abytes, not %T",
v,result);
Py_DECREF(result);
return NULL;
}
Expand DownExpand Up@@ -2788,8 +2788,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 abytes, not %T",
x,bytes);
Py_DECREF(bytes);
return NULL;
}
Expand Down
8 changes: 4 additions & 4 deletionsObjects/complexobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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);
"%T.__complex__() must return acomplex, 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 acomplex, 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;
}
Expand Down
8 changes: 4 additions & 4 deletionsObjects/fileobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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)) {
Expand DownExpand Up@@ -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;
}
Expand Down
8 changes: 4 additions & 4 deletionsObjects/floatobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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 afloat, 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 afloat, 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;
}
Expand Down
5 changes: 3 additions & 2 deletionsObjects/funcobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -559,8 +559,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;
}
Expand Down
10 changes: 5 additions & 5 deletionsObjects/genobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1082,14 +1082,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);
}
}
Expand Down
5 changes: 3 additions & 2 deletionsObjects/iterobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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;
}
Expand Down
5 changes: 3 additions & 2 deletionsObjects/moduleobject.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1330,8 +1330,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);
Expand Down
10 changes: 4 additions & 6 deletionsObjects/object.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -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;
}
Expand DownExpand Up@@ -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;
}
Expand DownExpand Up@@ -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 abytes, not %T",
v,result);
Py_DECREF(result);
return NULL;
}
Expand Down
Loading
Loading

[8]ページ先頭

©2009-2025 Movatter.jp