Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
16 changes: 16 additions & 0 deletions Lib/test/test_extcall.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,10 @@
Traceback (most recent call last):
...
TypeError: myerror
>>> g(*range(1), *(broken() for i in range(1)))
Traceback (most recent call last):
...
TypeError: myerror

>>> class BrokenIterable1:
... def __iter__(self):
Expand All @@ -172,6 +176,10 @@
Traceback (most recent call last):
...
TypeError: myerror
>>> g(*range(1), *BrokenIterable1())
Traceback (most recent call last):
...
TypeError: myerror

>>> class BrokenIterable2:
... def __iter__(self):
Expand All @@ -182,6 +190,10 @@
Traceback (most recent call last):
...
TypeError: myerror
>>> g(*range(1), *BrokenIterable2())
Traceback (most recent call last):
...
TypeError: myerror

>>> class BrokenSequence:
... def __getitem__(self, idx):
Expand All @@ -191,6 +203,10 @@
Traceback (most recent call last):
...
TypeError: myerror
>>> g(*range(1), *BrokenSequence())
Traceback (most recent call last):
...
TypeError: myerror

Make sure that the function doesn't stomp the dictionary

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
Avoid masking original TypeError in call with * unpacking when other
arguments are passed.
63 changes: 34 additions & 29 deletions Python/ceval.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@ static void format_exc_unbound(PyCodeObject *co, int oparg);
static PyObject * unicode_concatenate(PyObject *, PyObject *,
PyFrameObject *, const _Py_CODEUNIT *);
static PyObject * special_lookup(PyObject *, _Py_Identifier *);
static int check_args_iterable(PyObject *func, PyObject *vararg);
static void format_kwargs_mapping_error(PyObject *func, PyObject *kwargs);

#define NAME_ERROR_MSG \
"name '%.200s' is not defined"
Expand Down Expand Up @@ -2512,14 +2514,9 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
none_val = _PyList_Extend((PyListObject *)sum, PEEK(i));
if (none_val == NULL) {
if (opcode == BUILD_TUPLE_UNPACK_WITH_CALL &&
PyErr_ExceptionMatches(PyExc_TypeError)) {
PyObject *func = PEEK(1 + oparg);
PyErr_Format(PyExc_TypeError,
"%.200s%.200s argument after * "
"must be an iterable, not %.200s",
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func),
PEEK(i)->ob_type->tp_name);
PyErr_ExceptionMatches(PyExc_TypeError))
{
check_args_iterable(PEEK(1 + oparg), PEEK(i));
}
Py_DECREF(sum);
goto error;
Expand Down Expand Up @@ -2732,12 +2729,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
if (_PyDict_MergeEx(sum, arg, 2) < 0) {
PyObject *func = PEEK(2 + oparg);
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Format(PyExc_TypeError,
"%.200s%.200s argument after ** "
"must be a mapping, not %.200s",
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func),
arg->ob_type->tp_name);
format_kwargs_mapping_error(func, arg);
}
else if (PyErr_ExceptionMatches(PyExc_KeyError)) {
PyObject *exc, *val, *tb;
Expand Down Expand Up @@ -3390,13 +3382,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
* is not a mapping.
*/
if (PyErr_ExceptionMatches(PyExc_AttributeError)) {
func = SECOND();
PyErr_Format(PyExc_TypeError,
"%.200s%.200s argument after ** "
"must be a mapping, not %.200s",
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func),
kwargs->ob_type->tp_name);
format_kwargs_mapping_error(SECOND(), kwargs);
}
Py_DECREF(kwargs);
goto error;
Expand All @@ -3409,14 +3395,7 @@ _PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
callargs = POP();
func = TOP();
if (!PyTuple_CheckExact(callargs)) {
if (Py_TYPE(callargs)->tp_iter == NULL &&
!PySequence_Check(callargs)) {
PyErr_Format(PyExc_TypeError,
"%.200s%.200s argument after * "
"must be an iterable, not %.200s",
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func),
callargs->ob_type->tp_name);
if (check_args_iterable(func, callargs) < 0) {
Py_DECREF(callargs);
goto error;
}
Expand Down Expand Up @@ -5178,6 +5157,32 @@ import_all_from(PyObject *locals, PyObject *v)
return err;
}

static int
check_args_iterable(PyObject *func, PyObject *args)
{
if (args->ob_type->tp_iter == NULL && !PySequence_Check(args)) {
PyErr_Format(PyExc_TypeError,
"%.200s%.200s argument after * "
"must be an iterable, not %.200s",
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func),
args->ob_type->tp_name);
return -1;
}
return 0;
}

static void
format_kwargs_mapping_error(PyObject *func, PyObject *kwargs)
{
PyErr_Format(PyExc_TypeError,
"%.200s%.200s argument after ** "
"must be a mapping, not %.200s",
PyEval_GetFuncName(func),
PyEval_GetFuncDesc(func),
kwargs->ob_type->tp_name);
}

static void
format_exc_check_arg(PyObject *exc, const char *format_str, PyObject *obj)
{
Expand Down