Index: Objects/rangeobject.c =================================================================== --- Objects/rangeobject.c (revision 66146) +++ Objects/rangeobject.c (working copy) @@ -14,6 +14,7 @@ PyObject *start; PyObject *stop; PyObject *step; + Py_ssize_t length; } rangeobject; /* Helper function for validating step. Always returns a new reference or @@ -43,6 +44,28 @@ return step; } +static Py_ssize_t +range_compute_length(PyObject *start, PyObject *stop, PyObject *step); + +static rangeobject * +make_range_object(PyTypeObject *type, PyObject *start, + PyObject *stop, PyObject *step) +{ + rangeobject *obj = NULL; + Py_ssize_t length; + length = range_compute_length(start, stop, step); + if (length < 0) + return NULL; + obj = PyObject_New(rangeobject, type); + if (obj == NULL) + return NULL; + obj->start = start; + obj->stop = stop; + obj->step = step; + obj->length = length; + return obj; +} + /* XXX(nnorwitz): should we error check if the user passes any empty ranges? range(-10) range(0, -5) @@ -51,7 +74,7 @@ static PyObject * range_new(PyTypeObject *type, PyObject *args, PyObject *kw) { - rangeobject *obj = NULL; + rangeobject *obj; PyObject *start = NULL, *stop = NULL, *step = NULL; if (!_PyArg_NoKeywords("range()", kw)) @@ -81,14 +104,9 @@ goto Fail; } - obj = PyObject_New(rangeobject, &PyRange_Type); - if (obj == NULL) - goto Fail; - obj->start = start; - obj->stop = stop; - obj->step = step; - return (PyObject *) obj; - + obj = make_range_object(type, start, stop, step); + if (obj != NULL) + return (PyObject *) obj; Fail: Py_XDECREF(start); Py_XDECREF(stop); @@ -99,7 +117,7 @@ PyDoc_STRVAR(range_doc, "range([start,] stop[, step]) -> range object\n\ \n\ -Returns an iterator that generates the numbers in the range on demand."); +Returns a virtual sequence of numbers from start to stop by step."); static void range_dealloc(rangeobject *r) @@ -116,16 +134,16 @@ * Arguments MUST return 1 with either PyLong_Check() or * PyLong_Check(). Return -1 when there is an error. */ -static PyObject* -range_length_obj(rangeobject *r) +static Py_ssize_t +range_compute_length(PyObject *start, PyObject *stop, PyObject *step) { /* ------------------------------------------------------------- Algorithm is equal to that of get_len_of_range(), but it operates on PyObjects (which are assumed to be PyLong or PyInt objects). ---------------------------------------------------------------*/ + Py_ssize_t length; int cmp_result, cmp_call; PyObject *lo, *hi; - PyObject *step = NULL; PyObject *diff = NULL; PyObject *one = NULL; PyObject *tmp1 = NULL, *tmp2 = NULL, *result; @@ -133,30 +151,29 @@ PyObject *zero = PyLong_FromLong(0); if (zero == NULL) - return NULL; - cmp_call = PyObject_Cmp(r->step, zero, &cmp_result); + return -1; + cmp_call = PyObject_Cmp(step, zero, &cmp_result); Py_DECREF(zero); if (cmp_call == -1) - return NULL; + return -1; assert(cmp_result != 0); if (cmp_result > 0) { - lo = r->start; - hi = r->stop; - step = r->step; + lo = start; + hi = stop; Py_INCREF(step); } else { - lo = r->stop; - hi = r->start; - step = PyNumber_Negative(r->step); + lo = stop; + hi = start; + step = PyNumber_Negative(step); if (!step) - return NULL; + return -1; } /* if (lo >= hi), return length of 0. */ if (PyObject_Compare(lo, hi) >= 0) { Py_XDECREF(step); - return PyLong_FromLong(0); + return 0; } if ((one = PyLong_FromLong(1L)) == NULL) @@ -179,7 +196,12 @@ Py_DECREF(step); Py_DECREF(tmp1); Py_DECREF(one); - return result; + length = PyLong_AsSsize_t(result); + if (length == -1 && PyErr_ExceptionMatches(PyExc_OverflowError)) + PyErr_SetString(PyExc_OverflowError, + "range length exceeded sys.maxsize"); + Py_DECREF(result); + return length; Fail: Py_XDECREF(tmp2); @@ -187,38 +209,21 @@ Py_XDECREF(step); Py_XDECREF(tmp1); Py_XDECREF(one); - return NULL; + return -1; } static Py_ssize_t range_length(rangeobject *r) { - PyObject *len = range_length_obj(r); - Py_ssize_t result = -1; - if (len) { - result = PyLong_AsSsize_t(len); - Py_DECREF(len); - } - return result; + return r->length; } /* range(...)[x] is necessary for: seq[:] = range(...) */ - static PyObject * -range_item(rangeobject *r, Py_ssize_t i) +compute_range_item(rangeobject *r, Py_ssize_t i) { - Py_ssize_t len = range_length(r); PyObject *rem, *incr, *result; - /* XXX(nnorwitz): should negative indices be supported? */ - /* XXX(nnorwitz): should support range[x] where x > PY_SSIZE_T_MAX? */ - if (i < 0 || i >= len) { - if (!PyErr_Occurred()) - PyErr_SetString(PyExc_IndexError, - "range object index out of range"); - return NULL; - } - /* XXX(nnorwitz): optimize for short ints. */ rem = PyLong_FromSsize_t(i); if (!rem) @@ -233,6 +238,95 @@ } static PyObject * +range_item(rangeobject *r, Py_ssize_t i) +{ + /* XXX(nnorwitz): should negative indices be supported? */ + /* XXX(nnorwitz): should support range[x] where x > PY_SSIZE_T_MAX? */ + if (i < 0 || i >= r->length) { + if (!PyErr_Occurred()) + PyErr_SetString(PyExc_IndexError, + "range object index out of range"); + return NULL; + } + return compute_range_item(r, i); +} + +static int +range_contains(rangeobject *r, PyObject *orig_el) +{ + PyObject *diff = NULL, *rem = NULL, *zero = NULL, *el=NULL; + int cmp; + el = PyNumber_Index(orig_el); + if (el == NULL) { + if (!PyErr_ExceptionMatches(PyExc_TypeError) && + !PyErr_ExceptionMatches(PyExc_ValueError)) { + return -1; + } + /* Not an integer type */ + PyErr_Clear(); + el = PyNumber_Long(orig_el); + if (el == NULL) { + /* Not a numeric type */ + cmp = -1; + goto done; + } + cmp = PyObject_RichCompareBool(orig_el, el, Py_EQ); + if (cmp != 1) + /* Not an integer value */ + goto done; + } + if (Py_SIZE(r->step) > 0) { + cmp = PyObject_RichCompareBool(r->start, el, Py_LE); + if (cmp != 1) + /* Less than the min value */ + goto done; + cmp = PyObject_RichCompareBool(el, r->stop, Py_LT); + if (cmp != 1) + /* Greater than the max value */ + goto done; + } + else { + cmp = PyObject_RichCompareBool(r->start, el, Py_GT); + if (cmp != 1) + /* Greater than the max value */ + goto done; + cmp = PyObject_RichCompareBool(el, r->stop, Py_GT); + if (cmp != 1) + /* Less than the min value */ + goto done; + } + /* XXX: Optimize for step = 1 and small ints */ + diff = PyNumber_Subtract(el, r->start); + if (diff == NULL) { + cmp = -1; + goto done; + } + rem = PyNumber_Remainder(diff, r->step); + if (rem == NULL) { + cmp = -1; + goto done; + } + zero = PyLong_FromLong(0); + if (zero == NULL) { + cmp = -1; + goto done; + } + cmp = PyObject_RichCompareBool(rem, zero, Py_EQ); + Py_DECREF(zero); + done: + Py_XDECREF(rem); + Py_XDECREF(diff); + Py_XDECREF(el); + if (cmp == -1 && + (PyErr_ExceptionMatches(PyExc_TypeError) || + PyErr_ExceptionMatches(PyExc_ValueError))) { + PyErr_Clear(); + return 0; + } + return cmp; +} + +static PyObject * range_repr(rangeobject *r) { Py_ssize_t istep; @@ -256,18 +350,86 @@ static PyObject * range_reduce(rangeobject *r, PyObject *args) { - return Py_BuildValue("(O(OOO))", Py_TYPE(r), + return Py_BuildValue("(O(OOO))", Py_TYPE(r), r->start, r->stop, r->step); } static PySequenceMethods range_as_sequence = { (lenfunc)range_length, /* sq_length */ - 0, /* sq_concat */ - 0, /* sq_repeat */ - (ssizeargfunc)range_item, /* sq_item */ - 0, /* sq_slice */ + 0, /* sq_concat */ + 0, /* sq_repeat */ + (ssizeargfunc)range_item, /* sq_item */ + 0, /* sq_slice */ + 0, /* sq_ass_item */ + 0, /* sq_ass_slice */ + (objobjproc)range_contains, /* sq_contains */ }; +static PyObject * +range_subscript(rangeobject* self, PyObject* item) +{ + if (PyIndex_Check(item)) { + Py_ssize_t i; + i = PyNumber_AsSsize_t(item, PyExc_IndexError); + if (i == -1 && PyErr_Occurred()) + return NULL; + if (i < 0) + i += self->length; + return range_item(self, i); + } + if (PySlice_Check(item)) { + PySliceObject *slice = (PySliceObject*)item; + Py_ssize_t start, stop, step, len; + rangeobject *result; + PyObject *rstart = NULL, *rstep = NULL, *rstop = NULL; + + if (PySlice_GetIndicesEx(slice, self->length, + &start, &stop, &step, &len) < 0) { + return NULL; + } + if (step == 1) { + rstep = self->step; + Py_INCREF(rstep); + } else { + /* NB: slice step != Py_None here */ + rstep = PyNumber_Multiply(self->step, slice->step); + if (rstep == NULL) + goto fail; + } + rstart = compute_range_item(self, start); + if (rstart == NULL) + goto fail; + if (len <= 0) { + rstop = rstart; + Py_INCREF(rstop); + } + else { + rstop = compute_range_item(self, stop); + if (rstop == NULL) + goto fail; + } + result = make_range_object(Py_TYPE(self), rstart, rstop, rstep); + if (result != NULL) + return (PyObject *) result; + fail: + Py_XDECREF(rstart); + Py_XDECREF(rstep); + Py_XDECREF(rstop); + return NULL; + } + PyErr_Format(PyExc_TypeError, + "range indices must be integers, not %.200s", + item->ob_type->tp_name); + return NULL; +} + + +static PyMappingMethods range_as_mapping = { + (lenfunc)range_length, + (binaryfunc)range_subscript, + (objobjargproc)0, +}; + static PyObject * range_iter(PyObject *seq); static PyObject * range_reverse(PyObject *seq); @@ -276,50 +438,50 @@ static PyMethodDef range_methods[] = { {"__reversed__", (PyCFunction)range_reverse, METH_NOARGS, - reverse_doc}, + reverse_doc}, {"__reduce__", (PyCFunction)range_reduce, METH_VARARGS}, {NULL, NULL} /* sentinel */ }; PyTypeObject PyRange_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "range", /* Name of this type */ - sizeof(rangeobject), /* Basic object size */ - 0, /* Item size for varobject */ - (destructor)range_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - (reprfunc)range_repr, /* tp_repr */ - 0, /* tp_as_number */ - &range_as_sequence, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - range_doc, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - range_iter, /* tp_iter */ - 0, /* tp_iternext */ - range_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - range_new, /* tp_new */ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "range", /* Name of this type */ + sizeof(rangeobject), /* Basic object size */ + 0, /* Item size for varobject */ + (destructor)range_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + (reprfunc)range_repr, /* tp_repr */ + 0, /* tp_as_number */ + &range_as_sequence, /* tp_as_sequence */ + &range_as_mapping, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + range_doc, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + range_iter, /* tp_iter */ + 0, /* tp_iternext */ + range_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + range_new, /* tp_new */ }; /*********************** range Iterator **************************/ @@ -330,11 +492,11 @@ */ typedef struct { - PyObject_HEAD - long index; - long start; - long step; - long len; + PyObject_HEAD + long index; + long start; + long step; + long len; } rangeiterobject; static PyObject * @@ -372,50 +534,50 @@ static PyMethodDef rangeiter_methods[] = { {"__length_hint__", (PyCFunction)rangeiter_len, METH_NOARGS, - length_hint_doc}, + length_hint_doc}, {NULL, NULL} /* sentinel */ }; PyTypeObject PyRangeIter_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "range_iterator", /* tp_name */ - sizeof(rangeiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)PyObject_Del, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)rangeiter_next, /* tp_iternext */ - rangeiter_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - rangeiter_new, /* tp_new */ + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "range_iterator", /* tp_name */ + sizeof(rangeiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)PyObject_Del, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)rangeiter_next, /* tp_iternext */ + rangeiter_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + rangeiter_new, /* tp_new */ }; /* Return number of items in range/xrange (lo, hi, step). step > 0 @@ -480,7 +642,7 @@ static PyMethodDef longrangeiter_methods[] = { {"__length_hint__", (PyCFunction)longrangeiter_len, METH_NOARGS, - length_hint_doc}, + length_hint_doc}, {NULL, NULL} /* sentinel */ }; @@ -529,36 +691,36 @@ } PyTypeObject PyLongRangeIter_Type = { - PyVarObject_HEAD_INIT(&PyType_Type, 0) - "longrange_iterator", /* tp_name */ - sizeof(longrangeiterobject), /* tp_basicsize */ - 0, /* tp_itemsize */ - /* methods */ - (destructor)longrangeiter_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - PyObject_GenericGetAttr, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - PyObject_SelfIter, /* tp_iter */ - (iternextfunc)longrangeiter_next, /* tp_iternext */ - longrangeiter_methods, /* tp_methods */ - 0, + PyVarObject_HEAD_INIT(&PyType_Type, 0) + "longrange_iterator", /* tp_name */ + sizeof(longrangeiterobject), /* tp_basicsize */ + 0, /* tp_itemsize */ + /* methods */ + (destructor)longrangeiter_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + PyObject_GenericGetAttr, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + PyObject_SelfIter, /* tp_iter */ + (iternextfunc)longrangeiter_next, /* tp_iternext */ + longrangeiter_methods, /* tp_methods */ + 0, }; static PyObject * @@ -574,12 +736,12 @@ /* If all three fields convert to long, use the int version */ lstart = PyLong_AsLong(r->start); if (lstart != -1 || !PyErr_Occurred()) { - lstop = PyLong_AsLong(r->stop); - if (lstop != -1 || !PyErr_Occurred()) { - lstep = PyLong_AsLong(r->step); - if (lstep != -1 || !PyErr_Occurred()) - return int_range_iter(lstart, lstop, lstep); - } + lstop = PyLong_AsLong(r->stop); + if (lstop != -1 || !PyErr_Occurred()) { + lstep = PyLong_AsLong(r->step); + if (lstep != -1 || !PyErr_Occurred()) + return int_range_iter(lstart, lstop, lstep); + } } /* Some conversion failed, so there is an error set. Clear it, and try again with a long range. */ @@ -633,21 +795,23 @@ /* If all three fields convert to long, use the int version */ lstart = PyLong_AsLong(range->start); if (lstart != -1 || !PyErr_Occurred()) { - lstop = PyLong_AsLong(range->stop); - if (lstop != -1 || !PyErr_Occurred()) { - lstep = PyLong_AsLong(range->step); - if (lstep != -1 || !PyErr_Occurred()) { - /* XXX(nnorwitz): need to check for overflow and simplify. */ - long len = get_len_of_range(lstart, lstop, lstep); - long new_start = lstart + (len - 1) * lstep; - long new_stop = lstart; - if (lstep > 0) - new_stop -= 1; - else - new_stop += 1; - return int_range_iter(new_start, new_stop, -lstep); - } - } + lstop = PyLong_AsLong(range->stop); + if (lstop != -1 || !PyErr_Occurred()) { + lstep = PyLong_AsLong(range->step); + if (lstep != -1 || !PyErr_Occurred()) { + /* XXX(nnorwitz): need to check for overflow and simplify. */ + long len, new_start, new_stop; + if (lstep > 0) { + len = get_len_of_range(lstart, lstop, lstep); + new_stop = lstart - 1; + } else { + len = get_len_of_range(lstop, lstart, -lstep); + new_stop = lstart + 1; + } + new_start = lstart + (len - 1) * lstep; + return int_range_iter(new_start, new_stop, -lstep); + } + } } PyErr_Clear(); @@ -656,7 +820,7 @@ return NULL; /* start + (len - 1) * step */ - len = range_length_obj(range); + len = PyLong_FromSsize_t(range->length); if (!len) goto create_failure; Index: Lib/_abcoll.py =================================================================== --- Lib/_abcoll.py (revision 66146) +++ Lib/_abcoll.py (working copy) @@ -546,6 +546,7 @@ Sequence.register(tuple) Sequence.register(str) +Sequence.register(range) class ByteString(Sequence): Index: Lib/test/test_range.py =================================================================== --- Lib/test/test_range.py (revision 66146) +++ Lib/test/test_range.py (working copy) @@ -57,6 +57,8 @@ r = range(-sys.maxsize, sys.maxsize, 2) self.assertEqual(len(r), sys.maxsize) + self.assertEqual(len(range(sys.maxsize, sys.maxsize+10)), 10) + def test_repr(self): self.assertEqual(repr(range(1)), 'range(0, 1)') self.assertEqual(repr(range(1, 2)), 'range(1, 2)') @@ -71,6 +73,80 @@ self.assertEquals(list(pickle.loads(pickle.dumps(r, proto))), list(r)) + def test_slice(self): + def check(start, stop, step=None): + i = slice(start, stop, step) + self.assertEqual(list(r[i]), list(r)[i]) + self.assertEqual(len(r[i]), len(list(r)[i])) + for r in [range(10), + range(0), + range(1, 9, 3), + range(8, 0, -3), + range(sys.maxsize+1, sys.maxsize+10), + ]: + check(0, 2) + check(0, 20) + check(1, 2) + check(20, 30) + check(-30, -20) + check(-1, 100, 2) + check(0, -1) + check(-1, -3, -1) + + def test_contains(self): + r = range(10) + self.assertTrue(0 in r) + self.assertTrue(1 in r) + self.assertTrue(5.0 in r) + self.assertFalse(5.1 in r) + self.assertFalse(-1 in r) + self.assertFalse(10 in r) + self.assertFalse("" in r) + r = range(9, -1, -1) + self.assertTrue(0 in r) + self.assertTrue(1 in r) + self.assertTrue(5.0 in r) + self.assertFalse(5.1 in r) + self.assertFalse(-1 in r) + self.assertFalse(10 in r) + self.assertFalse("" in r) + r = range(0, 10, 2) + self.assertTrue(0 in r) + self.assertFalse(1 in r) + self.assertFalse(5.0 in r) + self.assertFalse(5.1 in r) + self.assertFalse(-1 in r) + self.assertFalse(10 in r) + self.assertFalse("" in r) + r = range(9, -1, -2) + self.assertFalse(0 in r) + self.assertTrue(1 in r) + self.assertTrue(5.0 in r) + self.assertFalse(5.1 in r) + self.assertFalse(-1 in r) + self.assertFalse(10 in r) + self.assertFalse("" in r) + # Ensure exceptions other than TypeError and ValueError + # aren't suppressed + class DodgyIndex(object): + def __index__(self): + raise RuntimeError + self.assertRaises(RuntimeError, lambda: DodgyIndex() in range(10)) + class DodgyInt(object): + def __int__(self): + raise RuntimeError + self.assertRaises(RuntimeError, lambda: DodgyInt() in range(10)) + + def test_reverse_iteration(self): + for r in [range(10), + range(0), + range(1, 9, 3), + range(8, 0, -3), + range(sys.maxsize+1, sys.maxsize+10), + ]: + self.assertEqual(list(reversed(r)), list(r)[::-1]) + + def test_main(): test.support.run_unittest(RangeTest) Index: Lib/test/test_builtin.py =================================================================== --- Lib/test/test_builtin.py (revision 66146) +++ Lib/test/test_builtin.py (working copy) @@ -979,10 +979,10 @@ self.assertRaises(TypeError, range, 0, "spam") self.assertRaises(TypeError, range, 0, 42, "spam") - #NEAL self.assertRaises(OverflowError, range, -sys.maxsize, sys.maxsize) - #NEAL self.assertRaises(OverflowError, range, 0, 2*sys.maxsize) + self.assertRaises(OverflowError, range, -sys.maxsize, sys.maxsize) + self.assertRaises(OverflowError, range, 0, 2*sys.maxsize) - self.assertRaises(OverflowError, len, range(0, sys.maxsize**10)) + # self.assertRaises(OverflowError, len, range(0, sys.maxsize**10)) def test_input(self): self.write_testfile()