[pypy-commit] pypy numpy-fixes: cleanup and call __array_wrap__ where needed, also add missing subtype compatability on reduce()

mattip noreply at buildbot.pypy.org
Sat May 9 22:36:13 CEST 2015


Author: mattip <matti.picus at gmail.com>
Branch: numpy-fixes
Changeset: r77263:ca9c0847ff2c
Date: 2015-05-09 23:08 +0300
http://bitbucket.org/pypy/pypy/changeset/ca9c0847ff2c/

Log:	cleanup and call __array_wrap__ where needed, also add missing
	subtype compatability on reduce()

diff --git a/pypy/module/micronumpy/base.py b/pypy/module/micronumpy/base.py
--- a/pypy/module/micronumpy/base.py
+++ b/pypy/module/micronumpy/base.py
@@ -3,16 +3,14 @@
 from rpython.tool.pairtype import extendabletype
 from pypy.module.micronumpy import support
 
-def wrap_impl(space, w_cls, w_instance, impl, postpone_finalize=False):
+def wrap_impl(space, w_cls, w_instance, impl):
     if w_cls is None or space.is_w(w_cls, space.gettypefor(W_NDimArray)):
         w_ret = W_NDimArray(impl)
     else:
         w_ret = space.allocate_instance(W_NDimArray, w_cls)
         W_NDimArray.__init__(w_ret, impl)
         assert isinstance(w_ret, W_NDimArray)
-        if not postpone_finalize:
-            # ufuncs need to call finalize after wrap
-            space.call_method(w_ret, '__array_finalize__', w_instance)
+        space.call_method(w_ret, '__array_finalize__', w_instance)
     return w_ret
 
 
@@ -35,8 +33,7 @@
         self.implementation = implementation
 
     @staticmethod
-    def from_shape(space, shape, dtype, order='C', w_instance=None,
-                   zero=True, postpone_finalize=False):
+    def from_shape(space, shape, dtype, order='C', w_instance=None, zero=True):
         from pypy.module.micronumpy import concrete, descriptor, boxes
         from pypy.module.micronumpy.strides import calc_strides
         strides, backstrides = calc_strides(shape, dtype.base, order)
@@ -45,8 +42,7 @@
         if dtype == descriptor.get_dtype_cache(space).w_objectdtype:
             impl.fill(space, boxes.W_ObjectBox(space.w_None))
         if w_instance:
-            return wrap_impl(space, space.type(w_instance), w_instance,
-                             impl, postpone_finalize=postpone_finalize)
+            return wrap_impl(space, space.type(w_instance), w_instance, impl)
         return W_NDimArray(impl)
 
     @staticmethod
diff --git a/pypy/module/micronumpy/loop.py b/pypy/module/micronumpy/loop.py
--- a/pypy/module/micronumpy/loop.py
+++ b/pypy/module/micronumpy/loop.py
@@ -22,9 +22,8 @@
     # handle array_priority
     # w_lhs and w_rhs could be of different ndarray subtypes. Numpy does:
     # 1. if __array_priorities__ are equal and one is an ndarray and the
-    #        other is a subtype,  flip the order
-    # 2. elif rhs.__array_priority__ is higher, flip the order
-    # Now return the subtype of the first one
+    #        other is a subtype,  return a subtype
+    # 2. elif rhs.__array_priority__ is higher, return the type of rhs
 
     w_ndarray = space.gettypefor(W_NDimArray)
     lhs_type = space.type(w_lhs)
@@ -38,10 +37,15 @@
     if not space.is_true(space.issubtype(rhs_type, w_ndarray)):
         rhs_type = space.type(w_rhs.base)
         rhs_for_subtype = w_rhs.base
+
+    w_highpriority = w_lhs
+    highpriority_subtype = lhs_for_subtype
     if space.is_w(lhs_type, w_ndarray) and not space.is_w(rhs_type, w_ndarray):
