[pypy-commit] pypy py3.5: merge translation fix

plan_rich pypy.commits at gmail.com
Tue Aug 30 14:49:02 EDT 2016


Author: Richard Plangger <planrichi at gmail.com>
Branch: py3.5
Changeset: r86754:21d53f6805c2
Date: 2016-08-30 20:46 +0200
http://bitbucket.org/pypy/pypy/changeset/21d53f6805c2/

Log:	merge translation fix

diff --git a/pypy/module/array/interp_array.py b/pypy/module/array/interp_array.py
--- a/pypy/module/array/interp_array.py
+++ b/pypy/module/array/interp_array.py
@@ -636,6 +636,18 @@
     def getlength(self):
         return self.array.len * self.array.itemsize
 
+    def getformat(self):
+        return self.array.typecode
+
+    def getitemsize(self):
+        return self.array.itemsize
+
+    def getndim(self):
+        return 1
+
+    def getstrides(self):
+        return [self.getitemsize()]
+
     def getitem(self, index):
         array = self.array
         data = array._charbuf_start()
diff --git a/pypy/module/micronumpy/test/__init__.py b/pypy/module/micronumpy/test/__init__.py
--- a/pypy/module/micronumpy/test/__init__.py
+++ b/pypy/module/micronumpy/test/__init__.py
@@ -1,2 +1,2 @@
 import py
-py.test.py3k_skip('not yet supported')
+# XXX py.test.py3k_skip('not yet supported')
diff --git a/pypy/module/micronumpy/test/dummy_module.py b/pypy/module/micronumpy/test/dummy_module.py
--- a/pypy/module/micronumpy/test/dummy_module.py
+++ b/pypy/module/micronumpy/test/dummy_module.py
@@ -20,7 +20,9 @@
 for t in types:
     globals()[t] = dtype(t).type
 
-types = ['bool', 'int', 'float', 'complex', 'str', 'string', 'unicode', 'object']
+# removed 'string' and 'unicode' from that list to handle an error in
+# make_new_dtype (micronumpy/descriptor.py)
+types = ['bool', 'int', 'float', 'complex', 'str', 'object']
 for t in types:
     globals()[t + '_'] = dtype(t).type
 del types
diff --git a/pypy/module/micronumpy/test/test_base.py b/pypy/module/micronumpy/test/test_base.py
--- a/pypy/module/micronumpy/test/test_base.py
+++ b/pypy/module/micronumpy/test/test_base.py
@@ -9,7 +9,7 @@
 
     @classmethod
     def setup_class(cls):
-        py.test.py3k_skip("micronumpy not supported on py3k")
+        # XXX py.test.py3k_skip("micronumpy not supported on py3k")
         if option.runappdirect:
             import sys
             if '__pypy__' not in sys.builtin_module_names:
diff --git a/pypy/objspace/std/bytearrayobject.py b/pypy/objspace/std/bytearrayobject.py
--- a/pypy/objspace/std/bytearrayobject.py
+++ b/pypy/objspace/std/bytearrayobject.py
@@ -502,6 +502,7 @@
     return data
 
 HEXDIGITS = "0123456789abcdef"
+PY_SIZE_T_MAX = intmask(2**(rffi.sizeof(rffi.SIZE_T)*8-1)-1)
 
 @specialize.arg(3) # raw access
 def _array_to_hexstring(space, buf, len=0, rawaccess=False):
@@ -509,11 +510,11 @@
         length = len
     else:
         length = buf.getlength()
+    hexstring = StringBuilder(length*2)
 
-    if length > sys.maxint / 2:
+    if length > PY_SIZE_T_MAX/2:
         raise OperationError(space.w_MemoryError, space.w_None)
 
-    hexstring = StringBuilder(length*2)
     for i in range(length):
         if rawaccess:
             byte = ord(buf[i])
diff --git a/pypy/objspace/std/bytesobject.py b/pypy/objspace/std/bytesobject.py
--- a/pypy/objspace/std/bytesobject.py
+++ b/pypy/objspace/std/bytesobject.py
@@ -659,6 +659,10 @@
     def descr_upper(self, space):
         return W_BytesObject(self._value.upper())
 
