Index: Python/ceval.c =================================================================== --- Python/ceval.c (revision 51214) +++ Python/ceval.c (working copy) @@ -3866,12 +3866,10 @@ if (v != NULL) { Py_ssize_t x; if (PyInt_Check(v)) { - x = PyInt_AsSsize_t(v); + x = PyInt_AS_LONG(v); } - else if (v->ob_type->tp_as_number && - PyType_HasFeature(v->ob_type, Py_TPFLAGS_HAVE_INDEX) - && v->ob_type->tp_as_number->nb_index) { - x = v->ob_type->tp_as_number->nb_index(v); + else if (PyIndex_Check(v)) { + x = PyNumber_AsSsize_t(v, NULL); if (x == -1 && PyErr_Occurred()) return 0; } @@ -3887,10 +3885,7 @@ } #undef ISINDEX -#define ISINDEX(x) ((x) == NULL || PyInt_Check(x) || PyLong_Check(x) || \ - ((x)->ob_type->tp_as_number && \ - PyType_HasFeature((x)->ob_type, Py_TPFLAGS_HAVE_INDEX) \ - && (x)->ob_type->tp_as_number->nb_index)) +#define ISINDEX(x) ((x) == NULL || PyInt_Check(x) || PyLong_Check(x) || PyIndex_Check(x)) static PyObject * apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */ Index: Include/abstract.h =================================================================== --- Include/abstract.h (revision 51214) +++ Include/abstract.h (working copy) @@ -758,14 +758,28 @@ */ - PyAPI_FUNC(Py_ssize_t) PyNumber_Index(PyObject *); +#define PyIndex_Check(obj) \ + ((obj)->ob_type->tp_as_number != NULL && \ + PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_INDEX) && \ + (obj)->ob_type->tp_as_number->nb_index != NULL) + + PyAPI_FUNC(PyObject *) PyNumber_Index(PyObject *); /* - Returns the object converted to Py_ssize_t on success - or -1 with an error raised on failure. + Returns the object converted to a Python long or int + or NULL with an error raised on failure. */ + PyAPI_FUNC(Py_ssize_t) PyNumber_AsSsize_t(PyObject *, PyObject *); + /* + Returns the object converted to Py_ssize_t by going through + PyNumber_Index first. If an overflow error occurs while + converting the int-or-long to Py_ssize_t, then the second argument + is the error-type to return. If it is NULL, then the overflow error + is cleared and the value is clipped. + */ + PyAPI_FUNC(PyObject *) PyNumber_Int(PyObject *o); /* Index: Include/object.h =================================================================== --- Include/object.h (revision 51214) +++ Include/object.h (working copy) @@ -208,7 +208,7 @@ binaryfunc nb_inplace_true_divide; /* Added in release 2.5 */ - lenfunc nb_index; + unaryfunc nb_index; } PyNumberMethods; typedef struct { Index: Objects/abstract.c =================================================================== --- Objects/abstract.c (revision 51214) +++ Objects/abstract.c (working copy) @@ -8,9 +8,7 @@ #define NEW_STYLE_NUMBER(o) PyType_HasFeature((o)->ob_type, \ Py_TPFLAGS_CHECKTYPES) -#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) - /* Shorthands to return certain errors */ static PyObject * @@ -122,9 +120,9 @@ return m->mp_subscript(o, key); if (o->ob_type->tp_as_sequence) { - PyNumberMethods *nb = key->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) { - Py_ssize_t key_value = nb->nb_index(key); + if PyIndex_Check(key) { + Py_ssize_t key_value; + key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) return NULL; return PySequence_GetItem(o, key_value); @@ -151,9 +149,9 @@ return m->mp_ass_subscript(o, key, value); if (o->ob_type->tp_as_sequence) { - PyNumberMethods *nb = key->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) { - Py_ssize_t key_value = nb->nb_index(key); + if PyIndex_Check(key) { + Py_ssize_t key_value; + key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) return -1; return PySequence_SetItem(o, key_value, value); @@ -183,9 +181,9 @@ return m->mp_ass_subscript(o, key, (PyObject*)NULL); if (o->ob_type->tp_as_sequence) { - PyNumberMethods *nb = key->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(key) && nb->nb_index != NULL) { - Py_ssize_t key_value = nb->nb_index(key); + if PyIndex_Check(key) { + Py_ssize_t key_value; + key_value = PyNumber_AsSsize_t(key, PyExc_IndexError); if (key_value == -1 && PyErr_Occurred()) return -1; return PySequence_DelItem(o, key_value); @@ -653,9 +651,8 @@ sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n) { Py_ssize_t count; - PyNumberMethods *nb = n->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(n) && nb->nb_index != NULL) { - count = nb->nb_index(n); + if PyIndex_Check(n) { + count = PyNumber_AsSsize_t(n, PyExc_OverflowError); if (count == -1 && PyErr_Occurred()) return NULL; } @@ -938,23 +935,88 @@ return x; } -/* Return a Py_ssize_t integer from the object item */ -Py_ssize_t +/* Return a Python Int or Long from the object item + Raise TypeError if the result is not an int-or-long + or if the object cannot be interpreted as an index. +*/ +PyObject * PyNumber_Index(PyObject *item) { - Py_ssize_t value = -1; - PyNumberMethods *nb = item->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { - value = nb->nb_index(item); + PyObject *res=NULL; + if (item == NULL) + return null_error(); + if (PyInt_CheckExact(item) || PyLong_CheckExact(item)) { + Py_INCREF(item); + return item; } + if PyIndex_Check(item) { + res = item->ob_type->tp_as_number->nb_index(item); + if (res && !PyInt_CheckExact(res) && !PyLong_CheckExact(res)) { + PyErr_Format(PyExc_TypeError, + "__index__ returned non-(int,long) " \ + "(type %.200s)", + res->ob_type->tp_name); + Py_DECREF(res); + return NULL; + } + } else { PyErr_Format(PyExc_TypeError, "'%.200s' object cannot be interpreted " "as an index", item->ob_type->tp_name); } - return value; + return res; } +/* Return an error on Overflow only if err is not NULL*/ + +Py_ssize_t +PyNumber_AsSsize_t(PyObject *item, PyObject *err) +{ + PyObject *value; + Py_ssize_t val; + PyObject *runerr; + value = PyNumber_Index(item); + if (value == NULL) return -1; + + val = PyInt_AsSsize_t(value); + runerr = PyErr_Occurred(); + if (!runerr) goto finish; + + /* Error handling code -- only manage + OverflowError differently + */ + if (!PyErr_GivenExceptionMatches(runerr, PyExc_OverflowError)) + goto finish; + + PyErr_Clear(); + /* If no error-handling desired then the default clipping + is sufficient. + */ + if (!err) { + /* Can only be a long integer at this point */ + /* Whether or not it is less than or equal to + zero is determined by the sign of ob_size + */ + if (((PyVarObject *)value)->ob_size < 0) + val = PY_SSIZE_T_MIN; + else + val = PY_SSIZE_T_MAX; + } + else { + /* Other-wise replace the error with + the caller's error object. */ + PyErr_Format(err, "cannot fit '%.200s' into an " \ + "index-sized integer", + item->ob_type->tp_name); + } + + finish: + Py_DECREF(value); + return val; +} + + PyObject * PyNumber_Int(PyObject *o) { Index: Objects/typeobject.c =================================================================== --- Objects/typeobject.c (revision 51214) +++ Objects/typeobject.c (working copy) @@ -3527,7 +3527,7 @@ if (!PyArg_UnpackTuple(args, "", 1, 1, &o)) return NULL; - i = PyNumber_Index(o); + i = PyNumber_AsSsize_t(o, PyExc_OverflowError); if (i == -1 && PyErr_Occurred()) return NULL; return (*func)(self, i); @@ -3538,7 +3538,7 @@ { Py_ssize_t i; - i = PyNumber_Index(arg); + i = PyNumber_AsSsize_t(arg, PyExc_OverflowError); if (i == -1 && PyErr_Occurred()) return -1; if (i < 0) { @@ -4344,25 +4344,12 @@ } -static Py_ssize_t +static PyObject * slot_nb_index(PyObject *self) { static PyObject *index_str; - PyObject *temp = call_method(self, "__index__", &index_str, "()"); - Py_ssize_t result; + PyObject *result = call_method(self, "__index__", &index_str, "()"); - if (temp == NULL) - return -1; - if (PyInt_CheckExact(temp) || PyLong_CheckExact(temp)) { - result = temp->ob_type->tp_as_number->nb_index(temp); - } - else { - PyErr_Format(PyExc_TypeError, - "__index__ must return an int or a long, " - "not '%.200s'", temp->ob_type->tp_name); - result = -1; - } - Py_DECREF(temp); return result; } @@ -5109,7 +5096,7 @@ "oct(x)"), UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc, "hex(x)"), - NBSLOT("__index__", nb_index, slot_nb_index, wrap_lenfunc, + NBSLOT("__index__", nb_index, slot_nb_index, wrap_unaryfunc, "x[y:z] <==> x[y.__index__():z.__index__()]"), IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add, wrap_binaryfunc, "+"), Index: Objects/unicodeobject.c =================================================================== --- Objects/unicodeobject.c (revision 51214) +++ Objects/unicodeobject.c (working copy) @@ -6985,14 +6985,11 @@ PyUnicode_Contains, /* sq_contains */ }; -#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) - static PyObject* unicode_subscript(PyUnicodeObject* self, PyObject* item) { - PyNumberMethods *nb = item->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { - Py_ssize_t i = nb->nb_index(item); + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; if (i < 0) Index: Objects/tupleobject.c =================================================================== --- Objects/tupleobject.c (revision 51214) +++ Objects/tupleobject.c (working copy) @@ -577,14 +577,11 @@ (objobjproc)tuplecontains, /* sq_contains */ }; -#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) - static PyObject* tuplesubscript(PyTupleObject* self, PyObject* item) { - PyNumberMethods *nb = item->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { - Py_ssize_t i = nb->nb_index(item); + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; if (i < 0) Index: Objects/intobject.c =================================================================== --- Objects/intobject.c (revision 51214) +++ Objects/intobject.c (working copy) @@ -193,15 +193,14 @@ PyIntObject *io; Py_ssize_t val; #endif + if (op && PyInt_Check(op)) + return PyInt_AS_LONG((PyIntObject*) op); if (op && !PyInt_CheckExact(op) && PyLong_Check(op)) return _PyLong_AsSsize_t(op); #if SIZEOF_SIZE_T == SIZEOF_LONG return PyInt_AsLong(op); #else - if (op && PyInt_Check(op)) - return PyInt_AS_LONG((PyIntObject*) op); - if (op == NULL || (nb = op->ob_type->tp_as_number) == NULL || (nb->nb_int == NULL && nb->nb_long == 0)) { PyErr_SetString(PyExc_TypeError, "an integer is required"); @@ -1079,7 +1078,7 @@ int_true_divide, /* nb_true_divide */ 0, /* nb_inplace_floor_divide */ 0, /* nb_inplace_true_divide */ - PyInt_AsSsize_t, /* nb_index */ + (unaryfunc)int_int, /* nb_index */ }; PyTypeObject PyInt_Type = { Index: Objects/listobject.c =================================================================== --- Objects/listobject.c (revision 51214) +++ Objects/listobject.c (working copy) @@ -2450,14 +2450,13 @@ "list() -> new list\n" "list(sequence) -> new list initialized from sequence's items"); -#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) static PyObject * list_subscript(PyListObject* self, PyObject* item) { - PyNumberMethods *nb = item->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { - Py_ssize_t i = nb->nb_index(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) @@ -2504,9 +2503,8 @@ static int list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) { - PyNumberMethods *nb = item->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { - Py_ssize_t i = nb->nb_index(item); + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return -1; if (i < 0) Index: Objects/sliceobject.c =================================================================== --- Objects/sliceobject.c (revision 51214) +++ Objects/sliceobject.c (working copy) @@ -252,7 +252,7 @@ { Py_ssize_t ilen, start, stop, step, slicelength; - ilen = PyInt_AsSsize_t(len); + ilen = PyNumber_AsSsize_t(len, PyExc_OverflowError); if (ilen == -1 && PyErr_Occurred()) { return NULL; Index: Objects/longobject.c =================================================================== --- Objects/longobject.c (revision 51214) +++ Objects/longobject.c (working copy) @@ -240,8 +240,11 @@ return -1; } -static Py_ssize_t -_long_as_ssize_t(PyObject *vv) { +/* Get a Py_ssize_t from a long int object. + Returns -1 and sets an error condition if overflow occurs. */ + +Py_ssize_t +_PyLong_AsSsize_t(PyObject *vv) { register PyLongObject *v; size_t x, prev; Py_ssize_t i; @@ -277,47 +280,9 @@ overflow: PyErr_SetString(PyExc_OverflowError, "long int too large to convert to int"); - if (sign > 0) - return PY_SSIZE_T_MAX; - else - return PY_SSIZE_T_MIN; + return -1; } -/* Get a Py_ssize_t from a long int object. - Returns -1 and sets an error condition if overflow occurs. */ - -Py_ssize_t -_PyLong_AsSsize_t(PyObject *vv) -{ - Py_ssize_t x; - - x = _long_as_ssize_t(vv); - if (PyErr_Occurred()) return -1; - return x; -} - - -/* Get a Py_ssize_t from a long int object. - Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX, - and silently boost values less than -PY_SSIZE_T_MAX-1 to -PY_SSIZE_T_MAX-1. - On error, return -1 with an exception set. -*/ - -static Py_ssize_t -long_index(PyObject *vv) -{ - Py_ssize_t x; - - x = _long_as_ssize_t(vv); - if (PyErr_Occurred()) { - /* If overflow error, ignore the error */ - if (x != -1) { - PyErr_Clear(); - } - } - return x; -} - /* Get a C unsigned long int from a long int object. Returns -1 and sets an error condition if overflow occurs. */ @@ -3405,7 +3370,7 @@ long_true_divide, /* nb_true_divide */ 0, /* nb_inplace_floor_divide */ 0, /* nb_inplace_true_divide */ - long_index, /* nb_index */ + long_long, /* nb_index */ }; PyTypeObject PyLong_Type = { Index: Objects/classobject.c =================================================================== --- Objects/classobject.c (revision 51214) +++ Objects/classobject.c (working copy) @@ -1670,40 +1670,28 @@ return outcome > 0; } -static Py_ssize_t +static PyObject * instance_index(PyInstanceObject *self) { PyObject *func, *res; - Py_ssize_t outcome; static PyObject *indexstr = NULL; if (indexstr == NULL) { indexstr = PyString_InternFromString("__index__"); if (indexstr == NULL) - return -1; + return NULL; } if ((func = instance_getattr(self, indexstr)) == NULL) { if (!PyErr_ExceptionMatches(PyExc_AttributeError)) - return -1; + return NULL; PyErr_Clear(); PyErr_SetString(PyExc_TypeError, "object cannot be interpreted as an index"); - return -1; + return NULL; } res = PyEval_CallObject(func, (PyObject *)NULL); Py_DECREF(func); - if (res == NULL) - return -1; - if (PyInt_Check(res) || PyLong_Check(res)) { - outcome = res->ob_type->tp_as_number->nb_index(res); - } - else { - PyErr_SetString(PyExc_TypeError, - "__index__ must return an int or a long"); - outcome = -1; - } - Py_DECREF(res); - return outcome; + return res; } @@ -2026,7 +2014,7 @@ instance_truediv, /* nb_true_divide */ instance_ifloordiv, /* nb_inplace_floor_divide */ instance_itruediv, /* nb_inplace_true_divide */ - (lenfunc)instance_index, /* nb_index */ + (unaryfunc)instance_index, /* nb_index */ }; PyTypeObject PyInstance_Type = { Index: Objects/stringobject.c =================================================================== --- Objects/stringobject.c (revision 51214) +++ Objects/stringobject.c (working copy) @@ -1184,14 +1184,11 @@ return x; } -#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) - static PyObject* string_subscript(PyStringObject* self, PyObject* item) { - PyNumberMethods *nb = item->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { - Py_ssize_t i = nb->nb_index(item); + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i == -1 && PyErr_Occurred()) return NULL; if (i < 0) Index: Doc/api/abstract.tex =================================================================== --- Doc/api/abstract.tex (revision 51214) +++ Doc/api/abstract.tex (working copy) @@ -693,12 +693,31 @@ \samp{float(\var{o})}.\bifuncindex{float} \end{cfuncdesc} -\begin{cfuncdesc}{Py_ssize_t}{PyNumber_Index}{PyObject *o} - Returns the \var{o} converted to a Py_ssize_t integer on success, or - -1 with an exception raised on failure. +\begin{cfuncdesc}{PyObject*}{PyNumber_Index}{PyObject *o} + Returns the \var{o} converted to a Python int or long on success or \NULL{} + with a TypeError exception raised on failure. \versionadded{2.5} \end{cfuncdesc} +\begin{cfuncdesc}{Py_ssize_t}{PyNumber_AsSsize_t}{PyObject *o, PyObject *err} + Returns the \var{o} converted to a Py_ssize_t value if o can be interpreted + as an integer. If o can be converted to a Python int or long but the + attempt to convert to a Py_ssize_t value raises an \exception{OverflowError}, + then the err argument is the exception to raise (usually + \exception{IndexError} or \exception{OverflowError}). If err is \NULL{}, then + the error indicator is cleared and the value is clipped to + \var{PY_SSIZE_T_MIN} for a negative integer and \var{PY_SSIZE_T_MAX} + for a positive integer. + \versionadded{2.5} +\end{cfuncdesc} + +\begin{cfuncdesc}{int}{PyIndex_Check}{PyObject *o} + Returns True if the object is an index integer (has the nb_index slot of + the tp_as_number structure filled in). + \versionadded{2.5} +\end{cfuncdesc} + + \section{Sequence Protocol \label{sequence}} \begin{cfuncdesc}{int}{PySequence_Check}{PyObject *o} Index: Lib/test/test_index.py =================================================================== --- Lib/test/test_index.py (revision 51214) +++ Lib/test/test_index.py (working copy) @@ -1,6 +1,7 @@ import unittest from test import test_support import operator +from sys import maxint class oldstyle: def __index__(self): @@ -10,68 +11,116 @@ def __index__(self): return self.ind +class TrapInt(int): + def __index__(self): + return self + +class TrapLong(long): + def __index__(self): + return self + class BaseTestCase(unittest.TestCase): def setUp(self): self.o = oldstyle() self.n = newstyle() - self.o2 = oldstyle() - self.n2 = newstyle() def test_basic(self): self.o.ind = -2 self.n.ind = 2 - assert(self.seq[self.n] == self.seq[2]) - assert(self.seq[self.o] == self.seq[-2]) - assert(operator.index(self.o) == -2) - assert(operator.index(self.n) == 2) + self.failUnless(operator.index(self.o) == -2) + self.failUnless(operator.index(self.n) == 2) + + def test_slice(self): + self.o.ind = 1 + self.n.ind = 2 + slc = slice(self.o, self.o, self.o) + check_slc = slice(1, 1, 1) + self.failUnless(slc.indices(self.o) == check_slc.indices(1)) + slc = slice(self.n, self.n, self.n) + check_slc = slice(2, 2, 2) + self.failUnless(slc.indices(self.n) == check_slc.indices(2)) + def test_wrappers(self): + self.o.ind = 4 + self.n.ind = 5 + self.failUnless(6 .__index__() == 6) + self.failUnless(-7L.__index__() == -7) + self.failUnless(self.o.__index__() == 4) + self.failUnless(self.n.__index__() == 5) + + def test_infinite_recursion(self): + self.failUnlessRaises(TypeError, operator.index, TrapInt()) + self.failUnlessRaises(TypeError, operator.index, TrapLong()) + self.failUnless(slice(TrapInt()).indices(0)==(0,0,1)) + self.failUnlessRaises(TypeError, slice(TrapLong()).indices, 0) + def test_error(self): self.o.ind = 'dumb' self.n.ind = 'bad' - myfunc = lambda x, obj: obj.seq[x] self.failUnlessRaises(TypeError, operator.index, self.o) self.failUnlessRaises(TypeError, operator.index, self.n) - self.failUnlessRaises(TypeError, myfunc, self.o, self) - self.failUnlessRaises(TypeError, myfunc, self.n, self) + self.failUnlessRaises(TypeError, slice(self.o).indices, 0) + self.failUnlessRaises(TypeError, slice(self.n).indices, 0) + +class SeqTestCase(unittest.TestCase): + # This test case isn't run directly. It just defines common tests + # to the different sequence types below + def setUp(self): + self.o = oldstyle() + self.n = newstyle() + self.o2 = oldstyle() + self.n2 = newstyle() + + def test_index(self): + self.o.ind = -2 + self.n.ind = 2 + self.failUnless(self.seq[self.n] == self.seq[2]) + self.failUnless(self.seq[self.o] == self.seq[-2]) + + def test_slice(self): self.o.ind = 1 self.o2.ind = 3 self.n.ind = 2 self.n2.ind = 4 - assert(self.seq[self.o:self.o2] == self.seq[1:3]) - assert(self.seq[self.n:self.n2] == self.seq[2:4]) + self.failUnless(self.seq[self.o:self.o2] == self.seq[1:3]) + self.failUnless(self.seq[self.n:self.n2] == self.seq[2:4]) + def test_repeat(self): self.o.ind = 3 self.n.ind = 2 - assert(self.seq * self.o == self.seq * 3) - assert(self.seq * self.n == self.seq * 2) - assert(self.o * self.seq == self.seq * 3) - assert(self.n * self.seq == self.seq * 2) + self.failUnless(self.seq * self.o == self.seq * 3) + self.failUnless(self.seq * self.n == self.seq * 2) + self.failUnless(self.o * self.seq == self.seq * 3) + self.failUnless(self.n * self.seq == self.seq * 2) def test_wrappers(self): - n = self.n - n.ind = 5 - assert n.__index__() == 5 - assert 6 .__index__() == 6 - assert -7L.__index__() == -7 - assert self.seq.__getitem__(n) == self.seq[5] - assert self.seq.__mul__(n) == self.seq * 5 - assert self.seq.__rmul__(n) == self.seq * 5 + self.o.ind = 4 + self.n.ind = 5 + self.failUnless(self.seq.__getitem__(self.o) == self.seq[4]) + self.failUnless(self.seq.__mul__(self.o) == self.seq * 4) + self.failUnless(self.seq.__rmul__(self.o) == self.seq * 4) + self.failUnless(self.seq.__getitem__(self.n) == self.seq[5]) + self.failUnless(self.seq.__mul__(self.n) == self.seq * 5) + self.failUnless(self.seq.__rmul__(self.n) == self.seq * 5) - def test_infinite_recusion(self): - class Trap1(int): - def __index__(self): - return self - class Trap2(long): - def __index__(self): - return self - self.failUnlessRaises(TypeError, operator.getitem, self.seq, Trap1()) - self.failUnlessRaises(TypeError, operator.getitem, self.seq, Trap2()) + def test_infinite_recursion(self): + self.failUnlessRaises(TypeError, operator.getitem, self.seq, TrapInt()) + self.failUnlessRaises(TypeError, operator.getitem, self.seq, TrapLong()) + def test_error(self): + self.o.ind = 'dumb' + self.n.ind = 'bad' + indexobj = lambda x, obj: obj.seq[x] + self.failUnlessRaises(TypeError, indexobj, self.o, self) + self.failUnlessRaises(TypeError, indexobj, self.n, self) + sliceobj = lambda x, obj: obj.seq[x:] + self.failUnlessRaises(TypeError, sliceobj, self.o, self) + self.failUnlessRaises(TypeError, sliceobj, self.n, self) -class ListTestCase(BaseTestCase): +class ListTestCase(SeqTestCase): seq = [0,10,20,30,40,50] def test_setdelitem(self): @@ -105,13 +154,13 @@ assert lst == [5, 6, 7, 8, 9, 11] * 3 -class TupleTestCase(BaseTestCase): +class TupleTestCase(SeqTestCase): seq = (0,10,20,30,40,50) -class StringTestCase(BaseTestCase): +class StringTestCase(SeqTestCase): seq = "this is a test" -class UnicodeTestCase(BaseTestCase): +class UnicodeTestCase(SeqTestCase): seq = u"this is a test" @@ -120,17 +169,49 @@ def test_xrange(self): n = newstyle() n.ind = 5 - assert xrange(1, 20)[n] == 6 - assert xrange(1, 20).__getitem__(n) == 6 + self.failUnless(xrange(1, 20)[n] == 6) + self.failUnless(xrange(1, 20).__getitem__(n) == 6) +class OverflowTestCase(unittest.TestCase): + def setUp(self): + self.pos = 2**100 + self.neg = -self.pos + + def test_large_longs(self): + self.failUnless(self.pos.__index__() == self.pos) + self.failUnless(self.neg.__index__() == self.neg) + + def test_getitem(self): + class GetItem(object): + def __len__(self): + return maxint + def __getitem__(self, key): + return key + def __getslice__(self, i, j): + return i, j + x = GetItem() + self.failUnless(x[self.pos] == self.pos) + self.failUnless(x[self.neg] == self.neg) + self.failUnless(x[self.neg:self.pos] == (-1, maxint)) + self.failUnless(x[self.neg:self.pos:1].indices(maxint) == (0, maxint, 1)) + + def test_sequence_repeat(self): + self.failUnlessRaises(OverflowError, lambda: "a" * self.pos) + self.failUnlessRaises(OverflowError, lambda: "a" * self.neg) + + + + def test_main(): test_support.run_unittest( + BaseTestCase, ListTestCase, TupleTestCase, StringTestCase, UnicodeTestCase, XRangeTestCase, + OverflowTestCase, ) if __name__ == "__main__": Index: Modules/mmapmodule.c =================================================================== --- Modules/mmapmodule.c (revision 51214) +++ Modules/mmapmodule.c (working copy) @@ -808,8 +808,6 @@ }; -#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) - /* extract the map size from the given PyObject Returns -1 on error, with an appropriate Python exception raised. On @@ -817,15 +815,15 @@ static Py_ssize_t _GetMapSize(PyObject *o) { - PyNumberMethods *nb = o->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(o) && nb->nb_index != NULL) { - Py_ssize_t i = nb->nb_index(o); + if (PyIndex_Check(o)) { + Py_ssize_t i = PyNumber_AsSsize_t(o, PyExc_OverflowError); if (i==-1 && PyErr_Occurred()) return -1; - if (i < 0) - goto onnegoverflow; - if (i==PY_SSIZE_T_MAX) - goto onposoverflow; + if (i < 0) { + PyErr_SetString(PyExc_OverflowError, + "memory mapped size must be positive"); + return -1; + } return i; } else { @@ -833,16 +831,6 @@ "map size must be an integral value"); return -1; } - - onnegoverflow: - PyErr_SetString(PyExc_OverflowError, - "memory mapped size must be positive"); - return -1; - - onposoverflow: - PyErr_SetString(PyExc_OverflowError, - "memory mapped size is too large (limited by C int)"); - return -1; } #ifdef UNIX Index: Modules/arraymodule.c =================================================================== --- Modules/arraymodule.c (revision 51214) +++ Modules/arraymodule.c (working copy) @@ -1570,14 +1570,11 @@ return s; } -#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) - static PyObject* array_subscr(arrayobject* self, PyObject* item) { - PyNumberMethods *nb = item->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { - Py_ssize_t i = nb->nb_index(item); + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i==-1 && PyErr_Occurred()) { return NULL; } @@ -1625,9 +1622,8 @@ static int array_ass_subscr(arrayobject* self, PyObject* item, PyObject* value) { - PyNumberMethods *nb = item->ob_type->tp_as_number; - if (nb != NULL && HASINDEX(item) && nb->nb_index != NULL) { - Py_ssize_t i = nb->nb_index(item); + if (PyIndex_Check(item)) { + Py_ssize_t i = PyNumber_AsSsize_t(item, PyExc_IndexError); if (i==-1 && PyErr_Occurred()) return -1; if (i < 0) Index: Modules/operator.c =================================================================== --- Modules/operator.c (revision 51214) +++ Modules/operator.c (working copy) @@ -137,17 +137,9 @@ } static PyObject * -op_index(PyObject *s, PyObject *a) +op_index(PyObject *s, PyObject *a1) { - Py_ssize_t i; - PyObject *a1; - if (!PyArg_UnpackTuple(a,"index", 1, 1, &a1)) - return NULL; - i = PyNumber_Index(a1); - if (i == -1 && PyErr_Occurred()) - return NULL; - else - return PyInt_FromSsize_t(i); + return PyNumber_Index(a1); } static PyObject* @@ -249,7 +241,7 @@ spam1(is_, "is_(a, b) -- Same as a is b.") spam1(is_not, "is_not(a, b) -- Same as a is not b.") -spam2(index, __index__, "index(a) -- Same as a.__index__()") +spam2o(index, __index__, "index(a) -- Same as a.__index__()") spam2(add,__add__, "add(a, b) -- Same as a + b.") spam2(sub,__sub__, "sub(a, b) -- Same as a - b.") spam2(mul,__mul__, "mul(a, b) -- Same as a * b.")