[pypy-commit] pypy py3k: hg merge py3k-memoryview

mjacob noreply at buildbot.pypy.org
Wed Feb 25 17:06:41 CET 2015


Author: Manuel Jacob <me at manueljacob.de>
Branch: py3k
Changeset: r76139:1091e0c8103b
Date: 2015-02-25 16:52 +0100
http://bitbucket.org/pypy/pypy/changeset/1091e0c8103b/

Log:	hg merge py3k-memoryview

	This fixes issue #1542.

diff --git a/lib-python/3/test/test_memoryview.py b/lib-python/3/test/test_memoryview.py
--- a/lib-python/3/test/test_memoryview.py
+++ b/lib-python/3/test/test_memoryview.py
@@ -50,7 +50,6 @@
         m = None
         self.assertEqual(getrefcount(b), oldrefcount)
 
-    @unittest.skip('XXX: https://bugs.pypy.org/issue1542')
     def test_getitem(self):
         for tp in self._types:
             self.check_getitem_with_type(tp)
@@ -75,7 +74,6 @@
         m = None
         self.assertEqual(getrefcount(b), oldrefcount)
 
-    @unittest.skip('XXX: https://bugs.pypy.org/issue1542')
     def test_setitem_writable(self):
         if not self.rw_type:
             return
@@ -128,7 +126,6 @@
             with self.assertRaises(TypeError):
                 del m[1:4]
 
-    @unittest.skip('XXX: https://bugs.pypy.org/issue1542')
     def test_tobytes(self):
         for tp in self._types:
             m = self._view(tp(self._source))
@@ -145,7 +142,6 @@
             l = m.tolist()
             self.assertEqual(l, list(b"abcdef"))
 
-    @unittest.skip('XXX: https://bugs.pypy.org/issue1542')
     def test_compare(self):
         # memoryviews can compare for equality with other objects
         # having the buffer interface.
@@ -193,7 +189,6 @@
         m = self.check_attributes_with_type(self.ro_type)
         self.assertEqual(m.readonly, True)
 
-    @unittest.skip('XXX: https://bugs.pypy.org/issue1542')
     def test_attributes_writable(self):
         if not self.rw_type:
             return
diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py
--- a/pypy/interpreter/baseobjspace.py
+++ b/pypy/interpreter/baseobjspace.py
@@ -25,6 +25,29 @@
                                       reds=['items', 'w_iterator'])
 
 
+# It seems there's no way to do it without top-level-functions.
+
+ at specialize.memo()
+def _does_override_buffer_w(type):
+    return type.buffer_w != W_Root.buffer_w
+
+ at specialize.memo()
+def _does_override_buffer_w_ex(type):
+    return type.buffer_w_ex != W_Root.buffer_w_ex
+
+ at specialize.argtype(0)
+def W_Root_buffer_w(self, space, flags):
+    if _does_override_buffer_w_ex(self.__class__):
+        return self.buffer_w_ex(space, flags)[0]
+    return self._buffer(space, flags).buffer_w(space, flags)
+
+ at specialize.argtype(0)
+def W_Root_buffer_w_ex(self, space, flags):
+    if _does_override_buffer_w(self.__class__):
+        return self.buffer_w(space, flags), 'B', 1
+    return self._buffer(space, flags).buffer_w_ex(space, flags)
+
+
 class W_Root(object):
     """This is the abstract root class of all wrapped objects that live
     in a 'normal' object space like StdObjSpace."""
@@ -195,11 +218,17 @@
         return None
 
     def buffer_w(self, space, flags):
+        return W_Root_buffer_w(self, space, flags)
+
+    def buffer_w_ex(self, space, flags):
+        return W_Root_buffer_w_ex(self, space, flags)
+
+    def _buffer(self, space, flags):
         w_impl = space.lookup(self, '__buffer__')
         if w_impl is not None:
             w_result = space.get_and_call_function(w_impl, self)
             if space.isinstance_w(w_result, space.w_memoryview):
-                return w_result.buffer_w(space, flags)
+                return w_result
         raise TypeError
 
     def bytes_w(self, space):
