diff options
-rw-r--r-- | c/_cffi_backend.c | 9 | ||||
-rw-r--r-- | c/cffi1_module.c | 3 | ||||
-rw-r--r-- | c/ffi_obj.c | 14 | ||||
-rw-r--r-- | c/minibuffer.h | 32 | ||||
-rw-r--r-- | c/test_c.py | 1 | ||||
-rw-r--r-- | cffi/api.py | 25 | ||||
-rw-r--r-- | doc/source/ref.rst | 7 | ||||
-rw-r--r-- | doc/source/whatsnew.rst | 3 | ||||
-rw-r--r-- | testing/cffi0/backend_tests.py | 1 | ||||
-rw-r--r-- | testing/cffi1/test_ffi_obj.py | 1 |
10 files changed, 67 insertions, 29 deletions
diff --git a/c/_cffi_backend.c b/c/_cffi_backend.c index 7d763ff..d9aaf6e 100644 --- a/c/_cffi_backend.c +++ b/c/_cffi_backend.c @@ -6029,8 +6029,10 @@ static PyObject *b_unpack(PyObject *self, PyObject *args, PyObject *kwds) return result; } -static PyObject *b_buffer(PyObject *self, PyObject *args, PyObject *kwds) +static PyObject * +b_buffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds) { + /* this is the constructor of the type implemented in minibuffer.h */ CDataObject *cd; Py_ssize_t size = -1; static char *keywords[] = {"cdata", "size", NULL}; @@ -6655,7 +6657,6 @@ static PyMethodDef FFIBackendMethods[] = { {"getcname", b_getcname, METH_VARARGS}, {"string", (PyCFunction)b_string, METH_VARARGS | METH_KEYWORDS}, {"unpack", (PyCFunction)b_unpack, METH_VARARGS | METH_KEYWORDS}, - {"buffer", (PyCFunction)b_buffer, METH_VARARGS | METH_KEYWORDS}, {"get_errno", b_get_errno, METH_NOARGS}, {"set_errno", b_set_errno, METH_O}, {"newp_handle", b_newp_handle, METH_VARARGS}, @@ -6959,6 +6960,10 @@ init_cffi_backend(void) INITERROR; } + Py_INCREF(&MiniBuffer_Type); + if (PyModule_AddObject(m, "buffer", (PyObject *)&MiniBuffer_Type) < 0) + INITERROR; + init_cffi_tls(); if (PyErr_Occurred()) INITERROR; diff --git a/c/cffi1_module.c b/c/cffi1_module.c index bf309f6..8776262 100644 --- a/c/cffi1_module.c +++ b/c/cffi1_module.c @@ -45,6 +45,9 @@ static int init_ffi_lib(PyObject *m) if (PyDict_SetItemString(FFI_Type.tp_dict, "CData", (PyObject *)&CData_Type) < 0) return -1; + if (PyDict_SetItemString(FFI_Type.tp_dict, "buffer", + (PyObject *)&MiniBuffer_Type) < 0) + return -1; for (i = 0; all_dlopen_flags[i].name != NULL; i++) { x = PyInt_FromLong(all_dlopen_flags[i].value); diff --git a/c/ffi_obj.c b/c/ffi_obj.c index 3c4866e..103f175 100644 --- a/c/ffi_obj.c +++ b/c/ffi_obj.c @@ -475,19 +475,6 @@ PyDoc_STRVAR(ffi_unpack_doc, #define ffi_unpack b_unpack /* ffi_unpack() => b_unpack() from _cffi_backend.c */ -PyDoc_STRVAR(ffi_buffer_doc, -"Return a read-write buffer object that references the raw C data\n" -"pointed to by the given 'cdata'. The 'cdata' must be a pointer or an\n" -"array. Can be passed to functions expecting a buffer, or directly\n" -"manipulated with:\n" -"\n" -" buf[:] get a copy of it in a regular string, or\n" -" buf[idx] as a single character\n" -" buf[:] = ...\n" -" buf[idx] = ... change the content"); - -#define ffi_buffer b_buffer /* ffi_buffer() => b_buffer() - from _cffi_backend.c */ PyDoc_STRVAR(ffi_offsetof_doc, "Return the offset of the named field inside the given structure or\n" @@ -1085,7 +1072,6 @@ static PyObject *ffi_init_once(FFIObject *self, PyObject *args, PyObject *kwds) static PyMethodDef ffi_methods[] = { {"addressof", (PyCFunction)ffi_addressof, METH_VARARGS, ffi_addressof_doc}, {"alignof", (PyCFunction)ffi_alignof, METH_O, ffi_alignof_doc}, - {"buffer", (PyCFunction)ffi_buffer, METH_VKW, ffi_buffer_doc}, {"def_extern", (PyCFunction)ffi_def_extern, METH_VKW, ffi_def_extern_doc}, {"callback", (PyCFunction)ffi_callback, METH_VKW, ffi_callback_doc}, {"cast", (PyCFunction)ffi_cast, METH_VARARGS, ffi_cast_doc}, diff --git a/c/minibuffer.h b/c/minibuffer.h index 92cf079..6cce3e1 100644 --- a/c/minibuffer.h +++ b/c/minibuffer.h @@ -238,6 +238,22 @@ static PyMappingMethods mb_as_mapping = { # define MINIBUF_TPFLAGS (Py_TPFLAGS_HAVE_GETCHARBUFFER | Py_TPFLAGS_HAVE_NEWBUFFER) #endif +PyDoc_STRVAR(ffi_buffer_doc, +"ffi.buffer(cdata):\n" +"Return a read-write buffer object that references the raw C data\n" +"pointed to by the given 'cdata'. The 'cdata' must be a pointer or an\n" +"array. Can be passed to functions expecting a buffer, or directly\n" +"manipulated with:\n" +"\n" +" buf[:] get a copy of it in a regular string, or\n" +" buf[idx] as a single character\n" +" buf[:] = ...\n" +" buf[idx] = ... change the content"); + +static PyObject * /* forward, implemented in _cffi_backend.c */ +b_buffer_new(PyTypeObject *type, PyObject *args, PyObject *kwds); + + static PyTypeObject MiniBuffer_Type = { PyVarObject_HEAD_INIT(NULL, 0) "_cffi_backend.buffer", @@ -268,11 +284,25 @@ static PyTypeObject MiniBuffer_Type = { &mb_as_buffer, /* tp_as_buffer */ (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_GC | MINIBUF_TPFLAGS), /* tp_flags */ - 0, /* tp_doc */ + ffi_buffer_doc, /* tp_doc */ (traverseproc)mb_traverse, /* tp_traverse */ (inquiry)mb_clear, /* tp_clear */ 0, /* tp_richcompare */ offsetof(MiniBufferObj, mb_weakreflist), /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + b_buffer_new, /* tp_new */ + 0, /* tp_free */ }; static PyObject *minibuffer_new(char *data, Py_ssize_t size, diff --git a/c/test_c.py b/c/test_c.py index fdc14ef..79c6fce 100644 --- a/c/test_c.py +++ b/c/test_c.py @@ -2299,6 +2299,7 @@ def test_buffer(): buf = buffer(c) assert repr(buf).startswith('<_cffi_backend.buffer object at 0x') assert bytes(buf) == b"hi there\x00" + assert type(buf) is buffer if sys.version_info < (3,): assert str(buf) == "hi there\x00" assert unicode(buf) == u+"hi there\x00" diff --git a/cffi/api.py b/cffi/api.py index 43b78f8..272a6a7 100644 --- a/cffi/api.py +++ b/cffi/api.py @@ -93,6 +93,7 @@ class FFI(object): # ctypes backend: attach these constants to the instance self.NULL = self.cast(self.BVoidP, 0) self.CData, self.CType = backend._get_types() + self.buffer = backend.buffer def cdef(self, csource, override=False, packed=False): """Parse the given C source. This registers all declared functions, @@ -316,18 +317,18 @@ class FFI(object): """ return self._backend.unpack(cdata, length) - def buffer(self, cdata, size=-1): - """Return a read-write buffer object that references the raw C data - pointed to by the given 'cdata'. The 'cdata' must be a pointer or - an array. Can be passed to functions expecting a buffer, or directly - manipulated with: - - buf[:] get a copy of it in a regular string, or - buf[idx] as a single character - buf[:] = ... - buf[idx] = ... change the content - """ - return self._backend.buffer(cdata, size) + #def buffer(self, cdata, size=-1): + # """Return a read-write buffer object that references the raw C data + # pointed to by the given 'cdata'. The 'cdata' must be a pointer or + # an array. Can be passed to functions expecting a buffer, or directly + # manipulated with: + # + # buf[:] get a copy of it in a regular string, or + # buf[idx] as a single character + # buf[:] = ... + # buf[idx] = ... change the content + # """ + # note that 'buffer' is a type, set on this instance by __init__ def from_buffer(self, python_buffer): """Return a <cdata 'char[]'> that points to the data of the diff --git a/doc/source/ref.rst b/doc/source/ref.rst index 9b5f8c9..dd99625 100644 --- a/doc/source/ref.rst +++ b/doc/source/ref.rst @@ -172,6 +172,9 @@ because it gives inconsistent results between Python 2 and Python 3. (This is similar to how ``str()`` gives inconsistent results on regular byte strings). Use ``buf[:]`` instead. +*New in version 1.10:* ``ffi.buffer`` is now the type of the returned +buffer objects; ``ffi.buffer()`` actually calls the constructor. + **ffi.from_buffer(python_buffer)**: return a ``<cdata 'char[]'>`` that points to the data of the given Python object, which must support the buffer interface. This is the opposite of ``ffi.buffer()``. It gives @@ -334,6 +337,10 @@ always present, and depending on the kind they may also have ``item``, ``length``, ``fields``, ``args``, ``result``, ``ellipsis``, ``abi``, ``elements`` and ``relements``. +*New in version 1.10:* ``ffi.buffer`` is now `a type`__ as well. + +.. __: #ffi-buffer + ffi.gc() ++++++++ diff --git a/doc/source/whatsnew.rst b/doc/source/whatsnew.rst index edc0b50..9db3b96 100644 --- a/doc/source/whatsnew.rst +++ b/doc/source/whatsnew.rst @@ -43,6 +43,9 @@ v1.10 aside, ``ffi.string()`` no longer works on ``_Bool[]`` (but it never made much sense, as this function stops on the first zero). +* ``ffi.buffer`` is now the name of cffi's buffer type, and + ``ffi.buffer()`` works like before but is the constructor of that type. + v1.9 ==== diff --git a/testing/cffi0/backend_tests.py b/testing/cffi0/backend_tests.py index 0a771ac..8eb279d 100644 --- a/testing/cffi0/backend_tests.py +++ b/testing/cffi0/backend_tests.py @@ -1130,6 +1130,7 @@ class BackendTests: b = ffi.buffer(a) except NotImplementedError as e: py.test.skip(str(e)) + assert type(b) is ffi.buffer content = b[:] assert len(content) == len(b) == 2 if sys.byteorder == 'little': diff --git a/testing/cffi1/test_ffi_obj.py b/testing/cffi1/test_ffi_obj.py index 4415115..2b5d764 100644 --- a/testing/cffi1/test_ffi_obj.py +++ b/testing/cffi1/test_ffi_obj.py @@ -233,6 +233,7 @@ def test_ffi_buffer(): a = ffi.new("signed char[]", [5, 6, 7]) assert ffi.buffer(a)[:] == b'\x05\x06\x07' assert ffi.buffer(cdata=a, size=2)[:] == b'\x05\x06' + assert type(ffi.buffer(a)) is ffi.buffer def test_ffi_from_buffer(): import array |