Commits

Alexander Schremmer committed b285407

(xorAxAx, gbrandl, armin with useful svn hints) Merged pypy-2.5 branch into dist.

Comments (0)

Files changed (36)

pypy/config/pypyoption.py

 default_modules = essential_modules.copy()
 default_modules.update(dict.fromkeys(
     ["_codecs", "gc", "_weakref", "array", "marshal", "errno",
-     "math", "_sre", "_pickle_support",
+     "math", "_sre", "_pickle_support", "operator",
      "recparser", "symbol", "_random", "pypymagic"]))
 
 

pypy/interpreter/baseobjspace.py

 from pypy.interpreter.miscutils import ThreadLocals
 from pypy.tool.cache import Cache
 from pypy.tool.uid import HUGEVAL_BYTES
-import os
+import os, sys
 
 __all__ = ['ObjSpace', 'OperationError', 'Wrappable', 'W_Root']
 
             step  = 0
         return start, stop, step
 
+    def getindex_w(self, w_obj, exception=None):
+        w_index = self.index(w_obj)
+        try:
+            index = self.int_w(w_index)
+        except OperationError, err:
+            if not err.match(self, self.w_OverflowError):
+                raise
+            if not exception:
+                # w_index is a long object
+                if w_index.get_sign() < 0:
+                    return -sys.maxint-1
+                else:
+                    return sys.maxint
+            else:
+                raise OperationError(
+                    exception, self.wrap(
+                    "cannot fit '%s' into an index-sized "
+                    "integer" % self.type(w_obj).getname(self, '?')))
+        else:
+            return index
+
+
 class AppExecCache(SpaceCache):
     def build(cache, source):
         """ NOT_RPYTHON """
     ('or_',             '|',         2, ['__or__', '__ror__']),
     ('xor',             '^',         2, ['__xor__', '__rxor__']),
     ('int',             'int',       1, ['__int__']),
+    ('index',           'index',     1, ['__index__']),
     ('float',           'float',     1, ['__float__']),
     ('long',            'long',      1, ['__long__']),
     ('inplace_add',     '+=',        2, ['__iadd__']),

pypy/interpreter/gateway.py

 
     def visit_self(self, cls, app_sig):
         self.visit__Wrappable(cls, app_sig)
-        
+
+    def checked_space_method(self, typ, app_sig):
+        argname = self.orig_arg()
+        assert not argname.startswith('w_'), (
+            "unwrapped %s argument %s of built-in function %r should "
+            "not start with 'w_'" % (typ.__name__, argname, self.func))
+        app_sig.append(argname)
+
+    def visit_index(self, index, app_sig):
+        self.checked_space_method(index, app_sig)
+
     def visit__Wrappable(self, el, app_sig):
         name = el.__name__
         argname = self.orig_arg()
     def visit__object(self, typ, app_sig):
         if typ not in (int, str, float):
             assert False, "unsupported basic type in unwrap_spec"
-        argname = self.orig_arg()
-        assert not argname.startswith('w_'), (
-            "unwrapped %s argument %s of built-in function %r should "
-            "not start with 'w_'" % (typ.__name__, argname, self.func))
-        app_sig.append(argname)        
+        self.checked_space_method(typ, app_sig)
 
 
 class UnwrapSpec_EmitRun(UnwrapSpecEmit):
         self.run_args.append("space.%s_w(%s)" %
                              (typ.__name__, self.scopenext()))
 
+    def visit_index(self, typ):
+        self.run_args.append("space.getindex_w(%s)" % (self.scopenext(), ))
+
     def _make_unwrap_activation_class(self, unwrap_spec, cache={}):
         try:
             key = tuple(unwrap_spec)
         self.unwrap.append("space.%s_w(%s)" % (typ.__name__,
                                                self.nextarg()))
 
+    def visit_index(self, typ):
+        self.unwrap.append("space.getindex_w(%s)" % (self.nextarg()), )
+
     def make_fastfunc(unwrap_spec, func):
         unwrap_info = UnwrapSpec_FastFunc_Unwrap()
         unwrap_info.apply_over(unwrap_spec)

pypy/interpreter/test/test_gateway.py

                                                    gateway.Arguments])
         assert code.signature() == (['x', 'y'], 'args', 'keywords')
 
+        def f(space, index):
+            pass
+        code = gateway.BuiltinCode(f, unwrap_spec=[gateway.ObjSpace, "index"])
+        assert code.signature() == (["index"], None, None)
+
+
     def test_call(self):
         def c(space, w_x, w_y, hello_w):
             u = space.unwrap
         w_result = code.funcrun(FakeFunc(self.space, "c"), args)
         assert self.space.eq_w(w_result, w(102))
 
+    def test_call_index(self):
+        def c(space, index):
+            assert type(index) is int
+        code = gateway.BuiltinCode(c, unwrap_spec=[gateway.ObjSpace,
+                                                   "index"])
+        w = self.space.wrap
+        args = argument.Arguments(self.space, [w(123)])
+        code.funcrun(FakeFunc(self.space, "c"), args)
+
     def test_call_args(self):
         def c(space, w_x, w_y, __args__):
             args_w, kwds_w = __args__.unpack()

pypy/interpreter/test/test_objspace.py

 from py.test import raises
 from pypy.interpreter.function import Function
 from pypy.interpreter.pycode import PyCode
+import sys
 
 # this test isn't so much to test that the objspace interface *works*
 # -- it's more to test that it's *there*
         res = self.space.interp_w(Function, w(None), can_be_None=True)
         assert res is None
 
+    def test_getindex_w(self):
+        w_instance1 = self.space.appexec([], """():
+            class X(object):
+                def __index__(self): return 42
+            return X()""")
+        w_instance2 = self.space.appexec([], """():
+            class Y(object):
+                def __index__(self): return 2**70
+            return Y()""")
+        first = self.space.getindex_w(w_instance1)
+        assert first == 42
+        second = self.space.getindex_w(w_instance2)
+        assert second == sys.maxint
+        self.space.raises_w(self.space.w_IndexError,
+                            self.space.getindex_w, w_instance2, self.space.w_IndexError)
+
+
 class TestModuleMinimal: 
     def test_sys_exists(self):
         assert self.space.sys 