@@ -1368,6 +1397,15 @@
             raise oefmt(self.w_TypeError,
                         "'%T' does not support the buffer interface", w_obj)
 
+    def buffer_w_ex(self, w_obj, flags):
+        # New buffer interface, returns a buffer based on flags (PyObject_GetBuffer)
+        # Returns extra information: (buffer, typecode, itemsize)
+        try:
+            return w_obj.buffer_w_ex(self, flags)
+        except TypeError:
+            raise oefmt(self.w_TypeError,
+                        "'%T' does not support the buffer interface", w_obj)
+
     def readbuf_w(self, w_obj):
         # Old buffer interface, returns a readonly buffer (PyObject_AsReadBuffer)
         try:
diff --git a/pypy/module/_cffi_backend/cbuffer.py b/pypy/module/_cffi_backend/cbuffer.py
--- a/pypy/module/_cffi_backend/cbuffer.py
+++ b/pypy/module/_cffi_backend/cbuffer.py
@@ -3,7 +3,6 @@
 from pypy.interpreter.gateway import unwrap_spec, interp2app
 from pypy.interpreter.typedef import TypeDef, make_weakref_descr
 from pypy.module._cffi_backend import cdataobj, ctypeptr, ctypearray
-from pypy.objspace.std.memoryobject import _buffer_setitem
 
 from rpython.rlib.buffer import Buffer
 from rpython.rtyper.annlowlevel import llstr
@@ -41,8 +40,6 @@
         copy_string_to_raw(llstr(string), raw_cdata, 0, len(string))
 
 
-# Override the typedef to narrow down the interface that's exposed to app-level
-
 class MiniBuffer(W_Root):
     def __init__(self, buffer, keepalive=None):
         self.buffer = buffer
@@ -63,7 +60,18 @@
         return space.wrapbytes(res)
 
     def descr_setitem(self, space, w_index, w_newstring):
