Author: Manuel Jacob <m...@manueljacob.de> Branch: Changeset: r90513:53fee63aea78 Date: 2017-03-03 17:22 +0100 http://bitbucket.org/pypy/pypy/changeset/53fee63aea78/
Log: hg merge diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py --- a/pypy/module/cpyext/api.py +++ b/pypy/module/cpyext/api.py @@ -574,6 +574,7 @@ 'PyObject_CallMethod', 'PyObject_CallFunctionObjArgs', 'PyObject_CallMethodObjArgs', '_PyObject_CallFunction_SizeT', '_PyObject_CallMethod_SizeT', + 'PyObject_GetBuffer', 'PyBuffer_Release', 'PyBuffer_FromMemory', 'PyBuffer_FromReadWriteMemory', 'PyBuffer_FromObject', 'PyBuffer_FromReadWriteObject', 'PyBuffer_New', 'PyBuffer_Type', '_Py_get_buffer_type', 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 @@ -1,19 +1,10 @@ from rpython.rtyper.lltypesystem import rffi, lltype from pypy.interpreter.error import oefmt from pypy.module.cpyext.api import ( - cpython_api, CANNOT_FAIL, Py_TPFLAGS_HAVE_NEWBUFFER, cts, Py_buffer, + cpython_api, CANNOT_FAIL, cts, Py_buffer, Py_ssize_t, Py_ssize_tP, generic_cpy_call, PyBUF_WRITABLE, PyBUF_FORMAT, PyBUF_ND, PyBUF_STRIDES) -from pypy.module.cpyext.pyobject import PyObject, Py_IncRef, Py_DecRef - -@cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL) -def PyObject_CheckBuffer(space, pyobj): - """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.c_bf_getbuffer): - return 1 - return 0 +from pypy.module.cpyext.pyobject import PyObject, Py_IncRef @cpython_api([lltype.Ptr(Py_buffer), PyObject, rffi.VOIDP, Py_ssize_t, lltype.Signed, lltype.Signed], rffi.INT, error=-1) @@ -48,23 +39,3 @@ view.c_internal = lltype.nullptr(rffi.VOIDP.TO) return 0 - - -@cpython_api([lltype.Ptr(Py_buffer)], lltype.Void, error=CANNOT_FAIL) -def PyBuffer_Release(space, view): - """ - Release the buffer view. This should be called when the buffer is - no longer being used as it may free memory from it - """ - obj = view.c_obj - if not obj: - return - assert obj.c_ob_type - as_buffer = obj.c_ob_type.c_tp_as_buffer - if as_buffer: - func = as_buffer.c_bf_releasebuffer - if func: - generic_cpy_call(space, func, obj, view) - Py_DecRef(space, obj) - view.c_obj = lltype.nullptr(PyObject.TO) - # XXX do other fields leak memory? diff --git a/pypy/module/cpyext/include/Python.h b/pypy/module/cpyext/include/Python.h --- a/pypy/module/cpyext/include/Python.h +++ b/pypy/module/cpyext/include/Python.h @@ -79,6 +79,7 @@ #include "pyconfig.h" #include "object.h" +#include "abstract.h" #include "pymath.h" #include "pyport.h" #include "warnings.h" diff --git a/pypy/module/cpyext/include/abstract.h b/pypy/module/cpyext/include/abstract.h --- a/pypy/module/cpyext/include/abstract.h +++ b/pypy/module/cpyext/include/abstract.h @@ -1,1 +1,35 @@ -/* empty */ +#ifndef Py_ABSTRACTOBJECT_H +#define Py_ABSTRACTOBJECT_H +#ifdef __cplusplus +extern "C" { +#endif + + /* new buffer API */ + +#define PyObject_CheckBuffer(obj) \ + (((obj)->ob_type->tp_as_buffer != NULL) && \ + (PyType_HasFeature((obj)->ob_type, Py_TPFLAGS_HAVE_NEWBUFFER)) && \ + ((obj)->ob_type->tp_as_buffer->bf_getbuffer != NULL)) + + /* Return 1 if the getbuffer function is available, otherwise + return 0 */ + + PyAPI_FUNC(int) PyObject_GetBuffer(PyObject *obj, Py_buffer *view, + int flags); + + /* This is a C-API version of the getbuffer function call. It checks + to make sure object has the required function pointer and issues the + call. Returns -1 and raises an error on failure and returns 0 on + success + */ + + PyAPI_FUNC(void) PyBuffer_Release(Py_buffer *view); + + /* Releases a Py_buffer obtained from getbuffer ParseTuple's s*. + */ + + +#ifdef __cplusplus +} +#endif +#endif /* Py_ABSTRACTOBJECT_H */ diff --git a/pypy/module/cpyext/memoryobject.py b/pypy/module/cpyext/memoryobject.py --- a/pypy/module/cpyext/memoryobject.py +++ b/pypy/module/cpyext/memoryobject.py @@ -97,35 +97,6 @@ _dealloc(space, py_obj) -@cpython_api([PyObject, Py_bufferP, rffi.INT_real], - rffi.INT_real, error=-1) -def PyObject_GetBuffer(space, w_obj, view, flags): - """Export obj into a Py_buffer, view. These arguments must - never be NULL. The flags argument is a bit field indicating what - kind of buffer the caller is prepared to deal with and therefore what - kind of buffer the exporter is allowed to return. The buffer interface - allows for complicated memory sharing possibilities, but some caller may - not be able to handle all the complexity but may want to see if the - exporter will let them take a simpler view to its memory. - - Some exporters may not be able to share memory in every possible way and - may need to raise errors to signal to some consumers that something is - just not possible. These errors should be a BufferError unless - there is another error that is actually causing the problem. The - exporter can use flags information to simplify how much of the - Py_buffer structure is filled in with non-default values and/or - raise an error if the object can't support a simpler view of its memory. - - 0 is returned on success and -1 on error.""" - if not PyObject_CheckBuffer(space, w_obj): - raise oefmt(space.w_TypeError, - "'%T' does not have the buffer interface", w_obj) - py_obj = as_pyobj(space, w_obj) - func = py_obj.c_ob_type.c_tp_as_buffer.c_bf_getbuffer - ret = generic_cpy_call(space, func, py_obj, view, flags) - keepalive_until_here(w_obj) - return ret - def fill_Py_buffer(space, buf, view): # c_buf, c_obj have been filled in ndim = buf.getndim() diff --git a/pypy/module/cpyext/src/abstract.c b/pypy/module/cpyext/src/abstract.c --- a/pypy/module/cpyext/src/abstract.c +++ b/pypy/module/cpyext/src/abstract.c @@ -101,6 +101,30 @@ return 0; } +/* Buffer C-API for Python 3.0 */ + +int +PyObject_GetBuffer(PyObject *obj, Py_buffer *view, int flags) +{ + if (!PyObject_CheckBuffer(obj)) { + PyErr_Format(PyExc_TypeError, + "'%100s' does not have the buffer interface", + Py_TYPE(obj)->tp_name); + return -1; + } + return (*(obj->ob_type->tp_as_buffer->bf_getbuffer))(obj, view, flags); +} + +void +PyBuffer_Release(Py_buffer *view) +{ + PyObject *obj = view->obj; + if (obj && Py_TYPE(obj)->tp_as_buffer && Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer) + Py_TYPE(obj)->tp_as_buffer->bf_releasebuffer(obj, view); + Py_XDECREF(obj); + view->obj = NULL; +} + /* Operations on callable objects */ static PyObject* 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 @@ -10,15 +10,6 @@ only_pypy ="config.option.runappdirect and '__pypy__' not in sys.builtin_module_names" class TestMemoryViewObject(BaseApiTest): - def test_fromobject(self, space, api): - w_hello = space.newbytes("hello") - assert api.PyObject_CheckBuffer(w_hello) - w_view = from_ref(space, api.PyMemoryView_FromObject(w_hello)) - w_char = space.call_method(w_view, '__getitem__', space.wrap(0)) - assert space.eq_w(w_char, space.wrap('h')) - w_bytes = space.call_method(w_view, "tobytes") - assert space.unwrap(w_bytes) == "hello" - def test_frombuffer(self, space, api): w_buf = space.newbuffer(StringBuffer("hello")) c_memoryview = rffi.cast( @@ -74,6 +65,19 @@ del result class AppTestBufferProtocol(AppTestCpythonExtensionBase): + def test_fromobject(self): + foo = self.import_extension('foo', [ + ("make_view", "METH_O", + """ + if (!PyObject_CheckBuffer(args)) + return Py_None; + return PyMemoryView_FromObject(args); + """)]) + hello = b'hello' + mview = foo.make_view(hello) + assert mview[0] == hello[0] + assert mview.tobytes() == hello + def test_buffer_protocol_app(self): import struct module = self.import_module(name='buffer_test') _______________________________________________ pypy-commit mailing list pypy-commit@python.org https://mail.python.org/mailman/listinfo/pypy-commit