pypy/lib/_classobj.py

 """, {"op": op})
     del op
 
+    def __index__(self):
+        func = instance_getattr1(self, '__index__', False)
+        if func:
+            return func()
+        else:
+            raise AttributeError('object cannot be interpreted as an index')
+
+
     # coerce
     def __coerce__(self, other):
         func = instance_getattr1(self, '__coerce__', False)

pypy/lib/_functools.py

+""" Supplies the internal functions for functools.py in the standard library """
+
+class partial:
+    """
+    partial(func, *args, **keywords) - new function with partial application
+	of the given arguments and keywords.
+    """
+    __slots__ = ['func', 'args', 'keywords']
+
+    def __init__(self, func, *args, **keywords):
+        if not callable(func):
+            raise TypeError("the first argument must be callable")
+        self.func = func
+        self.args = args
+        self.keywords = keywords
+
+    def __call__(self, *fargs, **fkeywords):
+        newkeywords = self.keywords.copy()
+        newkeywords.update(fkeywords)
+        return self.func(*(self.args + fargs), **newkeywords)
+

pypy/lib/operator.py

-'''Operator interface.
-
-This module exports a set of operators as functions. E.g. operator.add(x,y) is
-equivalent to x+y.
-'''
-import __builtin__
-
-def abs(obj,):
-    'abs(a) -- Same as abs(a).'
-    return __builtin__.abs(obj)
-__abs__ = abs
-def add(obj1, obj2):
-    'add(a, b) -- Same as a + b.'
-    return obj1 + obj2
-__add__ = add
-def and_(obj1,obj2):
-    'and_(a, b) -- Same as a & b.'
-    return obj1 & obj2
-__and__ = and_
-def attrgetter(attr):
-    def f(obj):
-        return getattr(obj, attr)
-    return f
-def concat(obj1, obj2):
-    'concat(a, b) -- Same as a + b, for a and b sequences.'
-    return obj1 + obj2  # XXX cPython only works on types with sequence api
-                        # we support any with __add__
-__concat__ = concat
-
-def contains(obj1,obj2):
-    'contains(a, b) -- Same as b in a (note reversed operands).'
-    return obj2 in obj1 
-__contains__ = contains
-def countOf(a,b): 
-    'countOf(a, b) -- Return the number of times b occurs in a.'
-    count = 0
-    for x in a:
-        if x == b:
-            count += 1
-    return count
-def delitem(obj, key):
-    'delitem(a, b) -- Same as del a[b].'
-    del obj[key]
-__delitem__ = delitem
-def delslice(obj, start, end):
-    'delslice(a, b, c) -- Same as del a[b:c].'
-    if not isinstance(start, int) or not isinstance(end, int):
-        raise TypeError("an integer is expected")
-    del obj[start:end]
-__delslice__ = delslice
-def div(a,b):
-    'div(a, b) -- Same as a / b when __future__.division is not in effect.'
-    return a / b
-__div__ = div
-def eq(a, b):
-    'eq(a, b) -- Same as a==b.'
-    return a == b 
-__eq__ = eq
-def floordiv(a, b):
-    'floordiv(a, b) -- Same as a // b.'
-    return a // b 
-__floordiv__ = floordiv
-def ge(a, b):
-    'ge(a, b) -- Same as a>=b.'
-    return a >= b
-__ge__ = ge
-def getitem(a, b):
-    'getitem(a, b) -- Same as a[b].'
-    return a[b] 
-__getitem__ = getitem
-def getslice(a, start, end):
-    'getslice(a, b, c) -- Same as a[b:c].'
-    if not isinstance(start, int) or not isinstance(end, int):
-        raise TypeError("an integer is expected")
-    return a[start:end] 
-__getslice__ = getslice
-def gt(a,b):
-    'gt(a, b) -- Same as a>b.'
-    return a > b
-__gt__ = gt
-def indexOf(a, b):
-    'indexOf(a, b) -- Return the first index of b in a.'
-    index = 0
-    for x in a:
-        if x == b:
-            return index
-        index += 1
-    raise ValueError, 'sequence.index(x): x not in sequence'
-def inv(obj,):
-    'inv(a) -- Same as ~a.'
-    return ~obj 
-__inv__ = inv
-def invert(obj,):
-    'invert(a) -- Same as ~a.'
-    return ~obj 
-__invert__ = invert
-def isCallable(obj,):
-    'isCallable(a) -- Same as callable(a).'
-    return callable(obj) 
-
-# XXX the following is approximative
-def isMappingType(obj,):
-    'isMappingType(a) -- Return True if a has a mapping type, False otherwise.'
-    # XXX this is fragile and approximative anyway
-    return hasattr(obj, '__getitem__') and hasattr(obj, 'keys')
-def isNumberType(obj,):
-    'isNumberType(a) -- Return True if a has a numeric type, False otherwise.'
-    return hasattr(obj, '__int__') or hasattr(obj, '__float__') 
-def isSequenceType(obj,):
-    'isSequenceType(a) -- Return True if a has a sequence type, False otherwise.'
-    return hasattr(obj, '__getitem__')
-
-def is_(a, b):
-    'is_(a, b) -- Same as a is b.'
-    return a is b 
-def is_not(a, b):
-    'is_not(a, b) -- Same as a is not b.'
-    return a is not b 
-def itemgetter(idx):
-    def f(obj):
-        return obj[idx]
-    return f
-def le(a, b):
-    'le(a, b) -- Same as a<=b.'
-    return a <= b 
-__le__ = le
-def lshift(a, b):
-    'lshift(a, b) -- Same as a << b.'
-    return a << b 
-__lshift__ = lshift
-def lt(a, b):
-    'lt(a, b) -- Same as a<b.'
-    return a < b 
-__lt__ = lt
-def mod(a, b):
-    'mod(a, b) -- Same as a % b.'
-    return a % b 
-__mod__ = mod
-def mul(a, b):
-    'mul(a, b) -- Same as a * b.'
-    return a * b 
-__mul__ = mul
-def ne(a, b):
-    'ne(a, b) -- Same as a!=b.'
-    return a != b 
-__ne__ = ne
-def neg(obj,):
-    'neg(a) -- Same as -a.'
-    return -obj
-__neg__ = neg
-def not_(obj,):
-    'not_(a) -- Same as not a.'
-    return not obj
-__not__ = not_
-
-def or_(a, b):
-    'or_(a, b) -- Same as a | b.'
-    return a | b 
-__or__ = or_
-def pos(obj,):
-    'pos(a) -- Same as +a.'
-    return +obj 
-__pos__ = pos
-def pow(a, b):
-    'pow(a, b) -- Same as a**b.'
-    return a ** b
-__pow__ = pow
-def repeat(obj, num):
-    'repeat(a, b) -- Return a * b, where a is a sequence, and b is an integer.'
-    if not isinstance(num, (int, long)):
-        raise TypeError, 'an integer is required'
-    return obj * num   # XXX cPython only supports objects with the sequence
-                       # protocol. We support any with a __mul__
-__repeat__ = repeat
-
-def rshift(a, b):
-    'rshift(a, b) -- Same as a >> b.'
-    return a >> b 
-__rshift__ = rshift
-def sequenceIncludes(a, b):
-    'sequenceIncludes(a, b) -- Same as b in a (note reversed operands; deprecated).'
-    for x in a:
-        if x == b:
-            return True
-    return False
-def setitem(obj, key, value):
-    'setitem(a, b, c) -- Same as a[b] = c.'
-    obj[key] = value 
-__setitem__ = setitem
-def setslice(a, b, c, d):
-    'setslice(a, b, c, d) -- Same as a[b:c] = d.'
-    a[b:c] = d 
-__setslice__ = setslice
-def sub(a, b):
-    'sub(a, b) -- Same as a - b.'
-    return a - b 
-__sub__ = sub
-
-exec """from __future__ import division
-def truediv(a, b):
-    'truediv(a, b) -- Same as a / b when __future__.division is in effect.'
-    return a / b 
-"""
-__truediv__ = truediv
-def truth(a,):
-    'truth(a) -- Return True if a is true, False otherwise.'
-    return not not a 
-def xor(a, b):
-    'xor(a, b) -- Same as a ^ b.'
-    return a ^ b 
-__xor__ = xor

pypy/module/__builtin__/app_functional.py

 """
 from __future__ import generators
 
+from operator import lt, gt
+
+
 def sum(sequence, total=0):
     """sum(sequence, start=0) -> value
 
 # min and max could be one function if we had operator.__gt__ and
 # operator.__lt__  Perhaps later when we have operator.
 
-def min(*arr):
+
+def _identity(arg):
+    return arg
+
+
+def min(*arr, **kwargs):
     """return the smallest number in a list,
     or its smallest argument if more than one is given."""
 
+    return min_max(gt, "min", *arr, **kwargs)
+
+def min_max(comp, funcname, *arr, **kwargs):
+    key = kwargs.pop("key", _identity)
+    if len(kwargs):
+        raise TypeError, '%s() got an unexpected keyword argument' % funcname
+
     if not arr:
-        raise TypeError, 'min() takes at least one argument'
+        raise TypeError, '%s() takes at least one argument' % funcname
 
     if len(arr) == 1:
         arr = arr[0]
 
     iterator = iter(arr)
     try:
-        min = iterator.next()
+        min_max_val = iterator.next()
     except StopIteration:
-        raise ValueError, 'min() arg is an empty sequence'
+        raise ValueError, '%s() arg is an empty sequence' % funcname
+
+    keyed_min_max_val = key(min_max_val)
 
     for i in iterator:
-        if min > i:
-            min = i
-    return min
+        keyed = key(i)
+        if comp(keyed_min_max_val, keyed):
+            min_max_val = i
+            keyed_min_max_val = keyed
+    return min_max_val
 
-def max(*arr):
+def max(*arr, **kwargs):
     """return the largest number in a list,
     or its largest argument if more than one is given."""
 
-    if not arr:
-        raise TypeError, 'max() takes at least one argument'
-
-    if len(arr) == 1:
-        arr = arr[0]
-
-    iterator = iter(arr)
-    try:
-        max = iterator.next()
-    except StopIteration:
-        raise ValueError, 'max() arg is an empty sequence'
-
-    for i in iterator:
-        if max < i:
-            max = i
-    return max
+    return min_max(lt, "max", *arr, **kwargs)
 
 class enumerate(object):
     """enumerate(iterable) -> iterator for (index, value) of iterable.
     def __len__(self):
         return self.len 
 
