Skip to content

bpo-15913 : Add PyBuffer_SizeFromFormat() #13873

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 20 commits into from
Aug 20, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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 @@ -460,10 +460,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 @@ -206,7 +206,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 @@ -3301,6 +3301,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 @@ -5087,6 +5107,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) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is not needed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

calcsize() might return a integer which doesn't fit into a C Py_ssize_t. It's unlikely, but I prefer to keep the test.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I know that. I meant that the explicit check is not needed because the control flow will fall through to the done label.

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