Author: Matti Picus <matti.pi...@gmail.com> Branch: buffer-interface2 Changeset: r87135:64f607343212 Date: 2016-09-16 16:55 +0300 http://bitbucket.org/pypy/pypy/changeset/64f607343212/
Log: add cpyext-specific __rbuffer__, __wbuffer__ slots for old buffer interface diff --git a/pypy/interpreter/baseobjspace.py b/pypy/interpreter/baseobjspace.py --- a/pypy/interpreter/baseobjspace.py +++ b/pypy/interpreter/baseobjspace.py @@ -207,6 +207,12 @@ def buffer_w(self, space, flags): w_impl = space.lookup(self, '__buffer__') + if w_impl is None: + # cpyext types that may have only old buffer interface + if flags & space.BUF_WRITABLE: + w_impl = space.lookup(self, '__wbuffer__') + else: + w_impl = space.lookup(self, '__wbuffer__') if w_impl is not None: w_result = space.get_and_call_function(w_impl, self, space.newint(flags)) @@ -215,7 +221,10 @@ raise BufferInterfaceNotFound def readbuf_w(self, space): - w_impl = space.lookup(self, '__buffer__') + # cpyext types that may have old buffer protocol + w_impl = space.lookup(self, '__rbuffer__') + if w_impl is None: + w_impl = space.lookup(self, '__buffer__') if w_impl is not None: w_result = space.get_and_call_function(w_impl, self, space.newint(space.BUF_FULL_RO)) @@ -224,7 +233,10 @@ raise BufferInterfaceNotFound def writebuf_w(self, space): - w_impl = space.lookup(self, '__buffer__') + # cpyext types that may have old buffer protocol + w_impl = space.lookup(self, '__wbuffer__') + if w_impl is None: + w_impl = space.lookup(self, '__buffer__') if w_impl is not None: w_result = space.get_and_call_function(w_impl, self, space.newint(space.BUF_FULL)) 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 @@ -344,6 +344,10 @@ def getndim(self): return self.ndim + def setitem(self, index, char): + # absolutely no safety checks, what could go wrong? + self.ptr[index] = char + def wrap_getreadbuffer(space, w_self, w_args, func): func_target = rffi.cast(readbufferproc, func) with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as ptr: @@ -353,6 +357,15 @@ space.fromcache(State).check_and_raise_exception(always=True) return space.newbuffer(CPyBuffer(ptr[0], size, w_self)) +def wrap_getwritebuffer(space, w_self, w_args, func): + func_target = rffi.cast(readbufferproc, func) + with lltype.scoped_alloc(rffi.VOIDPP.TO, 1) as ptr: + index = rffi.cast(Py_ssize_t, 0) + size = generic_cpy_call(space, func_target, w_self, index, ptr) + if size < 0: + space.fromcache(State).check_and_raise_exception(always=True) + return space.newbuffer(CPyBuffer(ptr[0], size, w_self, readonly=False)) + def wrap_getbuffer(space, w_self, w_args, func): func_target = rffi.cast(getbufferproc, func) with lltype.scoped_alloc(Py_buffer) as pybuf: @@ -919,13 +932,13 @@ slotdefs = eval(slotdefs_str) # PyPy addition slotdefs += ( - # XXX that might not be what we want! TPSLOT("__buffer__", "tp_as_buffer.c_bf_getbuffer", None, "wrap_getbuffer", ""), ) if not PY3: slotdefs += ( - TPSLOT("__buffer__", "tp_as_buffer.c_bf_getreadbuffer", None, "wrap_getreadbuffer", ""), + TPSLOT("__rbuffer__", "tp_as_buffer.c_bf_getreadbuffer", None, "wrap_getreadbuffer", ""), + TPSLOT("__wbuffer__", "tp_as_buffer.c_bf_getwritebuffer", None, "wrap_getwritebuffer", ""), ) diff --git a/pypy/module/cpyext/test/test_arraymodule.py b/pypy/module/cpyext/test/test_arraymodule.py --- a/pypy/module/cpyext/test/test_arraymodule.py +++ b/pypy/module/cpyext/test/test_arraymodule.py @@ -1,8 +1,16 @@ from pypy.module.cpyext.test.test_cpyext import AppTestCpythonExtensionBase - +from pypy.conftest import option class AppTestArrayModule(AppTestCpythonExtensionBase): - enable_leak_checking = False + + def setup_class(cls): + from rpython.tool.udir import udir + if option.runappdirect: + cls.w_udir = str(udir) + else: + cls.w_udir = cls.space.wrap(str(udir)) + + #enable_leak_checking = False def test_basic(self): module = self.import_module(name='array') @@ -109,3 +117,26 @@ assert val == 'abcd' val = module.readbuffer_as_string(u'\u03a3') assert val is not None + + def test_readinto(self): + module = self.import_module(name='array') + a = module.array('c') + a.fromstring('0123456789') + filename = self.udir + "/_test_file" + f = open(filename, 'w+b') + f.write('foobar') + f.seek(0) + n = f.readinto(a) + f.close() + assert n == 6 + assert len(a) == 10 + assert a.tostring() == 'foobar6789' + + def test_iowrite(self): + module = self.import_module(name='array') + from io import BytesIO + a = module.array('c') + a.fromstring('0123456789') + fd = BytesIO() + # only test that it works + fd.write(a) 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 @@ -806,23 +806,23 @@ if not pto.c_tp_as_buffer: pto.c_tp_as_buffer = base.c_tp_as_buffer if base.c_tp_as_buffer: - # also inherit all the base.c_tp_as_buffer functions, since they - # do not have real __slots__ they are not filled in otherwise - # - # skip bf_getbuffer, which is __buffer__ - # + # inherit base.c_tp_as_buffer functions not inherited from w_type # note: builtin types are handled in setup_buffer_procs pto_as = pto.c_tp_as_buffer base_as = base.c_tp_as_buffer + if not pto_as.c_bf_getbuffer: + pto_as.c_bf_getbuffer = base_as.c_bf_getbuffer + if not pto_as.c_bf_getcharbuffer: + pto_as.c_bf_getcharbuffer = base_as.c_bf_getcharbuffer + if not pto_as.c_bf_getwritebuffer: + pto_as.c_bf_getwritebuffer = base_as.c_bf_getwritebuffer if not pto_as.c_bf_getreadbuffer: pto_as.c_bf_getreadbuffer = base_as.c_bf_getreadbuffer - if not pto_as.c_bf_getwritebuffer: - pto_as.c_bf_getwritebuffer = base_as.c_bf_getwritebuffer if not pto_as.c_bf_getsegcount: pto_as.c_bf_getsegcount = base_as.c_bf_getsegcount if not pto_as.c_bf_getcharbuffer: pto_as.c_bf_getcharbuffer = base_as.c_bf_getcharbuffer - if not pto_as.c_bf_getcharbuffer: + if not pto_as.c_bf_releasebuffer: pto_as.c_bf_releasebuffer = base_as.c_bf_releasebuffer finally: Py_DecRef(space, base_pyo) @@ -853,13 +853,14 @@ w_obj = space.allocate_instance(W_PyCTypeObject, w_metatype) track_reference(space, py_obj, w_obj) - w_obj.__init__(space, py_type) + # __init__ wraps all slotdefs functions from py_type via add_operators + w_obj.__init__(space, py_type) w_obj.ready() finish_type_2(space, py_type, w_obj) - # inheriting tp_as_* slots base = py_type.c_tp_base if base: + # XXX refactor - parts of this are done in finish_type_2 -> inherit_slots if not py_type.c_tp_as_number: py_type.c_tp_as_number = base.c_tp_as_number py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_CHECKTYPES @@ -868,7 +869,7 @@ py_type.c_tp_as_sequence = base.c_tp_as_sequence py_type.c_tp_flags |= base.c_tp_flags & Py_TPFLAGS_HAVE_INPLACEOPS if not py_type.c_tp_as_mapping: py_type.c_tp_as_mapping = base.c_tp_as_mapping - if not py_type.c_tp_as_buffer: py_type.c_tp_as_buffer = base.c_tp_as_buffer + #if not py_type.c_tp_as_buffer: py_type.c_tp_as_buffer = base.c_tp_as_buffer return 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 @@ -32,6 +32,10 @@ def charbuf_w(self, space): return self.buf.as_str() + def descr_getbuffer(self, space, w_flags): + space.check_buf_flags(space.int_w(w_flags), self.buf.readonly) + return self + @staticmethod @unwrap_spec(offset=int, size=int) def descr_new_buffer(space, w_subtype, w_object, offset=0, size=-1): @@ -160,6 +164,7 @@ __mul__ = interp2app(W_Buffer.descr_mul), __rmul__ = interp2app(W_Buffer.descr_mul), __repr__ = interp2app(W_Buffer.descr_repr), + __buffer__ = interp2app(W_Buffer.descr_getbuffer), _pypy_raw_address = interp2app(W_Buffer.descr_pypy_raw_address), ) W_Buffer.typedef.acceptable_as_base_class = False _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit