Author: Matti Picus <matti.pi...@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__), _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit