...
TypeError: Value after ** must be a mapping, not function
+ >>> class OnlyKeys:
+ ... def keys(self):
+ ... return ['key']
+ >>> h(**OnlyKeys())
+ Traceback (most recent call last):
+ ...
+ TypeError: 'OnlyKeys' object is not subscriptable
+
+ >>> class BrokenKeys:
+ ... def keys(self):
+ ... return 1
+ >>> h(**BrokenKeys())
+ Traceback (most recent call last):
+ ...
+ TypeError: test.test_extcall.BrokenKeys.keys() must return an iterable, not int
+
>>> dir(b=1, **{'b': 1})
Traceback (most recent call last):
...
"""
+def test_errors_in_iter():
+ """
+ >>> class A:
+ ... def __iter__(self):
+ ... raise exc
+ ...
+ >>> def f(*args, **kwargs): pass
+ >>> exc = ZeroDivisionError('some error')
+ >>> f(*A())
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> exc = AttributeError('some error')
+ >>> f(*A())
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> exc = TypeError('some error')
+ >>> f(*A())
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+ """
+
+def test_errors_in_next():
+ """
+ >>> class I:
+ ... def __iter__(self):
+ ... return self
+ ... def __next__(self):
+ ... raise exc
+ ...
+ >>> class A:
+ ... def __iter__(self):
+ ... return I()
+ ...
+
+ >>> def f(*args, **kwargs): pass
+ >>> exc = ZeroDivisionError('some error')
+ >>> f(*A())
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> exc = AttributeError('some error')
+ >>> f(*A())
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> exc = TypeError('some error')
+ >>> f(*A())
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+ """
+
+def test_errors_in_keys():
+ """
+ >>> class D:
+ ... def keys(self):
+ ... raise exc
+ ...
+ >>> def f(*args, **kwargs): pass
+ >>> exc = ZeroDivisionError('some error')
+ >>> f(**D())
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> exc = AttributeError('some error')
+ >>> f(**D())
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> exc = TypeError('some error')
+ >>> f(**D())
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+ """
+
+def test_errors_in_keys_next():
+ """
+ >>> class I:
+ ... def __iter__(self):
+ ... return self
+ ... def __next__(self):
+ ... raise exc
+ ...
+ >>> class D:
+ ... def keys(self):
+ ... return I()
+ ...
+ >>> def f(*args, **kwargs): pass
+ >>> exc = ZeroDivisionError('some error')
+ >>> f(**D())
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> exc = AttributeError('some error')
+ >>> f(**D())
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> exc = TypeError('some error')
+ >>> f(**D())
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+ """
+
+def test_errors_in_getitem():
+ """
+ >>> class D:
+ ... def keys(self):
+ ... return ['key']
+ ... def __getitem__(self, key):
+ ... raise exc
+ ...
+ >>> def f(*args, **kwargs): pass
+ >>> exc = ZeroDivisionError('some error')
+ >>> f(**D())
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> exc = AttributeError('some error')
+ >>> f(**D())
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> exc = TypeError('some error')
+ >>> f(**D())
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+ """
+
import doctest
import unittest
...
TypeError: 'list' object is not a mapping
+ >>> class OnlyKeys:
+ ... def keys(self):
+ ... return ['key']
+ >>> {**OnlyKeys()}
+ Traceback (most recent call last):
+ ...
+ TypeError: 'OnlyKeys' object is not subscriptable
+
+ >>> class BrokenKeys:
+ ... def keys(self):
+ ... return 1
+ >>> {**BrokenKeys()}
+ Traceback (most recent call last):
+ ...
+ TypeError: test.test_unpack_ex.BrokenKeys.keys() must return an iterable, not int
+
>>> len(eval("{" + ", ".join("**{{{}: {}}}".format(i, i)
... for i in range(1000)) + "}"))
1000
"""
+def test_errors_in_iter():
+ """
+ >>> class A:
+ ... def __iter__(self):
+ ... raise exc
+ ...
+ >>> exc = ZeroDivisionError('some error')
+ >>> [*A()]
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> {*A()}
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> exc = AttributeError('some error')
+ >>> [*A()]
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> {*A()}
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> exc = TypeError('some error')
+ >>> [*A()]
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+
+ >>> {*A()}
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+ """
+
+def test_errors_in_next():
+ """
+ >>> class I:
+ ... def __iter__(self):
+ ... return self
+ ... def __next__(self):
+ ... raise exc
+ ...
+ >>> class A:
+ ... def __iter__(self):
+ ... return I()
+ ...
+
+ >>> exc = ZeroDivisionError('some error')
+ >>> [*A()]
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> {*A()}
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> exc = AttributeError('some error')
+ >>> [*A()]
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> {*A()}
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> exc = TypeError('some error')
+ >>> [*A()]
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+
+ >>> {*A()}
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+ """
+
+def test_errors_in_keys():
+ """
+ >>> class D:
+ ... def keys(self):
+ ... raise exc
+ ...
+ >>> exc = ZeroDivisionError('some error')
+ >>> {**D()}
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> exc = AttributeError('some error')
+ >>> {**D()}
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> exc = TypeError('some error')
+ >>> {**D()}
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+ """
+
+def test_errors_in_keys_next():
+ """
+ >>> class I:
+ ... def __iter__(self):
+ ... return self
+ ... def __next__(self):
+ ... raise exc
+ ...
+ >>> class D:
+ ... def keys(self):
+ ... return I()
+ ...
+ >>> exc = ZeroDivisionError('some error')
+ >>> {**D()}
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> exc = AttributeError('some error')
+ >>> {**D()}
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> exc = TypeError('some error')
+ >>> {**D()}
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+ """
+
+def test_errors_in_getitem():
+ """
+ >>> class D:
+ ... def keys(self):
+ ... return ['key']
+ ... def __getitem__(self, key):
+ ... raise exc
+ ...
+ >>> exc = ZeroDivisionError('some error')
+ >>> {**D()}
+ Traceback (most recent call last):
+ ...
+ ZeroDivisionError: some error
+
+ >>> exc = AttributeError('some error')
+ >>> {**D()}
+ Traceback (most recent call last):
+ ...
+ AttributeError: some error
+
+ >>> exc = TypeError('some error')
+ >>> {**D()}
+ Traceback (most recent call last):
+ ...
+ TypeError: some error
+ """
+
__test__ = {'doctests' : doctests}
def load_tests(loader, tests, pattern):
--- /dev/null
+:exc:`AttributeError`\ s raised in :meth:`!keys` or :meth:`!__getitem__`
+during dictionary unpacking (``{**mymapping}`` or ``func(**mymapping)``) are
+no longer masked by :exc:`TypeError`.
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches) {
_PyFrame_SetStackPointer(frame, stack_pointer);
- _PyErr_Format(tstate, PyExc_TypeError,
- "'%.200s' object is not a mapping",
- Py_TYPE(update_o)->tp_name);
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ int has_keys = PyObject_HasAttrWithError(update_o, &_Py_ID(keys));
stack_pointer = _PyFrame_GetStackPointer(frame);
+ if (has_keys == 0) {
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "'%T' object is not a mapping",
+ update_o);
+ Py_DECREF(exc);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ }
+ else {
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ _PyErr_ChainExceptions1(exc);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ }
}
JUMP_TO_LABEL(error);
}
if (err < 0) {
int matches = _PyErr_ExceptionMatches(tstate, PyExc_AttributeError);
if (matches) {
- _PyErr_Format(tstate, PyExc_TypeError,
- "'%.200s' object is not a mapping",
- Py_TYPE(update_o)->tp_name);
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ int has_keys = PyObject_HasAttrWithError(update_o, &_Py_ID(keys));
+ if (has_keys == 0) {
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "'%T' object is not a mapping",
+ update_o);
+ Py_DECREF(exc);
+ }
+ else {
+ _PyErr_ChainExceptions1(exc);
+ }
}
ERROR_NO_POP();
}
* is not a mapping.
*/
if (_PyErr_ExceptionMatches(tstate, PyExc_AttributeError)) {
- _PyErr_Format(
- tstate, PyExc_TypeError,
- "Value after ** must be a mapping, not %.200s",
- Py_TYPE(kwargs)->tp_name);
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ int has_keys = PyObject_HasAttrWithError(kwargs, &_Py_ID(keys));
+ if (has_keys == 0) {
+ _PyErr_Format(
+ tstate, PyExc_TypeError,
+ "Value after ** must be a mapping, not %T",
+ kwargs);
+ Py_DECREF(exc);
+ }
+ else {
+ _PyErr_ChainExceptions1Tstate(tstate, exc);
+ }
}
else if (_PyErr_ExceptionMatches(tstate, PyExc_KeyError)) {
PyObject *exc = _PyErr_GetRaisedException(tstate);
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches) {
_PyFrame_SetStackPointer(frame, stack_pointer);
- _PyErr_Format(tstate, PyExc_TypeError,
- "'%.200s' object is not a mapping",
- Py_TYPE(update_o)->tp_name);
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ int has_keys = PyObject_HasAttrWithError(update_o, &_Py_ID(keys));
stack_pointer = _PyFrame_GetStackPointer(frame);
+ if (has_keys == 0) {
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "'%T' object is not a mapping",
+ update_o);
+ Py_DECREF(exc);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ }
+ else {
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ _PyErr_ChainExceptions1(exc);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ }
}
SET_CURRENT_CACHED_VALUES(0);
JUMP_TO_ERROR();
stack_pointer = _PyFrame_GetStackPointer(frame);
if (matches) {
_PyFrame_SetStackPointer(frame, stack_pointer);
- _PyErr_Format(tstate, PyExc_TypeError,
- "'%.200s' object is not a mapping",
- Py_TYPE(update_o)->tp_name);
+ PyObject *exc = _PyErr_GetRaisedException(tstate);
+ int has_keys = PyObject_HasAttrWithError(update_o, &_Py_ID(keys));
stack_pointer = _PyFrame_GetStackPointer(frame);
+ if (has_keys == 0) {
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ _PyErr_Format(tstate, PyExc_TypeError,
+ "'%T' object is not a mapping",
+ update_o);
+ Py_DECREF(exc);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ }
+ else {
+ _PyFrame_SetStackPointer(frame, stack_pointer);
+ _PyErr_ChainExceptions1(exc);
+ stack_pointer = _PyFrame_GetStackPointer(frame);
+ }
}
JUMP_TO_LABEL(error);
}