+    def descr_hex(self, space):
+        from pypy.objspace.std.bytearrayobject import _array_to_hexstring
+        return _array_to_hexstring(space, StringBuffer(self._value))
+
     @staticmethod
     def _iter_getitem_result(self, space, index):
         assert isinstance(self, W_BytesObject)
@@ -843,6 +847,7 @@
 
     fromhex = interp2app(W_BytesObject.descr_fromhex, as_classmethod=True),
     maketrans = interp2app(W_BytesObject.descr_maketrans, as_classmethod=True),
+    hex = interp2app(W_BytesObject.descr_hex),
 )
 W_BytesObject.typedef.flag_sequence_bug_compat = True
 
diff --git a/pypy/objspace/std/memoryobject.py b/pypy/objspace/std/memoryobject.py
--- a/pypy/objspace/std/memoryobject.py
+++ b/pypy/objspace/std/memoryobject.py
@@ -10,27 +10,73 @@
 from pypy.interpreter.error import OperationError, oefmt
 from pypy.interpreter.gateway import interp2app
 from pypy.interpreter.typedef import TypeDef, GetSetProperty,  make_weakref_descr
+from pypy.module.struct.formatiterator import UnpackFormatIterator, PackFormatIterator
 from pypy.objspace.std.bytesobject import getbytevalue
-from pypy.module.struct.formatiterator import UnpackFormatIterator, PackFormatIterator
+from rpython.rlib.unroll import unrolling_iterable
+
+MEMORYVIEW_MAX_DIM = 64
+MEMORYVIEW_SCALAR   = 0x0001
+MEMORYVIEW_C        = 0x0002
+MEMORYVIEW_FORTRAN  = 0x0004
+MEMORYVIEW_SCALAR   = 0x0008
+MEMORYVIEW_PIL      = 0x0010
 
 
 class W_MemoryView(W_Root):
     """Implement the built-in 'memoryview' type as a wrapper around
     an interp-level buffer.
     """
-    _immutable_fields_ = ['format', 'itemsize']
 
-    def __init__(self, buf, format='B', itemsize=1):
+    def __init__(self, buf, format=None, itemsize=1, ndim=-1,
+                 shape=None, strides=None, suboffsets=None):
         assert isinstance(buf, Buffer)
         self.buf = buf
         self._hash = -1
+        # private copies of format, shape, itemsize, ... on this class
         self.format = format
         self.itemsize = itemsize
+        self.shape = shape
+        self.strides = strides
+        self.suboffsets = suboffsets
+        self.ndim = ndim
+        self.flags = 0
+        self.length = -1
+        self._init_flags()
+
+    # several fields are "overwritten" by the memory view (shape, strides, ...)
+    # thus use only those getter fields instead of directly accessing the fields
+    def getndim(self):
+        if self.ndim == -1:
+            return self.buf.getndim()
+        return self.ndim
+
+    def getshape(self):
+        if self.shape is None:
+            return self.buf.getshape()
+        return self.shape
+
+    def getstrides(self):
+        if self.strides is None:
+            return self.buf.getstrides()
+        return self.strides
+
+    def getitemsize(self):
+        return self.itemsize
+
+    # memoryview needs to modify the field 'format', to prevent the modification
+    # of the buffer, we save the new format here!
+    def getformat(self):
+        if self.format is None:
+            return self.buf.getformat()
+        return self.format
+
+    def setformat(self, value):
+        self.format = value
 
     def buffer_w_ex(self, space, flags):
         self._check_released(space)
         space.check_buf_flags(flags, self.buf.readonly)
-        return self.buf, self.format, self.itemsize
+        return self.buf, self.getformat(), self.itemsize
 
     @staticmethod
     def descr_new_memoryview(space, w_subtype, w_object):
@@ -63,10 +109,45 @@
     descr_ne = _make_descr__cmp('ne')
 
     def as_str(self):
+        return ''.join(self.copy_buffer())
+
+    def copy_buffer(self):
         buf = self.buf
