Skip to content
Draft
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: 5 additions & 1 deletion Doc/library/array.rst
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ defined:
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'D'`` | double complex | complex | 16 | \(4) |
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'Zf'`` | float complex | complex | 8 | \(4) |
+-----------+--------------------+-------------------+-----------------------+-------+
| ``'Zd'`` | double complex | complex | 16 | \(4) |
+-----------+--------------------+-------------------+-----------------------+-------+


Notes:
Expand Down Expand Up @@ -80,7 +84,7 @@ Notes:
.. versionadded:: 3.15

(4)
Complex types (``F`` and ``D``) are available unconditionally,
Complex types (``F``, ``D``, ``Zf`` and ``Zd``) are available unconditionally,
regardless on support for complex types (the Annex G of the C11 standard)
by the C compiler.
As specified in the C11 standard, each complex type is represented by a
Expand Down
9 changes: 8 additions & 1 deletion Doc/library/struct.rst
Original file line number Diff line number Diff line change
Expand Up @@ -264,6 +264,10 @@ platform-dependent.
+--------+--------------------------+--------------------+----------------+------------+
| ``D`` | :c:expr:`double complex` | complex | 16 | \(10) |
+--------+--------------------------+--------------------+----------------+------------+
| ``Zf`` | :c:expr:`float complex` | complex | 8 | \(10) |
+--------+--------------------------+--------------------+----------------+------------+
| ``Zd`` | :c:expr:`double complex` | complex | 16 | \(10) |
+--------+--------------------------+--------------------+----------------+------------+
| ``s`` | :c:expr:`char[]` | bytes | | \(9) |
+--------+--------------------------+--------------------+----------------+------------+
| ``p`` | :c:expr:`char[]` | bytes | | \(8) |
Expand All @@ -280,6 +284,9 @@ platform-dependent.
.. versionchanged:: 3.14
Added support for the ``'F'`` and ``'D'`` formats.

.. versionchanged:: next
Added support for the ``'Zf'`` and ``'Zd'`` formats.

.. seealso::

The :mod:`array` and :ref:`ctypes <ctypes-fundamental-data-types>` modules,
Expand Down Expand Up @@ -368,7 +375,7 @@ Notes:
For the ``'F'`` and ``'D'`` format characters, the packed representation uses
the IEEE 754 binary32 and binary64 format for components of the complex
number, regardless of the floating-point format used by the platform.
Note that complex types (``F`` and ``D``) are available unconditionally,
Note that complex types (``F``/``Zf`` and ``D``/``Zd``) are available unconditionally,
despite complex types being an optional feature in C.
As specified in the C11 standard, each complex type is represented by a
two-element C array containing, respectively, the real and imaginary parts.
Expand Down
2 changes: 1 addition & 1 deletion Doc/whatsnew/3.15.rst
Original file line number Diff line number Diff line change
Expand Up @@ -679,7 +679,7 @@ array
-----

* Support the :c:expr:`float complex` and :c:expr:`double complex` C types:
formatting characters ``'F'`` and ``'D'`` respectively.
formatting characters ``'F'``/``'Zd'`` and ``'D'``/``'Zd'`` respectively.
(Contributed by Sergey B Kirpichev in :gh:`146151`.)

* Support half-floats (16-bit IEEE 754 binary interchange format): formatting
Expand Down
2 changes: 1 addition & 1 deletion Lib/test/test_array.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ def test_array_is_sequence(self):
def test_bad_constructor(self):
self.assertRaises(TypeError, array.array)
self.assertRaises(TypeError, array.array, spam=42)
self.assertRaises(TypeError, array.array, 'xx')
self.assertRaises(ValueError, array.array, 'xx')
self.assertRaises(ValueError, array.array, 'x')

@support.cpython_only
Expand Down
2 changes: 2 additions & 0 deletions Lib/test/test_ctypes/test_c_simple_type_meta.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,8 @@ class F(metaclass=PyCSimpleType):
if not MS_WINDOWS:
expected_type_chars.remove('X')
self.assertIn("'" + ''.join(expected_type_chars) + "'", message)
if hasattr(ctypes, 'c_float_complex'):
self.assertIn("'Zf', 'Zd', 'Zg'", message)

