Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit b594422

Browse files
committed
Issue #4806: Avoid masking original TypeError in call with * unpacking
Based on patch by Hagen Fürstenau and Daniel Urban.
1 parent 4c5ad94 commit b594422

3 files changed

Lines changed: 58 additions & 13 deletions

File tree

Lib/test/test_extcall.py

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@
114114
>>> g(*Nothing())
115115
Traceback (most recent call last):
116116
...
117-
TypeError: g() argument after * must be a sequence, not Nothing
117+
TypeError: g() argument after * must be an iterable, not Nothing
118118
119119
>>> class Nothing:
120120
... def __len__(self): return 5
@@ -123,7 +123,7 @@
123123
>>> g(*Nothing())
124124
Traceback (most recent call last):
125125
...
126-
TypeError: g() argument after * must be a sequence, not Nothing
126+
TypeError: g() argument after * must be an iterable, not Nothing
127127
128128
>>> class Nothing():
129129
... def __len__(self): return 5
@@ -149,6 +149,45 @@
149149
>>> g(*Nothing())
150150
0 (1, 2, 3) {}
151151
152+
Check for issue #4806: Does a TypeError in a generator get propagated with the
153+
right error message? (Also check with other iterables.)
154+
155+
>>> def broken(): raise TypeError("myerror")
156+
...
157+
158+
>>> g(*(broken() for i in range(1)))
159+
Traceback (most recent call last):
160+
...
161+
TypeError: myerror
162+
163+
>>> class BrokenIterable1:
164+
... def __iter__(self):
165+
... raise TypeError('myerror')
166+
...
167+
>>> g(*BrokenIterable1())
168+
Traceback (most recent call last):
169+
...
170+
TypeError: myerror
171+
172+
>>> class BrokenIterable2:
173+
... def __iter__(self):
174+
... yield 0
175+
... raise TypeError('myerror')
176+
...
177+
>>> g(*BrokenIterable2())
178+
Traceback (most recent call last):
179+
...
180+
TypeError: myerror
181+
182+
>>> class BrokenSequence:
183+
... def __getitem__(self, idx):
184+
... raise TypeError('myerror')
185+
...
186+
>>> g(*BrokenSequence())
187+
Traceback (most recent call last):
188+
...
189+
TypeError: myerror
190+
152191
Make sure that the function doesn't stomp the dictionary
153192
154193
>>> d = {'a': 1, 'b': 2, 'c': 3}
@@ -188,17 +227,17 @@
188227
>>> h(*h)
189228
Traceback (most recent call last):
190229
...
191-
TypeError: h() argument after * must be a sequence, not function
230+
TypeError: h() argument after * must be an iterable, not function
192231
193232
>>> dir(*h)
194233
Traceback (most recent call last):
195234
...
196-
TypeError: dir() argument after * must be a sequence, not function
235+
TypeError: dir() argument after * must be an iterable, not function
197236
198237
>>> None(*h)
199238
Traceback (most recent call last):
200239
...
201-
TypeError: NoneType object argument after * must be a sequence, \
240+
TypeError: NoneType object argument after * must be an iterable, \
202241
not function
203242
204243
>>> h(**h)

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ Release date: tba
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #4806: Avoid masking the original TypeError exception when using star
14+
(*) unpacking in function calls. Based on patch by Hagen Fürstenau and
15+
Daniel Urban.
16+
1317
- Issue #26154: Add a new private _PyThreadState_UncheckedGet() function to get
1418
the current Python thread state, but don't issue a fatal error if it is NULL.
1519
This new function must be used instead of accessing directly the

Python/ceval.c

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4935,16 +4935,18 @@ ext_do_call(PyObject *func, PyObject ***pp_stack, int flags, int na, int nk)
49354935
stararg = EXT_POP(*pp_stack);
49364936
if (!PyTuple_Check(stararg)) {
49374937
PyObject *t = NULL;
4938+
if (Py_TYPE(stararg)->tp_iter == NULL &&
4939+
!PySequence_Check(stararg)) {
4940+
PyErr_Format(PyExc_TypeError,
4941+
"%.200s%.200s argument after * "
4942+
"must be an iterable, not %.200s",
4943+
PyEval_GetFuncName(func),
4944+
PyEval_GetFuncDesc(func),
4945+
stararg->ob_type->tp_name);
4946+
goto ext_call_fail;
4947+
}
49384948
t = PySequence_Tuple(stararg);
49394949
if (t == NULL) {
4940-
if (PyErr_ExceptionMatches(PyExc_TypeError)) {
4941-
PyErr_Format(PyExc_TypeError,
4942-
"%.200s%.200s argument after * "
4943-
"must be a sequence, not %.200s",
4944-
PyEval_GetFuncName(func),
4945-
PyEval_GetFuncDesc(func),
4946-
stararg->ob_type->tp_name);
4947-
}
49484950
goto ext_call_fail;
49494951
}
49504952
Py_DECREF(stararg);

0 commit comments

Comments
 (0)