Index: Python/bltinmodule.c =================================================================== --- Python/bltinmodule.c (revision 80673) +++ Python/bltinmodule.c (working copy) @@ -1746,6 +1746,39 @@ return -1; } +static PyObject * +get_range_argument(PyObject *arg, const char *name) +{ + PyObject *v; + PyNumberMethods *nb; + if (PyInt_Check(arg) || PyLong_Check(arg)) + return arg; + + if (PyFloat_Check(arg) || + (nb = Py_TYPE(arg)->tp_as_number) == NULL || + nb->nb_int == NULL) { + Py_DECREF(arg); + PyErr_Format(PyExc_TypeError, + "range() integer %s argument expected, got %s.", + name, arg->ob_type->tp_name); + return NULL; + } + + v = nb->nb_int(arg); + Py_DECREF(arg); + + if (v == NULL) + return NULL; + + if (PyInt_Check(v) || PyLong_Check(v)) + return v; + + Py_DECREF(v); + PyErr_SetString(PyExc_TypeError, + "nb_int should return int object"); + return NULL; +} + /* An extension of builtin_range() that handles the case when PyLong * arguments are given. */ static PyObject * @@ -1799,29 +1832,18 @@ Py_INCREF(istep); } - if (!PyInt_Check(ilow) && !PyLong_Check(ilow)) { - PyErr_Format(PyExc_TypeError, - "range() integer start argument expected, got %s.", - ilow->ob_type->tp_name); + if (!(ilow = get_range_argument(ilow, "start"))) goto Fail; - } - if (!PyInt_Check(ihigh) && !PyLong_Check(ihigh)) { - PyErr_Format(PyExc_TypeError, - "range() integer end argument expected, got %s.", - ihigh->ob_type->tp_name); + if (!(ihigh = get_range_argument(ihigh, "end"))) goto Fail; - } - if (!PyInt_Check(istep) && !PyLong_Check(istep)) { - PyErr_Format(PyExc_TypeError, - "range() integer step argument expected, got %s.", - istep->ob_type->tp_name); + if (!(istep = get_range_argument(istep, "step"))) goto Fail; - } if (PyObject_Cmp(istep, zero, &cmp_result) == -1) goto Fail; + if (cmp_result == 0) { PyErr_SetString(PyExc_ValueError, "range() step argument must not be zero"); @@ -1875,8 +1897,8 @@ return v; Fail: - Py_DECREF(ilow); - Py_DECREF(ihigh); + Py_XDECREF(ilow); + Py_XDECREF(ihigh); Py_XDECREF(istep); Py_DECREF(zero); Py_XDECREF(curnum); Index: Lib/test/test_builtin.py =================================================================== --- Lib/test/test_builtin.py (revision 80673) +++ Lib/test/test_builtin.py (working copy) @@ -1080,6 +1080,36 @@ self.assertRaises(OverflowError, range, -sys.maxint, sys.maxint) self.assertRaises(OverflowError, range, 0, 2*sys.maxint) + bignum = 2*sys.maxint + # Old-style user-defined class with __int__ method + class I0: + def __init__(self, n): + self.n = int(n) + def __int__(self): + return self.n + self.assertEqual(range(I0(bignum), I0(bignum + 1)), [bignum]) + + # New-style user-defined class with __int__ method + class I1(object): + def __init__(self, n): + self.n = int(n) + def __int__(self): + return self.n + self.assertEqual(range(I1(bignum), I1(bignum + 1)), [bignum]) + + # New-style user-defined class with failing __int__ method + class IX(object): + def __int__(self): + raise RuntimeError + self.assertRaises(RuntimeError, range, IX()) + + # New-style user-defined class with invalid __int__ method + class IN(object): + def __int__(self): + return "not a number" + self.assertRaises(TypeError, range, IN()) + + def test_input_and_raw_input(self): self.write_testfile() fp = open(TESTFN, 'r')