From 92b6cbbfa1ae5b224441fd50ecbfb58f7b3a6b6f Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 4 May 2026 05:08:35 +0300 Subject: [PATCH 1/3] gh-61103: use PEP 3118 codes in the ctypes This change only buffer protocol support for complex types, `_type_` properties aren't affected. --- Lib/test/test_ctypes/test_pep3118.py | 9 +++++++ ...6-05-04-05-08-17.gh-issue-61103.mONh4V.rst | 2 ++ Modules/_ctypes/_ctypes.c | 25 +++++++++++++++++-- 3 files changed, 34 insertions(+), 2 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-04-05-08-17.gh-issue-61103.mONh4V.rst diff --git a/Lib/test/test_ctypes/test_pep3118.py b/Lib/test/test_ctypes/test_pep3118.py index 11a0744f5a8e36..9740e0c77b5c87 100644 --- a/Lib/test/test_ctypes/test_pep3118.py +++ b/Lib/test/test_ctypes/test_pep3118.py @@ -1,3 +1,4 @@ +import ctypes import re import sys import unittest @@ -231,6 +232,14 @@ class Complete(Structure): ] +if hasattr(ctypes, 'c_float_complex'): + c_float_complex = ctypes.c_float_complex + c_double_complex = ctypes.c_double_complex + c_longdouble_complex = ctypes.c_longdouble_complex + native_types.extend([(c_float_complex * 4, "' : '<'; result[1] = pep_code; result[2] = '\0'; + result[3] = '\0'; return result; } @@ -3120,7 +3121,27 @@ PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags) view->len = self->b_size; view->readonly = 0; /* use default format character if not set */ - view->format = info->format ? info->format : "B"; + if (!info->format) { + view->format = "B"; + } + else { + view->format = info->format; + if (view->format[1] == 'F') { + view->format[1] = 'Z'; + view->format[2] = 'f'; + view->format[3] = '\0'; + } + if (view->format[1] == 'D') { + view->format[1] = 'Z'; + view->format[2] = 'd'; + view->format[3] = '\0'; + } + if (view->format[1] == 'G') { + view->format[1] = 'Z'; + view->format[2] = 'g'; + view->format[3] = '\0'; + } + } view->ndim = info->ndim; view->shape = info->shape; view->itemsize = item_info->size; From 9528d510bb523d5ddb8baa04eb4170e45a909a08 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 4 May 2026 06:06:57 +0300 Subject: [PATCH 2/3] +correct --- Modules/_ctypes/_ctypes.c | 53 ++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 7146fa70c007a0..4a5b4f61712727 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -305,13 +305,41 @@ _ctypes_alloc_format_string_for_type(char code, int big_endian) #else # error SIZEOF__BOOL has an unexpected value #endif /* SIZEOF__BOOL */ +#if defined(_Py_FFI_SUPPORT_C_COMPLEX) + /* complex types */ + case 'F': + case 'D': + case 'G': + { + result = PyMem_Malloc(4); + if (result == NULL) { + PyErr_NoMemory(); + return NULL; + } + + result[0] = big_endian ? '>' : '<'; + result[1] = 'Z'; + switch (code) { + case 'F': + result[2] = 'f'; + break; + case 'D': + result[2] = 'd'; + break; + default: + result[2] = 'g'; + } + result[3] = '\0'; + return result; + } +#endif default: /* The standard-size code is the same as the ctypes one */ pep_code = code; break; } - result = PyMem_Malloc(4); + result = PyMem_Malloc(3); if (result == NULL) { PyErr_NoMemory(); return NULL; @@ -320,7 +348,6 @@ _ctypes_alloc_format_string_for_type(char code, int big_endian) result[0] = big_endian ? '>' : '<'; result[1] = pep_code; result[2] = '\0'; - result[3] = '\0'; return result; } @@ -3121,27 +3148,7 @@ PyCData_NewGetBuffer(PyObject *myself, Py_buffer *view, int flags) view->len = self->b_size; view->readonly = 0; /* use default format character if not set */ - if (!info->format) { - view->format = "B"; - } - else { - view->format = info->format; - if (view->format[1] == 'F') { - view->format[1] = 'Z'; - view->format[2] = 'f'; - view->format[3] = '\0'; - } - if (view->format[1] == 'D') { - view->format[1] = 'Z'; - view->format[2] = 'd'; - view->format[3] = '\0'; - } - if (view->format[1] == 'G') { - view->format[1] = 'Z'; - view->format[2] = 'g'; - view->format[3] = '\0'; - } - } + view->format = info->format ? info->format : "B"; view->ndim = info->ndim; view->shape = info->shape; view->itemsize = item_info->size; From 7aa47c369aeaa8e8fcf39453fce9ac6f45a22b73 Mon Sep 17 00:00:00 2001 From: Sergey B Kirpichev Date: Mon, 4 May 2026 16:01:55 +0300 Subject: [PATCH 3/3] add news --- Doc/whatsnew/3.15.rst | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 586a1306d83c4c..6fff4c62a8b529 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -879,6 +879,15 @@ contextlib (Contributed by Alex Grönholm & Gregory P. Smith in :gh:`125862`.) +ctypes +------ + +* Change the ``format`` field of exported buffers from ``F``, ``D`` and ``G`` + to ``Zf``, ``Zd`` and ``Zg``, respectively, for compatibility with + the :pep:`3118` and NumPy. + (Contributed by Sergey B Kirpichev in :gh:`149344`.) + + dataclasses -----------