Skip to content

Commit

Permalink
bpo-15913: Implement PyBuffer_SizeFromFormat() (pythonGH-13873)
Browse files Browse the repository at this point in the history
Implement PyBuffer_SizeFromFormat() function (previously
documented but not implemented): call struct.calcsize().
  • Loading branch information
nanjekyejoannah authored and vstinner committed Aug 20, 2019
1 parent 18f8dcf commit 9e66aba
Show file tree
Hide file tree
Showing 6 changed files with 83 additions and 3 deletions.
6 changes: 4 additions & 2 deletions Doc/c-api/buffer.rst
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion Include/cpython/abstract.h
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
12 changes: 12 additions & 0 deletions Lib/test/test_buffer.py
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@
except ImportError:
numpy_array = None

try:
import _testcapi
except ImportError:
_testcapi = None


SHORT_TEST = True

Expand Down Expand Up @@ -4412,6 +4417,13 @@ def test_issue_7385(self):
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()
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Implement :c:func:`PyBuffer_SizeFromFormat()` function (previously
documented but not implemented): call :func:`struct.calcsize`.
Patch by Joannah Nanjekye.
21 changes: 21 additions & 0 deletions Modules/_testcapimodule.c
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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 *
Expand Down Expand Up @@ -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},
Expand Down
42 changes: 42 additions & 0 deletions Objects/abstract.c
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
Expand Down

0 comments on commit 9e66aba

Please sign in to comment.