[pypy-commit] pypy default: merge numpy-flags which completes the ndarray.flags property

mattip noreply at buildbot.pypy.org
Mon May 18 23:15:06 CEST 2015


Author: mattip <matti.picus at gmail.com>
Branch: 
Changeset: r77384:cf50e5142096
Date: 2015-05-18 23:46 +0300
http://bitbucket.org/pypy/pypy/changeset/cf50e5142096/

Log:	merge numpy-flags which completes the ndarray.flags property

diff --git a/pypy/doc/whatsnew-head.rst b/pypy/doc/whatsnew-head.rst
--- a/pypy/doc/whatsnew-head.rst
+++ b/pypy/doc/whatsnew-head.rst
@@ -109,3 +109,8 @@
 
 branch pythonoptimize-env
 Implement PYTHONOPTIMIZE environment variable, fixing issue #2044
+
+.. branch: numpy-flags
+
+branch numpy-flags
+Finish implementation of ndarray.flags, including str() and repr()
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
@@ -22,6 +22,9 @@
     """Base class for ndarrays and scalars (aka boxes)."""
     _attrs_ = []
 
+    def get_flags(self):
+        return 0
+
 
 class W_NDimArray(W_NumpyObject):
     __metaclass__ = extendabletype
@@ -134,6 +137,9 @@
     def get_start(self):
         return self.implementation.start
 
+    def get_flags(self):
+        return self.implementation.flags
+
     def ndims(self):
         return len(self.get_shape())
     ndims._always_inline_ = True
diff --git a/pypy/module/micronumpy/boxes.py b/pypy/module/micronumpy/boxes.py
--- a/pypy/module/micronumpy/boxes.py
+++ b/pypy/module/micronumpy/boxes.py
@@ -143,6 +143,10 @@
     def get_scalar_value(self):
         return self
 
+    def get_flags(self):
+        return (NPY.ARRAY_C_CONTIGUOUS | NPY.ARRAY_F_CONTIGUOUS | 
+                NPY.ARRAY_WRITEABLE | NPY.ARRAY_OWNDATA)
+
     def item(self, space):
         return self.get_dtype(space).itemtype.to_builtin_type(space, self)
 
diff --git a/pypy/module/micronumpy/concrete.py b/pypy/module/micronumpy/concrete.py
--- a/pypy/module/micronumpy/concrete.py
+++ b/pypy/module/micronumpy/concrete.py
@@ -7,11 +7,12 @@
 from rpython.rtyper.lltypesystem import rffi, lltype, llmemory
 from pypy.module.micronumpy import support, loop, constants as NPY
 from pypy.module.micronumpy.base import convert_to_array, W_NDimArray, \
-    ArrayArgumentException
+    ArrayArgumentException, W_NumpyObject
 from pypy.module.micronumpy.iterators import ArrayIter
 from pypy.module.micronumpy.strides import (Chunk, Chunks, NewAxisChunk,
     RecordChunk, calc_strides, calc_new_strides, shape_agreement,
-    calculate_broadcast_strides, calc_backstrides, calc_start)
+    calculate_broadcast_strides, calc_backstrides, calc_start, is_c_contiguous,
+    is_f_contiguous)
 from rpython.rlib.objectmodel import keepalive_until_here
 from rpython.rtyper.annlowlevel import cast_gcref_to_instance
 from pypy.interpreter.baseobjspace import W_Root
@@ -19,7 +20,8 @@
 
 class BaseConcreteArray(object):
     _immutable_fields_ = ['dtype?', 'storage', 'start', 'size', 'shape[*]',
-                          'strides[*]', 'backstrides[*]', 'order', 'gcstruct']
+                          'strides[*]', 'backstrides[*]', 'order', 'gcstruct',
+                          'flags']
     start = 0
     parent = None
     flags = 0
@@ -443,6 +445,11 @@
         ConcreteArrayNotOwning.__init__(self, shape, dtype, order, strides, backstrides,
                                         storage, start=start)
         self.gcstruct = gcstruct
+        self.flags = NPY.ARRAY_ALIGNED | NPY.ARRAY_WRITEABLE
+        if is_c_contiguous(self):
+            self.flags |= NPY.ARRAY_C_CONTIGUOUS
+        if is_f_contiguous(self):
+            self.flags |= NPY.ARRAY_F_CONTIGUOUS
 
     def __del__(self):
         if self.gcstruct:
@@ -456,18 +463,39 @@
         ConcreteArrayNotOwning.__init__(self, shape, dtype, order,
                                         strides, backstrides, storage, start)
         self.orig_base = orig_base
