bpo-15913: Implement PyBuffer_SizeFromFormat() (GH-13873)

Implement PyBuffer_SizeFromFormat() function (previously
documented but not implemented): call struct.calcsize().
This commit is contained in:
Joannah Nanjekye 2019-08-20 11:46:36 -03:00 committed by Victor Stinner
parent 18f8dcfa10
commit 9e66aba999
6 changed files with 83 additions and 3 deletions

6
Doc/c-api/buffer.rst Normal file → Executable file
View File

@ -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)

2
Include/cpython/abstract.h Normal file → Executable file
View File

@ -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,

12
Lib/test/test_buffer.py Normal file → Executable file
View File

@ -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()

View File

@ -0,0 +1,3 @@
Implement :c:func:`PyBuffer_SizeFromFormat()` function (previously
documented but not implemented): call :func:`struct.calcsize`.
Patch by Joannah Nanjekye.

21
Modules/_testcapimodule.c Normal file → Executable file
View File

@ -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},

42
Objects/abstract.c Normal file → Executable file
View File

@ -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)
{