[pypy-commit] pypy PyBuffer-backport: Backport memoryview changes
rlamy
pypy.commits at gmail.com
Tue May 2 14:47:02 EDT 2017
Author: Ronan Lamy <ronan.lamy at gmail.com>
Branch: PyBuffer-backport
Changeset: r91172:fea54844618f
Date: 2017-05-02 19:45 +0100
http://bitbucket.org/pypy/pypy/changeset/fea54844618f/
Log: Backport memoryview changes
diff --git a/pypy/interpreter/buffer.py b/pypy/interpreter/buffer.py
new file mode 100644
--- /dev/null
+++ b/pypy/interpreter/buffer.py
@@ -0,0 +1,321 @@
+from rpython.rlib.rstruct.error import StructError
+from rpython.rlib.buffer import StringBuffer, SubBuffer
+
+from pypy.interpreter.error import oefmt
+
+class BufferInterfaceNotFound(Exception):
+ pass
+
+
+class BufferView(object):
+ """Abstract base class for buffers."""
+ _attrs_ = ['readonly']
+ _immutable_ = True
+
+ def getlength(self):
+ """Returns the size in bytes (even if getitemsize() > 1)."""
+ raise NotImplementedError
+
+ def as_str(self):
+ "Returns an interp-level string with the whole content of the buffer."
+ return ''.join(self._copy_buffer())
+
+ def getbytes(self, start, size):
+ """Return `size` bytes starting at byte offset `start`.
+
+ This is a low-level operation, it is up to the caller to ensure that
+ the data requested actually correspond to items accessible from the
+ BufferView.
+ Note that `start` may be negative, e.g. if the buffer is reversed.
+ """
+ raise NotImplementedError
+
+ def setbytes(self, start, string):
+ raise NotImplementedError
+
+ def get_raw_address(self):
+ raise ValueError("no raw buffer")
+
+ def as_readbuf(self):
+ # Inefficient. May be overridden.
+ return StringBuffer(self.as_str())
+
+ def as_writebuf(self):
+ """Return a writable Buffer sharing the same data as `self`."""
+ raise BufferInterfaceNotFound
+
+ def getformat(self):
+ raise NotImplementedError
+
+ def getitemsize(self):
+ raise NotImplementedError
+
+ def getndim(self):
+ raise NotImplementedError
+
+ def getshape(self):
+ raise NotImplementedError
+
+ def getstrides(self):
+ raise NotImplementedError
+
+ def releasebuffer(self):
+ pass
+
+ def value_from_bytes(self, space, s):
+ from pypy.module.struct.formatiterator import UnpackFormatIterator
+ buf = StringBuffer(s)
+ fmtiter = UnpackFormatIterator(space, buf)
+ fmtiter.interpret(self.getformat())
+ return fmtiter.result_w[0]
+
+ def bytes_from_value(self, space, w_val):
+ from pypy.module.struct.formatiterator import PackFormatIterator
+ itemsize = self.getitemsize()
+ fmtiter = PackFormatIterator(space, [w_val], itemsize)
+ try:
+ fmtiter.interpret(self.getformat())
+ except StructError as e:
+ raise oefmt(space.w_TypeError,
+ "memoryview: invalid type for format '%s'",
+ self.getformat())
+ return fmtiter.result.build()
+
+ def _copy_buffer(self):
+ if self.getndim() == 0:
+ itemsize = self.getitemsize()
+ return [self.getbytes(0, itemsize)]
+ 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
+
+ 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()
+ bytesize = self.getlength()
+ copiedbytes = 0
+ for i in range(step):
+ bytes = self.getbytes(off, itemsize)
+ data.append(bytes)
+ copiedbytes += len(bytes)
+ off += strides[0]
+ # do notcopy data if the sub buffer is out of bounds
+ if copiedbytes >= bytesize:
+ break
+
+ def get_offset(self, space, dim, index):
+ "Convert index at dimension `dim` into a byte offset"
+ shape = self.getshape()
+ 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)
+ # TODO suboffsets?
+ strides = self.getstrides()
+ return strides[dim] * index
+
+ def w_getitem(self, space, idx):
+ offset = self.get_offset(space, 0, idx)
+ itemsize = self.getitemsize()
+ # TODO: this probably isn't very fast
+ data = self.getbytes(offset, itemsize)
+ return self.value_from_bytes(space, data)
+
+ def new_slice(self, start, step, slicelength):
+ return BufferSlice(self, start, step, slicelength)
+
+ def setitem_w(self, space, idx, w_obj):
+ offset = self.get_offset(space, 0, idx)
+ # TODO: this probably isn't very fast
+ byteval = self.bytes_from_value(space, w_obj)
+ self.setbytes(offset, byteval)
+
+ def w_tolist(self, space):
+ dim = self.getndim()
+ if dim == 0:
+ raise NotImplementedError
+ elif dim == 1:
+ n = self.getshape()[0]
+ values_w = [space.ord(self.w_getitem(space, i)) for i in range(n)]
+ return space.newlist(values_w)
+ else:
+ return self._tolist_rec(space, 0, 0)
+
+ def _tolist_rec(self, space, start, idim):
+ 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)
+ values_w = [
+ self.value_from_bytes(space, self.getbytes(pos, itemsize))
+ for pos in range(start, start + bytecount, stride)]
+ return space.newlist(values_w)
+
+ items = [None] * dimshape
+ for i in range(dimshape):
+ item = self._tolist_rec(space, start, idim + 1)
+ items[i] = item
+ start += stride
+
+ return space.newlist(items)
+
+ def wrap(self, space):
+ return space.newmemoryview(self)
+
+
+class SimpleView(BufferView):
+ _attrs_ = ['readonly', 'data']
+ _immutable_ = True
+
+ def __init__(self, data):
+ self.data = data
+ self.readonly = self.data.readonly
+
+ def getlength(self):
+ return self.data.getlength()
+
+ def as_str(self):
+ return self.data.as_str()
+
+ def getbytes(self, start, size):
+ return self.data[start:start + size]
+
+ def setbytes(self, offset, s):
+ self.data.setslice(offset, s)
+
+ def get_raw_address(self):
+ return self.data.get_raw_address()
+
+ def as_readbuf(self):
+ return self.data
+
+ def as_writebuf(self):
+ assert not self.data.readonly
+ return self.data
+
+ def getformat(self):
+ return 'B'
+
+ def getitemsize(self):
+ return 1
+
+ def getndim(self):
+ return 1
+
+ def getshape(self):
+ return [self.getlength()]
+
+ def getstrides(self):
+ return [1]
+
+ def get_offset(self, space, dim, index):
+ "Convert index at dimension `dim` into a byte offset"
+ assert dim == 0
+ nitems = self.getlength()
+ 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)
+ return index
+
+ def w_getitem(self, space, idx):
+ idx = self.get_offset(space, 0, idx)
+ ch = self.data[idx]
+ return space.newbytes(ch)
+
+ def new_slice(self, start, step, slicelength):
+ if step == 1:
+ return SimpleView(SubBuffer(self.data, start, slicelength))
+ else:
+ return BufferSlice(self, start, step, slicelength)
+
+ def setitem_w(self, space, idx, w_obj):
+ idx = self.get_offset(space, 0, idx)
+ self.data[idx] = space.byte_w(w_obj)
+
+
+class BufferSlice(BufferView):
+ _immutable_ = True
+ _attrs_ = ['parent', 'readonly', 'shape', 'strides', 'start', 'step']
+
+ def __init__(self, parent, start, step, length):
+ self.parent = parent
+ self.readonly = self.parent.readonly
+ self.strides = parent.getstrides()[:]
+ self.start = start
+ self.step = step
+ self.strides[0] *= step
+ self.shape = parent.getshape()[:]
+ self.shape[0] = length
+
+ def getlength(self):
+ return self.shape[0] * self.getitemsize()
+
+ def getbytes(self, start, size):
+ offset = self.start * self.parent.getstrides()[0]
+ return self.parent.getbytes(offset + start, size)
+
+ def setbytes(self, start, string):
+ if len(string) == 0:
+ return # otherwise, adding self.offset might make 'start'
+ # out of bounds
+ offset = self.start * self.parent.getstrides()[0]
+ self.parent.setbytes(offset + start, string)
+
+ def get_raw_address(self):
+ from rpython.rtyper.lltypesystem import rffi
+ offset = self.start * self.parent.getstrides()[0]
+ return rffi.ptradd(self.parent.get_raw_address(), offset)
+
+ def getformat(self):
+ return self.parent.getformat()
+
+ def getitemsize(self):
+ return self.parent.getitemsize()
+
+ def getndim(self):
+ return self.parent.getndim()
+
+ def getshape(self):
+ return self.shape
+
+ def getstrides(self):
+ return self.strides
+
+ def parent_index(self, idx):
+ return self.start + self.step * idx
+
+ def w_getitem(self, space, idx):
+ return self.parent.w_getitem(space, self.parent_index(idx))
+
+ def new_slice(self, start, step, slicelength):
+ real_start = start + self.start
+ real_step = self.step * step
+ return BufferSlice(self.parent, real_start, real_step, slicelength)
+
+ def setitem_w(self, space, idx, w_obj):
+ return self.parent.setitem_w(space, self.parent_index(idx), w_obj)
diff --git a/pypy/objspace/std/bufferobject.py b/pypy/objspace/std/bufferobject.py
--- a/pypy/objspace/std/bufferobject.py
+++ b/pypy/objspace/std/bufferobject.py
@@ -5,6 +5,7 @@
from rpython.rlib.objectmodel import compute_hash
from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.buffer import SimpleView
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.gateway import interp2app, unwrap_spec
from pypy.interpreter.typedef import TypeDef
@@ -19,7 +20,7 @@
def buffer_w(self, space, flags):
space.check_buf_flags(flags, self.buf.readonly)
- return self.buf
+ return SimpleView(self.buf)
def readbuf_w(self, space):
return self.buf
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
@@ -8,6 +8,7 @@
from rpython.rlib.rstring import StringBuilder, replace
from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.buffer import SimpleView
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.gateway import (
WrappedDefault, interp2app, interpindirect2app, unwrap_spec)
@@ -455,7 +456,7 @@
def buffer_w(self, space, flags):
space.check_buf_flags(flags, True)
- return StringBuffer(self._value)
+ return SimpleView(StringBuffer(self._value))
def readbuf_w(self, space):
return StringBuffer(self._value)
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
@@ -3,48 +3,78 @@
"""
import operator
-from rpython.rlib.buffer import Buffer, SubBuffer
+from rpython.rlib.buffer import SubBuffer
from pypy.interpreter.baseobjspace import W_Root
+from pypy.interpreter.buffer import BufferView
from pypy.interpreter.error import OperationError, oefmt
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.typedef import TypeDef, GetSetProperty
+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.
"""
- _attrs_ = ['buf']
- def __init__(self, buf):
- assert isinstance(buf, Buffer)
- self.buf = buf
+ def __init__(self, view):
+ assert isinstance(view, BufferView)
+ self.view = view
+ self._hash = -1
+ self.flags = 0
+ self._init_flags()
+
+ def getndim(self):
+ return self.view.getndim()
+
+ def getshape(self):
+ return self.view.getshape()
+
+ def getstrides(self):
+ return self.view.getstrides()
+
+ def getitemsize(self):
+ return self.view.getitemsize()
+
+ def getformat(self):
+ return self.view.getformat()
def buffer_w(self, space, flags):
- space.check_buf_flags(flags, self.buf.readonly)
- return self.buf
+ self._check_released(space)
+ space.check_buf_flags(flags, self.view.readonly)
+ return self.view
@staticmethod
def descr_new_memoryview(space, w_subtype, w_object):
- return W_MemoryView(space.buffer_w(w_object, space.BUF_FULL_RO))
+ if isinstance(w_object, W_MemoryView):
+ w_object._check_released(space)
+ return W_MemoryView.copy(w_object)
+ view = space.buffer_w(w_object, space.BUF_FULL_RO)
+ return view.wrap(space)
def _make_descr__cmp(name):
def descr__cmp(self, space, w_other):
if isinstance(w_other, W_MemoryView):
# xxx not the most efficient implementation
- str1 = self.as_str()
- str2 = w_other.as_str()
+ str1 = self.view.as_str()
+ str2 = w_other.view.as_str()
return space.newbool(getattr(operator, name)(str1, str2))
try:
- buf = space.buffer_w(w_other, space.BUF_CONTIG_RO)
+ view = space.buffer_w(w_other, space.BUF_CONTIG_RO)
except OperationError as e:
if not e.match(space, space.w_TypeError):
raise
return space.w_NotImplemented
else:
- str1 = self.as_str()
- str2 = buf.as_str()
+ str1 = self.view.as_str()
+ str2 = view.as_str()
return space.newbool(getattr(operator, name)(str1, str2))
descr__cmp.func_name = name
return descr__cmp
@@ -60,101 +90,149 @@
return self.buf.as_str()
def getlength(self):
- return self.buf.getlength()
+ return self.view.getlength()
def descr_tobytes(self, space):
- return space.newbytes(self.as_str())
+ self._check_released(space)
+ return space.newbytes(self.view.as_str())
def descr_tolist(self, space):
- buf = self.buf
- result = []
- for i in range(buf.getlength()):
- result.append(space.newint(ord(buf.getitem(i))))
- return space.newlist(result)
+ self._check_released(space)
+ return self.view.w_tolist(space)
+
+ def _decode_index(self, space, w_index, is_slice):
+ shape = self.getshape()
+ if len(shape) == 0:
+ count = 1
+ else:
+ count = shape[0]
+ return space.decode_index4(w_index, count)
def descr_getitem(self, space, w_index):
- start, stop, step, size = space.decode_index4(w_index, self.getlength())
- itemsize = self.buf.getitemsize()
- if itemsize > 1:
- start *= itemsize
- size *= itemsize
- stop = start + size
- if step == 0:
- step = 1
- if stop > self.getlength():
- raise oefmt(space.w_IndexError, 'index out of range')
+ is_slice = space.isinstance_w(w_index, space.w_slice)
+ start, stop, step, slicelength = self._decode_index(space, w_index, is_slice)
+ # ^^^ for a non-slice index, this returns (index, 0, 0, 1)
if step not in (0, 1):
raise oefmt(space.w_NotImplementedError, "")
if step == 0: # index only
- return space.newbytes(self.buf.getitem(start))
+ dim = self.getndim()
+ if dim == 0:
+ raise oefmt(space.w_TypeError, "invalid indexing of 0-dim memory")
+ elif dim == 1:
+ return self.view.w_getitem(space, start)
+ else:
+ raise oefmt(space.w_NotImplementedError, "multi-dimensional sub-views are not implemented")
+ elif is_slice:
+ return self.view.new_slice(start, step, slicelength).wrap(space)
+ # multi index is handled at the top of this function
else:
- buf = SubBuffer(self.buf, start, size)
- return W_MemoryView(buf)
+ raise TypeError("memoryview: invalid slice key")
def descr_setitem(self, space, w_index, w_obj):
- if self.buf.readonly:
+ self._check_released(space)
+ if self.view.readonly:
raise oefmt(space.w_TypeError, "cannot modify read-only memory")
start, stop, step, size = space.decode_index4(w_index, self.getlength())
- itemsize = self.buf.getitemsize()
- if itemsize > 1:
- start *= itemsize
- size *= itemsize
- stop = start + size
- if step == 0:
- step = 1
- if stop > self.getlength():
- raise oefmt(space.w_IndexError, 'index out of range')
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")
+ is_slice = space.isinstance_w(w_index, space.w_slice)
+ start, stop, step, slicelength = self._decode_index(space, w_index, is_slice)
+ itemsize = self.getitemsize()
if step == 0: # index only
- self.buf.setitem(start, value.getitem(0))
+ self.view.setitem_w(space, start, w_obj)
elif step == 1:
- self.buf.setslice(start, value.as_str())
+ value = space.buffer_w(w_obj, space.BUF_CONTIG_RO)
+ if value.getlength() != slicelength * itemsize:
+ raise oefmt(space.w_ValueError,
+ "cannot modify size of memoryview object")
+ self.view.setbytes(start * itemsize, value.as_str())
def descr_len(self, space):
- return space.newint(self.buf.getlength() / self.buf.getitemsize())
+ self._check_released(space)
+ dim = self.getndim()
+ if dim == 0:
+ return space.newint(1)
+ shape = self.getshape()
+ return space.newint(shape[0])
def w_get_format(self, space):
- return space.newtext(self.buf.getformat())
+ self._check_released(space)
+ return space.newtext(self.getformat())
def w_get_itemsize(self, space):
- return space.newint(self.buf.getitemsize())
+ self._check_released(space)
+ return space.newint(self.getitemsize())
def w_get_ndim(self, space):
- return space.newint(self.buf.getndim())
+ self._check_released(space)
+ return space.newint(self.getndim())
def w_is_readonly(self, space):
- return space.newbool(bool(self.buf.readonly))
+ self._check_released(space)
+ return space.newbool(bool(self.view.readonly))
def w_get_shape(self, space):
- if self.buf.getndim() == 0:
+ self._check_released(space)
+ if self.view.getndim() == 0:
return space.w_None
- return space.newtuple([space.newint(x) for x in self.buf.getshape()])
+ return space.newtuple([space.newint(x) for x in self.getshape()])
def w_get_strides(self, space):
- if self.buf.getndim() == 0:
+ self._check_released(space)
+ if self.view.getndim() == 0:
return space.w_None
- return space.newtuple([space.newint(x) for x in self.buf.getstrides()])
+ return space.newtuple([space.newint(x) for x in self.getstrides()])
def w_get_suboffsets(self, space):
+ self._check_released(space)
# I've never seen anyone filling this field
return space.w_None
+ def _check_released(self, space):
+ if self.view is None:
+ raise oefmt(space.w_ValueError,
+ "operation forbidden on released memoryview object")
+
def descr_pypy_raw_address(self, space):
from rpython.rtyper.lltypesystem import lltype, rffi
try:
- ptr = self.buf.get_raw_address()
+ ptr = self.view.get_raw_address()
except ValueError:
- # report the error using the RPython-level internal repr of self.buf
+ # report the error using the RPython-level internal repr of
+ # self.view
msg = ("cannot find the underlying address of buffer that "
- "is internally %r" % (self.buf,))
+ "is internally %r" % (self.view,))
raise OperationError(space.w_ValueError, space.newtext(msg))
return space.newint(rffi.cast(lltype.Signed, ptr))
+ def _init_flags(self):
+ ndim = self.getndim()
+ flags = 0
+ if ndim == 0:
+ flags |= MEMORYVIEW_SCALAR | MEMORYVIEW_C | MEMORYVIEW_FORTRAN
+ elif ndim == 1:
+ shape = self.getshape()
+ strides = self.getstrides()
+ if shape[0] == 1 or strides[0] == self.getitemsize():
+ flags |= MEMORYVIEW_C | MEMORYVIEW_FORTRAN
+ else:
+ ndim = self.getndim()
+ shape = self.getshape()
+ strides = self.getstrides()
+ itemsize = self.getitemsize()
+ if PyBuffer_isContiguous(None, ndim, shape, strides,
+ itemsize, 'C'):
+ flags |= MEMORYVIEW_C
+ if PyBuffer_isContiguous(None, ndim, shape, strides,
+ itemsize, 'F'):
+ flags |= MEMORYVIEW_FORTRAN
+
+ if False: # TODO missing suboffsets
+ flags |= MEMORYVIEW_PIL
+ flags &= ~(MEMORYVIEW_C|MEMORYVIEW_FORTRAN)
+
+ self.flags = flags
+
W_MemoryView.typedef = TypeDef(
"memoryview",
__doc__ = """\
@@ -182,3 +260,49 @@
_pypy_raw_address = interp2app(W_MemoryView.descr_pypy_raw_address),
)
W_MemoryView.typedef.acceptable_as_base_class = False
+
+def _IsFortranContiguous(ndim, shape, strides, itemsize):
+ if ndim == 0:
+ return 1
+ if not strides:
+ return ndim == 1
+ sd = itemsize
+ if ndim == 1:
+ return shape[0] == 1 or sd == strides[0]
+ for i in range(ndim):
+ dim = shape[i]
+ if dim == 0:
+ return 1
+ if strides[i] != sd:
+ return 0
+ sd *= dim
+ return 1
+
+def _IsCContiguous(ndim, shape, strides, itemsize):
+ if ndim == 0:
+ return 1
+ if not strides:
+ return ndim == 1
+ sd = itemsize
+ if ndim == 1:
+ return shape[0] == 1 or sd == strides[0]
+ for i in range(ndim - 1, -1, -1):
+ dim = shape[i]
+ if dim == 0:
+ return 1
+ if strides[i] != sd:
+ return 0
+ sd *= dim
+ return 1
+
+def PyBuffer_isContiguous(suboffsets, ndim, shape, strides, itemsize, fort):
+ if suboffsets:
+ return 0
+ if (fort == 'C'):
+ return _IsCContiguous(ndim, shape, strides, itemsize)
+ elif (fort == 'F'):
+ return _IsFortranContiguous(ndim, shape, strides, itemsize)
+ elif (fort == 'A'):
+ return (_IsCContiguous(ndim, shape, strides, itemsize) or
+ _IsFortranContiguous(ndim, shape, strides, itemsize))
+ return 0
\ No newline at end of file
diff --git a/pypy/objspace/std/objspace.py b/pypy/objspace/std/objspace.py
--- a/pypy/objspace/std/objspace.py
+++ b/pypy/objspace/std/objspace.py
@@ -341,6 +341,9 @@
ret = W_Buffer(obj)
return ret
+ def newmemoryview(self, view):
+ return W_MemoryView(view)
+
def newbytes(self, s):
assert isinstance(s, str)
return W_BytesObject(s)
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,13 +1,13 @@
class AppTestMemoryView:
def test_basic(self):
- v = memoryview("abc")
- assert v.tobytes() == "abc"
+ v = memoryview(b"abc")
+ assert v.tobytes() == b"abc"
assert len(v) == 3
assert list(v) == ['a', 'b', 'c']
assert v.tolist() == [97, 98, 99]
assert v[1] == "b"
assert v[-1] == "c"
- exc = raises(TypeError, "v[1] = 'x'")
+ exc = raises(TypeError, "v[1] = b'x'")
assert str(exc.value) == "cannot modify read-only memory"
assert v.readonly is True
w = v[1:234]
@@ -17,7 +17,7 @@
assert str(exc.value) == ""
def test_rw(self):
- data = bytearray('abcefg')
+ data = bytearray(b'abcefg')
v = memoryview(data)
assert v.readonly is False
v[0] = 'z'
@@ -32,7 +32,7 @@
assert str(exc.value) == ""
def test_memoryview_attrs(self):
- v = memoryview("a"*100)
+ v = memoryview(b"a"*100)
assert v.format == "B"
assert v.itemsize == 1
assert v.shape == (100,)
@@ -40,22 +40,25 @@
assert v.strides == (1,)
def test_suboffsets(self):
- v = memoryview("a"*100)
+ v = memoryview(b"a"*100)
assert v.suboffsets == None
v = memoryview(buffer("a"*100, 2))
assert v.shape == (98,)
assert v.suboffsets == None
def test_compare(self):
- assert memoryview("abc") == "abc"
- assert memoryview("abc") == bytearray("abc")
- assert memoryview("abc") != 3
+ assert memoryview(b"abc") == b"abc"
+ assert memoryview(b"abc") == bytearray(b"abc")
+ assert memoryview(b"abc") != 3
assert not memoryview("abc") == u"abc"
assert memoryview("abc") != u"abc"
assert not u"abc" == memoryview("abc")
assert u"abc" != memoryview("abc")
def test_pypy_raw_address_base(self):
+ import sys
+ if '__pypy__' not in sys.modules:
+ skip('PyPy-only test')
a = memoryview(b"foobar")._pypy_raw_address()
assert a != 0
b = memoryview(bytearray(b"foobar"))._pypy_raw_address()
diff --git a/rpython/rlib/buffer.py b/rpython/rlib/buffer.py
--- a/rpython/rlib/buffer.py
+++ b/rpython/rlib/buffer.py
@@ -12,7 +12,7 @@
_immutable_ = True
def getlength(self):
- """Returns the size in bytes (even if getitemsize() > 1)."""
+ """Return the size in bytes."""
raise NotImplementedError
def __len__(self):
More information about the pypy-commit
mailing list