+        if isinstance(orig_base, W_NumpyObject):
+            self.flags = orig_base.get_flags() & NPY.ARRAY_ALIGNED
+            self.flags |=  orig_base.get_flags() & NPY.ARRAY_WRITEABLE
+        else:
+            self.flags = 0
+        if is_c_contiguous(self):
+            self.flags |= NPY.ARRAY_C_CONTIGUOUS
+        if is_f_contiguous(self):
+            self.flags |= NPY.ARRAY_F_CONTIGUOUS
 
     def base(self):
         return self.orig_base
 
 
 class ConcreteNonWritableArrayWithBase(ConcreteArrayWithBase):
+    def __init__(self, shape, dtype, order, strides, backstrides, storage,
+                 orig_base, start=0):
+        ConcreteArrayWithBase.__init__(self, shape, dtype, order, strides,
+                backstrides, storage, orig_base, start)
+        self.flags &= ~ NPY.ARRAY_WRITEABLE
+
     def descr_setitem(self, space, orig_array, w_index, w_value):
         raise OperationError(space.w_ValueError, space.wrap(
             "assignment destination is read-only"))
 
 
 class NonWritableArray(ConcreteArray):
+    def __init__(self, shape, dtype, order, strides, backstrides,
+                 storage=lltype.nullptr(RAW_STORAGE), zero=True):
+        ConcreteArray.__init__(self, shape, dtype, order, strides, backstrides,
+                    storage, zero)
+        self.flags &= ~ NPY.ARRAY_WRITEABLE
+        
     def descr_setitem(self, space, orig_array, w_index, w_value):
         raise OperationError(space.w_ValueError, space.wrap(
             "assignment destination is read-only"))
@@ -491,6 +519,12 @@
         self.size = support.product(shape) * self.dtype.elsize
         self.start = start
         self.orig_arr = orig_arr
+        self.flags = parent.flags & NPY.ARRAY_ALIGNED
+        self.flags |= parent.flags & NPY.ARRAY_WRITEABLE
+        if is_c_contiguous(self):
+            self.flags |= NPY.ARRAY_C_CONTIGUOUS
+        if is_f_contiguous(self):
+            self.flags |= NPY.ARRAY_F_CONTIGUOUS
 
     def base(self):
         return self.orig_arr
@@ -538,6 +572,12 @@
         return sort_array(self, space, w_axis, w_order)
 
 class NonWritableSliceArray(SliceArray):
+    def __init__(self, start, strides, backstrides, shape, parent, orig_arr,
+                 dtype=None):
+        SliceArray.__init__(self, start, strides, backstrides, shape, parent,
+                        orig_arr, dtype)
+        self.flags &= ~NPY.ARRAY_WRITEABLE
+
     def descr_setitem(self, space, orig_array, w_index, w_value):
         raise OperationError(space.w_ValueError, space.wrap(
             "assignment destination is read-only"))
@@ -549,6 +589,8 @@
         self.gcstruct = V_OBJECTSTORE
         self.dtype = dtype
         self.size = size
+        self.flags = (NPY.ARRAY_C_CONTIGUOUS | NPY.ARRAY_F_CONTIGUOUS |
+                     NPY.ARRAY_WRITEABLE | NPY.ARRAY_ALIGNED)
 
     def __del__(self):
         free_raw_storage(self.storage)
diff --git a/pypy/module/micronumpy/constants.py b/pypy/module/micronumpy/constants.py
--- a/pypy/module/micronumpy/constants.py
+++ b/pypy/module/micronumpy/constants.py
@@ -77,8 +77,20 @@
 WRAP = 1
 RAISE = 2
 
+# These can be requested in constructor functions and tested for
 ARRAY_C_CONTIGUOUS = 0x0001
 ARRAY_F_CONTIGUOUS = 0x0002
+ARRAY_ALIGNED      = 0x0100
+ARRAY_WRITEABLE    = 0x0400
+ARRAY_UPDATEIFCOPY = 0x1000 # base contains a ref to an array, update it too
+# These can be tested for
+ARRAY_OWNDATA     = 0x004
+# These can be requested in constructor functions
+ARRAY_FORECAST    = 0x0010 # causes a cast to occur even if not safe to do so
+ARRAY_ENSURECOPY  = 0x0020 # returned array will be CONTIGUOUS, ALIGNED, WRITEABLE
+ARRAY_ENSUREARRAY = 0x0040 # return only ndarray, not subtype
+ARRAY_ELEMENTSTRIDES = 0x0080 # strides  are units of the dtype element size
+ARRAY_NOTSWAPPED  = 0x0200 #native byte order
 
 LITTLE = '<'
 BIG = '>'
diff --git a/pypy/module/micronumpy/flagsobj.py b/pypy/module/micronumpy/flagsobj.py
--- a/pypy/module/micronumpy/flagsobj.py
+++ b/pypy/module/micronumpy/flagsobj.py
@@ -1,4 +1,5 @@
 from rpython.rlib import jit
