From 80fe44939c1a763385900acb8c3901640a4b0b03 Mon Sep 17 00:00:00 2001 From: Victor Stinner Date: Mon, 4 May 2026 16:17:24 +0200 Subject: [PATCH] gh-148675: Remove F and D formats from array and memoryview --- Doc/library/array.rst | 6 +-- Doc/whatsnew/3.15.rst | 6 +-- Lib/test/test_array.py | 20 +------- Lib/test/test_buffer.py | 12 ++--- Lib/test/test_memoryview.py | 6 +-- ...-05-04-16-26-33.gh-issue-148675.xZwXa6.rst | 2 + Modules/arraymodule.c | 21 ++------ Objects/memoryobject.c | 48 ------------------- 8 files changed, 17 insertions(+), 104 deletions(-) create mode 100644 Misc/NEWS.d/next/Library/2026-05-04-16-26-33.gh-issue-148675.xZwXa6.rst diff --git a/Doc/library/array.rst b/Doc/library/array.rst index 3cd107460596d1..02eb775f31effc 100644 --- a/Doc/library/array.rst +++ b/Doc/library/array.rst @@ -48,10 +48,6 @@ defined: +-----------+--------------------+-------------------+-----------------------+-------+ | ``'d'`` | double | float | 8 | | +-----------+--------------------+-------------------+-----------------------+-------+ -| ``'F'`` | float complex | complex | 8 | \(4) | -+-----------+--------------------+-------------------+-----------------------+-------+ -| ``'D'`` | double complex | complex | 16 | \(4) | -+-----------+--------------------+-------------------+-----------------------+-------+ | ``'Zf'`` | float complex | complex | 8 | \(4) | +-----------+--------------------+-------------------+-----------------------+-------+ | ``'Zd'`` | double complex | complex | 16 | \(4) | @@ -84,7 +80,7 @@ Notes: .. versionadded:: 3.15 (4) - Complex types (``F``, ``D``, ``Zf`` and ``Zd``) are available unconditionally, + Complex types (``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 diff --git a/Doc/whatsnew/3.15.rst b/Doc/whatsnew/3.15.rst index 2e408f258e2805..29576d15b3b181 100644 --- a/Doc/whatsnew/3.15.rst +++ b/Doc/whatsnew/3.15.rst @@ -671,8 +671,8 @@ Other language changes (Contributed by James Hilton-Balfe in :gh:`128335`.) * The class :class:`memoryview` now supports the :c:expr:`float complex` and - :c:expr:`double complex` C types: formatting characters ``'F'``/``'Zf'`` - and ``'D'``/``'Zd'`` respectively. + :c:expr:`double complex` C types: formatting characters ``'Zf'`` and ``'Zd'`` + respectively. (Contributed by Victor Stinner in :gh:`146151` and :gh:`148675`.) * Allow the *count* argument of :meth:`bytes.replace` to be a keyword. @@ -724,7 +724,7 @@ array ----- * Support the :c:expr:`float complex` and :c:expr:`double complex` C types: - formatting characters ``'F'``/``'Zf'`` and ``'D'``/``'Zd'`` respectively. + formatting characters ``'Zf'`` and ``'Zd'`` respectively. (Contributed by Victor Stinner in :gh:`146151` and :gh:`148675`.) * Support half-floats (16-bit IEEE 754 binary interchange format): formatting diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index 54ecc886917dc7..f7fa56a6e4bfa0 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -33,7 +33,7 @@ def __init__(self, typecode, newarg=None): typecodes = ( 'u', 'w', 'b', 'B', 'h', 'H', 'i', 'I', 'l', 'L', - 'f', 'd', 'q', 'Q', 'F', 'D', 'e', 'Zf', 'Zd') + 'f', 'd', 'q', 'Q', 'e', 'Zf', 'Zd') class MiscTest(unittest.TestCase): @@ -210,14 +210,6 @@ def test_numbers(self): [9006104071832581.0, float('inf'), float('-inf'), -0.0]), (['d'], IEEE_754_DOUBLE_BE, '>dddd', [9006104071832581.0, float('inf'), float('-inf'), -0.0]), - (['F'], IEEE_754_FLOAT_COMPLEX_LE, 'FFFF', - [16711938.0j, float('inf'), complex('1-infj'), -0.0]), - (['D'], IEEE_754_DOUBLE_COMPLEX_LE, 'DDDD', - [9006104071832581.0j, float('inf'), complex('1-infj'), -0.0]), (['Zf'], IEEE_754_FLOAT_COMPLEX_LE, 'ZfZfZfZf', @@ -1645,18 +1637,10 @@ def test_alloc_overflow(self): class ComplexFloatTest(CFPTest, unittest.TestCase): - typecode = 'F' - minitemsize = 8 - -class ComplexDoubleTest(CFPTest, unittest.TestCase): - typecode = 'D' - minitemsize = 16 - -class ComplexZfFloatTest(CFPTest, unittest.TestCase): typecode = 'Zf' minitemsize = 8 -class ComplexZdDoubleTest(CFPTest, unittest.TestCase): +class ComplexDoubleTest(CFPTest, unittest.TestCase): typecode = 'Zd' minitemsize = 16 diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 21a3d0b3422ad2..f08faa14b24c64 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -67,7 +67,7 @@ 'h':0, 'H':0, 'i':0, 'I':0, 'l':0, 'L':0, 'n':0, 'N':0, 'e':0, 'f':0, 'd':0, 'P':0, - 'F':0, 'D':0, 'Zf':0, 'Zd':0, + 'Zf':0, 'Zd':0, } # NumPy does not have 'n' or 'N': @@ -94,8 +94,6 @@ 'q':(-(1<<63), 1<<63), 'Q':(0, 1<<64), 'e':(-65519, 65520), 'f':(-(1<<63), 1<<63), 'd':(-(1<<1023), 1<<1023), - 'F':(-(1<<63), 1<<63), - 'D':(-(1<<1023), 1<<1023), 'Zf':(-(1<<63), 1<<63), 'Zd':(-(1<<1023), 1<<1023), } @@ -112,9 +110,9 @@ def native_type_range(fmt): lh = (-(1<<63), 1<<63) elif fmt == 'd': lh = (-(1<<1023), 1<<1023) - elif fmt in ('F', 'Zf'): + elif fmt == 'Zf': lh = (-(1<<63), 1<<63) - elif fmt in ('D', 'Zd'): + elif fmt == 'Zd': lh = (-(1<<1023), 1<<1023) else: for exp in (128, 127, 64, 63, 32, 31, 16, 15, 8, 7): @@ -184,7 +182,7 @@ def randrange_fmt(mode, char, obj): if char in 'efd': x = struct.pack(char, x) x = struct.unpack(char, x)[0] - if char in ('F', 'D', 'Zf', 'Zd'): + if char in ('Zf', 'Zd'): y = randrange(*fmtdict[mode][char]) x = complex(x, y) x = struct.pack(char, x) @@ -3055,7 +3053,7 @@ def test_memoryview_assign(self): continue m2 = m1.cast(fmt) lo, hi = _range - if fmt in ("d", "f", "D", "F", "Zd", "Zf"): + if fmt in ("d", "f", "Zd", "Zf"): lo, hi = -2**1024, 2**1024 if fmt != 'P': # PyLong_AsVoidPtr() accepts negative numbers self.assertRaises(ValueError, m2.__setitem__, 0, lo-1) diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py index f777ba583c5c06..f71b6f53486509 100644 --- a/Lib/test/test_memoryview.py +++ b/Lib/test/test_memoryview.py @@ -637,7 +637,7 @@ def check_equal(view, is_equal): check_equal(m, True) # Test complex formats - for complex_format in ('F', 'D', 'Zf', 'Zd'): + for complex_format in ('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) @@ -719,10 +719,6 @@ def test_half_float(self): def test_complex_types(self): float_complex_data = struct.pack('FFF', 0.0, -1.5j, 1+2j) double_complex_data = struct.pack('DDD', 0.0, -1.5j, 1+2j) - float_complex_view = memoryview(float_complex_data).cast('F') - 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) diff --git a/Misc/NEWS.d/next/Library/2026-05-04-16-26-33.gh-issue-148675.xZwXa6.rst b/Misc/NEWS.d/next/Library/2026-05-04-16-26-33.gh-issue-148675.xZwXa6.rst new file mode 100644 index 00000000000000..6ba2e7aabf9ec8 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-05-04-16-26-33.gh-issue-148675.xZwXa6.rst @@ -0,0 +1,2 @@ +Remove ``F`` and ``D`` formats from :mod:`array` and :class:`memoryview`. +Patch by Victor Stinner. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 56a2a98fe42731..a8347123e6496a 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -782,8 +782,6 @@ static const struct arraydescr descriptors[] = { {"e", sizeof(short), e_getitem, e_setitem, NULL, 0, 0}, {"f", sizeof(float), f_getitem, f_setitem, NULL, 0, 0}, {"d", sizeof(double), d_getitem, d_setitem, NULL, 0, 0}, - {"F", 2*sizeof(float), cf_getitem, cf_setitem, NULL, 0, 0}, - {"D", 2*sizeof(double), cd_getitem, cd_setitem, NULL, 0, 0}, {"Zf", 2*sizeof(float), cf_getitem, cf_setitem, NULL, 0, 0}, {"Zd", 2*sizeof(double), cd_getitem, cd_setitem, NULL, 0, 0}, {NULL, 0, 0, 0, 0, 0, 0} /* Sentinel */ @@ -1612,9 +1610,7 @@ array_array_byteswap_impl(arrayobject *self) } break; case 8: - if (strcmp(self->ob_descr->typecode, "F") != 0 - && strcmp(self->ob_descr->typecode, "Zf") != 0) - { + if (strcmp(self->ob_descr->typecode, "Zf") != 0) { for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 8) { char p0 = p[0]; char p1 = p[1]; @@ -1648,8 +1644,7 @@ array_array_byteswap_impl(arrayobject *self) } break; case 16: - assert(strcmp(self->ob_descr->typecode, "D") == 0 - || strcmp(self->ob_descr->typecode, "Zd") == 0); + assert(strcmp(self->ob_descr->typecode, "Zd") == 0); for (p = self->ob_item, i = Py_SIZE(self); --i >= 0; p += 8) { char t0 = p[0]; char t1 = p[1]; @@ -2159,14 +2154,6 @@ typecode_to_mformat_code(const char *typecode) case 'd': return _PY_FLOAT_BIG_ENDIAN ? IEEE_754_DOUBLE_BE : IEEE_754_DOUBLE_LE; - case 'F': - return _PY_FLOAT_BIG_ENDIAN ? \ - IEEE_754_FLOAT_COMPLEX_BE : IEEE_754_FLOAT_COMPLEX_LE; - - case 'D': - return _PY_FLOAT_BIG_ENDIAN ? \ - IEEE_754_DOUBLE_COMPLEX_BE : IEEE_754_DOUBLE_COMPLEX_LE; - case 'Z': { switch (typecode[1]) { case 'f': @@ -3167,7 +3154,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds) } Py_XDECREF(it); PyErr_SetString(PyExc_ValueError, - "bad typecode (must be b, B, u, w, h, H, i, I, l, L, q, Q, e, f, d, F, D, Zf or Zd)"); + "bad typecode (must be b, B, u, w, h, H, i, I, l, L, q, Q, e, f, d, Zf or Zd)"); return NULL; } @@ -3205,8 +3192,6 @@ The following type codes are defined:\n\ 'e' 16-bit IEEE floats 2\n\ 'f' floating-point 4\n\ 'd' floating-point 8\n\ - 'F' float complex 8\n\ - 'D' double complex 16\n\ 'Zf' float complex 8\n\ 'Zd' double complex 16\n\ \n\ diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index 2c2f85ebf6acc0..900db864621a84 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -1217,8 +1217,6 @@ get_native_fmtchar(const char **result, const char *fmt) case 'f': size = sizeof(float); break; case 'd': size = sizeof(double); break; case 'e': size = sizeof(float) / 2; break; - case 'F': size = 2*sizeof(float); break; - case 'D': size = 2*sizeof(double); break; case '?': size = sizeof(_Bool); break; case 'P': size = sizeof(void *); break; case 'Z': { @@ -1284,8 +1282,6 @@ get_native_fmtstr(const char *fmt) case 'f': RETURN("f"); case 'd': RETURN("d"); case 'e': RETURN("e"); - case 'F': RETURN("F"); - case 'D': RETURN("D"); case 'Z': { switch (fmt[1]) { case 'f': RETURN("Zf"); @@ -1865,16 +1861,6 @@ unpack_single(PyMemoryViewObject *self, const char *ptr, const char *fmt) case 'e': d[0] = PyFloat_Unpack2(ptr, endian); goto convert_double; /* complexes */ - case 'F': - d[0] = PyFloat_Unpack4(ptr, endian); - d[1] = PyFloat_Unpack4(ptr + sizeof(float), endian); - goto convert_double_complex; - - case 'D': - d[0] = PyFloat_Unpack8(ptr, endian); - d[1] = PyFloat_Unpack8(ptr + sizeof(double), endian); - goto convert_double_complex; - case 'Z': { switch (fmt[1]) { case 'f': @@ -2055,24 +2041,6 @@ pack_single(PyMemoryViewObject *self, char *ptr, PyObject *item, const char *fmt break; /* complexes */ - case 'F': case 'D': - c = PyComplex_AsCComplex(item); - if (c.real == -1.0 && PyErr_Occurred()) { - goto err_occurred; - } - CHECK_RELEASED_INT_AGAIN(self); - if (fmt[0] == 'D') { - double x[2] = {c.real, c.imag}; - - memcpy(ptr, &x, sizeof(x)); - } - else { - float x[2] = {(float)c.real, (float)c.imag}; - - memcpy(ptr, &x, sizeof(x)); - } - break; - case 'Z': { switch (fmt[1]) { case 'f': case 'd': @@ -3138,22 +3106,6 @@ unpack_cmp(const char *p, const char *q, const char *fmt, } /* complexes */ - case 'F': - { - float x[2], y[2]; - - memcpy(&x, p, sizeof(x)); - memcpy(&y, q, sizeof(y)); - return (x[0] == y[0]) && (x[1] == y[1]); - } - case 'D': - { - double x[2], y[2]; - - memcpy(&x, p, sizeof(x)); - memcpy(&y, q, sizeof(y)); - return (x[0] == y[0]) && (x[1] == y[1]); - } case 'Z': { switch (fmt[1]) { case 'f':