[3.14] gh-148464: Add missing `__ctype_le/be__` attributes for complex types in the ctype module (GH-148485) (GH-148677)

(cherry picked from commit 769cc8338f)

Co-authored-by: Sergey B Kirpichev <skirpichev@gmail.com>
Co-authored-by: sunmy2019 <59365878+sunmy2019@users.noreply.github.com>
This commit is contained in:
Miss Islington (bot)
2026-04-23 15:57:55 +02:00
committed by GitHub
parent b6a7212edb
commit 5e758ff525
4 changed files with 154 additions and 14 deletions
+42
View File
@@ -166,6 +166,48 @@ class Test(unittest.TestCase, StructCheckMixin):
self.assertEqual(s.value, math.pi)
self.assertEqual(bin(struct.pack(">d", math.pi)), bin(s))
@unittest.skipUnless(hasattr(ctypes, 'c_float_complex'), "No complex types")
def test_endian_float_complex(self):
c_float_complex = ctypes.c_float_complex
if sys.byteorder == "little":
self.assertIs(c_float_complex.__ctype_le__, c_float_complex)
self.assertIs(c_float_complex.__ctype_be__.__ctype_le__,
c_float_complex)
else:
self.assertIs(c_float_complex.__ctype_be__, c_float_complex)
self.assertIs(c_float_complex.__ctype_le__.__ctype_be__,
c_float_complex)
s = c_float_complex(math.pi+1j)
self.assertEqual(bin(struct.pack("F", math.pi+1j)), bin(s))
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
s = c_float_complex.__ctype_le__(math.pi+1j)
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
self.assertEqual(bin(struct.pack("<F", math.pi+1j)), bin(s))
s = c_float_complex.__ctype_be__(math.pi+1j)
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
self.assertEqual(bin(struct.pack(">F", math.pi+1j)), bin(s))
@unittest.skipUnless(hasattr(ctypes, 'c_double_complex'), "No complex types")
def test_endian_double_complex(self):
c_double_complex = ctypes.c_double_complex
if sys.byteorder == "little":
self.assertIs(c_double_complex.__ctype_le__, c_double_complex)
self.assertIs(c_double_complex.__ctype_be__.__ctype_le__,
c_double_complex)
else:
self.assertIs(c_double_complex.__ctype_be__, c_double_complex)
self.assertIs(c_double_complex.__ctype_le__.__ctype_be__,
c_double_complex)
s = c_double_complex(math.pi+1j)
self.assertEqual(bin(struct.pack("D", math.pi+1j)), bin(s))
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
s = c_double_complex.__ctype_le__(math.pi+1j)
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
self.assertEqual(bin(struct.pack("<D", math.pi+1j)), bin(s))
s = c_double_complex.__ctype_be__(math.pi+1j)
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
self.assertEqual(bin(struct.pack(">D", math.pi+1j)), bin(s))
def test_endian_other(self):
self.assertIs(c_byte.__ctype_le__, c_byte)
self.assertIs(c_byte.__ctype_be__, c_byte)
@@ -0,0 +1,3 @@
Add missing ``__ctype_le/be__`` attributes for
:class:`~ctypes.c_float_complex` and :class:`~ctypes.c_double_complex`. Patch
by Sergey B Kirpichev.
+31 -14
View File
@@ -2232,6 +2232,31 @@ c_void_p_from_param_impl(PyObject *type, PyTypeObject *cls, PyObject *value)
return NULL;
}
static int
set_stginfo_ffi_type_pointer(StgInfo *stginfo, struct fielddesc *fmt)
{
if (!fmt->pffi_type->elements) {
stginfo->ffi_type_pointer = *fmt->pffi_type;
}
else {
/* From primitive types - only complex types have the elements
struct field as non-NULL (two element array). */
assert(fmt->pffi_type->type == FFI_TYPE_COMPLEX);
const size_t els_size = 2 * sizeof(ffi_type *);
stginfo->ffi_type_pointer.size = fmt->pffi_type->size;
stginfo->ffi_type_pointer.alignment = fmt->pffi_type->alignment;
stginfo->ffi_type_pointer.type = fmt->pffi_type->type;
stginfo->ffi_type_pointer.elements = PyMem_Malloc(els_size);
if (!stginfo->ffi_type_pointer.elements) {
PyErr_NoMemory();
return -1;
}
memcpy(stginfo->ffi_type_pointer.elements,
fmt->pffi_type->elements, els_size);
}
return 0;
}
static PyMethodDef c_void_p_methods[] = {C_VOID_P_FROM_PARAM_METHODDEF {0}};
static PyMethodDef c_char_p_methods[] = {C_CHAR_P_FROM_PARAM_METHODDEF {0}};
static PyMethodDef c_wchar_p_methods[] = {C_WCHAR_P_FROM_PARAM_METHODDEF {0}};
@@ -2276,8 +2301,10 @@ static PyObject *CreateSwappedType(ctypes_state *st, PyTypeObject *type,
Py_DECREF(result);
return NULL;
}
stginfo->ffi_type_pointer = *fmt->pffi_type;
if (set_stginfo_ffi_type_pointer(stginfo, fmt)) {
Py_DECREF(result);
return NULL;
}
stginfo->align = fmt->pffi_type->alignment;
stginfo->length = 0;
stginfo->size = fmt->pffi_type->size;
@@ -2372,18 +2399,8 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
if (!stginfo) {
goto error;
}
if (!fmt->pffi_type->elements) {
stginfo->ffi_type_pointer = *fmt->pffi_type;
}
else {
const size_t els_size = sizeof(fmt->pffi_type->elements);
stginfo->ffi_type_pointer.size = fmt->pffi_type->size;
stginfo->ffi_type_pointer.alignment = fmt->pffi_type->alignment;
stginfo->ffi_type_pointer.type = fmt->pffi_type->type;
stginfo->ffi_type_pointer.elements = PyMem_Malloc(els_size);
memcpy(stginfo->ffi_type_pointer.elements,
fmt->pffi_type->elements, els_size);
if (set_stginfo_ffi_type_pointer(stginfo, fmt)) {
goto error;
}
stginfo->align = fmt->pffi_type->alignment;
stginfo->length = 0;
+78
View File
@@ -792,6 +792,44 @@ D_get(void *ptr, Py_ssize_t size)
return PyComplex_FromDoubles(x[0], x[1]);
}
static PyObject *
D_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(double)));
Py_complex c = PyComplex_AsCComplex(value);
if (c.real == -1 && PyErr_Occurred()) {
return NULL;
}
#ifdef WORDS_BIGENDIAN
if (PyFloat_Pack8(c.real, ptr, 1)
|| PyFloat_Pack8(c.imag, ptr + sizeof(double), 1))
{
return NULL;
}
#else
if (PyFloat_Pack8(c.real, ptr, 0)
|| PyFloat_Pack8(c.imag, ptr + sizeof(double), 0))
{
return NULL;
}
#endif
_RET(value);
}
static PyObject *
D_get_sw(void *ptr, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(double)));
#ifdef WORDS_BIGENDIAN
return PyComplex_FromDoubles(PyFloat_Unpack8(ptr, 1),
PyFloat_Unpack8(ptr + sizeof(double), 1));
#else
return PyComplex_FromDoubles(PyFloat_Unpack8(ptr, 0),
PyFloat_Unpack8(ptr + sizeof(double), 0));
#endif
}
/* F: float complex */
static PyObject *
F_set(void *ptr, PyObject *value, Py_ssize_t size)
@@ -817,6 +855,44 @@ F_get(void *ptr, Py_ssize_t size)
return PyComplex_FromDoubles(x[0], x[1]);
}
static PyObject *
F_set_sw(void *ptr, PyObject *value, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(float)));
Py_complex c = PyComplex_AsCComplex(value);
if (c.real == -1 && PyErr_Occurred()) {
return NULL;
}
#ifdef WORDS_BIGENDIAN
if (PyFloat_Pack4(c.real, ptr, 1)
|| PyFloat_Pack4(c.imag, ptr + sizeof(float), 1))
{
return NULL;
}
#else
if (PyFloat_Pack4(c.real, ptr, 0)
|| PyFloat_Pack4(c.imag, ptr + sizeof(float), 0))
{
return NULL;
}
#endif
_RET(value);
}
static PyObject *
F_get_sw(void *ptr, Py_ssize_t size)
{
assert(NUM_BITS(size) || (size == 2*sizeof(float)));
#ifdef WORDS_BIGENDIAN
return PyComplex_FromDoubles(PyFloat_Unpack4(ptr, 1),
PyFloat_Unpack4(ptr + sizeof(float), 1));
#else
return PyComplex_FromDoubles(PyFloat_Unpack4(ptr, 0),
PyFloat_Unpack4(ptr + sizeof(float), 0));
#endif
}
/* G: long double complex */
static PyObject *
G_set(void *ptr, PyObject *value, Py_ssize_t size)
@@ -1602,7 +1678,9 @@ for base_code, base_c_type in [
#if defined(_Py_FFI_SUPPORT_C_COMPLEX)
if (Py_FFI_COMPLEX_AVAILABLE) {
TABLE_ENTRY(D, &ffi_type_complex_double);
TABLE_ENTRY_SW(D, &ffi_type_complex_double);
TABLE_ENTRY(F, &ffi_type_complex_float);
TABLE_ENTRY_SW(F, &ffi_type_complex_float);
TABLE_ENTRY(G, &ffi_type_complex_longdouble);
}
#endif