[pypy-commit] pypy default: test, fix for matrix subtype which modfies shape in __getitem__

mattip noreply at buildbot.pypy.org
Sun Dec 15 06:46:36 CET 2013


Author: Matti Picus <matti.picus at gmail.com>
Branch: 
Changeset: r68441:bacd9679adbf
Date: 2013-12-15 07:43 +0200
http://bitbucket.org/pypy/pypy/changeset/bacd9679adbf/

Log:	test, fix for matrix subtype which modfies shape in __getitem__
	causing an infinite loop in find_shape_and_elems

diff --git a/pypy/module/micronumpy/strides.py b/pypy/module/micronumpy/strides.py
--- a/pypy/module/micronumpy/strides.py
+++ b/pypy/module/micronumpy/strides.py
@@ -51,8 +51,8 @@
             rstrides.append(strides[i])
             rbackstrides.append(backstrides[i])
     if backwards:
-        rstrides = rstrides + [0] * (len(res_shape) - len(orig_shape))  
-        rbackstrides = rbackstrides + [0] * (len(res_shape) - len(orig_shape)) 
+        rstrides = rstrides + [0] * (len(res_shape) - len(orig_shape))
+        rbackstrides = rbackstrides + [0] * (len(res_shape) - len(orig_shape))
     else:
         rstrides = [0] * (len(res_shape) - len(orig_shape)) + rstrides
         rbackstrides = [0] * (len(res_shape) - len(orig_shape)) + rbackstrides
@@ -62,7 +62,7 @@
     if (is_rec_type and space.isinstance_w(w_elem, space.w_tuple)):
         return True
     if (space.isinstance_w(w_elem, space.w_tuple) or
-        isinstance(w_elem, W_NDimArray) or    
+        isinstance(w_elem, W_NDimArray) or
         space.isinstance_w(w_elem, space.w_list)):
         return False
     return True
@@ -87,6 +87,12 @@
                 space.len_w(w_elem) != size):
                 raise OperationError(space.w_ValueError, space.wrap(
                     "setting an array element with a sequence"))
+            w_array = space.lookup(w_elem, '__array__')
+            if w_array is not None:
+                # Make sure we call the array implementation of listview,
+                # since for some ndarray subclasses (matrix, for instance)
+                # listview does not reduce but rather returns the same class
+                w_elem = space.get_and_call_function(w_array, w_elem, space.w_None)
             new_batch += space.listview(w_elem)
         shape.append(size)
         batch = new_batch
diff --git a/pypy/module/micronumpy/test/test_subtype.py b/pypy/module/micronumpy/test/test_subtype.py
--- a/pypy/module/micronumpy/test/test_subtype.py
+++ b/pypy/module/micronumpy/test/test_subtype.py
@@ -258,3 +258,46 @@
             assert isinstance(b, D)
         c = array(a, float)
         assert c.dtype is dtype(float)
+
+    def test__getitem_modifies_shape(self):
+        import numpypy as N
+        # numpy's matrix class caused an infinite loop
+        class matrix(N.ndarray):
+            getcnt = 0
+            def __new__(subtype, data, dtype=None, copy=True):
+                arr = N.array(data, dtype=dtype, copy=copy)
+                shape = arr.shape
+
+                ret = N.ndarray.__new__(subtype, shape, arr.dtype,
+                                        buffer=arr,
+                                        order=True)
+                return ret
+
+            def __getitem__(self, index):
+                matrix.getcnt += 1
+                if matrix.getcnt > 10:
+                    # XXX strides.find_shape_and_elems is sensitive
+                    # to shape modification
+                    xxx
+                out = N.ndarray.__getitem__(self, index)
+
+                if not isinstance(out, N.ndarray):
+                    return out
+                    # Determine when we should have a column array
+                old_shape = out.shape
+                if out.ndim < 2:
+                    sh = out.shape[0]
+                    try:
+                        n = len(index)
+                    except:
+                        n = 0
+                    if n > 1:
+                        out.shape = (sh, 1)
+                    else:
+                        out.shape = (1, sh)
+                print 'out, shape was',old_shape,'now',out.shape
+                return out
+        a = matrix([[1., 2.]])
+        b = N.array([a])
+
+


More information about the pypy-commit mailing list