def test_creating_pointer_in_dunder_init_3(self):
"""Check if interfcase subclasses properly creates according internal
Expand Down
14 changes: 13 additions & 1 deletion Lib/test/test_ctypes/test_numbers.py
Original file line number Diff line number Diff line change
Expand Up @@ -119,8 +119,20 @@ def test_floats(self):
@unittest.skipUnless(hasattr(ctypes, "c_double_complex"),
"requires C11 complex type")
def test_complex(self):
class c_double_complex2(ctypes._SimpleCData):
_type_ = "Zd"
ctypes._check_size(c_double_complex2)

class c_float_complex2(ctypes._SimpleCData):
_type_ = "Zf"
ctypes._check_size(c_float_complex2)

class c_longdouble_complex2(ctypes._SimpleCData):
_type_ = "Zg"

for t in [ctypes.c_double_complex, ctypes.c_float_complex,
ctypes.c_longdouble_complex]:
ctypes.c_longdouble_complex,
c_double_complex2, c_float_complex2, c_longdouble_complex2]:
self.assertEqual(t(1).value, 1+0j)
self.assertEqual(t(1.0).value, 1+0j)
self.assertEqual(t(1+0.125j).value, 1+0.125j)
Expand Down
6 changes: 5 additions & 1 deletion Lib/test/test_memoryview.py
Original file line number Diff line number Diff line change
Expand Up @@ -637,7 +637,7 @@ def check_equal(view, is_equal):
check_equal(m, True)

# Test complex formats
for complex_format in 'FD':
for complex_format in ('F', 'D', 'Zf', 'Zd'):
with self.subTest(format=complex_format):
data = struct.pack(complex_format * 3, 1.0, 2.0, float('nan'))
m = memoryview(data).cast(complex_format)
Expand Down Expand Up @@ -723,6 +723,10 @@ def test_complex_types(self):
double_complex_view = memoryview(double_complex_data).cast('D')
self.assertEqual(float_complex_view.nbytes * 2, double_complex_view.nbytes)
self.assertListEqual(float_complex_view.tolist(), double_complex_view.tolist())
float_complex_view = memoryview(float_complex_data).cast('Zf')
double_complex_view = memoryview(double_complex_data).cast('Zd')
self.assertEqual(float_complex_view.nbytes * 2, double_complex_view.nbytes)
self.assertListEqual(float_complex_view.tolist(), double_complex_view.tolist())

def test_memoryview_hex(self):
# Issue #9951: memoryview.hex() segfaults with non-contiguous buffers.
Expand Down
6 changes: 5 additions & 1 deletion Lib/test/test_struct.py
Original file line number Diff line number Diff line change
Expand Up @@ -995,7 +995,11 @@ def test_c_complex_round_trip(self):
values = [complex(*_) for _ in combinations([1, -1, 0.0, -0.0, 2,
-3, INF, -INF, NAN], 2)]
for z in values:
for f in ['F', 'D', '>F', '>D', '<F', '<D']:
for f in [
'F', 'D', 'Zf', 'Zd',
'>F', '>D', '>Zf', '>Zd',
'<F', '<D', '<Zf', '<Zd',
]:
with self.subTest(z=z, format=f):
round_trip = struct.unpack(f, struct.pack(f, z))[0]
self.assertComplexesAreIdentical(z, round_trip)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
:mod:`array`, :mod:`ctypes`, :mod:`struct`: Add support for ``Zd`` and ``Zf``
format for double complex and float complex. Add also support for ``Zg``
format for long double complex to :mod:`ctypes`. Patch by Victor Stinner.
31 changes: 18 additions & 13 deletions Modules/_ctypes/_ctypes.c
Original file line number Diff line number Diff line change
Expand Up @@ -2315,7 +2315,6 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
{
PyObject *proto;
const char *proto_str;
Py_ssize_t proto_len;
PyMethodDef *ml;
struct fielddesc *fmt;

Expand All @@ -2333,27 +2332,33 @@ PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds)
return -1;
}
if (PyUnicode_Check(proto)) {
proto_str = PyUnicode_AsUTF8AndSize(proto, &proto_len);
proto_str = PyUnicode_AsUTF8(proto);
if (!proto_str)
goto error;
} else {
PyErr_SetString(PyExc_TypeError,
"class must define a '_type_' string attribute");
goto error;
}
if (proto_len != 1) {
PyErr_SetString(PyExc_ValueError,
"class must define a '_type_' attribute "
"which must be a string of length 1");
goto error;
}
fmt = _ctypes_get_fielddesc(proto_str);
if (!fmt) {
PyErr_Format(PyExc_AttributeError,
"class must define a '_type_' attribute which must be\n"
"a single character string containing one of the\n"
"supported types: '%s'.",
_ctypes_get_simple_type_chars());
const char *complex_formats = _ctypes_get_complex_type_formats();
if (complex_formats) {
PyErr_Format(PyExc_AttributeError,
"class must define a '_type_' attribute which must be\n"
"a single character string containing one of the\n"
"supported types: '%s', or one of these strings:\n"
"%s.",
_ctypes_get_simple_type_chars(),
complex_formats);
}
else {
PyErr_Format(PyExc_AttributeError,
"class must define a '_type_' attribute which must be\n"
"a single character string containing one of the\n"
"supported types: '%s'.\n",
_ctypes_get_simple_type_chars());
}
goto error;
}

Expand Down
6 changes: 3 additions & 3 deletions Modules/_ctypes/callproc.c
Original file line number Diff line number Diff line change
Expand Up @@ -641,9 +641,9 @@ union result {
double d;
float f;
void *p;
double D[2];
float F[2];
long double G[2];
double Zd[2];
float Zf[2];
long double Zg[2];
};

struct argument {
Expand Down
Loading
Loading