-        return buf.as_str()
+        n_bytes = buf.getlength()
+        data = []
+        self._copy_rec(0, data, 0)
+        return data
+
+    def _copy_rec(self, idim, data, off):
+        shapes = self.getshape()
+        shape = shapes[idim]
+        strides = self.getstrides()
+
+        if self.getndim()-1 == idim:
+            self._copy_base(data,off)
+            return
+
+        # TODO add a test that has at least 2 dims
+        for i in range(shape):
+            self._copy_rec(idim+1,data,off)
+            off += strides[idim]
+
+    def _copy_base(self, data, off):
+        shapes = self.getshape()
+        step = shapes[0]
+        strides = self.getstrides()
+        itemsize = self.getitemsize()
+        for i in range(step):
+            bytes = self.buf.getslice(off, off+itemsize, 1, itemsize)
+            data.append(bytes)
+            off += strides[0]
+            # do notcopy data if the sub buffer is out of bounds
+            if off >= self.buf.getlength():
+                break
 
     def getlength(self):
+        if self.length != -1:
+            return self.length // self.itemsize
         return self.buf.getlength() // self.itemsize
 
     def descr_tobytes(self, space):
@@ -75,43 +156,184 @@
 
     def descr_tolist(self, space):
         self._check_released(space)
+
+        buf = self.buf
+        dim = self.getndim()
+        fmt = self.getformat()
+        if dim == 0:
+            raise NotImplementedError
+        elif dim == 1:
+            itemsize = self.getitemsize()
+            return self._tolist(space, buf, buf.getlength() // itemsize, fmt)
+        else:
+            return self._tolist_rec(space, buf, 0, 0, fmt)
+
+    def _tolist(self, space, buf, count, fmt):
         # TODO: this probably isn't very fast
-        fmtiter = UnpackFormatIterator(space, self.buf)
-        fmtiter.interpret(self.format * self.getlength())
+        fmtiter = UnpackFormatIterator(space, buf)
+        fmtiter.interpret(fmt * count)
         return space.newlist(fmtiter.result_w)
 
+    def _tolist_rec(self, space, buf, start, idim, fmt):
+        strides = self.getstrides()
+        shape = self.getshape()
+        #
+        dim = idim+1
+        stride = strides[idim]
+        itemsize = self.getitemsize()
+        dimshape = shape[idim]
+        #
+        if dim >= self.getndim():
+            bytecount = (stride * dimshape)
+            count = bytecount // itemsize
+            return self._tolist(space, buf, count, fmt)
+        items = [None] * dimshape
+
+        for i in range(dimshape):
+            item = self._tolist_rec(space, SubBuffer(buf, start, stride), start, idim+1, fmt)
+            items[i] = item
+            start += stride
+
+        return space.newlist(items)
+
+
+    def _start_from_tuple(self, space, w_tuple):
+        from pypy.objspace.std.tupleobject import W_TupleObject
+        start = 0
+
+        view = self.buf
+        length = space.len_w(w_tuple)
+        dim = view.getndim()
+        dim = 0
+        assert isinstance(w_tuple, W_TupleObject)
+        while dim < length:
+            w_obj = w_tuple.getitem(space, dim)
+            index = w_obj.int_w(space)
+            start = self.lookup_dimension(space, start, dim, index)
+            dim += 1
+        return start
+
+    def lookup_dimension(self, space, start, dim, index):
+        view = self.buf
+        shape = view.getshape()
+        strides = view.getstrides()
+        nitems = shape[dim]
+        if index < 0:
+            index += nitems
+        if index < 0 or index >= nitems:
+            raise oefmt(space.w_IndexError,
+                "index out of bounds on dimension %d", dim+1)
+        start += strides[dim] * index
+        # TODO suboffsets?
+        return start
+
+    def _getitem_tuple_indexed(self, space, w_index):
+        view = self.buf
+
+        fmt = view.getformat() # TODO adjust format?
+
+        length = space.len_w(w_index)
+        ndim = view.getndim()
+        if length < ndim:
+            raise OperationError(space.w_NotImplementedError, \
+                    space.wrap("sub-views are not implemented"))
+
+        if length > ndim:
+            raise oefmt(space.w_TypeError, \
+                    "cannot index %d-dimension view with %d-element tuple",
+                    length, ndim)
+
+        start = self._start_from_tuple(space, w_index)
+
+        buf = SubBuffer(self.buf, start, view.getitemsize())
+        fmtiter = UnpackFormatIterator(space, buf)
+        fmtiter.interpret(fmt)
+        return fmtiter.result_w[0]
+
+
     def descr_getitem(self, space, w_index):
         self._check_released(space)
+
+        if space.isinstance_w(w_index, space.w_tuple):
+            return self._getitem_tuple_indexed(space, w_index)
+
         start, stop, step, size = space.decode_index4(w_index, self.getlength())
         # ^^^ for a non-slice index, this returns (index, 0, 0, 1)
-        itemsize = self.itemsize
+        itemsize = self.getitemsize()
+        start, stop, size = self._apply_itemsize(space, start, size, itemsize)
         if step == 0:  # index only
             if itemsize == 1:
                 ch = self.buf.getitem(start)
                 return space.newint(ord(ch))
             else:
                 # TODO: this probably isn't very fast
-                buf = SubBuffer(self.buf, start * itemsize, itemsize)
+                buf = SubBuffer(self.buf, start, itemsize)
                 fmtiter = UnpackFormatIterator(space, buf)
                 fmtiter.interpret(self.format)
                 return fmtiter.result_w[0]
         elif step == 1:
-            buf = SubBuffer(self.buf, start * itemsize, size * itemsize)
-            return W_MemoryView(buf, self.format, itemsize)
+            mv = W_MemoryView.copy(self)
+            mv.slice(start, stop, step, size)
+            mv._init_flags()
+            return mv
         else:
-            # XXX needs to return a W_MemoryView with a NonContiguousSubBuffer
-            # maybe?  Need to check the cpyext requirements for that
-            raise oefmt(space.w_NotImplementedError,
-                        "XXX extended slicing")
+            mv = W_MemoryView.copy(self)
+            mv.slice(start, stop, step, size)
+            mv.length = mv.bytecount_from_shape()
+            mv._init_flags()
+            return mv
+
+    def slice(self, start, stop, step, size):
+        # modifies the buffer, shape and stride to allow step to be > 1
+        # NOTE that start, stop & size are already byte offsets/count
+        # TODO subbuffer
+        strides = self.getstrides()[:]
+        shape = self.getshape()[:]
+        itemsize = self.getitemsize()
+        dim = 0
+        self.buf = SubBuffer(self.buf, strides[dim] * (start//itemsize), size*step)
+        shape[dim] = size
+        strides[dim] = strides[dim] * step
+        self.strides = strides
+        self.shape = shape
+
+    def bytecount_from_shape(self):
+        dim = self.getndim()
+        shape = self.getshape()
+        length = 1
+        for i in range(dim):
+            length *= shape[i]
+        return length * self.getitemsize()
+
+    @staticmethod
+    def copy(view, buf=None):
+        # TODO suboffsets
+        if buf == None:
+            buf = view.buf
+        return W_MemoryView(buf, view.getformat(), view.getitemsize(),
+                            view.getndim(), view.getshape()[:], view.getstrides()[:])
+
+    def _apply_itemsize(self, space, start, size, itemsize):
+        if itemsize > 1:
+            start *= itemsize
+            size *= itemsize
+
+        stop  = start + size
+        # start & stop are now byte offset, thus use self.buf.getlength()
+        if stop > self.buf.getlength():
+            raise oefmt(space.w_IndexError, 'index out of range')
+
+        return start, stop, size
 
     def descr_setitem(self, space, w_index, w_obj):
         self._check_released(space)
         if self.buf.readonly:
             raise oefmt(space.w_TypeError, "cannot modify read-only memory")
         if space.isinstance_w(w_index, space.w_tuple):
-            raise oefmt(space.w_NotImplementedError, "XXX tuple setitem")
+            raise oefmt(space.w_NotImplementedError, "")
         start, stop, step, size = space.decode_index4(w_index, self.getlength())
-        itemsize = self.itemsize
+        itemsize = self.getitemsize()
+        start, stop, size = self._apply_itemsize(space, start, size, itemsize)
         if step == 0:  # index only
             if itemsize == 1:
                 ch = getbytevalue(space, w_obj)
@@ -125,16 +347,41 @@
                     raise oefmt(space.w_TypeError,
                                 "memoryview: invalid type for format '%s'",
                                 self.format)
-                self.buf.setslice(start * itemsize, fmtiter.result.build())
+                self.buf.setslice(start, fmtiter.result.build())
         elif step == 1:
             value = space.buffer_w(w_obj, space.BUF_CONTIG_RO)
-            if value.getlength() != size * self.itemsize:
+            if value.getlength() != size:
                 raise oefmt(space.w_ValueError,
                             "cannot modify size of memoryview object")
-            self.buf.setslice(start * itemsize, value.as_str())
+            self.buf.setslice(start, value.as_str())
         else:
-            raise oefmt(space.w_NotImplementedError,
-                        "XXX extended slicing")
+            if self.getndim() != 1:
+                raise oefmt(space.w_NotImplementedError,
+                        "memoryview slice assignments are currently "
+                        "restricted to ndim = 1")
+            # this is the case of a one dimensional copy!
+            # NOTE we could maybe make use of copy_base, but currently we do not
+            itemsize = self.getitemsize()
+            data = []
+            src = space.buffer_w(w_obj, space.BUF_CONTIG_RO)
+            dst_strides = self.getstrides()
+            dim = 0
+            dst = SubBuffer(self.buf, start, size)
+            src_stride0 = dst_strides[dim]
+
+            off = 0
+            src_shape0 = size // itemsize
+            src_stride0 = src.getstrides()[0]
+            if isinstance(w_obj, W_MemoryView):
+                src_stride0 = w_obj.getstrides()[0]
+            for i in range(src_shape0):
+                data.append(src.getslice(off,off+itemsize,1,itemsize))
+                off += src_stride0
+            off = 0
+            dst_stride0 = self.getstrides()[0] * step
+            for dataslice in data:
+                dst.setslice(off, dataslice)
+                off += dst_stride0
 
     def descr_len(self, space):
         self._check_released(space)
@@ -142,11 +389,11 @@
 
     def w_get_format(self, space):
         self._check_released(space)
-        return space.wrap(self.format)
+        return space.wrap(self.getformat())
 
     def w_get_itemsize(self, space):
         self._check_released(space)
-        return space.newint(self.itemsize)
+        return space.wrap(self.itemsize)
 
     def w_get_ndim(self, space):
         self._check_released(space)
@@ -158,11 +405,11 @@
 
     def w_get_shape(self, space):
         self._check_released(space)
-        return space.newtuple([space.newint(self.getlength())])
+        return space.newtuple([space.wrap(x) for x in self.getshape()])
 
     def w_get_strides(self, space):
         self._check_released(space)
-        return space.newtuple([space.newint(self.itemsize)])
+        return space.newtuple([space.wrap(x) for x in self.getstrides()])
 
     def w_get_suboffsets(self, space):
         self._check_released(space)
@@ -240,20 +487,179 @@
             size = rffi.sizeof(rffi.VOIDP)
         return size
 
+    def _zero_in_shape(self):
+        # this method could be moved to the class Buffer
+        buf = self.buf
+        shape = buf.getshape()
+        for i in range(buf.getndim()):
+            if shape[i] == 0:
+                return True
+        return False
+
     def descr_cast(self, space, w_format, w_shape=None):
         self._check_released(space)
-        if not space.is_none(w_shape):
-            raise oefmt(space.w_NotImplementedError,
-                        "XXX cast() with a shape")
+
+        if not space.isinstance_w(w_format, space.w_unicode):
+            raise OperationError(space.w_TypeError, \
+                    space.wrap("memoryview: format argument must be a string"))
+
         fmt = space.str_w(w_format)
-        newitemsize = self.get_native_fmtchar(fmt)
-        return W_MemoryView(self.buf, fmt, newitemsize)
+        buf = self.buf
+        ndim = 1
+
+        if not memory_view_c_contiguous(space, self.flags):
+            raise OperationError(space.w_TypeError, \
+                    space.wrap("memoryview: casts are restricted" \
+                               " to C-contiguous views"))
+
+        if (w_shape or buf.getndim() != 1) and self._zero_in_shape():
+            raise OperationError(space.w_TypeError, \
+                    space.wrap("memoryview: cannot casts view with" \
+                               " zeros in shape or strides"))
+
+        itemsize = self.get_native_fmtchar(fmt)
+        if w_shape:
+            if not (space.isinstance_w(w_shape, space.w_list) or space.isinstance_w(w_shape, space.w_tuple)):
+                raise oefmt(space.w_TypeError, "expected list or tuple got %T", w_shape)
+            ndim = space.len_w(w_shape)
+            if ndim > MEMORYVIEW_MAX_DIM:
+                raise oefmt(space.w_ValueError, \
+                        "memoryview: number of dimensions must not exceed %d",
+                        ndim)
+            # yes access ndim as field
+            if self.ndim > 1 and buf.getndim() != 1:
+                raise OperationError(space.w_TypeError, \
+                    space.wrap("memoryview: cast must be 1D -> ND or ND -> 1D"))
+
+        mv = W_MemoryView(buf, self.format, self.itemsize)
+        origfmt = mv.getformat()
+        mv._cast_to_1D(space, origfmt, fmt, itemsize)
+        if w_shape:
+            fview = space.fixedview(w_shape)
+            shape = [space.int_w(w_obj) for w_obj in fview]
+            mv._cast_to_ND(space, shape, ndim)
+        return mv
+
+    def _init_flags(self):
+        buf = self.buf
+        ndim = buf.getndim()
+        flags = 0
+        if ndim == 0:
+            flags |= MEMORYVIEW_SCALAR | MEMORYVIEW_C | MEMORYVIEW_FORTRAN
+        if ndim == 1:
+            shape = buf.getshape()
+            strides = buf.getstrides()
+            if len(shape) > 0 and shape[0] == 1 and \
+               len(strides) > 0 and strides[0] == buf.getitemsize():
+                flags |= MEMORYVIEW_C | MEMORYVIEW_SCALAR
+        # TODO for now?
+        flags |= MEMORYVIEW_C
+        # TODO if buf.is_contiguous('C'):
+        # TODO     flags |= MEMORYVIEW_C
+        # TODO elif buf.is_contiguous('F'):
+        # TODO     flags |= MEMORYVIEW_FORTRAN
+
+        # TODO missing suboffsets
+
+        self.flags = flags
+
+    def _cast_to_1D(self, space, origfmt, fmt, itemsize):
+        buf = self.buf
+        if itemsize < 0:
+            raise oefmt(space.w_ValueError, "memoryview: destination" \
+                    " format must be a native single character format prefixed" \
+                    " with an optional '@'")
+
+        if self.get_native_fmtchar(origfmt) < 0 or \
+           (not is_byte_format(fmt) and not is_byte_format(origfmt)):
+            raise oefmt(space.w_TypeError,
+                    "memoryview: cannot cast between" \
+                    " two non-byte formats")
+
+        if buf.getlength() % itemsize != 0:
+            raise oefmt(space.w_TypeError,
+                    "memoryview: length is not a multiple of itemsize")
+
+        newfmt = self.get_native_fmtstr(fmt)
+        if not newfmt:
+            raise oefmt(space.w_RuntimeError,
+                    "memoryview: internal error")
+        self.format = newfmt
+        self.itemsize = itemsize
+        self.ndim = 1
+        self.shape = [buf.getlength() // itemsize]
+        self.strides = [itemsize]
+        # XX suboffsets
+
+        self._init_flags()
+
+    def get_native_fmtstr(self, fmt):
+        lenfmt = len(fmt)
+        nat = False
+        if lenfmt == 0:
+            return None
+        elif lenfmt == 1:
+            format = fmt[0] # fine!
+        elif lenfmt == 2:
+            if fmt[0] == '@':
+                nat = True
+                format = fmt[1]
+            else:
+                return None
+        else:
+            return None
+
+        chars = ['c','b','B','h','H','i','I','l','L','q',
+                 'Q','n','N','f','d','?','P']
+        for c in unrolling_iterable(chars):
+            if c == format:
+                if nat: return '@'+c
+                else: return c
+
+        return None
+
+    def _cast_to_ND(self, space, shape, ndim):
+        buf = self.buf
+
+        self.ndim = ndim
+        length = self.itemsize
+        if ndim == 0:
+            self.shape = []
+            self.strides = []
+        else:
+            self.shape = shape
+            for i in range(ndim):
+                length *= shape[i]
+            self._init_strides_from_shape()
+
+        if length != self.buf.getlength():
+            raise OperationError(space.w_TypeError,
+                    space.wrap("memoryview: product(shape) * itemsize != buffer size"))
+
+        self._init_flags()
+
+    def _init_strides_from_shape(self):
+        shape = self.getshape()
+        s = [0] * len(shape)
+        self.strides = s
+        ndim = self.getndim()
+        s[ndim-1] = self.itemsize
+        i = ndim-2
+        while i >= 0:
+            s[i] = s[i+1] * shape[i+1]
+            i -= 1
 
     def descr_hex(self, space):
         from pypy.objspace.std.bytearrayobject import _array_to_hexstring
         self._check_released(space)
         return _array_to_hexstring(space, self.buf)
 
+def is_byte_format(char):
+    return char == 'b' or char == 'B' or char == 'c'
+
+def memory_view_c_contiguous(space, flags):
+    return flags & (space.BUF_CONTIG_RO|MEMORYVIEW_C) != 0
+
 W_MemoryView.typedef = TypeDef(
     "memoryview",
     __doc__ = """\
diff --git a/pypy/objspace/std/test/test_memoryobject.py b/pypy/objspace/std/test/test_memoryobject.py
--- a/pypy/objspace/std/test/test_memoryobject.py
+++ b/pypy/objspace/std/test/test_memoryobject.py
@@ -1,3 +1,11 @@
+import py
+import struct
+from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.gateway import interp2app
+from pypy.interpreter.typedef import TypeDef
+from rpython.rlib.buffer import Buffer
+from pypy.conftest import option
+
 class AppTestMemoryView:
     spaceconfig = dict(usemodules=['array'])
 
@@ -38,7 +46,7 @@
         assert len(w) == 1
         assert list(w) == [97]
         v[::2] = b'ABC'
-        assert data == bytearray(b'AbBeCg')
+        assert data == bytearray(eval("b'AbBeCg'"))
 
     def test_memoryview_attrs(self):
         v = memoryview(b"a"*100)
@@ -217,4 +225,159 @@
         data = bytearray(b'abcdefghij')
         m3 = memoryview(data).cast('h')
         m3[1:5:2] = memoryview(b"xyXY").cast('h')
-        assert data == bytearray(b'abxyefXYij')
+        assert data == bytearray(eval("b'abxyefXYij'"))
+
+class MockBuffer(Buffer):
+    def __init__(self, space, w_arr, w_dim, w_fmt, \
+                 w_itemsize, w_strides, w_shape):
+        self.space = space
+        self.w_arr = w_arr
+        self.arr = []
+        self.ndim = space.int_w(w_dim)
+        self.format = space.str_w(w_fmt)
+        self.itemsize = space.int_w(w_itemsize)
+        self.strides = []
+        for w_i in w_strides.getitems_unroll():
+            self.strides.append(space.int_w(w_i))
+        self.shape = []
+        for w_i in w_shape.getitems_unroll():
+            self.shape.append(space.int_w(w_i))
+        self.readonly = True
+        self.shape.append(space.len_w(w_arr))
+        self.data = []
+        itemsize = 1
+        worklist = [(1,w_arr)]
+        while worklist:
+            dim, w_work = worklist.pop()
+            if space.isinstance_w(w_work, space.w_list):
+                for j, w_obj in enumerate(w_work.getitems_unroll()):
+                    worklist.insert(0, (dim+1, w_obj))
+                continue
+            byte = struct.pack(self.format, space.int_w(w_work))
+            for c in byte:
+                self.data.append(c)
+        self.data = ''.join(self.data)
+
+    def getformat(self):
+        return self.format
+
+    def getitem(self, index):
+        return self.data[index:index+1]
+
+    def getlength(self):
+        return len(self.data)
+
+    def getitemsize(self):
+        return self.itemsize
+
+    def getndim(self):
+        return self.ndim
+
+    def getstrides(self):
+        return self.strides
+
+    def getshape(self):
+        return self.shape
+
+    def is_contiguous(self, format):
+        return format == 'C'
+
+class W_MockArray(W_Root):
+    def __init__(self, w_list, w_dim, w_fmt, w_size, w_strides, w_shape):
+        self.w_list = w_list
+        self.w_dim = w_dim
+        self.w_fmt = w_fmt
+        self.w_size = w_size
+        self.w_strides = w_strides
+        self.w_shape = w_shape
+
+    @staticmethod
+    def descr_new(space, w_type, w_list, w_dim, w_fmt, \
+                         w_size, w_strides, w_shape):
+        return W_MockArray(w_list, w_dim, w_fmt, w_size, w_strides, w_shape)
+
+    def buffer_w(self, space, flags):
+        return MockBuffer(space, self.w_list, self.w_dim, self.w_fmt, \
+                          self.w_size, self.w_strides, self.w_shape)
+
+    def buffer_w_ex(self, space, flags):
+        return self.buffer_w(space, flags), space.str_w(self.w_fmt), space.int_w(self.w_size)
+
+W_MockArray.typedef = TypeDef("MockArray",
+    __new__ = interp2app(W_MockArray.descr_new),
+)
+
+class AppTestMemoryViewMockBuffer(object):
+    spaceconfig = dict(usemodules=[])
+    def setup_class(cls):
+        if option.runappdirect:
+            py.test.skip("Impossible to run on appdirect")
+        cls.w_MockArray = cls.space.gettypefor(W_MockArray)
+
+    def test_tuple_indexing(self):
+        content = self.MockArray([[0,1,2,3], [4,5,6,7], [8,9,10,11]],
+                                 dim=2, fmt='B', size=1,
+                                 strides=[4,1], shape=[3,4])
+        view = memoryview(content)
+        assert view[0,0] == 0
+        assert view[2,0] == 8
+        assert view[2,3] == 11
+        assert view[-1,-1] == 11
+        assert view[-3,-4] == 0
+
+        raises(IndexError, "view.__getitem__((2**63-1,0))")
+        raises(TypeError, "view.__getitem__((0, 0, 0))")
+
+    def test_tuple_indexing_int(self):
+        content = self.MockArray([ [[1],[2],[3]], [[4],[5],[6]] ],
+                                 dim=3, fmt='i', size=4,
+                                 strides=[12,4,4], shape=[2,3,1])
+        view = memoryview(content)
+        assert view[0,0,0] == 1
+        assert view[-1,2,0] == 6
+
+    def test_cast_non_byte(self):
+        empty = self.MockArray([], dim=1, fmt='i', size=4, strides=[1], shape=[1])
+        view = memoryview(empty)
+        raises(TypeError, "view.cast('l')")
+        try:
+            view.cast('l')
+            assert False, "i -> l not possible. buffer must be byte format"
+        except TypeError:
+            pass
+
+    def test_cast_empty(self):
+        empty = self.MockArray([], dim=1, fmt='b', size=1, strides=[1], shape=[1])
+        view = memoryview(empty)
+        cview = view.cast('i')
+        assert cview.tobytes() == b''
+        assert cview.tolist() == []
+        assert view.format == 'b'
+        assert cview.format == 'i'
+        #
+        assert cview.cast('b').cast('q').cast('b').tolist() == []
+        #
+        assert cview.format == 'i'
+        raises(TypeError, "cview.cast('i')")
+
+    def test_cast_with_shape(self):
+        empty = self.MockArray([1,0,2,0,3,0],
+                    dim=1, fmt='h', size=2,
+                    strides=[8], shape=[6])
+        view = memoryview(empty)
+        byteview = view.cast('b')
+        assert byteview.tolist() == [1,0,0,0,2,0,0,0,3,0,0,0]
+        i32view = byteview.cast('i', shape=[1,3])
+        assert i32view.format == 'i'
+        assert i32view.itemsize == 4
+        assert i32view.tolist() == [[1,2,3]]
+        i32view = byteview.cast('i', shape=(1,3))
+        assert i32view.tolist() == [[1,2,3]]
+
+    def test_cast_bytes(self):
+        bytes = b"\x02\x00\x03\x00\x04\x00" \
+                b"\x05\x00\x06\x00\x07\x00"
+        view = memoryview(bytes)
+        v = view.cast('h', shape=(3,2))
+        assert v.tolist() == [[2,3],[4,5],[6,7]]
+        raises(TypeError, "view.cast('h', shape=(3,3))")


More information about the pypy-commit mailing list