[pypy-svn] r58914 - in pypy/branch/2.5-merge/pypy: interpreter objspace objspace/std objspace/std/test

antocuni at codespeak.net antocuni at codespeak.net
Fri Oct 10 16:53:15 CEST 2008


Author: antocuni
Date: Fri Oct 10 16:53:15 2008
New Revision: 58914

Modified:
   pypy/branch/2.5-merge/pypy/interpreter/baseobjspace.py
   pypy/branch/2.5-merge/pypy/objspace/descroperation.py
   pypy/branch/2.5-merge/pypy/objspace/reflective.py
   pypy/branch/2.5-merge/pypy/objspace/std/builtinshortcut.py
   pypy/branch/2.5-merge/pypy/objspace/std/listobject.py
   pypy/branch/2.5-merge/pypy/objspace/std/objspace.py
   pypy/branch/2.5-merge/pypy/objspace/std/test/test_listmultiobject.py
   pypy/branch/2.5-merge/pypy/objspace/std/test/test_listobject.py
   pypy/branch/2.5-merge/pypy/objspace/thunk.py
Log:
(arigo, antocuni)

make {get,set,del}slice real multimethods, and implement
list.__{get,set,del}slice__



Modified: pypy/branch/2.5-merge/pypy/interpreter/baseobjspace.py
==============================================================================
--- pypy/branch/2.5-merge/pypy/interpreter/baseobjspace.py	(original)
+++ pypy/branch/2.5-merge/pypy/interpreter/baseobjspace.py	Fri Oct 10 16:53:15 2008
@@ -588,17 +588,6 @@
         w_s = self.interned_strings[s] = self.wrap(s)
         return w_s
 
