Index: Objects/typeobject.c =================================================================== --- Objects/typeobject.c (revision 66159) +++ Objects/typeobject.c (working copy) @@ -4630,13 +4630,19 @@ static PyObject *len_str; PyObject *res = call_method(self, "__len__", &len_str, "()"); Py_ssize_t len; + PyObject *err; if (res == NULL) return -1; - len = PyLong_AsSsize_t(res); + len = PyNumber_AsSsize_t(res, NULL); Py_DECREF(res); if (len < 0) { - if (!PyErr_Occurred()) + if ((err = PyErr_Occurred())) { + if (PyErr_GivenExceptionMatches(err, PyExc_TypeError)) + PyErr_SetString(PyExc_TypeError, + "__len__() should return an integer"); + } + else PyErr_SetString(PyExc_ValueError, "__len__() should return >= 0"); return -1; Index: Lib/test/test_builtin.py =================================================================== --- Lib/test/test_builtin.py (revision 66159) +++ Lib/test/test_builtin.py (working copy) @@ -623,6 +623,16 @@ def __len__(self): raise ValueError self.assertRaises(ValueError, len, BadSeq()) + class ReturnTypeCheck: + def __init__(self, value): + self.value = value + def __len__(self): + return self.value + self.assertRaises(TypeError, len, ReturnTypeCheck("foo")) + self.assertRaises(TypeError, len, ReturnTypeCheck(.1)) + self.assertRaises(ValueError, len, ReturnTypeCheck(-1)) + self.assertRaises(ValueError, len, ReturnTypeCheck(-1<<50)) + self.assertEqual(len(ReturnTypeCheck(1<<50)), sys.maxsize) def test_map(self): self.assertEqual(