-    def __getitem__(self, index):
+    def __getitem__(self, i):
         # xrange does NOT support slicing
-        if not isinstance(index, int):
-            raise TypeError, "sequence index must be integer"
+        import operator
+        i = operator.index(i)
         len = self.len 
-        if index < 0:
-            index += len
-        if 0 <= index < len:
-            return self.start + index * self.step
+        if i < 0:
+            i += len
+        if 0 <= i < len:
+            return self.start + i * self.step
         raise IndexError, "xrange object index out of range"
 
     def __iter__(self):

pypy/module/mmap/interp_mmap.py

                 self.space.wrap("seek out of range"))
         
         self.pos = where
-    seek.unwrap_spec = ['self', int, int]
+    seek.unwrap_spec = ['self', 'index', int]
     
     def tell(self):
         self.check_valid()
         m.setdata(res, map_size)
 
         return space.wrap(m)
-    mmap.unwrap_spec = [ObjSpace, int, int, int, int, int]
+    mmap.unwrap_spec = [ObjSpace, int, 'index', int, int, int]
 elif _MS_WINDOWS:
     def mmap(space, fileno, length, tagname="", access=_ACCESS_DEFAULT):
         # check size boundaries
 
         raise OperationError(space.w_EnvironmentError,
                              space.wrap(os.strerror(dwErr)))
-    mmap.unwrap_spec = [ObjSpace, int, int, str, int]
+    mmap.unwrap_spec = [ObjSpace, int, 'index', str, int]

pypy/module/operator/__init__.py

+from pypy.interpreter.mixedmodule import MixedModule 
+from pypy.interpreter.error import OperationError 
+
+class Module(MixedModule):
+    """Operator Builtin Module. """
+
+    appleveldefs = {} 
+    
+    app_names = ['__delslice__', '__getslice__', '__repeat__', '__setslice__',
+             'attrgetter', 'countOf', 'delslice', 'getslice', 'indexOf',
+             'isMappingType', 'isNumberType', 'isSequenceType',
+             'itemgetter','repeat', 'setslice',
+             ]
+
+    for name in app_names:
+        appleveldefs[name] = 'app_operator.%s' % name
+
+    interp_names = ['index', '__abs__', '__add__', '__and__',
+                    '__concat__', '__contains__', '__delitem__','__div__',
+                    '__eq__', '__floordiv__', '__ge__', '__getitem__',
+                    '__gt__', '__inv__', '__invert__', '__le__',
+                    '__lshift__', '__lt__', '__mod__', '__mul__',
+                    '__ne__', '__neg__', '__not__', '__or__',
+                    '__pos__', '__pow__', '__rshift__', '__setitem__',
+                    '__sub__', '__truediv__', '__xor__', 'abs', 'add',
+                    'and_', 'concat', 'contains', 'delitem', 'div', 'eq', 'floordiv',
+                    'ge', 'getitem', 'gt', 'inv',
+                    'invert', 'is_', 'is_not', 'isCallable', 'le',
+                    'lshift', 'lt', 'mod', 'mul',
+                    'ne', 'neg', 'not_', 'or_',
+                    'pos', 'pow', 'rshift', 'setitem', 'sequenceIncludes',
+                    'sub', 'truediv', 'truth', 'xor']
+    interpleveldefs = {}
+
+    for name in interp_names:
+        interpleveldefs[name] = 'interp_operator.%s' % name

pypy/module/operator/app_operator.py

+'''NOT_RPYTHON: because of attrgetter and itemgetter
+Operator interface.
+
+This module exports a set of operators as functions. E.g. operator.add(x,y) is
+equivalent to x+y.
+'''
+
+def attrgetter(attr):
+    def f(obj):
+        return getattr(obj, attr)
+    return f
+
+def countOf(a,b): 
+    'countOf(a, b) -- Return the number of times b occurs in a.'
+    count = 0
+    for x in a:
+        if x == b:
+            count += 1
+    return count
+
+def delslice(obj, start, end):
+    'delslice(a, b, c) -- Same as del a[b:c].'
+    if not isinstance(start, int) or not isinstance(end, int):
+        raise TypeError("an integer is expected")
+    del obj[start:end]
+__delslice__ = delslice
+
+def getslice(a, start, end):
+    'getslice(a, b, c) -- Same as a[b:c].'
+    if not isinstance(start, int) or not isinstance(end, int):
+        raise TypeError("an integer is expected")
+    return a[start:end] 
+__getslice__ = getslice
+
+def indexOf(a, b):
+    'indexOf(a, b) -- Return the first index of b in a.'
+    index = 0
+    for x in a:
+        if x == b:
+            return index
+        index += 1
+    raise ValueError, 'sequence.index(x): x not in sequence'
+
+# XXX the following is approximative
+def isMappingType(obj,):
+    'isMappingType(a) -- Return True if a has a mapping type, False otherwise.'
+    # XXX this is fragile and approximative anyway
+    return hasattr(obj, '__getitem__') and hasattr(obj, 'keys')
+
+def isNumberType(obj,):
+    'isNumberType(a) -- Return True if a has a numeric type, False otherwise.'
+    return hasattr(obj, '__int__') or hasattr(obj, '__float__')
+
+def isSequenceType(obj,):
+    'isSequenceType(a) -- Return True if a has a sequence type, False otherwise.'
+    return hasattr(obj, '__getitem__')
+
+def itemgetter(idx):
+    def f(obj):
+        return obj[idx]
+    return f
+
+def repeat(obj, num):
+    'repeat(a, b) -- Return a * b, where a is a sequence, and b is an integer.'
+    if not isinstance(num, (int, long)):
+        raise TypeError, 'an integer is required'
+    return obj * num   # XXX cPython only supports objects with the sequence
+                       # protocol. We support any with a __mul__
+__repeat__ = repeat
+
+def setslice(a, b, c, d):
+    'setslice(a, b, c, d) -- Same as a[b:c] = d.'
+    a[b:c] = d 
+__setslice__ = setslice
+

pypy/module/operator/interp_operator.py