-    # support for the deprecated __getslice__, __setslice__, __delslice__
-    def getslice(self, w_obj, w_start, w_stop):
-        w_slice = self.newslice(w_start, w_stop, self.w_None)
-        return self.getitem(w_obj, w_slice)
-    def setslice(self, w_obj, w_start, w_stop, w_sequence):
-        w_slice = self.newslice(w_start, w_stop, self.w_None)
-        self.setitem(w_obj, w_slice, w_sequence)
-    def delslice(self, w_obj, w_start, w_stop):
-        w_slice = self.newslice(w_start, w_stop, self.w_None)
-        self.delitem(w_obj, w_slice)
-
     def interpclass_w(space, w_obj):
         """
          If w_obj is a wrapped internal interpreter class instance unwrap to it,
@@ -1011,6 +1000,9 @@
     ('getitem',         'getitem',   2, ['__getitem__']),
     ('setitem',         'setitem',   3, ['__setitem__']),
     ('delitem',         'delitem',   2, ['__delitem__']),
+    ('getslice',        'getslice',  3, ['__getslice__']),
+    ('setslice',        'setslice',  4, ['__setslice__']),
+    ('delslice',        'delslice',  3, ['__delslice__']),
     ('pos',             'pos',       1, ['__pos__']),
     ('neg',             'neg',       1, ['__neg__']),
     ('nonzero',         'truth',     1, ['__nonzero__']),

Modified: pypy/branch/2.5-merge/pypy/objspace/descroperation.py
==============================================================================
--- pypy/branch/2.5-merge/pypy/objspace/descroperation.py	(original)
+++ pypy/branch/2.5-merge/pypy/objspace/descroperation.py	Fri Oct 10 16:53:15 2008
@@ -228,6 +228,30 @@
                    space.wrap("cannot delete items from object"))
         return space.get_and_call_function(w_descr, w_obj, w_key)
 
+    def getslice(space, w_obj, w_start, w_stop):
+        w_descr = space.lookup(w_obj, '__getslice__')
+        if w_descr is None:
+            w_slice = space.newslice(w_start, w_stop, space.w_None)
+            return space.getitem(w_obj, w_slice)
+        w_start, w_stop = old_slice_range(space, w_obj, w_start, w_stop)
+        return space.get_and_call_function(w_descr, w_obj, w_start, w_stop)
+
+    def setslice(space, w_obj, w_start, w_stop, w_sequence):
+        w_descr = space.lookup(w_obj, '__setslice__')
+        if w_descr is None:
+            w_slice = space.newslice(w_start, w_stop, space.w_None)
+            return space.setitem(w_obj, w_slice, w_sequence)
+        w_start, w_stop = old_slice_range(space, w_obj, w_start, w_stop)
+        return space.get_and_call_function(w_descr, w_obj, w_start, w_stop, w_sequence)
+
+    def delslice(space, w_obj, w_start, w_stop):
+        w_descr = space.lookup(w_obj, '__delslice__')
+        if w_descr is None:
+            w_slice = space.newslice(w_start, w_stop, space.w_None)
+            return space.delitem(w_obj, w_slice)
+        w_start, w_stop = old_slice_range(space, w_obj, w_start, w_stop)
+        return space.get_and_call_function(w_descr, w_obj, w_start, w_stop)
+
     def pow(space, w_obj1, w_obj2, w_obj3):
         w_typ1 = space.type(w_obj1)
         w_typ2 = space.type(w_obj2)
@@ -453,6 +477,35 @@
     return (space.lookup(w_obj, '__int__') is not None or
             space.lookup(w_obj, '__float__') is not None)
 
+
+
+# what is the maximum value slices can get on CPython?
+# we need to stick to that value, because fake.py etc.
+class Temp:
+    def __getslice__(self, i, j):
+        return j
+slice_max = Temp()[:]
+del Temp
+
+def old_slice_range(space, w_obj, w_start, w_stop):
+    """Only for backward compatibility for __getslice__()&co methods."""
+    if space.is_w(w_start, space.w_None):
+        w_start = space.wrap(0)
+    else:
+        w_start = space.wrap(space.getindex_w(w_start, None))
+        if space.is_true(space.lt(w_start, space.wrap(0))):
+            w_start = space.add(w_start, space.len(w_obj))
+            # NB. the language ref is inconsistent with the new-style class
+            # behavior when w_obj doesn't implement __len__(), so we just
+            # ignore this case.
+    if space.is_w(w_stop, space.w_None):
+        w_stop = space.wrap(slice_max)
+    else:
+        w_stop = space.wrap(space.getindex_w(w_stop, None))
+        if space.is_true(space.lt(w_stop, space.wrap(0))):
+            w_stop = space.add(w_stop, space.len(w_obj))
+    return w_start, w_stop
+
 # regular methods def helpers
 
 def _make_binop_impl(symbol, specialnames):
@@ -649,5 +702,3 @@
                            'ord', 'unichr', 'unicode']:
             raise Exception, "missing def for operation %s" % _name
             
-            
-

Modified: pypy/branch/2.5-merge/pypy/objspace/reflective.py
==============================================================================
--- pypy/branch/2.5-merge/pypy/objspace/reflective.py	(original)
+++ pypy/branch/2.5-merge/pypy/objspace/reflective.py	Fri Oct 10 16:53:15 2008
@@ -89,6 +89,14 @@
                     return parentfn(w_arg1, w_arg2, w_arg3)
                 finally:
                     reset_reflective_space(space, w_old_reflectivespace)
+        elif args == 4:
+            def func(self, space, w_arg1, w_arg2, w_arg3, w_arg4):
+                w_old_reflectivespace = get_reflective_space(space)
+                set_reflectivespace(space, self.w_reflectivespace)
+                try:
+                    return parentfn(w_arg1, w_arg2, w_arg3, w_arg4)
+                finally:
+                    reset_reflective_space(space, w_old_reflectivespace)
         else:
             raise NotImplementedError
         unwrap_spec = ["self", ObjSpace] + [W_Root] * args

Modified: pypy/branch/2.5-merge/pypy/objspace/std/builtinshortcut.py
==============================================================================
--- pypy/branch/2.5-merge/pypy/objspace/std/builtinshortcut.py	(original)
+++ pypy/branch/2.5-merge/pypy/objspace/std/builtinshortcut.py	Fri Oct 10 16:53:15 2008
@@ -22,6 +22,7 @@
      'len', 'nonzero', 'repr', 'str', 'hash',
      'neg', 'invert', 'index', 'iter', 'next', 'buffer',
      'getitem', 'setitem', 'int',
+     'getslice', 'setslice',
      # in-place
      'inplace_add', 'inplace_sub', 'inplace_mul', 'inplace_truediv',
      'inplace_floordiv', 'inplace_div', 'inplace_mod', 'inplace_pow',
@@ -32,7 +33,8 @@
 KNOWN_MISSING = ['getattr',   # mostly non-builtins or optimized by CALL_METHOD
                  'setattr', 'delattr', 'userdel',  # mostly for non-builtins
                  'get', 'set', 'delete',   # uncommon (except on functions)
-                 'delitem', 'abs', 'hex', 'oct',  # rare stuff?
+                 'delitem', 'delslice',           # rare stuff?
+                 'abs', 'hex', 'oct',             # rare stuff?
                  'pos', 'divmod', 'cmp',          # rare stuff?
                  'float', 'long', 'coerce',       # rare stuff?
                  ]

Modified: pypy/branch/2.5-merge/pypy/objspace/std/listobject.py
==============================================================================
--- pypy/branch/2.5-merge/pypy/objspace/std/listobject.py	(original)
+++ pypy/branch/2.5-merge/pypy/objspace/std/listobject.py	Fri Oct 10 16:53:15 2008
@@ -80,6 +80,30 @@
         start += step
     return w_res
 
+def normalize_slice(space, w_list, w_start, w_stop):
+    start = space.int_w(w_start)
+    stop = space.int_w(w_stop)
+    length = len(w_list.wrappeditems)
+    if start < 0:
+        start = 0
+    if stop > length:
+        stop = length
+    if stop < start:
+        stop = start
+    return start, stop
+
+def getslice__List_ANY_ANY(space, w_list, w_start, w_stop):
+    start, stop = normalize_slice(space, w_list, w_start, w_stop)
+    return W_ListObject(w_list.wrappeditems[start:stop])
+
+def setslice__List_ANY_ANY_ANY(space, w_list, w_start, w_stop, w_sequence):
+    start, stop = normalize_slice(space, w_list, w_start, w_stop)
+    _setitem_slice_helper(space, w_list, start, 1, stop-start, w_sequence)
+
+def delslice__List_ANY_ANY(space, w_list, w_start, w_stop):
+    start, stop = normalize_slice(space, w_list, w_start, w_stop)
+    _delitem_slice_helper(space, w_list, start, 1, stop-start)
+
 def contains__List_ANY(space, w_list, w_obj):
     # needs to be safe against eq_w() mutating the w_list behind our back
     i = 0
@@ -190,38 +214,35 @@
                              space.wrap("list deletion index out of range"))
     return space.w_None
 
+
 def delitem__List_Slice(space, w_list, w_slice):
     start, stop, step, slicelength = w_slice.indices4(space,
                                                       len(w_list.wrappeditems))
+    _delitem_slice_helper(space, w_list, start, step, slicelength)
 
+def _delitem_slice_helper(space, w_list, start, step, slicelength):
     if slicelength==0:
         return
 
     if step < 0:
         start = start + step * (slicelength-1)
         step = -step
-        # stop is invalid
         
     if step == 1:
-        _del_slice(w_list, start, start+slicelength)
+        assert start >= 0
+        assert slicelength >= 0
+        del w_list.wrappeditems[start:start+slicelength]
     else:
         items = w_list.wrappeditems
         n = len(items)
-
-        recycle = [None] * slicelength
         i = start
 
-        # keep a reference to the objects to be removed,
-        # preventing side effects during destruction
-        recycle[0] = items[i]
-
         for discard in range(1, slicelength):
             j = i+1
             i += step
             while j < i:
                 items[j-discard] = items[j]
                 j += 1
-            recycle[discard] = items[i]
 
         j = i+1
         while j < n:
@@ -229,13 +250,7 @@
             j += 1
         start = n - slicelength
         assert start >= 0 # annotator hint
-        # XXX allow negative indices in rlist
         del items[start:]
-        # now we can destruct recycle safely, regardless of
-        # side-effects to the list
-        del recycle[:]
-
-    return space.w_None
 
 def setitem__List_ANY_ANY(space, w_list, w_index, w_any):
     idx = get_list_index(space, w_index)
@@ -246,23 +261,25 @@
                              space.wrap("list index out of range"))
     return space.w_None
 
-def setitem__List_Slice_List(space, w_list, w_slice, w_list2):
-    l = w_list2.wrappeditems
-    return _setitem_slice_helper(space, w_list, w_slice, l, len(l))
-
 def setitem__List_Slice_ANY(space, w_list, w_slice, w_iterable):
-    l = space.unpackiterable(w_iterable)
-    return _setitem_slice_helper(space, w_list, w_slice, l, len(l))
-
-def _setitem_slice_helper(space, w_list, w_slice, sequence2, len2):
     oldsize = len(w_list.wrappeditems)
     start, stop, step, slicelength = w_slice.indices4(space, oldsize)
+    _setitem_slice_helper(space, w_list, start, step, slicelength, w_iterable)
+
+def _setitem_slice_helper(space, w_list, start, step, slicelength, w_iterable):
+    if isinstance(w_iterable, W_ListObject):
+        sequence2 = w_iterable.wrappeditems
+    else:
+        sequence2 = space.unpackiterable(w_iterable)
+
     assert slicelength >= 0
     items = w_list.wrappeditems
-
+    oldsize = len(items)
+    len2 = len(sequence2)
     if step == 1:  # Support list resizing for non-extended slices
-        delta = len2 - slicelength
-        if delta >= 0:
+        delta = slicelength - len2
+        if delta < 0:
+            delta = -delta
             newsize = oldsize + delta
             # XXX support this in rlist!
             items += [None] * delta
@@ -271,9 +288,10 @@
             while i >= lim:
                 items[i] = items[i-delta]
                 i -= 1
+        elif start >= 0:
+            del items[start:start+delta]
         else:
-            # shrinking requires the careful memory management of _del_slice()
-            _del_slice(w_list, start, start-delta)
+            assert delta==0
     elif len2 != slicelength:  # No resize for extended slices
         raise OperationError(space.w_ValueError, space.wrap("attempt to "
               "assign sequence of size %d to extended slice of size %d" %
@@ -290,14 +308,13 @@
                 items[start] = sequence2[i]
                 start -= step
                 i -= 1
-            return space.w_None
+            return
         else:
             # Make a shallow copy to more easily handle the reversal case
             sequence2 = list(sequence2)
     for i in range(len2):
         items[start] = sequence2[i]
         start += step
-    return space.w_None
 
 app = gateway.applevel("""
     def listrepr(currently_in_repr, l):
