Index: Python/ceval.c =================================================================== --- Python/ceval.c (revision 42810) +++ Python/ceval.c (working copy) @@ -3913,9 +3913,10 @@ return result; } -/* Extract a slice index from a PyInt or PyLong, and store in *pi. - Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX, - and silently boost values less than -PY_SSIZE_T_MAX to 0. +/* Extract a slice index from a PyInt or PyLong or an object with the + nb_index slot defined, and store in *pi. + Silently reduce values larger than PY_SSIZE_T_MAX to PY_SSIZE_T_MAX, + and silently boost values less than -PY_SSIZE_T_MAX to -PY_SSIZE_T_MAX. Return 0 on error, 1 on success. */ /* Note: If v is NULL, return success without storing into *pi. This @@ -3966,9 +3967,18 @@ else x = -PY_SSIZE_T_MAX; } - } else { + } + 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); + if (x == -1 && PyErr_Occurred()) + return 0; + } + else { PyErr_SetString(PyExc_TypeError, - "slice indices must be integers or None"); + "slice indices must be integers or " + "None or have an __index__ method"); return 0; } *pi = x; @@ -3976,8 +3986,11 @@ return 1; } -#undef ISINT -#define ISINT(x) ((x) == NULL || PyInt_Check(x) || PyLong_Check(x)) +#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)) static PyObject * apply_slice(PyObject *u, PyObject *v, PyObject *w) /* return u[v:w] */ @@ -3985,7 +3998,7 @@ PyTypeObject *tp = u->ob_type; PySequenceMethods *sq = tp->tp_as_sequence; - if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) { + if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) { Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX; if (!_PyEval_SliceIndex(v, &ilow)) return NULL; @@ -4012,7 +4025,7 @@ PyTypeObject *tp = u->ob_type; PySequenceMethods *sq = tp->tp_as_sequence; - if (sq && sq->sq_slice && ISINT(v) && ISINT(w)) { + if (sq && sq->sq_slice && ISINDEX(v) && ISINDEX(w)) { Py_ssize_t ilow = 0, ihigh = PY_SSIZE_T_MAX; if (!_PyEval_SliceIndex(v, &ilow)) return -1; Index: Include/abstract.h =================================================================== --- Include/abstract.h (revision 42810) +++ Include/abstract.h (working copy) @@ -748,6 +748,14 @@ */ + PyAPI_FUNC(Py_ssize_t) PyNumber_Index(PyObject *); + + /* + Returns the object converted to Py_ssize_t on success + or -1 with an error raised on failure. + */ + + PyAPI_FUNC(PyObject *) PyNumber_Int(PyObject *o); /* Index: Include/object.h =================================================================== --- Include/object.h (revision 42810) +++ Include/object.h (working copy) @@ -206,6 +206,9 @@ binaryfunc nb_true_divide; binaryfunc nb_inplace_floor_divide; binaryfunc nb_inplace_true_divide; + + /* Added in release 2.5 */ + lenfunc nb_index; } PyNumberMethods; typedef struct { @@ -503,13 +506,16 @@ /* Objects support garbage collection (see objimp.h) */ #define Py_TPFLAGS_HAVE_GC (1L<<14) -/* These two bits are preserved for Stackless Python, next after this is 16 */ +/* These two bits are preserved for Stackless Python, next after this is 17 */ #ifdef STACKLESS #define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION (3L<<15) #else #define Py_TPFLAGS_HAVE_STACKLESS_EXTENSION 0 #endif +/* Objects support nb_index in PyNumberMethods */ +#define Py_TPFLAGS_HAVE_INDEX (1L<<17) + #define Py_TPFLAGS_DEFAULT ( \ Py_TPFLAGS_HAVE_GETCHARBUFFER | \ Py_TPFLAGS_HAVE_SEQUENCE_IN | \ @@ -519,6 +525,7 @@ Py_TPFLAGS_HAVE_ITER | \ Py_TPFLAGS_HAVE_CLASS | \ Py_TPFLAGS_HAVE_STACKLESS_EXTENSION | \ + Py_TPFLAGS_HAVE_INDEX | \ 0) #define PyType_HasFeature(t,f) (((t)->tp_flags & (f)) != 0) Index: Objects/abstract.c =================================================================== --- Objects/abstract.c (revision 42810) +++ Objects/abstract.c (working copy) @@ -8,6 +8,8 @@ #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 * @@ -119,10 +121,9 @@ return m->mp_subscript(o, key); if (o->ob_type->tp_as_sequence) { - if (PyInt_Check(key)) - return PySequence_GetItem(o, PyInt_AsLong(key)); - else if (PyLong_Check(key)) { - long key_value = PyLong_AsLong(key); + 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 (key_value == -1 && PyErr_Occurred()) return NULL; return PySequence_GetItem(o, key_value); @@ -148,10 +149,9 @@ return m->mp_ass_subscript(o, key, value); if (o->ob_type->tp_as_sequence) { - if (PyInt_Check(key)) - return PySequence_SetItem(o, PyInt_AsLong(key), value); - else if (PyLong_Check(key)) { - long key_value = PyLong_AsLong(key); + 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 (key_value == -1 && PyErr_Occurred()) return -1; return PySequence_SetItem(o, key_value, value); @@ -180,10 +180,9 @@ return m->mp_ass_subscript(o, key, (PyObject*)NULL); if (o->ob_type->tp_as_sequence) { - if (PyInt_Check(key)) - return PySequence_DelItem(o, PyInt_AsLong(key)); - else if (PyLong_Check(key)) { - long key_value = PyLong_AsLong(key); + 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 (key_value == -1 && PyErr_Occurred()) return -1; return PySequence_DelItem(o, key_value); @@ -647,12 +646,10 @@ static PyObject * sequence_repeat(ssizeargfunc repeatfunc, PyObject *seq, PyObject *n) { - long count; - if (PyInt_Check(n)) { - count = PyInt_AsLong(n); - } - else if (PyLong_Check(n)) { - count = PyLong_AsLong(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 (count == -1 && PyErr_Occurred()) return NULL; } @@ -660,32 +657,7 @@ return type_error( "can't multiply sequence by non-int"); } -#if LONG_MAX != INT_MAX - if (count > INT_MAX) { - PyErr_SetString(PyExc_ValueError, - "sequence repeat count too large"); - return NULL; - } - else if (count < INT_MIN) - count = INT_MIN; - /* XXX Why don't I either - - - set count to -1 whenever it's negative (after all, - sequence repeat usually treats negative numbers - as zero(); or - - - raise an exception when it's less than INT_MIN? - - I'm thinking about a hypothetical use case where some - sequence type might use a negative value as a flag of - some kind. In those cases I don't want to break the - code by mapping all negative values to -1. But I also - don't want to break e.g. []*(-sys.maxint), which is - perfectly safe, returning []. As a compromise, I do - map out-of-range negative values. - */ -#endif - return (*repeatfunc)(seq, (int)count); + return (*repeatfunc)(seq, count); } PyObject * @@ -960,6 +932,22 @@ return x; } +/* Return a Py_ssize_t integer from the object item */ +Py_ssize_t +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); + } + else { + PyErr_SetString(PyExc_IndexError, + "object cannot be interpreted as an index"); + } + return value; +} + PyObject * PyNumber_Int(PyObject *o) { Index: Objects/typeobject.c =================================================================== --- Objects/typeobject.c (revision 42810) +++ Objects/typeobject.c (working copy) @@ -3051,6 +3051,9 @@ COPYNUM(nb_inplace_true_divide); COPYNUM(nb_inplace_floor_divide); } + if (base->tp_flags & Py_TPFLAGS_HAVE_INDEX) { + COPYNUM(nb_index); + } } if (type->tp_as_sequence != NULL && base->tp_as_sequence != NULL) { @@ -4343,6 +4346,42 @@ return result; } + +static Py_ssize_t +slot_nb_index(PyObject *self) +{ + PyObject *func, *args; + static PyObject *index_str; + Py_ssize_t result = -1; + + func = lookup_maybe(self, "__index__", &index_str); + if (func == NULL) { + if (!PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "object cannot be interpreted as an index"); + } + return -1; + } + args = PyTuple_New(0); + if (args != NULL) { + PyObject *temp = PyObject_Call(func, args, NULL); + Py_DECREF(args); + if (temp != NULL) { + if (!PyInt_Check(temp) && !PyLong_Check(temp)) { + PyErr_SetString(PyExc_TypeError, + "__index__ must return an int or a long"); + } + else { + result = PyInt_AsSsize_t(temp); + } + Py_DECREF(temp); + } + } + Py_DECREF(func); + return result; +} + + SLOT0(slot_nb_invert, "__invert__") SLOT1BIN(slot_nb_lshift, nb_lshift, "__lshift__", "__rlshift__") SLOT1BIN(slot_nb_rshift, nb_rshift, "__rshift__", "__rrshift__") @@ -5068,6 +5107,8 @@ "oct(x)"), UNSLOT("__hex__", nb_hex, slot_nb_hex, wrap_unaryfunc, "hex(x)"), + NBSLOT("__index__", nb_index, slot_nb_index, wrap_lenfunc, + "x[y:z] <==> x[y.__index__():z.__index__()]"), IBSLOT("__iadd__", nb_inplace_add, slot_nb_inplace_add, wrap_binaryfunc, "+"), IBSLOT("__isub__", nb_inplace_subtract, slot_nb_inplace_subtract, Index: Objects/unicodeobject.c =================================================================== --- Objects/unicodeobject.c (revision 42810) +++ Objects/unicodeobject.c (working copy) @@ -6459,11 +6459,14 @@ (objobjproc)PyUnicode_Contains, /*sq_contains*/ }; +#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) + static PyObject* unicode_subscript(PyUnicodeObject* self, PyObject* item) { - if (PyInt_Check(item) || PyLong_Check(item)) { - Py_ssize_t i = PyInt_AsSsize_t(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 (i == -1 && PyErr_Occurred()) return NULL; if (i < 0) Index: Objects/tupleobject.c =================================================================== --- Objects/tupleobject.c (revision 42810) +++ Objects/tupleobject.c (working copy) @@ -584,11 +584,14 @@ (objobjproc)tuplecontains, /* sq_contains */ }; +#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) + static PyObject* tuplesubscript(PyTupleObject* self, PyObject* item) { - if (PyInt_Check(item) || PyLong_Check(item)) { - Py_ssize_t i = PyInt_AsSsize_t(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 (i == -1 && PyErr_Occurred()) return NULL; if (i < 0) Index: Objects/intobject.c =================================================================== --- Objects/intobject.c (revision 42810) +++ Objects/intobject.c (working copy) @@ -1069,6 +1069,7 @@ int_true_divide, /* nb_true_divide */ 0, /* nb_inplace_floor_divide */ 0, /* nb_inplace_true_divide */ + (lenfunc)PyInt_AsSsize_t, /* nb_index */ }; PyTypeObject PyInt_Type = { Index: Objects/listobject.c =================================================================== --- Objects/listobject.c (revision 42810) +++ Objects/listobject.c (working copy) @@ -2452,11 +2452,14 @@ "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) { - if (PyInt_Check(item) || PyLong_Check(item)) { - Py_ssize_t i = PyInt_AsSsize_t(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 (i == -1 && PyErr_Occurred()) return NULL; if (i < 0) @@ -2503,14 +2506,9 @@ static int list_ass_subscript(PyListObject* self, PyObject* item, PyObject* value) { - if (PyInt_Check(item)) { - Py_ssize_t i = PyInt_AS_LONG(item); - if (i < 0) - i += PyList_GET_SIZE(self); - return list_ass_item(self, i, value); - } - else if (PyLong_Check(item)) { - Py_ssize_t i = PyInt_AsSsize_t(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 (i == -1 && PyErr_Occurred()) return -1; if (i < 0) Index: Objects/longobject.c =================================================================== --- Objects/longobject.c (revision 42810) +++ Objects/longobject.c (working copy) @@ -3125,6 +3125,7 @@ long_true_divide, /* nb_true_divide */ 0, /* nb_inplace_floor_divide */ 0, /* nb_inplace_true_divide */ + (lenfunc) PyInt_AsSsize_t, /* nb_index */ }; PyTypeObject PyLong_Type = { Index: Objects/classobject.c =================================================================== --- Objects/classobject.c (revision 42810) +++ Objects/classobject.c (working copy) @@ -1733,6 +1733,43 @@ return outcome > 0; } +static Py_ssize_t +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; + } + if ((func = instance_getattr(self, indexstr)) == NULL) { + if (!PyErr_ExceptionMatches(PyExc_AttributeError)) + return -1; + PyErr_Clear(); + PyErr_SetString(PyExc_TypeError, + "object cannot be interpreted as an index"); + return -1; + } + res = PyEval_CallObject(func, (PyObject *)NULL); + Py_DECREF(func); + if (res == NULL) + return -1; + if (!PyInt_Check(res) && !PyLong_Check(res)) { + PyErr_SetString(PyExc_TypeError, + "__index__ must return an int or a long"); + outcome = -1; + } + else { + outcome = PyInt_AsSsize_t(res); + } + Py_DECREF(res); + return outcome; +} + + UNARY(instance_invert, "__invert__") UNARY(instance_int, "__int__") UNARY(instance_long, "__long__") @@ -2052,6 +2089,7 @@ (binaryfunc)instance_truediv, /* nb_true_divide */ (binaryfunc)instance_ifloordiv, /* nb_inplace_floor_divide */ (binaryfunc)instance_itruediv, /* nb_inplace_true_divide */ + (inquiry)instance_index, /* nb_index */ }; PyTypeObject PyInstance_Type = { Index: Objects/stringobject.c =================================================================== --- Objects/stringobject.c (revision 42810) +++ Objects/stringobject.c (working copy) @@ -1187,16 +1187,19 @@ return x; } +#define HASINDEX(o) PyType_HasFeature((o)->ob_type, Py_TPFLAGS_HAVE_INDEX) + static PyObject* string_subscript(PyStringObject* self, PyObject* item) { - if (PyInt_Check(item) || PyLong_Check(item)) { - Py_ssize_t i = PyInt_AsSsize_t(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 (i == -1 && PyErr_Occurred()) return NULL; if (i < 0) i += PyString_GET_SIZE(self); - return string_item(self,i); + return string_item(self, i); } else if (PySlice_Check(item)) { Py_ssize_t start, stop, step, slicelength, cur, i; Index: Doc/lib/liboperator.tex =================================================================== --- Doc/lib/liboperator.tex (revision 42810) +++ Doc/lib/liboperator.tex (working copy) @@ -171,6 +171,10 @@ Return the bitwise exclusive or of \var{a} and \var{b}. \end{funcdesc} +\begin{funcdesc}{index}{a} +\funcline{__index__}{a} +Return \var{a} converted to an integer. Equivalent to \var{a}\code{.__index__()}. +\end{funcdesc} Operations which work with sequences include: Index: Doc/api/abstract.tex =================================================================== --- Doc/api/abstract.tex (revision 42810) +++ Doc/api/abstract.tex (working copy) @@ -689,6 +689,10 @@ \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. +\end{cfuncdesc} \section{Sequence Protocol \label{sequence}} Index: Doc/ref/ref3.tex =================================================================== --- Doc/ref/ref3.tex (revision 42810) +++ Doc/ref/ref3.tex (working copy) @@ -1978,6 +1978,12 @@ \function{hex()}\bifuncindex{hex}. Should return a string value. \end{methoddesc} +\begin{methoddesc}[numeric object]{__index__}{self} +Called to implement operator.index(). Also called whenever Python +needs an integer object (such as in slicing). Must return an integer +(int or long). +\end{methoddesc} + \begin{methoddesc}[numeric object]{__coerce__}{self, other} Called to implement ``mixed-mode'' numeric arithmetic. Should either return a 2-tuple containing \var{self} and \var{other} converted to Index: Lib/test/test_index.py =================================================================== --- Lib/test/test_index.py (revision 0) +++ Lib/test/test_index.py (revision 0) @@ -0,0 +1,159 @@ +import unittest +from test import test_support +import operator + +class oldstyle: + def __index__(self): + return self.ind + +class newstyle(object): + def __index__(self): + return self.ind + +class ListTestCase(unittest.TestCase): + def setUp(self): + self.seq = [0,10,20,30,40,50] + 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] == 20) + assert(self.seq[self.o] == 40) + assert(operator.index(self.o) == -2) + assert(operator.index(self.n) == 2) + + 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) + + 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]) + +class TupleTestCase(unittest.TestCase): + def setUp(self): + self.seq = (0,10,20,30,40,50) + 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] == 20) + assert(self.seq[self.o] == 40) + assert(operator.index(self.o) == -2) + assert(operator.index(self.n) == 2) + + 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) + + 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]) + +class StringTestCase(unittest.TestCase): + def setUp(self): + self.seq = "this is a test" + 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) + + 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) + + 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]) + + +class UnicodeTestCase(unittest.TestCase): + def setUp(self): + self.seq = u"this is a test" + 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) + + 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) + + 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]) + + +def test_main(): + test_support.run_unittest( + ListTestCase, + TupleTestCase, + StringTestCase, + UnicodeTestCase + ) + +if __name__ == "__main__": + test_main() Property changes on: Lib/test/test_index.py ___________________________________________________________________ Name: svn:keywords + Id Name: svn:eol-style + native Index: Modules/operator.c =================================================================== --- Modules/operator.c (revision 42810) +++ Modules/operator.c (working copy) @@ -130,6 +130,20 @@ return NULL; } +static PyObject * +op_index(PyObject *s, PyObject *a) +{ + 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); +} + static PyObject* is_(PyObject *s, PyObject *a) { @@ -229,6 +243,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__()") 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.")