Patch #1507676: improve exception messages in abstract.c, object.c and typeobject.c.
diff --git a/Lib/test/test_genexps.py b/Lib/test/test_genexps.py
index e414757..2598a79 100644
--- a/Lib/test/test_genexps.py
+++ b/Lib/test/test_genexps.py
@@ -109,7 +109,7 @@
Traceback (most recent call last):
File "<pyshell#4>", line 1, in -toplevel-
(i for i in 6)
- TypeError: iteration over non-sequence
+ TypeError: 'int' object is not iterable
Verify late binding for the outermost if-expression
diff --git a/Objects/abstract.c b/Objects/abstract.c
index e85fe20..d16660b 100644
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -14,9 +14,9 @@
/* Shorthands to return certain errors */
static PyObject *
-type_error(const char *msg)
+type_error(const char *msg, PyObject *obj)
{
- PyErr_SetString(PyExc_TypeError, msg);
+ PyErr_Format(PyExc_TypeError, msg, obj->ob_type->tp_name);
return NULL;
}
@@ -130,10 +130,11 @@
return PySequence_GetItem(o, key_value);
}
else if (o->ob_type->tp_as_sequence->sq_item)
- return type_error("sequence index must be integer");
+ return type_error("sequence index must "
+ "be integer, not '%.200s'", key);
}
- return type_error("unsubscriptable object");
+ return type_error("'%.200s' object is unsubscriptable", o);
}
int
@@ -158,12 +159,13 @@
return PySequence_SetItem(o, key_value, value);
}
else if (o->ob_type->tp_as_sequence->sq_ass_item) {
- type_error("sequence index must be integer");
+ type_error("sequence index must be "
+ "integer, not '%.200s'", key);
return -1;
}
}
- type_error("object does not support item assignment");
+ type_error("'%.200s' object does not support item assignment", o);
return -1;
}
@@ -189,12 +191,13 @@
return PySequence_DelItem(o, key_value);
}
else if (o->ob_type->tp_as_sequence->sq_ass_item) {
- type_error("sequence index must be integer");
+ type_error("sequence index must be "
+ "integer, not '%.200s'", key);
return -1;
}
}
- type_error("object does not support item deletion");
+ type_error("'%.200s' object does not support item deletion", o);
return -1;
}
@@ -435,7 +438,8 @@
binop_type_error(PyObject *v, PyObject *w, const char *op_name)
{
PyErr_Format(PyExc_TypeError,
- "unsupported operand type(s) for %s: '%s' and '%s'",
+ "unsupported operand type(s) for %.100s: "
+ "'%.100s' and '%.100s'",
op_name,
v->ob_type->tp_name,
w->ob_type->tp_name);
@@ -601,14 +605,14 @@
PyErr_Format(
PyExc_TypeError,
"unsupported operand type(s) for ** or pow(): "
- "'%s' and '%s'",
+ "'%.100s' and '%.100s'",
v->ob_type->tp_name,
w->ob_type->tp_name);
else
PyErr_Format(
PyExc_TypeError,
"unsupported operand type(s) for pow(): "
- "'%s', '%s', '%s'",
+ "'%.100s', '%.100s', '%.100s'",
v->ob_type->tp_name,
w->ob_type->tp_name,
z->ob_type->tp_name);
@@ -656,8 +660,8 @@
return NULL;
}
else {
- return type_error(
- "can't multiply sequence by non-int");
+ return type_error("can't multiply sequence by "
+ "non-int of type '%.200s'", n);
}
return (*repeatfunc)(seq, count);
}
@@ -870,7 +874,7 @@
if (m && m->nb_negative)
return (*m->nb_negative)(o);
- return type_error("bad operand type for unary -");
+ return type_error("bad operand type for unary -: '%.200s'", o);
}
PyObject *
@@ -884,7 +888,7 @@
if (m && m->nb_positive)
return (*m->nb_positive)(o);
- return type_error("bad operand type for unary +");
+ return type_error("bad operand type for unary +: '%.200s'", o);
}
PyObject *
@@ -898,7 +902,7 @@
if (m && m->nb_invert)
return (*m->nb_invert)(o);
- return type_error("bad operand type for unary ~");
+ return type_error("bad operand type for unary ~: '%.200s'", o);
}
PyObject *
@@ -912,7 +916,7 @@
if (m && m->nb_absolute)
return m->nb_absolute(o);
- return type_error("bad operand type for abs()");
+ return type_error("bad operand type for abs(): '%.200s'", o);
}
/* Add a check for embedded NULL-bytes in the argument. */
@@ -992,7 +996,8 @@
if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len))
return int_from_string((char*)buffer, buffer_len);
- return type_error("int() argument must be a string or a number");
+ return type_error("int() argument must be a string or a "
+ "number, not '%.200s'", o);
}
/* Add a check for embedded NULL-bytes in the argument. */
@@ -1054,7 +1059,8 @@
if (!PyObject_AsCharBuffer(o, &buffer, &buffer_len))
return long_from_string(buffer, buffer_len);
- return type_error("long() argument must be a string or a number");
+ return type_error("long() argument must be a string or a "
+ "number, not '%.200s'", o);
}
PyObject *
@@ -1108,7 +1114,7 @@
if (m && m->sq_length)
return m->sq_length(s);
- type_error("len() of unsized object");
+ type_error("non-sequence object of type '%.200s' has no len()", s);
return -1;
}
@@ -1141,7 +1147,7 @@
return result;
Py_DECREF(result);
}
- return type_error("object can't be concatenated");
+ return type_error("'%.200s' object can't be concatenated", s);
}
PyObject *
@@ -1170,7 +1176,7 @@
return result;
Py_DECREF(result);
}
- return type_error("object can't be repeated");
+ return type_error("'%.200s' object can't be repeated", o);
}
PyObject *
@@ -1194,7 +1200,7 @@
return result;
Py_DECREF(result);
}
- return type_error("object can't be concatenated");
+ return type_error("'%.200s' object can't be concatenated", s);
}
PyObject *
@@ -1223,7 +1229,7 @@
return result;
Py_DECREF(result);
}
- return type_error("object can't be repeated");
+ return type_error("'%.200s' object can't be repeated", o);
}
PyObject *
@@ -1247,7 +1253,7 @@
return m->sq_item(s, i);
}
- return type_error("unindexable object");
+ return type_error("'%.200s' object is unindexable", s);
}
PyObject *
@@ -1282,7 +1288,7 @@
return res;
}
- return type_error("unsliceable object");
+ return type_error("'%.200s' object is unsliceable", s);
}
int
@@ -1308,7 +1314,7 @@
return m->sq_ass_item(s, i, o);
}
- type_error("object does not support item assignment");
+ type_error("'%.200s' object does not support item assignment", s);
return -1;
}
@@ -1335,7 +1341,7 @@
return m->sq_ass_item(s, i, (PyObject *)NULL);
}
- type_error("object doesn't support item deletion");
+ type_error("'%.200s' object doesn't support item deletion", s);
return -1;
}
@@ -1374,7 +1380,7 @@
return res;
}
- type_error("object doesn't support slice assignment");
+ type_error("'%.200s' object doesn't support slice assignment", s);
return -1;
}
@@ -1403,7 +1409,7 @@
}
return m->sq_ass_slice(s, i1, i2, (PyObject *)NULL);
}
- type_error("object doesn't support slice deletion");
+ type_error("'%.200s' object doesn't support slice deletion", s);
return -1;
}
@@ -1534,7 +1540,7 @@
it = PyObject_GetIter(v);
if (it == NULL) {
if (PyErr_ExceptionMatches(PyExc_TypeError))
- return type_error(m);
+ PyErr_SetString(PyExc_TypeError, m);
return NULL;
}
@@ -1564,7 +1570,7 @@
it = PyObject_GetIter(seq);
if (it == NULL) {
- type_error("iterable argument required");
+ type_error("argument of type '%.200s' is not iterable", seq);
return -1;
}
@@ -1699,7 +1705,7 @@
if (m && m->mp_length)
return m->mp_length(o);
- type_error("len() of unsized object");
+ type_error("non-mapping object of type '%.200s' has no len()", o);
return -1;
}
@@ -1807,7 +1813,7 @@
"NULL result without error in PyObject_Call");
return result;
}
- PyErr_Format(PyExc_TypeError, "'%s' object is not callable",
+ PyErr_Format(PyExc_TypeError, "'%.200s' object is not callable",
func->ob_type->tp_name);
return NULL;
}
@@ -1896,7 +1902,7 @@
}
if (!PyCallable_Check(func)) {
- type_error("call of non-callable attribute");
+ type_error("attribute of type '%.200s' is not callable", func);
goto exit;
}
@@ -1935,7 +1941,7 @@
}
if (!PyCallable_Check(func)) {
- type_error("call of non-callable attribute");
+ type_error("attribute of type '%.200s' is not callable", func);
goto exit;
}
@@ -2287,9 +2293,7 @@
if (f == NULL) {
if (PySequence_Check(o))
return PySeqIter_New(o);
- PyErr_SetString(PyExc_TypeError,
- "iteration over non-sequence");
- return NULL;
+ return type_error("'%.200s' object is not iterable", o);
}
else {
PyObject *res = (*f)(o);
diff --git a/Objects/object.c b/Objects/object.c
index 59d3960..73c8941 100644
--- a/Objects/object.c
+++ b/Objects/object.c
@@ -1068,7 +1068,8 @@
return _Py_HashPointer(v); /* Use address as hash value */
}
/* If there's a cmp but no hash defined, the object can't be hashed */
- PyErr_SetString(PyExc_TypeError, "unhashable type");
+ PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'",
+ v->ob_type->tp_name);
return -1;
}
@@ -1133,8 +1134,9 @@
else
#endif
{
- PyErr_SetString(PyExc_TypeError,
- "attribute name must be string");
+ PyErr_Format(PyExc_TypeError,
+ "attribute name must be string, not '%.200s'",
+ name->ob_type->tp_name);
return NULL;
}
}
@@ -1179,8 +1181,9 @@
else
#endif
{
- PyErr_SetString(PyExc_TypeError,
- "attribute name must be string");
+ PyErr_Format(PyExc_TypeError,
+ "attribute name must be string, not '%.200s'",
+ name->ob_type->tp_name);
return -1;
}
}
@@ -1277,8 +1280,9 @@
else
#endif
{
- PyErr_SetString(PyExc_TypeError,
- "attribute name must be string");
+ PyErr_Format(PyExc_TypeError,
+ "attribute name must be string, not '%.200s'",
+ name->ob_type->tp_name);
return NULL;
}
}
@@ -1399,8 +1403,9 @@
else
#endif
{
- PyErr_SetString(PyExc_TypeError,
- "attribute name must be string");
+ PyErr_Format(PyExc_TypeError,
+ "attribute name must be string, not '%.200s'",
+ name->ob_type->tp_name);
return -1;
}
}
@@ -1450,7 +1455,7 @@
if (descr == NULL) {
PyErr_Format(PyExc_AttributeError,
- "'%.50s' object has no attribute '%.400s'",
+ "'%.100s' object has no attribute '%.200s'",
tp->tp_name, PyString_AS_STRING(name));
goto done;
}
@@ -1773,8 +1778,9 @@
assert(result);
if (!PyList_Check(result)) {
- PyErr_SetString(PyExc_TypeError,
- "Expected keys() to be a list.");
+ PyErr_Format(PyExc_TypeError,
+ "Expected keys() to be a list, not '%.200s'",
+ result->ob_type->tp_name);
goto error;
}
if (PyList_Sort(result) != 0)
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 0881ab1..439676f 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -1470,8 +1470,9 @@
return -1;
}
if (value != NULL && !PyDict_Check(value)) {
- PyErr_SetString(PyExc_TypeError,
- "__dict__ must be set to a dictionary");
+ PyErr_Format(PyExc_TypeError,
+ "__dict__ must be set to a dictionary, "
+ "not a '%.200s'", value->ob_type->tp_name);
return -1;
}
dict = *dictptr;
@@ -1534,8 +1535,9 @@
Py_ssize_t i, n;
if (!PyString_Check(s)) {
- PyErr_SetString(PyExc_TypeError,
- "__slots__ must be strings");
+ PyErr_Format(PyExc_TypeError,
+ "__slots__ items must be strings, not '%.200s'",
+ s->ob_type->tp_name);
return 0;
}
p = (unsigned char *) PyString_AS_STRING(s);
@@ -2575,8 +2577,9 @@
args = PyObject_CallObject(getnewargs, NULL);
Py_DECREF(getnewargs);
if (args != NULL && !PyTuple_Check(args)) {
- PyErr_SetString(PyExc_TypeError,
- "__getnewargs__ should return a tuple");
+ PyErr_Format(PyExc_TypeError,
+ "__getnewargs__ should return a tuple, "
+ "not '%.200s'", args->ob_type->tp_name);
goto end;
}
}
@@ -4352,8 +4355,9 @@
result = temp->ob_type->tp_as_number->nb_index(temp);
}
else {
- PyErr_SetString(PyExc_TypeError,
- "__index__ must return an int or a long");
+ PyErr_Format(PyExc_TypeError,
+ "__index__ must return an int or a long, "
+ "not '%.200s'", temp->ob_type->tp_name);
result = -1;
}
Py_DECREF(temp);
@@ -4564,8 +4568,9 @@
func = lookup_method(self, "__cmp__", &cmp_str);
}
if (func != NULL) {
+ PyErr_Format(PyExc_TypeError, "unhashable type: '%.200s'",
+ self->ob_type->tp_name);
Py_DECREF(func);
- PyErr_SetString(PyExc_TypeError, "unhashable type");
return -1;
}
PyErr_Clear();
@@ -4742,8 +4747,9 @@
PyErr_Clear();
func = lookup_method(self, "__getitem__", &getitem_str);
if (func == NULL) {
- PyErr_SetString(PyExc_TypeError,
- "iteration over non-sequence");
+ PyErr_Format(PyExc_TypeError,
+ "'%.200s' object is not iterable",
+ self->ob_type->tp_name);
return NULL;
}
Py_DECREF(func);
@@ -4816,8 +4822,9 @@
if (res == NULL)
return -1;
if (res != Py_None) {
- PyErr_SetString(PyExc_TypeError,
- "__init__() should return None");
+ PyErr_Format(PyExc_TypeError,
+ "__init__() should return None, not '%.200s'",
+ res->ob_type->tp_name);
Py_DECREF(res);
return -1;
}