@@ -350,26 +367,6 @@
     w_list.wrappeditems += space.unpackiterable(w_any)
     return space.w_None
 
-def _del_slice(w_list, ilow, ihigh):
-    """ similar to the deletion part of list_ass_slice in CPython """
-    items = w_list.wrappeditems
-    n = len(items)
-    if ilow < 0:
-        ilow = 0
-    elif ilow > n:
-        ilow = n
-    if ihigh < ilow:
-        ihigh = ilow
-    elif ihigh > n:
-        ihigh = n
-    # keep a reference to the objects to be removed,
-    # preventing side effects during destruction
-    recycle = items[ilow:ihigh]
-    del items[ilow:ihigh]
-    # now we can destruct recycle safely, regardless of
-    # side-effects to the list
-    del recycle[:]
-
 # note that the default value will come back wrapped!!!
 def list_pop__List_ANY(space, w_list, w_idx=-1):
     items = w_list.wrappeditems

Modified: pypy/branch/2.5-merge/pypy/objspace/std/objspace.py
==============================================================================
--- pypy/branch/2.5-merge/pypy/objspace/std/objspace.py	(original)
+++ pypy/branch/2.5-merge/pypy/objspace/std/objspace.py	Fri Oct 10 16:53:15 2008
@@ -764,33 +764,6 @@
         else:
             return ObjSpace.call_method(self, w_obj, methname, *arg_w)
 
