gh-136327: Fix inconsistent `TypeError` messages regarding invalid values after * and ** (#136395)

This commit is contained in:
Tapeline
2025-10-25 00:12:49 +05:00
committed by GitHub
parent b3c713a0af
commit 4f8e7b5ac5
4 changed files with 23 additions and 36 deletions

View File

@@ -1882,7 +1882,7 @@ class AbstractPicklingErrorTests:
with self.assertRaises(TypeError) as cm:
self.dumps(obj, proto)
self.assertEqual(str(cm.exception),
'functools.partial() argument after ** must be a mapping, not list')
'Value after ** must be a mapping, not list')
self.assertEqual(cm.exception.__notes__, [
'when serializing test.pickletester.REX object'])
else:

View File

@@ -137,7 +137,7 @@ Verify clearing of SF bug #733667
>>> g(*Nothing())
Traceback (most recent call last):
...
TypeError: test.test_extcall.g() argument after * must be an iterable, not Nothing
TypeError: Value after * must be an iterable, not Nothing
>>> class Nothing:
... def __len__(self): return 5
@@ -146,7 +146,7 @@ Verify clearing of SF bug #733667
>>> g(*Nothing())
Traceback (most recent call last):
...
TypeError: test.test_extcall.g() argument after * must be an iterable, not Nothing
TypeError: Value after * must be an iterable, not Nothing
>>> class Nothing():
... def __len__(self): return 5
@@ -266,7 +266,7 @@ What about willful misconduct?
>>> h(*h)
Traceback (most recent call last):
...
TypeError: test.test_extcall.h() argument after * must be an iterable, not function
TypeError: Value after * must be an iterable, not function
>>> h(1, *h)
Traceback (most recent call last):
@@ -281,55 +281,53 @@ What about willful misconduct?
>>> dir(*h)
Traceback (most recent call last):
...
TypeError: dir() argument after * must be an iterable, not function
TypeError: Value after * must be an iterable, not function
>>> nothing = None
>>> nothing(*h)
Traceback (most recent call last):
...
TypeError: None argument after * must be an iterable, \
not function
TypeError: Value after * must be an iterable, not function
>>> h(**h)
Traceback (most recent call last):
...
TypeError: test.test_extcall.h() argument after ** must be a mapping, not function
TypeError: Value after ** must be a mapping, not function
>>> h(**[])
Traceback (most recent call last):
...
TypeError: test.test_extcall.h() argument after ** must be a mapping, not list
TypeError: Value after ** must be a mapping, not list
>>> h(a=1, **h)
Traceback (most recent call last):
...
TypeError: test.test_extcall.h() argument after ** must be a mapping, not function
TypeError: Value after ** must be a mapping, not function
>>> h(a=1, **[])
Traceback (most recent call last):
...
TypeError: test.test_extcall.h() argument after ** must be a mapping, not list
TypeError: Value after ** must be a mapping, not list
>>> h(**{'a': 1}, **h)
Traceback (most recent call last):
...
TypeError: test.test_extcall.h() argument after ** must be a mapping, not function
TypeError: Value after ** must be a mapping, not function
>>> h(**{'a': 1}, **[])
Traceback (most recent call last):
...
TypeError: test.test_extcall.h() argument after ** must be a mapping, not list
TypeError: Value after ** must be a mapping, not list
>>> dir(**h)
Traceback (most recent call last):
...
TypeError: dir() argument after ** must be a mapping, not function
TypeError: Value after ** must be a mapping, not function
>>> nothing(**h)
Traceback (most recent call last):
...
TypeError: None argument after ** must be a mapping, \
not function
TypeError: Value after ** must be a mapping, not function
>>> dir(b=1, **{'b': 1})
Traceback (most recent call last):

View File

@@ -0,0 +1,2 @@
Errors when calling functions with invalid values after ``*`` and ``**`` now do not
include the function name. Patch by Ilia Solin.

View File

@@ -3272,17 +3272,9 @@ int
_Py_Check_ArgsIterable(PyThreadState *tstate, PyObject *func, PyObject *args)
{
if (Py_TYPE(args)->tp_iter == NULL && !PySequence_Check(args)) {
/* _Py_Check_ArgsIterable() may be called with a live exception:
* clear it to prevent calling _PyObject_FunctionStr() with an
* exception set. */
_PyErr_Clear(tstate);
PyObject *funcstr = _PyObject_FunctionStr(func);
if (funcstr != NULL) {
_PyErr_Format(tstate, PyExc_TypeError,
"%U argument after * must be an iterable, not %.200s",
funcstr, Py_TYPE(args)->tp_name);
Py_DECREF(funcstr);
}
_PyErr_Format(tstate, PyExc_TypeError,
"Value after * must be an iterable, not %.200s",
Py_TYPE(args)->tp_name);
return -1;
}
return 0;
@@ -3298,15 +3290,10 @@ _PyEval_FormatKwargsError(PyThreadState *tstate, PyObject *func, PyObject *kwarg
* is not a mapping.
*/
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
_PyErr_Clear(tstate);
PyObject *funcstr = _PyObject_FunctionStr(func);
if (funcstr != NULL) {
_PyErr_Format(
tstate, PyExc_TypeError,
"%U argument after ** must be a mapping, not %.200s",
funcstr, Py_TYPE(kwargs)->tp_name);
Py_DECREF(funcstr);
}
_PyErr_Format(
tstate, PyExc_TypeError,
"Value after ** must be a mapping, not %.200s",
Py_TYPE(kwargs)->tp_name);
}
else if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
PyObject *exc = _PyErr_GetRaisedException(tstate);