[pypy-commit] pypy buffer-interface2: add cpyext-specific __rbuffer__, __wbuffer__ slots for old buffer interface
mattip
pypy.commits at gmail.com
Fri Sep 16 09:57:08 EDT 2016
Author: Matti Picus <matti.picus at 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
More information about the pypy-commit
mailing list