-    # support for the deprecated __getslice__, __setslice__, __delslice__
-
-    def getslice(self, w_obj, w_start, w_stop):
-        w_descr = self.lookup(w_obj, '__getslice__')
-        if w_descr is not None:
-            w_start, w_stop = old_slice_range(self, w_obj, w_start, w_stop)
-            return self.get_and_call_function(w_descr, w_obj, w_start, w_stop)
-        else:
-            return ObjSpace.getslice(self, w_obj, w_start, w_stop)
-
-    def setslice(self, w_obj, w_start, w_stop, w_sequence):
-        w_descr = self.lookup(w_obj, '__setslice__')
-        if w_descr is not None:
-            w_start, w_stop = old_slice_range(self, w_obj, w_start, w_stop)
-            self.get_and_call_function(w_descr, w_obj, w_start, w_stop,
-                                       w_sequence)
-        else:
-            ObjSpace.setslice(self, w_obj, w_start, w_stop, w_sequence)
-
-    def delslice(self, w_obj, w_start, w_stop):
-        w_descr = self.lookup(w_obj, '__delslice__')
-        if w_descr is not None:
-            w_start, w_stop = old_slice_range(self, w_obj, w_start, w_stop)
-            self.get_and_call_function(w_descr, w_obj, w_start, w_stop)
-        else:
-            ObjSpace.delslice(self, w_obj, w_start, w_stop)
-
     def raise_key_error(self, w_key):
         e = self.call_function(self.w_KeyError, w_key)
         raise OperationError(self.w_KeyError, e)