+def index(space, w_a):
+    return space.index(w_a)
+
+def abs(space, w_obj):
+    'abs(a) -- Same as abs(a).'
+    return space.abs(w_obj)
+
+__abs__ = abs
+
+def add(space, w_obj1, w_obj2):
+    'add(a, b) -- Same as a a + b'
+    return space.add(w_obj1, w_obj2)
+__add__ = add
+
+def and_(space, w_obj1, w_obj2):
+    'and_(a, b) -- Same as a a & b'
+    return space.and_(w_obj1, w_obj2)
+__and__ = and_
+
+# attrgetter
+
+def concat(space, w_obj1, w_obj2):
+    'concat(a, b) -- Same as a a + b, for a and b sequences.'
+    return space.add(w_obj1, w_obj2) # XXX cPython only works on types with sequence api
+                                     # we support any with __add__
+__concat__ = concat
+
+def contains(space, w_obj1, w_obj2):
+    'contains(a, b) -- Same as b in a (note reversed operands).'
+    return space.contains(w_obj1, w_obj2)
+__contains__ = contains
+sequenceIncludes = contains
+
+# countOf
+
+def delitem(space, w_obj, w_key):
+    'delitem(a,b) -- Same as del a[b]'
+    space.delitem(w_obj, w_key)
+
+__delitem__ = delitem
+
+# delslice
+
+def div(space, w_a, w_b):
+    'div(a, b) -- Same as a / b when __future__.division is no in effect'
+    return space.div(w_a, w_b)
+__div__ = div
+
+def eq(space, w_a, w_b):
+    'eq(a, b) -- Same as a==b'
+    return space.eq(w_a, w_b)
+__eq__ = eq
+
+def floordiv(space, w_a, w_b):
+    'floordiv(a, b) -- Same as a // b.'
+    return space.floordiv(w_a, w_b)
+__floordiv__ = floordiv
+
+def ge(space, w_a, w_b):
+    'ge(a, b) -- Same as a>=b.'
+    return space.ge(w_a, w_b)
+__ge__ = ge
+
+def getitem(space, w_a, w_b):
+    'getitem(a, b) -- Same as a[b].'
+    return space.getitem(w_a, w_b)
+__getitem__ = getitem
+
+# getslice
+
+def gt(space, w_a, w_b):
+    'gt(a, b) -- Same as a>b.'
+    return space.gt(w_a, w_b)
+__gt__ = gt
+
+# indexOf
+
+def inv(space, w_obj,):
+    'inv(a) -- Same as ~a.'
+    return space.invert(w_obj)
+__inv__ = inv
+
+def invert(space, w_obj,):
+    'invert(a) -- Same as ~a.'
+    return space.invert(w_obj) 
+__invert__ = invert
+
+def isCallable(space, w_obj):
+    'isCallable(a) -- Same as callable(a).'
+    return space.callable(w_obj)
+
+# isMappingType
+
+# isNumberType
+
+# isSequenceType
+
+def is_(space, w_a, w_b):
+    'is_(a,b) -- Same as a is b'
+    return space.is_(w_a, w_b)
+
+def is_not(space, w_a, w_b):
+    'is_not(a, b) -- Same as a is not b'
+    return space.not_(space.is_(w_a, w_b))
+
+# itemgetter
+
+def le(space, w_a, w_b):
+    'le(a, b) -- Same as a<=b.'
+    return space.le(w_a, w_b)
+__le__ = le
+
+def lshift(space, w_a, w_b):
+    'lshift(a, b) -- Same as a << b.'
+    return space.lshift(w_a, w_b) 
+__lshift__ = lshift
+
+def lt(space, w_a, w_b):
+    'lt(a, b) -- Same as a<b.'
+    return space.lt(w_a, w_b)
+__lt__ = lt
+
+def mod(space, w_a, w_b):
+    'mod(a, b) -- Same as a % b.'
+    return space.mod(w_a, w_b)
+__mod__ = mod
+
+def mul(space, w_a, w_b):
+    'mul(a, b) -- Same as a * b.'
+    return space.mul(w_a, w_b)
+__mul__ = mul
+
+def ne(space, w_a, w_b):
+    'ne(a, b) -- Same as a!=b.'
+    return space.ne(w_a, w_b) 
+__ne__ = ne
+
+def neg(space, w_obj,):
+    'neg(a) -- Same as -a.'
+    return space.neg(w_obj)
+__neg__ = neg
+
+def not_(space, w_obj,):
+    'not_(a) -- Same as not a.'
+    return space.not_(w_obj)
+__not__ = not_
+
+def or_(space, w_a, w_b):
+    'or_(a, b) -- Same as a | b.'
+    return space.or_(w_a, w_b)
+__or__ = or_
+
+def pos(space, w_obj,):
+    'pos(a) -- Same as +a.'
+    return space.pos(w_obj) 
+__pos__ = pos
+
+def pow(space, w_a, w_b):
+    'pow(a, b) -- Same as a**b.'
+    return space.pow(w_a, w_b, space.w_None)
+__pow__ = pow
+
+# reapeat
+
+def rshift(space, w_a, w_b):
+    'rshift(a, b) -- Same as a >> b.'
+    return space.rshift(w_a, w_b) 
+__rshift__ = rshift
+
+# sequenceIncludes
+
+def setitem(space, w_obj, w_key, w_value):
+    'setitem(a, b, c) -- Same as a[b] = c.'
+    space.setitem(w_obj, w_key, w_value)
+__setitem__ = setitem
+
+# setslice
+
+def sub(space, w_a, w_b):
+    'sub(a, b) -- Same as a - b.'
+    return space.sub(w_a, w_b) 
+__sub__ = sub
+
+def truediv(space, w_a, w_b):
+    'truediv(a, b) -- Same as a / b when __future__.division is in effect.'
+    return space.truediv(w_a, w_b)
+__truediv__ = truediv
+
+def truth(space, w_a,):
+    'truth(a) -- Return True if a is true, False otherwise.'
+    return space.nonzero(w_a)
+
+def xor(space, w_a, w_b):
+    'xor(a, b) -- Same as a ^ b.'
+    return space.xor(w_a, w_b)
+__xor__ = xor

pypy/objspace/cpy/function.py

     def visit__object(self, el):
         convertermap = {int: 'int_w',
                         str: 'str_w',
-                        float: 'float_w'}
+                        float: 'float_w',
+                        "index": 'getindex_w'
+                        }
         argname = self.orig_arg()
         assert not argname.startswith('w_')
         self.inputargs.append(argname)
                                 argname))
         self.passedargs.append(argname)
 
+    def visit_index(self, el):
+        self.visit__object("index")
+
     def visit_args_w(self, el):
         argname = self.orig_arg()
         assert argname.endswith('_w')

pypy/objspace/cpy/objspace.py

     repr    = staticmethod(PyObject_Repr)
     id      = staticmethod(PyLong_FromVoidPtr_PYOBJ)
 
+    def index(self, w_obj):
+        # XXX we do not support 2.5 yet, so we just do some
+        # hack here to have index working
+        return self.wrap(self.int_w(w_obj))
+
     def bigint_w(self, w_obj):
         if self.is_true(self.isinstance(w_obj, self.w_long)):
             sign = _PyLong_Sign(w_obj)

pypy/objspace/descroperation.py

 
 for targetname, specialname, checkerspec in [
     ('int', '__int__', ("space.w_int", "space.w_long")), 
+    ('index', '__index__', ("space.w_int", "space.w_long")),
     ('long', '__long__', ("space.w_int", "space.w_long")), 
     ('float', '__float__', ("space.w_float",))]:
 
         assert not hasattr(DescrOperation, %(targetname)r)
         DescrOperation.%(targetname)s = %(targetname)s
         del %(targetname)s 
-        \n""" % locals() 
+        \n""" % locals()
     exec compile2(source) 
 
 for targetname, specialname in [
 for _name, _symbol, _arity, _specialnames in ObjSpace.MethodTable:
     if not hasattr(DescrOperation, _name):
         _impl_maker = None
-        if _arity ==2 and _name in ['lt', 'le', 'gt', 'ge', 'ne', 'eq']:
+        if _arity == 2 and _name in ['lt', 'le', 'gt', 'ge', 'ne', 'eq']:
             #print "comparison", _specialnames
             _impl_maker = _make_comparison_impl
         elif _arity == 2 and _name.startswith('inplace_'):

pypy/objspace/flow/operation.py

 def do_int(x):
     return x.__int__()
 
+def do_index(x):
+    return x.__index__()
+
 def do_float(x):
     return x.__float__()
 
     ('divmod',          divmod),
     ('pow',             pow),
     ('int',             do_int),
+    ('index',           do_index),
     ('float',           do_float),
     ('long',            do_long),
     ('inplace_add',     inplace_add),

pypy/objspace/std/dictmultiobject.py

 
     def get(self, w_lookup):
         return None
+
     def setitem(self, w_key, w_value):
         if _is_str(self.space, w_key):
             return StrDictImplementation(self.space).setitem_str(w_key, w_value)
             result[key] = val
         return result
 
+    def missing_method(w_dict, space, w_key):
+        if not space.is_w(space.type(w_dict), space.w_dict):
+            w_missing = space.lookup(w_dict, "__missing__")
+            if w_missing is None:
+                return None
+            return space.call_function(w_missing, w_dict, w_key)
+        else:
+            return None
+
     def len(w_self):
         return w_self.implementation.length()
 
     w_value = w_dict.implementation.get(w_lookup)
     if w_value is not None:
         return w_value
+
+    w_missing_item = w_dict.missing_method(space, w_lookup)
+    if w_missing_item is not None:
+        return w_missing_item
+
     raise OperationError(space.w_KeyError, w_lookup)
 
 def setitem__DictMulti_ANY_ANY(space, w_dict, w_newkey, w_newvalue):

pypy/objspace/std/dictobject.py

     def get(w_dict, w_lookup, w_default):
         return w_dict.content.get(w_lookup, w_default)
 
+    def missing_method(w_dict, space, w_key):
+        if not space.is_w(space.type(w_dict), space.w_dict):
+            w_missing = space.lookup(w_dict, "__missing__")
+            if w_missing is None:
+                return None
+            return space.call_function(w_missing, w_dict, w_key)
+        else:
+            return None
+
     def set_str_keyed_item(w_dict, w_key, w_value, shadows_type=True):
         w_dict.content[w_key] = w_value
 
     try:
         return w_dict.content[w_lookup]
     except KeyError:
-        raise OperationError(space.w_KeyError, w_lookup)
+        w_missing_item = w_dict.missing_method(space, w_lookup)
+        if w_missing_item is None:
+            raise OperationError(space.w_KeyError, w_lookup)
+        else:
+            return w_missing_item
 
 def setitem__Dict_ANY_ANY(space, w_dict, w_newkey, w_newvalue):
     w_dict.content[w_newkey] = w_newvalue

pypy/objspace/std/intobject.py

     a = w_int1.intval
     return wrapint(space, a)
 
+def index__Int(space, w_int1):
+    return int__Int(space, w_int1)
+
 def float__Int(space, w_int1):
     a = w_int1.intval
     x = float(a)

pypy/objspace/std/listmultiobject.py

 from pypy.objspace.std.objspace import *
 from pypy.objspace.std.inttype import wrapint
+from pypy.objspace.std.listtype import get_list_index
 from pypy.objspace.std.sliceobject import W_SliceObject
 
 from pypy.objspace.std import slicetype
     return wrapint(space, result)
 
 def getitem__ListMulti_ANY(space, w_list, w_index):
-    idx = space.int_w(w_index)
+    idx = get_list_index(space, w_index)
     idx = _adjust_index(space, idx, w_list.implementation.length(),
                         "list index out of range")
     return w_list.implementation.getitem(idx)
 
 def mul_list_times(space, w_list, w_times):
     try:
-        times = space.int_w(w_times)
+        times = space.getindex_w(w_times, space.w_OverflowError)
     except OperationError, e:
         if e.match(space, space.w_TypeError):
             raise FailedToImplement
 
 def inplace_mul__ListMulti_ANY(space, w_list, w_times):
     try:
-        times = space.int_w(w_times)
+        times = space.getindex_w(w_times, space.w_OverflowError)
     except OperationError, e:
         if e.match(space, space.w_TypeError):
             raise FailedToImplement
         w_list2.implementation)
 
 def delitem__ListMulti_ANY(space, w_list, w_idx):
-    idx = space.int_w(w_idx)
+    idx = get_list_index(space, w_idx)
     length = w_list.implementation.length()
     idx = _adjust_index(space, idx, length, "list deletion index out of range")
     if length == 1:
     return space.w_None
 
 def setitem__ListMulti_ANY_ANY(space, w_list, w_index, w_any):
-    idx = space.int_w(w_index)
+    idx = get_list_index(space, w_index)
     idx = _adjust_index(space, idx, w_list.implementation.length(),
                         "list index out of range")
     w_list.implementation = w_list.implementation.i_setitem(idx, w_any)

pypy/objspace/std/listobject.py

 from pypy.objspace.std.objspace import *
 from pypy.objspace.std.inttype import wrapint
+from pypy.objspace.std.listtype import get_list_index
 from pypy.objspace.std.sliceobject import W_SliceObject
 from pypy.objspace.std.tupleobject import W_TupleObject
 
     return wrapint(space, result)
 
 def getitem__List_ANY(space, w_list, w_index):
-    idx = space.int_w(w_index)
     try:
-        return w_list.wrappeditems[idx]
+        return w_list.wrappeditems[get_list_index(space, w_index)]
     except IndexError:
         raise OperationError(space.w_IndexError,
                              space.wrap("list index out of range"))
 
 def mul_list_times(space, w_list, w_times):
     try:
-        times = space.int_w(w_times)
+        times = space.getindex_w(w_times, space.w_OverflowError)
     except OperationError, e:
         if e.match(space, space.w_TypeError):
             raise FailedToImplement
 
 def inplace_mul__List_ANY(space, w_list, w_times):
     try:
-        times = space.int_w(w_times)
+        times = space.getindex_w(w_times, space.w_OverflowError)
     except OperationError, e:
         if e.match(space, space.w_TypeError):
             raise FailedToImplement
         w_list2.wrappeditems)
 
 def delitem__List_ANY(space, w_list, w_idx):
-    idx = space.int_w(w_idx)
+    idx = get_list_index(space, w_idx)
     try:
         del w_list.wrappeditems[idx]
     except IndexError:
     return space.w_None
 
 def setitem__List_ANY_ANY(space, w_list, w_index, w_any):
-    idx = space.int_w(w_index)
+    idx = get_list_index(space, w_index)
     try:
         w_list.wrappeditems[idx] = w_any
     except IndexError:

pypy/objspace/std/listtype.py

 from __future__ import generators
 from pypy.interpreter import gateway
+from pypy.interpreter.error import OperationError
 from pypy.objspace.std.stdtypedef import *
 from pypy.objspace.std.register_all import register_all
 from sys import maxint
     __hash__ = no_hash_descr,
     )
 list_typedef.registermethods(globals())
+
+# ____________________________________________________________
+
+def get_list_index(space, w_index):
+    if not space.lookup(w_index, '__index__'):
+        raise OperationError(
+            space.w_TypeError,
+            space.wrap("list indices must be integers, not %s" %
+                       space.type(w_index).getname(space, '?')))
+    return space.getindex_w(w_index, space.w_IndexError)

pypy/objspace/std/longobject.py

     def is_odd(self):
         return self.num.is_odd()
 
+    def get_sign(self):
+        return self.num.sign
+
 registerimplementation(W_LongObject)
 
 # bool-to-long
     except OverflowError:
         return long__Long(space, w_value)
 
+def index__Long(space, w_value):
+    return long__Long(space, w_value)
+
 def float__Long(space, w_longobj):
     try:
         return space.newfloat(w_longobj.num.tofloat())

pypy/objspace/std/rangeobject.py

 def getitem__RangeList_ANY(space, w_rangelist, w_index):
     if w_rangelist.w_list is not None:
         return space.getitem(w_rangelist.w_list, w_index)
-    idx = space.int_w(w_index)
+    idx = space.getindex_w(w_index, space.w_IndexError)
     try:
         return wrapint(space, w_rangelist.getitem(idx))
     except IndexError:

pypy/objspace/std/sliceobject.py

 # indices impl
 
 def slice_indices__Slice_ANY(space, w_slice, w_length):
-    length = space.int_w(w_length)
+    length = space.getindex_w(w_length, space.w_OverflowError)
     start, stop, step = w_slice.indices3(space, length)
     return space.newtuple([space.wrap(start), space.wrap(stop),
                            space.wrap(step)])

pypy/objspace/std/slicetype.py

 
 # utility functions
 def _Eval_SliceIndex(space, w_int):
