summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoannah Nanjekye <33177550+nanjekyejoannah@users.noreply.github.com>2019-08-20 14:46:36 (GMT)
committerVictor Stinner <vstinner@redhat.com>2019-08-20 14:46:36 (GMT)
commit9e66aba99925eebacfe137d9deb0ef1fdbc2d5db (patch)
treee9353ac99e9911959aadb9092ae35237ec06b5e2
parent18f8dcfa10d8a858b152d12a9ad8fa83b7e967f0 (diff)
downloadcpython-9e66aba99925eebacfe137d9deb0ef1fdbc2d5db.zip
cpython-9e66aba99925eebacfe137d9deb0ef1fdbc2d5db.tar.gz
cpython-9e66aba99925eebacfe137d9deb0ef1fdbc2d5db.tar.bz2
bpo-15913: Implement PyBuffer_SizeFromFormat() (GH-13873)
Implement PyBuffer_SizeFromFormat() function (previously documented but not implemented): call struct.calcsize().
-rwxr-xr-x[-rw-r--r--]Doc/c-api/buffer.rst6
-rwxr-xr-x[-rw-r--r--]Include/cpython/abstract.h2
-rwxr-xr-x[-rw-r--r--]Lib/test/test_buffer.py12
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2019-06-06-20-52-38.bpo-15913.5Sg5cv.rst3
-rwxr-xr-x[-rw-r--r--]Modules/_testcapimodule.c21
-rwxr-xr-x[-rw-r--r--]Objects/abstract.c42
6 files changed, 83 insertions, 3 deletions
diff --git a/Doc/c-api/buffer.rst b/Doc/c-api/buffer.rst
index fdb8bd1..2536c74 100644..100755
--- a/Doc/c-api/buffer.rst
+++ b/Doc/c-api/buffer.rst
@@ -462,10 +462,12 @@ Buffer-related functions
:c:func:`PyObject_GetBuffer`.
-.. c:function:: Py_ssize_t PyBuffer_SizeFromFormat(const char *)
+.. c:function:: Py_ssize_t PyBuffer_SizeFromFormat(const char *format)
Return the implied :c:data:`~Py_buffer.itemsize` from :c:data:`~Py_buffer.format`.
- This function is not yet implemented.
+ On error, raise an exception and return -1.
+
+ .. versionadded:: 3.9
.. c:function:: int PyBuffer_IsContiguous(Py_buffer *view, char order)
diff --git a/Include/cpython/abstract.h b/Include/cpython/abstract.h
index 62a113f..04e4a9e 100644..100755
--- a/Include/cpython/abstract.h
+++ b/Include/cpython/abstract.h
@@ -243,7 +243,7 @@ PyAPI_FUNC(void *) PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices);
/* Return the implied itemsize of the data-format area from a
struct-style description. */
-PyAPI_FUNC(int) PyBuffer_SizeFromFormat(const char *);
+PyAPI_FUNC(Py_ssize_t) PyBuffer_SizeFromFormat(const char *format);
/* Implementation in memoryobject.c */
PyAPI_FUNC(int) PyBuffer_ToContiguous(void *buf, Py_buffer *view,
diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py
index 47413c0..5fa52bf 100644..100755
--- a/Lib/test/test_buffer.py
+++ b/Lib/test/test_buffer.py
@@ -43,6 +43,11 @@ try:
except ImportError:
numpy_array = None
+try:
+ import _testcapi
+except ImportError:
+ _testcapi = None
+
SHORT_TEST = True
@@ -4412,6 +4417,13 @@ class TestBufferProtocol(unittest.TestCase):
x = ndarray([1,2,3], shape=[3], flags=ND_GETBUF_FAIL)
self.assertRaises(BufferError, memoryview, x)
+ @support.cpython_only
+ def test_pybuffer_size_from_format(self):
+ # basic tests
+ for format in ('', 'ii', '3s'):
+ self.assertEqual(_testcapi.PyBuffer_SizeFromFormat(format),
+ struct.calcsize(format))
+
if __name__ == "__main__":
unittest.main()
diff --git a/Misc/NEWS.d/next/Core and Builtins/2019-06-06-20-52-38.bpo-15913.5Sg5cv.rst b/Misc/NEWS.d/next/Core and Builtins/2019-06-06-20-52-38.bpo-15913.5Sg5cv.rst
new file mode 100644
index 0000000..0fbfcb3
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2019-06-06-20-52-38.bpo-15913.5Sg5cv.rst
@@ -0,0 +1,3 @@
+Implement :c:func:`PyBuffer_SizeFromFormat()` function (previously
+documented but not implemented): call :func:`struct.calcsize`.
+Patch by Joannah Nanjekye.
diff --git a/Modules/_testcapimodule.c b/Modules/_testcapimodule.c
index 8a6e741..84f2651 100644..100755
--- a/Modules/_testcapimodule.c
+++ b/Modules/_testcapimodule.c
@@ -3363,6 +3363,26 @@ getbuffer_with_null_view(PyObject* self, PyObject *obj)
Py_RETURN_NONE;
}
+/* PyBuffer_SizeFromFormat() */
+static PyObject *
+test_PyBuffer_SizeFromFormat(PyObject *self, PyObject *args)
+{
+ const char *format;
+ Py_ssize_t result;
+
+ if (!PyArg_ParseTuple(args, "s:test_PyBuffer_SizeFromFormat",
+ &format)) {
+ return NULL;
+ }
+
+ result = PyBuffer_SizeFromFormat(format);
+ if (result == -1) {
+ return NULL;
+ }
+
+ return PyLong_FromSsize_t(result);
+}
+
/* Test that the fatal error from not having a current thread doesn't
cause an infinite loop. Run via Lib/test/test_capi.py */
static PyObject *
@@ -5153,6 +5173,7 @@ static PyMethodDef TestMethods[] = {
{"test_pep3118_obsolete_write_locks", (PyCFunction)test_pep3118_obsolete_write_locks, METH_NOARGS},
#endif
{"getbuffer_with_null_view", getbuffer_with_null_view, METH_O},
+ {"PyBuffer_SizeFromFormat", test_PyBuffer_SizeFromFormat, METH_VARARGS},
{"test_buildvalue_N", test_buildvalue_N, METH_NOARGS},
{"get_args", get_args, METH_VARARGS},
{"get_kwargs", (PyCFunction)(void(*)(void))get_kwargs, METH_VARARGS|METH_KEYWORDS},
diff --git a/Objects/abstract.c b/Objects/abstract.c
index f93d73f..3db56fa 100644..100755
--- a/Objects/abstract.c
+++ b/Objects/abstract.c
@@ -495,6 +495,48 @@ _Py_add_one_to_index_C(int nd, Py_ssize_t *index, const Py_ssize_t *shape)
}
}
+Py_ssize_t
+PyBuffer_SizeFromFormat(const char *format)
+{
+ PyObject *structmodule = NULL;
+ PyObject *calcsize = NULL;
+ PyObject *res = NULL;
+ PyObject *fmt = NULL;
+ Py_ssize_t itemsize = -1;
+
+ structmodule = PyImport_ImportModule("struct");
+ if (structmodule == NULL) {
+ return itemsize;
+ }
+
+ calcsize = PyObject_GetAttrString(structmodule, "calcsize");
+ if (calcsize == NULL) {
+ goto done;
+ }
+
+ fmt = PyUnicode_FromString(format);
+ if (fmt == NULL) {
+ goto done;
+ }
+
+ res = PyObject_CallFunctionObjArgs(calcsize, fmt, NULL);
+ if (res == NULL) {
+ goto done;
+ }
+
+ itemsize = PyLong_AsSsize_t(res);
+ if (itemsize < 0) {
+ goto done;
+ }
+
+done:
+ Py_DECREF(structmodule);
+ Py_XDECREF(calcsize);
+ Py_XDECREF(fmt);
+ Py_XDECREF(res);
+ return itemsize;
+}
+
int
PyBuffer_FromContiguous(Py_buffer *view, void *buf, Py_ssize_t len, char fort)
{