[pypy-commit] pypy memoryview-attributes: add test of getitem, fix CPyBuffer object so they pass. Add __buffer__ slot to str.
mattip
pypy.commits at gmail.com
Fri Aug 19 18:27:44 EDT 2016
Author: Matti Picus <matti.picus at gmail.com>
Branch: memoryview-attributes
Changeset: r86333:0a85b1b3bb7f
Date: 2016-08-20 10:26 +1200
http://bitbucket.org/pypy/pypy/changeset/0a85b1b3bb7f/
Log: add test of getitem, fix CPyBuffer object so they pass. Add
__buffer__ slot to str.
diff --git a/pypy/module/cpyext/buffer.py b/pypy/module/cpyext/buffer.py
--- a/pypy/module/cpyext/buffer.py
+++ b/pypy/module/cpyext/buffer.py
@@ -9,7 +9,7 @@
"""Return 1 if obj supports the buffer interface otherwise 0."""
as_buffer = pyobj.c_ob_type.c_tp_as_buffer
flags = pyobj.c_ob_type.c_tp_flags
- if (flags & Py_TPFLAGS_HAVE_NEWBUFFER and as_buffer.bf_getbuffer):
+ if (flags & Py_TPFLAGS_HAVE_NEWBUFFER and as_buffer.c_bf_getbuffer):
return 1
return 0
diff --git a/pypy/module/cpyext/slotdefs.py b/pypy/module/cpyext/slotdefs.py
--- a/pypy/module/cpyext/slotdefs.py
+++ b/pypy/module/cpyext/slotdefs.py
@@ -5,7 +5,7 @@
from rpython.rtyper.lltypesystem import rffi, lltype
from pypy.module.cpyext.api import (
cpython_api, generic_cpy_call, PyObject, Py_ssize_t, Py_TPFLAGS_CHECKTYPES,
- mangle_name, pypy_decl, Py_buffer)
+ mangle_name, pypy_decl, Py_buffer, Py_bufferP)
from pypy.module.cpyext.typeobjectdefs import (
unaryfunc, wrapperfunc, ternaryfunc, PyTypeObjectPtr, binaryfunc, ternaryfunc,
getattrfunc, getattrofunc, setattrofunc, lenfunc, ssizeargfunc, inquiry,
@@ -301,24 +301,42 @@
# Similar to Py_buffer
_immutable_ = True
- def __init__(self, ptr, size, w_obj):
- # XXX leak of ptr
+ def __init__(self, ptr, size, w_obj, pybuf=None):
self.ptr = ptr
self.size = size
self.w_obj = w_obj # kept alive
- self.readonly = True
+ if pybuf is None:
+ self.format = 'B'
+ self.shape = [size]
+ self.strides = [1]
+ self.ndim = 1
+ self.itemsize = 1
+ self.readonly = True
+ else:
+ self.format = rffi.charp2str(pybuf.c_format)
+ self.ndim = pybuf.c_ndim
+ self.shape = [pybuf.c_shape[i] for i in range(self.ndim)]
+ self.strides = [pybuf.c_strides[i] for i in range(self.ndim)]
+ self.itemsize = pybuf.c_itemsize
+ self.readonly = pybuf.c_readonly
def getlength(self):
return self.size
def getitem(self, index):
- return self.ptr[index]
+ start = index * self.itemsize
+ stop = (index + 1) * self.itemsize
+ return ''.join([self.ptr[i] for i in range(start, stop)])
def get_raw_address(self):
return rffi.cast(rffi.CCHARP, self.ptr)
def getformat(self):
- return rffi.charp2str(self.ptr.c_format)
+ return self.format
+
+ def getshape(self):
+ return self.shape
+
def wrap_getreadbuffer(space, w_self, w_args, func):
func_target = rffi.cast(readbufferproc, func)
@@ -332,13 +350,15 @@
def wrap_getbuffer(space, w_self, w_args, func):
func_target = rffi.cast(getbufferproc, func)
# XXX leak
- pybuf = lltype.malloc(Py_buffer, flavor='raw', track_allocation=False)
- # XXX flags are not in w_args?
- flags = rffi.cast(rffi.INT_real,0)
- size = generic_cpy_call(space, func_target, w_self, pybuf, flags)
- if size < 0:
- space.fromcache(State).check_and_raise_exception(always=True)
- return space.newbuffer(CPyBuffer(pybuf, size, w_self))
+ with lltype.scoped_alloc(Py_buffer) as pybuf:
+ # XXX flags are not in w_args?
+ flags = rffi.cast(rffi.INT_real,0)
+ size = generic_cpy_call(space, func_target, w_self, pybuf, flags)
+ if size < 0:
+ space.fromcache(State).check_and_raise_exception(always=True)
+ ptr = pybuf.c_buf
+ size = pybuf.c_len
+ return space.newbuffer(CPyBuffer(ptr, size, w_self, pybuf))
def get_richcmp_func(OP_CONST):
def inner(space, w_self, w_args, func):
@@ -504,8 +524,6 @@
def slot_tp_getattro(space, w_self, w_name):
return space.call_function(getattr_fn, w_self, w_name)
api_func = slot_tp_getattro.api_func
- elif name == 'tp_as_buffer':
- raise NotImplementedError
elif name == 'tp_call':
call_fn = w_type.getdictvalue(space, '__call__')
if call_fn is None:
@@ -561,6 +579,19 @@
w_stararg=w_args, w_starstararg=w_kwds)
return space.call_args(space.get(new_fn, w_self), args)
api_func = slot_tp_new.api_func
+ elif name == 'tp_as_buffer.c_bf_getbuffer':
+ buf_fn = w_type.getdictvalue(space, '__buffer__')
+ if buf_fn is None:
+ return
+ @cpython_api([PyObject, Py_bufferP, rffi.INT_real],
+ rffi.INT_real, header=None, error=-1)
+ @func_renamer("cpyext_%s_%s" % (name.replace('.', '_'), typedef.name))
+ def buff_w(space, w_self, w_args, w_kwds):
+ # XXX this is wrong, needs a test
+ args = Arguments(space, [w_self],
+ w_stararg=w_args, w_starstararg=w_kwds)
+ return space.call_args(space.get(buff_fn, w_self), args)
+ api_func = buff_w.api_func
else:
# missing: tp_as_number.nb_nonzero, tp_as_number.nb_coerce
# tp_as_sequence.c_sq_contains, tp_as_sequence.c_sq_length
@@ -881,6 +912,7 @@
# partial sort to solve some slot conflicts:
# Number slots before Mapping slots before Sequence slots.
+# also prefer the new buffer interface
# These are the only conflicts between __name__ methods
def slotdef_sort_key(slotdef):
if slotdef.slot_name.startswith('tp_as_number'):
@@ -889,6 +921,10 @@
return 2
if slotdef.slot_name.startswith('tp_as_sequence'):
return 3
+ if slodef.slot_name == 'tp_as_buffer.c_bf_getbuffer':
+ return 100
+ if slodef.slot_name == 'tp_as_buffer.c_bf_getreadbuffer':
+ return 101
return 0
slotdefs = sorted(slotdefs, key=slotdef_sort_key)
diff --git a/pypy/module/cpyext/test/test_memoryobject.py b/pypy/module/cpyext/test/test_memoryobject.py
--- a/pypy/module/cpyext/test/test_memoryobject.py
+++ b/pypy/module/cpyext/test/test_memoryobject.py
@@ -3,7 +3,6 @@
from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase
-
class TestMemoryViewObject(BaseApiTest):
def test_fromobject(self, space, api):
if space.is_true(space.lt(space.sys.get('version_info'),
@@ -13,14 +12,20 @@
w_hello = space.newbytes("hello")
assert api.PyObject_CheckBuffer(w_hello)
w_view = api.PyMemoryView_FromObject(w_hello)
+ w_char = space.call_method(w_view, '__getitem__', space.wrap(0))
+ assert w_char == space.wrap('h')
w_bytes = space.call_method(w_view, "tobytes")
assert space.unwrap(w_bytes) == "hello"
class AppTestBufferProtocol(AppTestCpythonExtensionBase):
def test_buffer_protocol(self):
+ import struct
module = self.import_module(name='buffer_test')
arr = module.PyMyArray(10)
y = memoryview(arr)
assert y.format == 'i'
+ s = y[3]
+ assert len(s) == struct.calcsize('i')
+ assert s == struct.pack('i', 3)
diff --git a/pypy/module/cpyext/typeobject.py b/pypy/module/cpyext/typeobject.py
--- a/pypy/module/cpyext/typeobject.py
+++ b/pypy/module/cpyext/typeobject.py
@@ -17,7 +17,8 @@
generic_cpy_call, Py_TPFLAGS_READY, Py_TPFLAGS_READYING,
Py_TPFLAGS_HEAPTYPE, METH_VARARGS, METH_KEYWORDS, CANNOT_FAIL,
Py_TPFLAGS_HAVE_GETCHARBUFFER, build_type_checkers, StaticObjectBuilder,
- PyObjectFields, Py_TPFLAGS_BASETYPE, PyTypeObject, PyTypeObjectPtr)
+ PyObjectFields, Py_TPFLAGS_BASETYPE, PyTypeObject, PyTypeObjectPtr,
+ Py_TPFLAGS_HAVE_NEWBUFFER)
from pypy.module.cpyext.methodobject import (W_PyCClassMethodObject,
W_PyCWrapperObject, PyCFunction_NewEx, PyCFunction_typedef, PyMethodDef,
W_PyCMethodObject, W_PyCFunctionObject)
@@ -608,6 +609,7 @@
bf_getwritebuffer.api_func.get_wrapper(space))
pto.c_tp_as_buffer = c_buf
pto.c_tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER
+ pto.c_tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER
@cpython_api([PyObject], lltype.Void, header=None)
def type_dealloc(space, obj):
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
@@ -464,6 +464,9 @@
raise oefmt(space.w_TypeError,
"Cannot use string as modifiable buffer")
+ def descr_getbuffer(self, space):
+ return self
+
charbuf_w = str_w
def listview_bytes(self):
@@ -925,6 +928,7 @@
translate = interpindirect2app(W_AbstractBytesObject.descr_translate),
upper = interpindirect2app(W_AbstractBytesObject.descr_upper),
zfill = interpindirect2app(W_AbstractBytesObject.descr_zfill),
+ __buffer__ = interp2app(W_BytesObject.descr_getbuffer),
format = interpindirect2app(W_BytesObject.descr_format),
__format__ = interpindirect2app(W_BytesObject.descr__format__),
More information about the pypy-commit
mailing list