-        lhs_for_subtype = rhs_for_subtype
-
-    # TODO handle __array_priorities__ and maybe flip the order
+        highpriority_subtype = rhs_for_subtype
+        w_highpriority = w_rhs
+    if support.is_rhs_priority_higher(space, w_lhs, w_rhs):
+        highpriority_subtype = rhs_for_subtype
+        w_highpriority = w_rhs
 
     if w_lhs.get_size() == 1:
         w_left = w_lhs.get_scalar_value().convert_to(space, calc_dtype)
@@ -61,7 +65,7 @@
 
     if out is None:
         w_ret = W_NDimArray.from_shape(space, shape, res_dtype,
-                                     w_instance=lhs_for_subtype, postpone_finalize=True)
+                                     w_instance=highpriority_subtype)
     else:
         w_ret = out
     out_iter, out_state = w_ret.create_iter(shape)
@@ -79,8 +83,7 @@
             space, res_dtype))
         out_state = out_iter.next(out_state)
     if out is None:
-        w_ret = space.call_method(w_rhs, '__array_wrap__', w_ret)
-        space.call_method(w_ret, '__array_finalize__', lhs_for_subtype)
+        w_ret = space.call_method(w_highpriority, '__array_wrap__', w_ret)
     return w_ret
 
 call1_driver = jit.JitDriver(
@@ -93,8 +96,10 @@
     obj_iter.track_index = False
 
     if out is None:
-        out = W_NDimArray.from_shape(space, shape, res_dtype, w_instance=w_obj)
-    out_iter, out_state = out.create_iter(shape)
+        w_ret = W_NDimArray.from_shape(space, shape, res_dtype, w_instance=w_obj)
+    else:
+        w_ret = out
+    out_iter, out_state = w_ret.create_iter(shape)
     shapelen = len(shape)
     while not out_iter.done(out_state):
         call1_driver.jit_merge_point(shapelen=shapelen, func=func,
@@ -103,7 +108,9 @@
         out_iter.setitem(out_state, func(calc_dtype, elem).convert_to(space, res_dtype))
         out_state = out_iter.next(out_state)
         obj_state = obj_iter.next(obj_state)
-    return out
+    if out is None:
+        w_ret = space.call_method(w_obj, '__array_wrap__', w_ret)
+    return w_ret
 
 call_many_to_one_driver = jit.JitDriver(
     name='numpy_call_many_to_one',
diff --git a/pypy/module/micronumpy/support.py b/pypy/module/micronumpy/support.py
--- a/pypy/module/micronumpy/support.py
+++ b/pypy/module/micronumpy/support.py
@@ -152,3 +152,9 @@
 def get_storage_as_int(storage, start=0):
         return rffi.cast(lltype.Signed, storage) + start
 
+def is_rhs_priority_higher(space, w_lhs, w_rhs):
+    w_zero = space.wrap(0.0)
+    w_priority_l = space.findattr(w_lhs, space.wrap('__array_priority__')) or w_zero
+    w_priority_r = space.findattr(w_rhs, space.wrap('__array_priority__')) or w_zero
+    # XXX what is better, unwrapping values or space.gt?
+    return space.is_true(space.gt(w_priority_r, w_priority_l))
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
@@ -640,7 +640,7 @@
             def __array_finalize__(self, obj):
                 self.output += 'In __array_finalize__:'
                 self.output += '   self is %s' % repr(self)
-                self.output += '   obj is %s' % repr(obj)
+                self.output += '   obj is %s\n' % repr(obj)
                 print self.output
                 if obj is None: return
                 self.info = getattr(obj, 'info', None)
@@ -648,7 +648,7 @@
             def __array_wrap__(self, out_arr, context=None):
                 self.output += 'In __array_wrap__:'
                 self.output += '   self is %s' % repr(self)
-                self.output += '   arr is %s' % repr(out_arr)
+                self.output += '   arr is %r\n' % (out_arr,)
                 # then just call the parent
                 ret = np.ndarray.__array_wrap__(self, out_arr, context)
                 print 'wrap',self.output
@@ -657,15 +657,18 @@
         obj = MySubClass(np.arange(5), info='spam')
         assert obj.output.startswith('In __array_finalize')
         obj.output = ''
-        arr2 = np.arange(5)+1
+        print 'np.arange(5) + 1'
+        arr2 = np.arange(5) + 1
         assert len(obj.output) < 1
+        print 'np.add(arr2, obj)'
         ret = np.add(arr2, obj)
-        print obj.output
         assert obj.output.startswith('In __array_wrap')
         assert 'finalize' not in obj.output
         assert ret.info == 'spam'
+        print 'np.negative(obj)'
         ret = np.negative(obj)
         assert ret.info == 'spam'
+        print 'obj.sum()'
         ret = obj.sum()
+        print type(ret)
         assert ret.info == 'spam'
-        assert False
diff --git a/pypy/module/micronumpy/ufuncs.py b/pypy/module/micronumpy/ufuncs.py
--- a/pypy/module/micronumpy/ufuncs.py
+++ b/pypy/module/micronumpy/ufuncs.py
@@ -13,7 +13,8 @@
 from pypy.module.micronumpy.ctors import numpify
 from pypy.module.micronumpy.nditer import W_NDIter, coalesce_iter
 from pypy.module.micronumpy.strides import shape_agreement
-from pypy.module.micronumpy.support import _parse_signature, product, get_storage_as_int
+from pypy.module.micronumpy.support import (_parse_signature, product, 
+        get_storage_as_int, is_rhs_priority_higher)
 from rpython.rlib.rawstorage import (raw_storage_setitem, free_raw_storage,
              alloc_raw_storage)
 from rpython.rtyper.lltypesystem import rffi, lltype
@@ -286,8 +287,7 @@
                                        axis, out, self.identity, cumulative,
                                        temp)
             if call__array_wrap__:
-                pass
-                # XXX if out is not type(obj) call __array_wrap__ 
+                out = space.call_method(w_obj, '__array_wrap__', out)
             return out
         if cumulative:
             if out:
@@ -301,8 +301,7 @@
             loop.compute_reduce_cumulative(space, obj, out, dtype, self.func,
                                            self.identity)
             if call__array_wrap__:
-                pass
-                # XXX if out is not a type(obj) call __array_wrap__ 
+                out = space.call_method(w_obj, '__array_wrap__', out)
             return out
         if out:
             call__array_wrap__ = False
@@ -318,13 +317,16 @@
             return out
         if keepdims:
             shape = [1] * len(obj_shape)
-            out = W_NDimArray.from_shape(space, [1] * len(obj_shape), dtype,
-                                         w_instance=obj)
+            out = W_NDimArray.from_shape(space, shape, dtype, w_instance=obj)
+            out.implementation.setitem(0, res)
+            res = out
+        elif not space.is_w(space.gettypefor(w_obj), space.gettypefor(W_NDimArray)):
+            # subtypes return a ndarray subtype, not a scalar
+            out = W_NDimArray.from_shape(space, [1], dtype, w_instance=obj)
             out.implementation.setitem(0, res)
             res = out
         if call__array_wrap__:
-            pass
-            # XXX if res is not a type(obj) call __array_wrap__ 
+            res = space.call_method(w_obj, '__array_wrap__', res)
         return res
 
     def descr_outer(self, space, __args__):
@@ -494,11 +496,7 @@
             # the __r<op>__ method and has __array_priority__ as
             # an attribute (signalling it can handle ndarray's)
             # and is not already an ndarray or a subtype of the same type.
-            w_zero = space.wrap(0.0)
-            w_priority_l = space.findattr(w_lhs, space.wrap('__array_priority__')) or w_zero
-            w_priority_r = space.findattr(w_rhs, space.wrap('__array_priority__')) or w_zero
-            # XXX what is better, unwrapping values or space.gt?
-            r_greater = space.is_true(space.gt(w_priority_r, w_priority_l))
+            r_greater = is_rhs_priority_higher(space, w_lhs, w_rhs)
             if r_greater and _has_reflected_op(space, w_rhs, self.name):
                 return space.w_NotImplemented
         w_lhs = numpify(space, w_lhs)


More information about the pypy-commit mailing list