+from rpython.rlib.rstring import StringBuilder
 
 from pypy.interpreter.baseobjspace import W_Root
 from pypy.interpreter.error import OperationError
@@ -13,54 +14,55 @@
 def clear_flags(arr, flags):
     arr.flags &= ~flags
 
-def _update_contiguous_flags(arr):
-    is_c_contig = is_c_contiguous(arr)
-    if is_c_contig:
-        enable_flags(arr, NPY.ARRAY_C_CONTIGUOUS)
-    else:
-        clear_flags(arr, NPY.ARRAY_C_CONTIGUOUS)
-
-    is_f_contig = is_f_contiguous(arr)
-    if is_f_contig:
-        enable_flags(arr, NPY.ARRAY_F_CONTIGUOUS)
-    else:
-        clear_flags(arr, NPY.ARRAY_F_CONTIGUOUS)
-
+def get_tf_str(flags, key):
+    if flags & key:
+        return 'True'
+    return 'False'
 
 class W_FlagsObject(W_Root):
     def __init__(self, arr):
-        self.flags = 0
+        if arr:
+            self.flags = arr.get_flags()
+        else:
+            self.flags = (NPY.ARRAY_C_CONTIGUOUS | NPY.ARRAY_F_CONTIGUOUS |
+                          NPY.ARRAY_OWNDATA | NPY.ARRAY_ALIGNED)
 
     def descr__new__(space, w_subtype):
         self = space.allocate_instance(W_FlagsObject, w_subtype)
         W_FlagsObject.__init__(self, None)
         return self
 
-    def descr_get_contiguous(self, space):
-        return space.w_True
+    def descr_c_contiguous(self, space):
+        return space.wrap(bool(self.flags & NPY.ARRAY_C_CONTIGUOUS))
 
-    def descr_get_fortran(self, space):
-        return space.w_False
+    def descr_f_contiguous(self, space):
+        return space.wrap(bool(self.flags & NPY.ARRAY_F_CONTIGUOUS))
 
     def descr_get_writeable(self, space):
-        return space.w_True
+        return space.wrap(bool(self.flags & NPY.ARRAY_WRITEABLE))
+
+    def descr_get_owndata(self, space):
+        return space.wrap(bool(self.flags & NPY.ARRAY_OWNDATA))
+
+    def descr_get_aligned(self, space):
+        return space.wrap(bool(self.flags & NPY.ARRAY_ALIGNED))
 
     def descr_get_fnc(self, space):
-        return space.wrap(
-            space.is_true(self.descr_get_fortran(space)) and not
-            space.is_true(self.descr_get_contiguous(space)))
+        return space.wrap(bool(
+            self.flags & NPY.ARRAY_F_CONTIGUOUS and not
+            self.flags & NPY.ARRAY_C_CONTIGUOUS ))
 
     def descr_get_forc(self, space):
-        return space.wrap(
-            space.is_true(self.descr_get_fortran(space)) or
-            space.is_true(self.descr_get_contiguous(space)))
+        return space.wrap(bool(
+            self.flags & NPY.ARRAY_F_CONTIGUOUS or
+            self.flags & NPY.ARRAY_C_CONTIGUOUS ))
 
     def descr_getitem(self, space, w_item):
         key = space.str_w(w_item)
         if key == "C" or key == "CONTIGUOUS" or key == "C_CONTIGUOUS":
-            return self.descr_get_contiguous(space)
+            return self.descr_c_contiguous(space)
         if key == "F" or key == "FORTRAN" or key == "F_CONTIGUOUS":
-            return self.descr_get_fortran(space)
+            return self.descr_f_contiguous(space)
         if key == "W" or key == "WRITEABLE":
             return self.descr_get_writeable(space)
         if key == "FNC":
@@ -85,6 +87,22 @@
     def descr_ne(self, space, w_other):
         return space.wrap(not self.eq(space, w_other))
 
