]> granicus.if.org Git - python/commitdiff
bpo-15913: Implement PyBuffer_SizeFromFormat() (GH-13873)
authorJoannah Nanjekye <33177550+nanjekyejoannah@users.noreply.github.com>
Tue, 20 Aug 2019 14:46:36 +0000 (11:46 -0300)
committerVictor Stinner <vstinner@redhat.com>
Tue, 20 Aug 2019 14:46:36 +0000 (15:46 +0100)
Implement PyBuffer_SizeFromFormat() function (previously
documented but not implemented): call struct.calcsize().

Doc/c-api/buffer.rst [changed mode: 0644->0755]
Include/cpython/abstract.h [changed mode: 0644->0755]
Lib/test/test_buffer.py [changed mode: 0644->0755]
Misc/NEWS.d/next/Core and Builtins/2019-06-06-20-52-38.bpo-15913.5Sg5cv.rst [new file with mode: 0644]
Modules/_testcapimodule.c [changed mode: 0644->0755]
Objects/abstract.c [changed mode: 0644->0755]

old mode 100644 (file)
new mode 100755 (executable)
index fdb8bd1..2536c74
@@ -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)
old mode 100644 (file)
new mode 100755 (executable)
index 62a113f..04e4a9e
@@ -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,
old mode 100644 (file)
new mode 100755 (executable)
index 47413c0..5fa52bf
@@ -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 (file)
index 0000000..0fbfcb3
--- /dev/null
@@ -0,0 +1,3 @@
+Implement :c:func:`PyBuffer_SizeFromFormat()` function (previously
+documented but not implemented): call :func:`struct.calcsize`.
+Patch by Joannah Nanjekye.
old mode 100644 (file)
new mode 100755 (executable)
index 8a6e741..84f2651
@@ -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},
old mode 100644 (file)
new mode 100755 (executable)
index f93d73f..3db56fa
@@ -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)
 {