10000 bpo-15913: Implement PyBuffer_SizeFromFormat() (GH-13873) · python/cpython@9e66aba · GitHub
[go: up one dir, main page]

Skip to content

Commit 9e66aba

Browse files
nanjekyejoannahvstinner
authored andcommitted
bpo-15913: Implement PyBuffer_SizeFromFormat() (GH-13873)
Implement PyBuffer_SizeFromFormat() function (previously documented but not implemented): call struct.calcsize().
1 parent 18f8dcf commit 9e66aba

File tree

6 files changed

+83
-3
lines changed

6 files changed

+83
-3
lines changed

Doc/c-api/buffer.rst

100644100755
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,10 +462,12 @@ Buffer-related functions
462462
:c:func:`PyObject_GetBuffer`.
463463
464464
465-
.. c:function:: Py_ssize_t PyBuffer_SizeFromFormat(const char *)
465+
.. c:function:: Py_ssize_t PyBuffer_SizeFromFormat(const char *format)
466466
467467
Return the implied :c:data:`~Py_buffer.itemsize` from :c:data:`~Py_buffer.format`.
468-
This function is not yet implemented.
468+
On error, raise an exception and return -1.
469+
470+
.. versionadded:: 3.9
469471
470472
471473
.. c:function:: int PyBuffer_IsContiguous(Py_buffer *view, char order)

Include/cpython/abstract.h

100644100755
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,7 @@ PyAPI_FUNC(void *) PyBuffer_GetPointer(Py_buffer *view, Py_ssize_t *indices);
243243

244244
/* Return the implied itemsize of the data-format area from a
245245
struct-style description. */
246-
PyAPI_FUNC(int) PyBuffer_SizeFromFormat(const char *);
246+
PyAPI_FUNC(Py_ssize_t) PyBuffer_SizeFromFormat(const char *format);
247247

248248
/* Implementation in memoryobject.c */
249249
PyAPI_FUNC(int) PyBuffer_ToContiguous(void *buf, Py_buffer *view,

Lib/test/test_buffer.py

100644100755
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@
4343
except ImportError:
4444
numpy_array = None
4545

46+
try:
47+
import _testcapi
48+
except ImportError:
49+
_testcapi = None
50+
4651

4752
SHORT_TEST = True
4853

@@ -4412,6 +4417,13 @@ def test_issue_7385(self):
44124417
x = ndarray([1,2,3], shape=[3], flags=ND_GETBUF_FAIL)
44134418
self.assertRaises(BufferError, memoryview, x)
44144419

4420+
@support.cpython_only
4421+
def test_pybuffer_size_from_format(self):
4422+
# basic tests
4423+
for format in ('', 'ii', '3s'):
4424+
self.assertEqual(_testcapi.PyBuffer_SizeFromFormat(format),
4425+
struct.calcsize(format))
4426+
44154427

44164428
if __name__ == "__main__":
44174429
unittest.main()
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
Implement :c:func:`PyBuffer_SizeFromFormat()` function (previously
2+
documented but not implemented): call :func:`struct.calcsize`.
3+
Patch by Joannah Nanjekye.

Modules/_testcapimodule.c

100644100755
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3363,6 +3363,26 @@ getbuffer_with_null_view(PyObject* self, PyObject *obj)
33633363
Py_RETURN_NONE;
33643364
}
33653365

3366+
/* PyBuffer_SizeFromFormat() */
3367+
static PyObject *
3368+
test_PyBuffer_SizeFromFormat(PyObject *self, PyObject *args)
3369+
{
3370+
const char *format;
3371+
Py_ssize_t result;
3372+
3373+
if (!PyArg_ParseTuple(args, "s:test_PyBuffer_SizeFromFormat",
3374+
&format)) {
3375+
return NULL;
3376+
}
3377+
3378+
result = PyBuffer_SizeFromFormat(format);
3379+
if (result == -1) {
3380+
return NULL;
3381+
}
3382+
3383+
return PyLong_FromSsize_t(result);
3384+
}
3385+
33663386
/* Test that the fatal error from not having a current thread doesn't
33673387
cause an infinite loop. Run via Lib/test/test_capi.py */
33683388
static PyObject *
@@ -5153,6 +5173,7 @@ static PyMethodDef TestMethods[] = {
51535173
{"test_pep3118_obsolete_write_locks", (PyCFunction)test_pep3118_obsolete_write_locks, METH_NOARGS},
51545174
#endif
51555175
{"getbuffer_with_null_view", getbuffer_with_null_view, METH_O},
5176+
{"PyBuffer_SizeFromFormat", test_PyBuffer_SizeFromFormat, METH_VARARGS},
51565177
{"test_buildvalue_N", test_buildvalue_N, METH_NOARGS},
51575178
{"get_args", get_args, METH_VARARGS},
51585179
{"get_kwargs", (PyCFunction)(void(*)(void))get_kwargs, METH_VARARGS|METH_KEYWORDS},

Objects/abstract.c

100644100755
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,48 @@ _Py_add_one_to_index_C(int nd, Py_ssize_t *index, const Py_ssize_t *shape)
495495
}
496496
}
497497

498+
Py_ssize_t
499+
PyBuffer_SizeFromFormat(const char *format)
500+
{
501+
PyObject *structmodule = NULL;
502+
PyObject *calcsize = NULL;
503+
PyObject *res = NULL;
504+
PyObject *fmt = NULL;
505+
Py_ssize_t itemsize = -1;
506+
507+
structmodule = PyImport_ImportModule("struct");
508+
if (structmodule == NULL) {
509+
return itemsize;
510+
}
511+
512+
calcsize = PyObject_GetAttrString(structmodule, "calcsize");
513+
if (calcsize == NULL) {
514+
goto done;
515+
}
516+
517+
fmt = PyUnicode_FromString(format);
518+
if (fmt == NULL) {
519+
goto done;
520+
}
521+
522+
res = PyObject_CallFunctionObjArgs(calcsize, fmt, NULL);
523+
if (res == NULL) {
524+
goto done;
525+
}
526+
527+
itemsize = PyLong_AsSsize_t(res);
528+
if (itemsize < 0) {
529+
goto done;
530+
}
531+
532+
done:
533+
Py_DECREF(structmodule);
534+
Py_XDECREF(calcsize);
535+
Py_XDECREF(fmt);
536+
Py_XDECREF(res);
537+
return itemsize;
538+
}
539+
498540
int
499541
PyBuffer_FromContiguous(Py_buffer *view, void *buf, Py_ssize_t len, char fort)
500542
{

0 commit comments

Comments
 (0)
0