+    def descr___str__(self, space):
+        s = StringBuilder()
+        s.append('  C_CONTIGUOUS : ')
+        s.append(get_tf_str(self.flags, NPY.ARRAY_C_CONTIGUOUS))
+        s.append('\n  F_CONTIGUOUS : ')
+        s.append(get_tf_str(self.flags, NPY.ARRAY_F_CONTIGUOUS))
+        s.append('\n  OWNDATA : ')
+        s.append(get_tf_str(self.flags, NPY.ARRAY_OWNDATA))
+        s.append('\n  WRITEABLE : ')
+        s.append(get_tf_str(self.flags, NPY.ARRAY_WRITEABLE))
+        s.append('\n  ALIGNED : ')
+        s.append(get_tf_str(self.flags, NPY.ARRAY_ALIGNED))
+        s.append('\n  UPDATEIFCOPY : ')
+        s.append(get_tf_str(self.flags, NPY.ARRAY_UPDATEIFCOPY))
+        return space.wrap(s.build())
+
 W_FlagsObject.typedef = TypeDef("numpy.flagsobj",
     __new__ = interp2app(W_FlagsObject.descr__new__.im_func),
 
@@ -92,12 +110,16 @@
     __setitem__ = interp2app(W_FlagsObject.descr_setitem),
     __eq__ = interp2app(W_FlagsObject.descr_eq),
     __ne__ = interp2app(W_FlagsObject.descr_ne),
+    __str__ = interp2app(W_FlagsObject.descr___str__),
+    __repr__ = interp2app(W_FlagsObject.descr___str__),
 
-    contiguous = GetSetProperty(W_FlagsObject.descr_get_contiguous),
-    c_contiguous = GetSetProperty(W_FlagsObject.descr_get_contiguous),
-    f_contiguous = GetSetProperty(W_FlagsObject.descr_get_fortran),
-    fortran = GetSetProperty(W_FlagsObject.descr_get_fortran),
+    contiguous = GetSetProperty(W_FlagsObject.descr_c_contiguous),
+    c_contiguous = GetSetProperty(W_FlagsObject.descr_c_contiguous),
+    f_contiguous = GetSetProperty(W_FlagsObject.descr_f_contiguous),
+    fortran = GetSetProperty(W_FlagsObject.descr_f_contiguous),
     writeable = GetSetProperty(W_FlagsObject.descr_get_writeable),
+    owndata = GetSetProperty(W_FlagsObject.descr_get_owndata),
+    aligned = GetSetProperty(W_FlagsObject.descr_get_aligned),
     fnc = GetSetProperty(W_FlagsObject.descr_get_fnc),
     forc = GetSetProperty(W_FlagsObject.descr_get_forc),
 )
diff --git a/pypy/module/micronumpy/iterators.py b/pypy/module/micronumpy/iterators.py
--- a/pypy/module/micronumpy/iterators.py
+++ b/pypy/module/micronumpy/iterators.py
@@ -39,8 +39,6 @@
 from rpython.rlib import jit
 from pypy.module.micronumpy import support, constants as NPY
 from pypy.module.micronumpy.base import W_NDimArray
-from pypy.module.micronumpy.flagsobj import _update_contiguous_flags
-
 
 class PureShapeIter(object):
     def __init__(self, shape, idx_w):
@@ -96,7 +94,6 @@
     @jit.unroll_safe
     def __init__(self, array, size, shape, strides, backstrides):
         assert len(shape) == len(strides) == len(backstrides)
-        _update_contiguous_flags(array)
         self.contiguous = (array.flags & NPY.ARRAY_C_CONTIGUOUS and
                            array.shape == shape and array.strides == strides)
 
diff --git a/pypy/module/micronumpy/nditer.py b/pypy/module/micronumpy/nditer.py
--- a/pypy/module/micronumpy/nditer.py
+++ b/pypy/module/micronumpy/nditer.py
@@ -4,7 +4,7 @@
 from pypy.interpreter.gateway import interp2app, unwrap_spec, WrappedDefault
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.module.micronumpy import support, concrete
-from pypy.module.micronumpy.base import W_NDimArray, convert_to_array
+from pypy.module.micronumpy.base import W_NDimArray, convert_to_array, W_NumpyObject
 from pypy.module.micronumpy.descriptor import decode_w_dtype
 from pypy.module.micronumpy.iterators import ArrayIter
 from pypy.module.micronumpy.strides import (calculate_broadcast_strides,
@@ -363,7 +363,7 @@
         return ret
 
 
-class W_NDIter(W_Root):
+class W_NDIter(W_NumpyObject):
     _immutable_fields_ = ['ndim', ]
     def __init__(self, space, w_seq, w_flags, w_op_flags, w_op_dtypes,
                  w_casting, w_op_axes, w_itershape, buffersize=0, order='K'):
diff --git a/pypy/module/micronumpy/test/test_flagsobj.py b/pypy/module/micronumpy/test/test_flagsobj.py
--- a/pypy/module/micronumpy/test/test_flagsobj.py
+++ b/pypy/module/micronumpy/test/test_flagsobj.py
@@ -9,6 +9,10 @@
         b = type(a.flags)()
         assert b is not a.flags
         assert b['C'] is True
+        s = str(b)
+        assert s == '%s' %('  C_CONTIGUOUS : True\n  F_CONTIGUOUS : True'
+                         '\n  OWNDATA : True\n  WRITEABLE : False'
+                         '\n  ALIGNED : True\n  UPDATEIFCOPY : False')
 
     def test_repr(self):
         import numpy as np


More information about the pypy-commit mailing list