-        _buffer_setitem(space, self.buffer, w_index, w_newstring)
+        start, stop, step, size = space.decode_index4(w_index,
+                                                      self.buffer.getlength())
+        if step not in (0, 1):
+            raise oefmt(space.w_NotImplementedError, "")
+        value = space.buffer_w(w_newstring, space.BUF_CONTIG_RO)
+        if value.getlength() != size:
+            raise oefmt(space.w_ValueError,
+                        "cannot modify size of memoryview object")
+        if step == 0:  # index only
+            self.buffer.setitem(start, value.getitem(0))
+        elif step == 1:
+            self.buffer.setslice(start, value.as_str())
 
 
 MiniBuffer.typedef = TypeDef(
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
@@ -59,10 +59,12 @@
 
 
 def descr_itemsize(space, self):
+    assert isinstance(self, W_ArrayBase)
     return space.wrap(self.itemsize)
 
 
 def descr_typecode(space, self):
+    assert isinstance(self, W_ArrayBase)
     return space.wrap(self.typecode)
 
 arr_eq_driver = jit.JitDriver(name='array_eq_driver', greens=['comp_func'],
@@ -135,8 +137,8 @@
         self.len = 0
         self.allocated = 0
 
-    def buffer_w(self, space, flags):
-        return ArrayBuffer(self, False)
+    def buffer_w_ex(self, space, flags):
+        return ArrayBuffer(self, False), self.typecode, self.itemsize
 
     def descr_append(self, space, w_x):
         """ append(x)
diff --git a/pypy/module/array/test/test_array.py b/pypy/module/array/test/test_array.py
--- a/pypy/module/array/test/test_array.py
+++ b/pypy/module/array/test/test_array.py
@@ -411,7 +411,16 @@
     def test_buffer(self):
         a = self.array('h', b'Hi')
         buf = memoryview(a)
-        assert buf[1] == b'i'
+        assert buf[0] == b'Hi'
+        raises(IndexError, 'buf[1]')
+        assert buf.tobytes() == b'Hi'
+        #assert buf.tolist() == [26952]
+        assert buf.format == 'h'
+        assert buf.itemsize == 2
+        assert buf.shape == (1,)
+        assert buf.ndim == 1
+        assert buf.strides == (2,)
+        assert not buf.readonly
 
     def test_buffer_write(self):
         a = self.array('b', b'hello')
@@ -431,6 +440,11 @@
         a.fromstring(b'some extra text')
         assert buf[:] == b'foobarbazsome extra text'
 
+    def test_memview_multi_tobytes(self):
+        a = self.array('i', list(b"abcdef"))
+        m = memoryview(a)
+        assert m.tobytes() == a.tobytes()
+
     def test_list_methods(self):
         assert repr(self.array('i')) == "array('i')"
         assert repr(self.array('i', [1, 2, 3])) == "array('i', [1, 2, 3])"
diff --git a/pypy/module/cpyext/bytesobject.py b/pypy/module/cpyext/bytesobject.py
--- a/pypy/module/cpyext/bytesobject.py
+++ b/pypy/module/cpyext/bytesobject.py
@@ -255,5 +255,3 @@
         return w_obj
     buffer = space.buffer_w(w_obj, space.BUF_FULL_RO)
     return space.wrapbytes(buffer.as_str())
-    
-
diff --git a/pypy/module/micronumpy/ndarray.py b/pypy/module/micronumpy/ndarray.py
--- a/pypy/module/micronumpy/ndarray.py
+++ b/pypy/module/micronumpy/ndarray.py
@@ -633,6 +633,7 @@
             "ctypes not implemented yet"))
 
     def buffer_w(self, space, flags):
+        # XXX format isn't always 'B' probably
         return self.implementation.get_buffer(space, True)
 
     def descr_get_data(self, space):
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,39 +10,25 @@
 from pypy.interpreter.typedef import TypeDef, GetSetProperty
 
 
-def _buffer_setitem(space, buf, w_index, w_obj):
-    if buf.readonly:
-        raise oefmt(space.w_TypeError, "cannot modify read-only memory")
-    start, stop, step, size = space.decode_index4(w_index, buf.getlength())
-    if step not in (0, 1):
-        raise oefmt(space.w_NotImplementedError, "")
-    value = space.buffer_w(w_obj, space.BUF_CONTIG_RO)
-    if value.getlength() != size:
-        raise oefmt(space.w_ValueError,
-                    "cannot modify size of memoryview object")
-    if step == 0:  # index only
-        buf.setitem(start, value.getitem(0))
-    elif step == 1:
-        buf.setslice(start, value.as_str())
-
-
 class W_MemoryView(W_Root):
     """Implement the built-in 'memoryview' type as a wrapper around
     an interp-level buffer.
     """
 
-    def __init__(self, buf):
+    def __init__(self, buf, format='B', itemsize=1):
         assert isinstance(buf, Buffer)
         self.buf = buf
+        self.format = format
+        self.itemsize = itemsize
 
-    def buffer_w(self, space, flags):
+    def buffer_w_ex(self, space, flags):
         self._check_released(space)
         space.check_buf_flags(flags, self.buf.readonly)
-        return self.buf
+        return self.buf, self.format, self.itemsize
 
     @staticmethod
     def descr_new_memoryview(space, w_subtype, w_object):
-        return W_MemoryView(space.buffer_w(w_object, space.BUF_FULL_RO))
+        return W_MemoryView(*space.buffer_w_ex(w_object, space.BUF_FULL_RO))
 
     def _make_descr__cmp(name):
         def descr__cmp(self, space, w_other):
@@ -71,10 +57,12 @@
     descr_ne = _make_descr__cmp('ne')
 
     def as_str(self):
-        return self.buf.as_str()
+        buf = self.buf
+        n_bytes = buf.getlength()
+        return buf.getslice(0, n_bytes, 1, n_bytes)
 
     def getlength(self):
-        return self.buf.getlength()
+        return self.buf.getlength() // self.itemsize
 
     def descr_tobytes(self, space):
         self._check_released(space)
@@ -83,9 +71,12 @@
     def descr_tolist(self, space):
         self._check_released(space)
         buf = self.buf
+        if self.format != 'B':
+            raise oefmt(space.w_NotImplementedError,
+                        "tolist() only supports byte views")
         result = []
         for i in range(buf.getlength()):
-            result.append(space.wrap(ord(buf.getitem(i))))
+            result.append(space.wrap(ord(buf.getitem(i)[0])))
         return space.newlist(result)
 
     def descr_getitem(self, space, w_index):
@@ -94,26 +85,39 @@
         if step not in (0, 1):
             raise oefmt(space.w_NotImplementedError, "")
         if step == 0:  # index only
-            return space.wrapbytes(self.buf.getitem(start))
+            a = start * self.itemsize
+            b = a + self.itemsize
+            return space.wrapbytes(
+                ''.join([self.buf.getitem(i) for i in range(a, b)]))
         else:
-            buf = SubBuffer(self.buf, start, size)
-            return W_MemoryView(buf)
+            buf = SubBuffer(self.buf, start * self.itemsize,
+                            size * self.itemsize)
+            return W_MemoryView(buf, self.format, self.itemsize)
 
     def descr_setitem(self, space, w_index, w_obj):
         self._check_released(space)
-        _buffer_setitem(space, self.buf, w_index, w_obj)
+        if self.buf.readonly:
+            raise oefmt(space.w_TypeError, "cannot modify read-only memory")
+        start, stop, step, size = space.decode_index4(w_index, self.getlength())
+        if step not in (0, 1):
+            raise oefmt(space.w_NotImplementedError, "")
+        value = space.buffer_w(w_obj, space.BUF_CONTIG_RO)
+        if value.getlength() != size * self.itemsize:
+            raise oefmt(space.w_ValueError,
+                        "cannot modify size of memoryview object")
+        self.buf.setslice(start * self.itemsize, value.as_str())
 
     def descr_len(self, space):
         self._check_released(space)
-        return space.wrap(self.buf.getlength())
+        return space.wrap(self.getlength())
 
     def w_get_format(self, space):
         self._check_released(space)
-        return space.wrap("B")
+        return space.wrap(self.format)
 
     def w_get_itemsize(self, space):
         self._check_released(space)
-        return space.wrap(1)
+        return space.wrap(self.itemsize)
 
     def w_get_ndim(self, space):
         self._check_released(space)
@@ -129,7 +133,7 @@
 
     def w_get_strides(self, space):
         self._check_released(space)
-        return space.newtuple([space.wrap(1)])
+        return space.newtuple([space.wrap(self.itemsize)])
 
     def w_get_suboffsets(self, space):
         self._check_released(space)
@@ -147,8 +151,8 @@
 
     def _check_released(self, space):
         if self.buf is None:
-            raise OperationError(space.w_ValueError, space.wrap(
-                    "operation forbidden on released memoryview object"))
+            raise oefmt(space.w_ValueError,
+                        "operation forbidden on released memoryview object")
 
     def descr_enter(self, space):
         self._check_released(space)
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
@@ -128,8 +128,31 @@
         raises(ValueError, bytes, v)
         assert "released memory" in repr(v)
 
+    def test_int_array_buffer(self):
+        import array
+        m = memoryview(array.array('i', list(range(10))))
+        assert m.format == 'i'
+        assert m.itemsize == 4
+        assert len(m) == 10
+        assert len(m.tobytes()) == 40
+        assert m[0] == b'\x00\x00\x00\x00'
+        m[0] = b'\x00\x00\x00\x01'
+        assert m[0] == b'\x00\x00\x00\x01'
+
+    def test_int_array_slice(self):
+        import array
+        m = memoryview(array.array('i', list(range(10))))
+        slice = m[2:8]
+        assert slice.format == 'i'
+        assert slice.itemsize == 4
+        assert len(slice) == 6
+        assert len(slice.tobytes()) == 24
+        assert slice[0] in (b'\x00\x00\x00\x02', b'\x02\x00\x00\x00')
+        slice[0] = b'\x00\x00\x00\x01'
+        assert slice[0] == b'\x00\x00\x00\x01'
+        assert m[2] == b'\x00\x00\x00\x01'
+
     def test_pypy_raw_address_base(self):
         raises(ValueError, memoryview(b"foobar")._pypy_raw_address)
         e = raises(ValueError, memoryview(bytearray(b"foobar"))._pypy_raw_address)
         assert 'BytearrayBuffer' in str(e.value)
-


More information about the pypy-commit mailing list