@@ -820,32 +793,3 @@
                 del mm
 
         pow.extras['defaults'] = (None,)
-
-
-# what is the maximum value slices can get on CPython?
-# we need to stick to that value, because fake.py etc.
-class Temp:
-    def __getslice__(self, i, j):
-        return j
-slice_max = Temp()[:]
-del Temp
-
-
-def old_slice_range(space, w_obj, w_start, w_stop):
-    """Only for backward compatibility for __getslice__()&co methods."""
-    if space.is_w(w_start, space.w_None):
-        w_start = space.wrap(0)
-    else:
-        w_start = space.wrap(space.getindex_w(w_start, None))
-        if space.is_true(space.lt(w_start, space.wrap(0))):
-            w_start = space.add(w_start, space.len(w_obj))
-            # NB. the language ref is inconsistent with the new-style class
-            # behavior when w_obj doesn't implement __len__(), so we just
-            # ignore this case.
-    if space.is_w(w_stop, space.w_None):
-        w_stop = space.wrap(slice_max)
-    else:
-        w_stop = space.wrap(space.getindex_w(w_stop, None))
-        if space.is_true(space.lt(w_stop, space.wrap(0))):
-            w_stop = space.add(w_stop, space.len(w_obj))
-    return w_start, w_stop

Modified: pypy/branch/2.5-merge/pypy/objspace/std/test/test_listmultiobject.py
==============================================================================
--- pypy/branch/2.5-merge/pypy/objspace/std/test/test_listmultiobject.py	(original)
+++ pypy/branch/2.5-merge/pypy/objspace/std/test/test_listmultiobject.py	Fri Oct 10 16:53:15 2008
@@ -39,6 +39,15 @@
         # These few here ^ would have failed before, but for good coverage,
         # all the list methods etc. should be tested also...
 
+    def test___getslice__(self):
+        skip("don't care for now")
+
+    def test___setslice__(self):
+        skip("don't care for now")
+        
+    def test___delslice__(self):
+        skip("don't care for now")
+
 class AppTest_ListMultiObject(BaseAppTest_ListMultiObject):
     def setup_class(cls):
         BaseAppTest_ListMultiObject.setup_class(cls)

Modified: pypy/branch/2.5-merge/pypy/objspace/std/test/test_listobject.py
==============================================================================
--- pypy/branch/2.5-merge/pypy/objspace/std/test/test_listobject.py	(original)
+++ pypy/branch/2.5-merge/pypy/objspace/std/test/test_listobject.py	Fri Oct 10 16:53:15 2008
@@ -754,3 +754,18 @@
             A()
             while lst:
                 keepalive.append(lst[:])
+
+    def test___getslice__(self):
+        l = [1,2,3,4]
+        res = l.__getslice__(0, 2)
+        assert res == [1, 2]
+
+    def test___setslice__(self):
+        l = [1,2,3,4]
+        l.__setslice__(0, 2, [5, 6])
+        assert l == [5, 6, 3, 4]
+
+    def test___delslice__(self):
+        l = [1,2,3,4]
+        l.__delslice__(0, 2)
+        assert l == [3, 4]

Modified: pypy/branch/2.5-merge/pypy/objspace/thunk.py
==============================================================================
--- pypy/branch/2.5-merge/pypy/objspace/thunk.py	(original)
+++ pypy/branch/2.5-merge/pypy/objspace/thunk.py	Fri Oct 10 16:53:15 2008
@@ -193,6 +193,13 @@
             w2 = force(space, w2)
             w3 = force(space, w3)
             return parentfn(w1, w2, w3, *extra)
+    elif nb_args == 4:
+        def proxy(w1, w2, w3, w4, *extra):
+            w1 = force(space, w1)
+            w2 = force(space, w2)
+            w3 = force(space, w3)
+            w4 = force(space, w4)
+            return parentfn(w1, w2, w3, w4, *extra)
     else:
         raise NotImplementedError("operation %r has arity %d" %
                                   (opname, nb_args))



More information about the Pypy-commit mailing list