-    try:
-        x = space.int_w(w_int)
-    except OperationError, e:
-        if not e.match(space, space.w_OverflowError):
-            raise
-        cmp = space.is_true(space.ge(w_int, space.wrap(0)))
-        if cmp:
-            x = sys.maxint
-        else:
-            x = -sys.maxint
-    return x
+    return space.getindex_w(w_int) # clamp if long integer is too large
+    # This is done by getindex_w already.
+    #try:
+    #    x = space.getindex_w(w_int)
+    #except OperationError, e:
+    #    if not e.match(space, space.w_OverflowError):
+    #        raise
+    #    cmp = space.is_true(space.ge(w_int, space.wrap(0)))
+    #    if cmp:
+    #        x = sys.maxint
+    #    else:
+    #        x = -sys.maxint
+    #return x
 
 def adapt_bound(space, w_index, w_size):
     if not (space.is_true(space.isinstance(w_index, space.w_int)) or

pypy/objspace/std/stringobject.py

-# -*- Coding: Latin-1 -*-
+# -*- coding: latin-1 -*-
 
 from pypy.objspace.std.objspace import *
 from pypy.interpreter import gateway
 from pypy.objspace.std.noneobject import W_NoneObject
 from pypy.objspace.std.tupleobject import W_TupleObject
 
-from pypy.objspace.std.stringtype import sliced, joined, wrapstr, wrapchar
+from pypy.objspace.std.stringtype import sliced, joined, wrapstr, wrapchar, \
+     stringendswith, stringstartswith
 
 
 class W_StringObject(W_Object):
         return W_StringObject.EMPTY
 
 def str_rjust__String_ANY_ANY(space, w_self, w_arg, w_fillchar):
-
     u_arg = space.int_w(w_arg)
     u_self = w_self._value
     fillchar = space.str_w(w_fillchar)
 
 
 def str_ljust__String_ANY_ANY(space, w_self, w_arg, w_fillchar):
-
     u_self = w_self._value
     u_arg = space.int_w(w_arg)
     fillchar = space.str_w(w_fillchar)
     return space.newbool(self.find(sub) >= 0)
 
 def str_find__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-
     (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
     res = self.find(sub, start, end)
     return space.wrap(res)
 
 def str_rfind__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-
     (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
     res = self.rfind(sub, start, end)
     return space.wrap(res)
 
+def str_partition__String_String(space, w_self, w_sub):
+    self = w_self._value
+    sub = w_sub._value
+    if not sub:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("empty separator"))
+    pos = self.find(sub)
+    if pos == -1:
+        return space.newtuple([w_self, space.wrap(''), space.wrap('')])
+    else:
+        return space.newtuple([sliced(space, self, 0, pos),
+                               w_sub,
+                               sliced(space, self, pos+len(sub), len(self))])
+
+def str_rpartition__String_String(space, w_self, w_sub):
+    self = w_self._value
+    sub = w_sub._value
+    if not sub:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("empty separator"))
+    pos = self.rfind(sub)
+    if pos == -1:
+        return space.newtuple([space.wrap(''), space.wrap(''), w_self])
+    else:
+        return space.newtuple([sliced(space, self, 0, pos),
+                               w_sub,
+                               sliced(space, self, pos+len(sub), len(self))])
+
+
 def str_index__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-
     (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
     res = self.find(sub, start, end)
     if res < 0:
 
 
 def str_rindex__String_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-
     (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
     res = self.rfind(sub, start, end)
     if res < 0:
 
 
 def str_replace__String_String_String_ANY(space, w_self, w_sub, w_by, w_maxsplit=-1):
-
     input = w_self._value
     sub = w_sub._value
     by = w_by._value
 def str_endswith__String_String_ANY_ANY(space, w_self, w_suffix, w_start, w_end):
     (u_self, suffix, start, end) = _convert_idx_params(space, w_self,
                                                        w_suffix, w_start, w_end)
-    begin = end - len(suffix)
-    if begin < start:
-        return space.w_False
-    for i in range(len(suffix)):
-        if u_self[begin+i] != suffix[i]:
-            return space.w_False
-    return space.w_True
-    
-    
+    return space.newbool(stringendswith(u_self, suffix, start, end))
+
+def str_endswith__String_Tuple_ANY_ANY(space, w_self, w_suffixes, w_start, w_end):
+    (u_self, _, start, end) = _convert_idx_params(space, w_self,
+                                                  space.wrap(''), w_start, w_end)
+    for w_suffix in space.unpacktuple(w_suffixes):
+        suffix = space.str_w(w_suffix) 
+        if stringendswith(u_self, suffix, start, end):
+            return space.w_True
+    return space.w_False
+
 def str_startswith__String_String_ANY_ANY(space, w_self, w_prefix, w_start, w_end):
     (u_self, prefix, start, end) = _convert_idx_params(space, w_self,
                                                        w_prefix, w_start, w_end)
-    stop = start + len(prefix)
-    if stop > end:
-        return space.w_False
-    for i in range(len(prefix)):
-        if u_self[start+i] != prefix[i]:
-            return space.w_False
-    return space.w_True
-    
+    return space.newbool(stringstartswith(u_self, prefix, start, end))
+
+def str_startswith__String_Tuple_ANY_ANY(space, w_self, w_prefixes, w_start, w_end):
+    (u_self, _, start, end) = _convert_idx_params(space, w_self, space.wrap(''),
+                                                  w_start, w_end)
+    for w_prefix in space.unpacktuple(w_prefixes):
+        prefix = space.str_w(w_prefix)
+        if stringstartswith(u_self, prefix, start, end):
+            return space.w_True
+    return space.w_False
     
 def _tabindent(u_token, u_tabsize):
     "calculates distance behind the token to the next tabstop"
         return space.w_False
 
 def getitem__String_ANY(space, w_str, w_index):
-    ival = space.int_w(w_index)
+    if not space.lookup(w_index, '__index__'):
+        raise OperationError(
+            space.w_TypeError,
+            space.wrap("string indices must be integers, not %s" %
+                       space.type(w_index).getname(space, '?')))
+    ival = space.getindex_w(w_index, space.w_IndexError)
     str = w_str._value
     slen = len(str)
     if ival < 0:
 
 def mul_string_times(space, w_str, w_times):
     try:
-        mul = space.int_w(w_times)
+        mul = space.getindex_w(w_times, space.w_OverflowError)
     except OperationError, e:
         if e.match(space, space.w_TypeError):
             raise FailedToImplement

pypy/objspace/std/stringtype.py

         return W_StringObject(c)
 
 def sliced(space, s, start, stop):
+    assert start >= 0
+    assert stop >= 0 
     if space.config.objspace.std.withstrslice:
         from pypy.objspace.std.strsliceobject import W_StringSliceObject
         # XXX heuristic, should be improved!
                          ' s[start,end].  Optional\narguments start and end'
                          ' are interpreted as in slice notation.\n\nReturn -1'
                          ' on failure.')
+str_partition  = SMM('partition', 2,
+                     doc='S.partition(sep) -> (head, sep, tail)\n\nSearches'
+                         ' for the separator sep in S, and returns the part before'
+                         ' it,\nthe separator itself, and the part after it.  If'
+                         ' the separator is not\nfound, returns S and two empty'
+                         ' strings.')
+str_rpartition = SMM('rpartition', 2,
+                     doc='S.rpartition(sep) -> (tail, sep, head)\n\nSearches'
+                         ' for the separator sep in S, starting at the end of S,'
+                         ' and returns\nthe part before it, the separator itself,'
+                         ' and the part after it.  If the\nseparator is not found,'
+                         ' returns two empty strings and S.')
 str_index      = SMM('index', 4, defaults=(0, maxint),
                      doc='S.index(sub [,start [,end]]) -> int\n\nLike S.find()'
                          ' but raise ValueError when the substring is not'
 
 str_typedef.custom_hash = True
 str_typedef.registermethods(globals())
+
+# ____________________________________________________________
+
+# Helpers for several string implementations
+
+def stringendswith(u_self, suffix, start, end):
+    begin = end - len(suffix)
+    if begin < start:
+        return False
+    for i in range(len(suffix)):
+        if u_self[begin+i] != suffix[i]:
+            return False
+    return True
+
+def stringstartswith(u_self, prefix, start, end):
+    stop = start + len(prefix)
+    if stop > end:
+        return False
+    for i in range(len(prefix)):
+        if u_self[start+i] != prefix[i]:
+            return False
+    return True
+    

pypy/objspace/std/strsliceobject.py

 from pypy.objspace.std.stringobject import W_StringObject
 from pypy.objspace.std.unicodeobject import delegate_String2Unicode
 from pypy.objspace.std.sliceobject import W_SliceObject
+from pypy.objspace.std.tupleobject import W_TupleObject
 from pypy.objspace.std import slicetype
 from pypy.objspace.std.inttype import wrapint
 
-from pypy.objspace.std.stringtype import wrapstr, wrapchar
+from pypy.objspace.std.stringtype import wrapstr, wrapchar, sliced, \
+     stringendswith, stringstartswith
 
 
 class W_StringSliceObject(W_Object):
     from pypy.objspace.std.stringtype import str_typedef as typedef
 
     def __init__(w_self, str, start, stop):
+        assert start >= 0
+        assert stop >= 0 
         w_self.str = str
         w_self.start = start
         w_self.stop = stop
 
 
 def str_find__StringSlice_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-
     (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
     res = self.find(sub, start, end)
     if res >= 0:
     else:
         return space.wrap(res)
 
+def str_partition__StringSlice_String(space, w_self, w_sub):
+    self = w_self.str
+    sub = w_sub._value
+    if not sub:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("empty separator"))
+    pos = self.find(sub, w_self.start, w_self.stop)
+    if pos == -1:
+        return space.newtuple([w_self, space.wrap(''), space.wrap('')])
+    else:
+        return space.newtuple([sliced(space, self, w_self.start, pos),
+                               w_sub,
+                               sliced(space, self, pos+len(sub), w_self.stop)])
+
+def str_rpartition__StringSlice_String(space, w_self, w_sub):
+    self = w_self.str
+    sub = w_sub._value
+    if not sub:
+        raise OperationError(space.w_ValueError,
+                             space.wrap("empty separator"))
+    pos = self.rfind(sub, w_self.start, w_self.stop)
+    if pos == -1:
+        return space.newtuple([space.wrap(''), space.wrap(''), w_self])
+    else:
+        return space.newtuple([sliced(space, self, w_self.start, pos),
+                               w_sub,
+                               sliced(space, self, pos+len(sub), w_self.stop)])
+
+
 def str_count__StringSlice_String_ANY_ANY(space, w_self, w_arg, w_start, w_end): 
     (s, arg, start, end) =  _convert_idx_params(
             space, w_self, w_arg, w_start, w_end)
     return wrapint(space, s.count(arg, start, end))
 
 def str_rfind__StringSlice_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-
     (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
     res = self.rfind(sub, start, end)
     if res >= 0:
         return space.wrap(res)
 
 def str_index__StringSlice_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-
     (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
     res = self.find(sub, start, end)
     if res < 0:
 
 
 def str_rindex__StringSlice_String_ANY_ANY(space, w_self, w_sub, w_start, w_end):
-
     (self, sub, start, end) =  _convert_idx_params(space, w_self, w_sub, w_start, w_end)
     res = self.rfind(sub, start, end)
     if res < 0:
 
     return space.wrap(res - w_self.start)
 
+def str_endswith__StringSlice_String_ANY_ANY(space, w_self, w_suffix, w_start, w_end):
+    (u_self, suffix, start, end) = _convert_idx_params(space, w_self,
+                                                       w_suffix, w_start, w_end)
+    return space.newbool(stringendswith(u_self, suffix, start, end))
+
+def str_endswith__StringSlice_Tuple_ANY_ANY(space, w_self, w_suffixes, w_start, w_end):
+    (u_self, _, start, end) = _convert_idx_params(space, w_self,
+                                                  space.wrap(''), w_start, w_end)
+    for w_suffix in space.unpacktuple(w_suffixes):
+        suffix = space.str_w(w_suffix) 
+        if stringendswith(u_self, suffix, start, end):
+            return space.w_True
+    return space.w_False
+
+def str_startswith__StringSlice_String_ANY_ANY(space, w_self, w_prefix, w_start, w_end):
+    (u_self, prefix, start, end) = _convert_idx_params(space, w_self,
+                                                       w_prefix, w_start, w_end)
+    return space.newbool(stringstartswith(u_self, prefix, start, end))
+
+def str_startswith__StringSlice_Tuple_ANY_ANY(space, w_self, w_prefixes, w_start, w_end):
+    (u_self, _, start, end) = _convert_idx_params(space, w_self, space.wrap(''),
+                                                  w_start, w_end)
+    for w_prefix in space.unpacktuple(w_prefixes):
+        prefix = space.str_w(w_prefix)
+        if stringstartswith(u_self, prefix, start, end):
+            return space.w_True
+    return space.w_False
+
 
 def str_w__StringSlice(space, w_str):
     return w_str.force()
 
 
 def getitem__StringSlice_ANY(space, w_str, w_index):
-    ival = space.int_w(w_index)
+    if not space.lookup(w_index, '__index__'):
+        raise OperationError(
+            space.w_TypeError,
+            space.wrap("string indices must be integers, not %s" %
+                       space.type(w_index).getname(space, '?')))
+    ival = space.getindex_w(w_index, space.w_IndexError)
     slen = w_str.stop - w_str.start
     if ival < 0:
         ival += slen
         return w_str
     return W_StringSliceObject(w_str.str, w_str.start, w_str.stop)
 
+
 from pypy.objspace.std import stringtype
 register_all(vars(), stringtype)

pypy/objspace/std/test/test_index.py

+from py.test import raises
+
+class AppTest_IndexProtocol:
+    def setup_class(self):
+        w_oldstyle = self.space.appexec([], """():
+            class oldstyle:
+                def __index__(self):
+                    return self.ind
+            return oldstyle""")
+
+        w_newstyle = self.space.appexec([], """():
+            class newstyle(object):
+                def __index__(self):
+                    return self.ind
+            return newstyle""")
+
+        w_TrapInt = self.space.appexec([], """(): 
+            class TrapInt(int):
+                def __index__(self):
+                    return self
+            return TrapInt""")
+
+        w_TrapLong = self.space.appexec([], """():
+            class TrapLong(long):
+                def __index__(self):
+                    return self
+            return TrapLong""")
+
+        self.w_oldstyle = w_oldstyle
+        self.w_o = self.space.call_function(w_oldstyle)
+        self.w_newstyle = w_newstyle
+        self.w_n = self.space.call_function(w_newstyle)
+
+        self.w_TrapInt = w_TrapInt
+        self.w_TrapLong = w_TrapLong
+
+    def test_basic(self):
+        self.o.ind = -2
+        self.n.ind = 2
+        import operator
+        assert operator.index(self.o) == -2
+        assert 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)
+        assert slc.indices(self.o) == check_slc.indices(1)
+        slc = slice(self.n, self.n, self.n)
+        check_slc = slice(2, 2, 2)
+        assert slc.indices(self.n) == check_slc.indices(2)
+
+    def test_wrappers(self):
+        self.o.ind = 4
+        self.n.ind = 5
+        assert 6 .__index__() == 6
+        assert -7L.__index__() == -7
+        assert self.o.__index__() == 4
+        assert self.n.__index__() == 5
+
+    def test_subclasses(self):
+        r = range(10)
+        assert r[self.TrapInt(5):self.TrapInt(10)] == r[5:10]
+        assert r[self.TrapLong(5):self.TrapLong(10)] == r[5:10]
+        assert slice(self.TrapInt()).indices(0) == (0,0,1)
+        assert slice(self.TrapLong(0)).indices(0) == (0,0,1)
+
+    def test_error(self):
+        self.o.ind = 'dumb'
+        self.n.ind = 'bad'
+        import operator
+        raises(TypeError, operator.index, self.o)
+        raises(TypeError, operator.index, self.n)
+        raises(TypeError, slice(self.o).indices, 0)
+        raises(TypeError, slice(self.n).indices, 0)
+
+
+class SeqTestCase:
+    # This test case isn't run directly. It just defines common tests
+    # to the different sequence types below
+    def setup_method(self, method):
+        w_oldstyle = self.space.appexec([], """():
+            class oldstyle:
+                def __index__(self):
+                    return self.ind
+            return oldstyle""")
+
+        w_newstyle = self.space.appexec([], """():
+            class newstyle(object):
+                def __index__(self):
+                    return self.ind
+            return newstyle""")
+
+        w_TrapInt = self.space.appexec([], """(): 
+            class TrapInt(int):
+                def __index__(self):
+                    return self
+            return TrapInt""")
+
+        w_TrapLong = self.space.appexec([], """():
+            class TrapLong(long):
+                def __index__(self):
+                    return self
+            return TrapLong""")
+
+        self.w_o = self.space.call_function(w_oldstyle)
+        self.w_n = self.space.call_function(w_newstyle)
+        self.w_o2 = self.space.call_function(w_oldstyle)
+        self.w_n2 = self.space.call_function(w_newstyle)
+
+        self.w_TrapInt = w_TrapInt
+        self.w_TrapLong = w_TrapLong
+
+    def test_index(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]
+
+    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_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
+
+    def test_wrappers(self):
+        self.o.ind = 4
+        self.n.ind = 5
+        assert self.seq.__getitem__(self.o) == self.seq[4]
+        assert self.seq.__mul__(self.o) == self.seq * 4
+        assert self.seq.__rmul__(self.o) == self.seq * 4
+        assert self.seq.__getitem__(self.n) == self.seq[5]
+        assert self.seq.__mul__(self.n) == self.seq * 5
+        assert self.seq.__rmul__(self.n) == self.seq * 5
+
+    def test_subclasses(self):
+        assert self.seq[self.TrapInt()] == self.seq[0]
+        assert self.seq[self.TrapLong()] == self.seq[0]
+
+    def test_error(self):
+        self.o.ind = 'dumb'
+        self.n.ind = 'bad'
+        indexobj = lambda x, obj: obj.seq[x]
+        raises(TypeError, indexobj, self.o, self)
+        raises(TypeError, indexobj, self.n, self)
+        sliceobj = lambda x, obj: obj.seq[x:]
+        raises(TypeError, sliceobj, self.o, self)
+        raises(TypeError, sliceobj, self.n, self)
+
+
+class AppTest_ListTestCase(SeqTestCase):
+    def setup_method(self, method):
+        SeqTestCase.setup_method(self, method)
+        self.w_seq = self.space.newlist([self.space.wrap(x) for x in (0,10,20,30,40,50)])
+
+    def test_setdelitem(self):
+        self.o.ind = -2
+        self.n.ind = 2
+        lst = list('ab!cdefghi!j')
+        del lst[self.o]
+        del lst[self.n]
+        lst[self.o] = 'X'
+        lst[self.n] = 'Y'
+        assert lst == list('abYdefghXj')
+
+        lst = [5, 6, 7, 8, 9, 10, 11]
+        lst.__setitem__(self.n, "here")
+        assert lst == [5, 6, "here", 8, 9, 10, 11]
+        lst.__delitem__(self.n)
+        assert lst == [5, 6, 8, 9, 10, 11]
+
+    def test_inplace_repeat(self):
+        self.o.ind = 2
+        self.n.ind = 3
+        lst = [6, 4]
+        lst *= self.o
+        assert lst == [6, 4, 6, 4]
+        lst *= self.n
+        assert lst == [6, 4, 6, 4] * 3
+
+        lst = [5, 6, 7, 8, 9, 11]
+        l2 = lst.__imul__(self.n)
+        assert l2 is lst
+        assert lst == [5, 6, 7, 8, 9, 11] * 3
+
+
+class AppTest_TupleTestCase(SeqTestCase):
+    def setup_method(self, method):
+        SeqTestCase.setup_method(self, method)
+        self.w_seq = self.space.newtuple([self.space.wrap(x) for x in (0,10,20,30,40,50)])
+
+class AppTest_StringTestCase(SeqTestCase):
+    def setup_method(self, method):
+        SeqTestCase.setup_method(self, method)
+        self.w_seq = self.space.wrap("this is a test")
+    
+class AppTest_UnicodeTestCase(SeqTestCase):
+    def setup_method(self, method):
+        SeqTestCase.setup_method(self, method)
+        self.w_seq = self.space.wrap(u"this is a test")
+
+
+class AppTest_XRangeTestCase:
+
+    def test_xrange(self):
+        class newstyle(object):
+            def __index__(self):
+                return self.ind
+        n = newstyle()
+        n.ind = 5
+        assert xrange(1, 20)[n] == 6
+        assert xrange(1, 20).__getitem__(n) == 6
+
+class AppTest_OverflowTestCase:
+
+    def setup_class(self):
+        self.w_pos = self.space.wrap(2**100)
+        self.w_neg = self.space.wrap(-2**100)
+
+    def test_large_longs(self):
+        assert self.pos.__index__() == self.pos
+        assert self.neg.__index__() == self.neg
+
+    def test_getitem(self):
+        from sys import maxint
+        class GetItem(object):
+            def __len__(self):
+                return maxint
+            def __getitem__(self, key):
+                return key
+            def __getslice__(self, i, j):
+                return i, j
+        x = GetItem()
+        assert x[self.pos] == self.pos
+        assert x[self.neg] == self.neg
+        assert x[self.neg:self.pos] == (-1, maxint)
+        assert x[self.neg:self.pos:1].indices(maxint) == (0, maxint, 1)
+
+    def test_getitem_classic(self):
+        from sys import maxint
+        class Empty: pass
+        class GetItem(Empty):
+            def __len__(self):
+                return maxint
+            def __getitem__(self, key):
+                return key
+            def __getslice__(self, i, j):
+                return i, j
+        x = GetItem()
+        assert x[self.pos] == self.pos
+        assert x[self.neg] == self.neg
+        assert x[self.neg:self.pos] == (-1, maxint)
+        assert x[self.neg:self.pos:1].indices(maxint) == (0, maxint, 1)
+
+    def test_sequence_repeat(self):
+        raises(OverflowError, lambda: "a" * self.pos)
+        raises(OverflowError, lambda: "a" * self.neg)

pypy/objspace/std/test/test_stringobject.py

 
 class TestW_StringObject:
 
-    def teardown_method(self,method):
+    def teardown_method(self, method):
         pass
 
 ##    def test_order_rich(self):
         assert 'abc'.startswith('bc', 1, 2) is False
         assert 'abc'.startswith('c', -1, 4) is True
 
+    def test_startswith_tuples(self):
+        assert 'hello'.startswith(('he', 'ha'))
+        assert not 'hello'.startswith(('lo', 'llo'))
+        assert 'hello'.startswith(('hellox', 'hello'))
+        assert not 'hello'.startswith(())
+        assert 'helloworld'.startswith(('hellowo', 'rld', 'lowo'), 3)
+        assert not 'helloworld'.startswith(('hellowo', 'ello', 'rld'), 3)
+        assert 'hello'.startswith(('lo', 'he'), 0, -1)
+        assert not 'hello'.startswith(('he', 'hel'), 0, 1)
+        assert 'hello'.startswith(('he', 'hel'), 0, 2)
+        raises(TypeError, 'hello'.startswith, (42,))
+    
     def test_endswith(self):
         assert 'ab'.endswith('ab') is True
         assert 'ab'.endswith('b') is True
         assert 'abc'.endswith('bc', 1) is True
         assert 'abc'.endswith('bc', 2) is False
         assert 'abc'.endswith('b', -3, -1) is True
-      
+
+    def test_endswith_tuple(self):
+        assert not 'hello'.endswith(('he', 'ha'))
+        assert 'hello'.endswith(('lo', 'llo'))
+        assert 'hello'.endswith(('hellox', 'hello'))
+        assert not 'hello'.endswith(())
+        assert 'helloworld'.endswith(('hellowo', 'rld', 'lowo'), 3)
+        assert not 'helloworld'.endswith(('hellowo', 'ello', 'rld'), 3, -1)
+        assert 'hello'.endswith(('hell', 'ell'), 0, -1)
+        assert not 'hello'.endswith(('he', 'hel'), 0, 1)
+        assert 'hello'.endswith(('he', 'hell'), 0, 4)
+        raises(TypeError, 'hello'.endswith, (42,))
+
     def test_expandtabs(self):
         assert 'abc\rab\tdef\ng\thi'.expandtabs() ==    'abc\rab      def\ng       hi'
         assert 'abc\rab\tdef\ng\thi'.expandtabs(8) ==   'abc\rab      def\ng       hi'
         raises(TypeError, 'abcdefghijklmn'.rindex, 'abc', -10.0, 30)
 
 
+    def test_partition(self):
+
+        assert ('this is the par', 'ti', 'tion method') == \
+            'this is the partition method'.partition('ti')
+
+        # from raymond's original specification
+        S = 'http://www.python.org'
+        assert ('http', '://', 'www.python.org') == S.partition('://')
+        assert ('http://www.python.org', '', '') == S.partition('?')
+        assert ('', 'http://', 'www.python.org') == S.partition('http://')
+        assert ('http://www.python.', 'org', '') == S.partition('org')
+
+        raises(ValueError, S.partition, '')