Skip to content

Commit 40795f2

Browse files
skirpichevvstinner
andauthored
gh-121249: Deprecate using F/D type codes in the struct module (#152309)
Co-authored-by: Victor Stinner <vstinner@python.org>
1 parent 9e10f14 commit 40795f2

9 files changed

Lines changed: 72 additions & 19 deletions

File tree

Doc/deprecations/pending-removal-in-3.21.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,9 @@ Pending removal in Python 3.21
1717
are not generated by the parser or accepted by the code generator.
1818
* The ``dims`` property of ``ast.Tuple`` will be removed in Python 3.21. Use
1919
the ``ast.Tuple.elts`` property instead.
20+
21+
* :mod:`struct`:
22+
23+
* Soft-deprecated since Python 3.15, using ``'F'`` and ``'D'`` type codes are now
24+
deprecated. These codes will be removed in Python 3.21. Use instead
25+
two-letter forms ``'Zf'`` and ``'Zd'``.

Doc/deprecations/soft-deprecations.rst

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,3 @@ There are no plans to remove :term:`soft deprecated` APIs.
1919

2020
(Contributed by Gregory P. Smith in :gh:`86519` and
2121
Hugo van Kemenade in :gh:`148100`.)
22-
23-
* Using ``'F'`` and ``'D'`` format type codes of the :mod:`struct` module
24-
now are :term:`soft deprecated` in favor of two-letter forms ``'Zf'``
25-
and ``'Zd'``.
26-
(Contributed by Sergey B Kirpichev in :gh:`121249`.)

Doc/library/struct.rst

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,9 @@ platform-dependent.
283283

284284
.. versionchanged:: 3.15
285285
Added support for the ``'Zf'`` and ``'Zd'`` formats.
286-
``'F'`` and ``'D'`` formats are :term:`soft deprecated`.
286+
287+
.. versionchanged:: 3.16
288+
``'F'`` and ``'D'`` formats are deprecated.
287289

288290
.. seealso::
289291

Doc/whatsnew/3.16.rst

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,13 @@ New deprecations
550550
3.9, now issues a deprecation warning on use. This property is slated for
551551
removal in 3.21. Use ``ast.Tuple.elts`` instead.
552552

553+
* :mod:`struct`:
554+
555+
* Soft-deprecated since Python 3.15, using ``'F'`` and ``'D'`` type codes are now
556+
deprecated. These codes will be removed in Python 3.21. Use instead
557+
two-letter forms ``'Zf'`` and ``'Zd'``.
558+
(Contributed by Sergey B Kirpichev in :gh:`121249`.)
559+
553560
.. Add deprecations above alphabetically, not here at the end.
554561
555562
.. include:: ../deprecations/pending-removal-in-3.17.rst

Lib/test/test_ctypes/test_byteswap.py

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -178,14 +178,14 @@ def test_endian_float_complex(self):
178178
self.assertIs(c_float_complex.__ctype_le__.__ctype_be__,
179179
c_float_complex)
180180
s = c_float_complex(math.pi+1j)
181-
self.assertEqual(bin(struct.pack("F", math.pi+1j)), bin(s))
181+
self.assertEqual(bin(struct.pack("Zf", math.pi+1j)), bin(s))
182182
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
183183
s = c_float_complex.__ctype_le__(math.pi+1j)
184184
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
185-
self.assertEqual(bin(struct.pack("<F", math.pi+1j)), bin(s))
185+
self.assertEqual(bin(struct.pack("<Zf", math.pi+1j)), bin(s))
186186
s = c_float_complex.__ctype_be__(math.pi+1j)
187187
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
188-
self.assertEqual(bin(struct.pack(">F", math.pi+1j)), bin(s))
188+
self.assertEqual(bin(struct.pack(">Zf", math.pi+1j)), bin(s))
189189

190190
@unittest.skipUnless(hasattr(ctypes, 'c_double_complex'), "No complex types")
191191
def test_endian_double_complex(self):
@@ -199,14 +199,14 @@ def test_endian_double_complex(self):
199199
self.assertIs(c_double_complex.__ctype_le__.__ctype_be__,
200200
c_double_complex)
201201
s = c_double_complex(math.pi+1j)
202-
self.assertEqual(bin(struct.pack("D", math.pi+1j)), bin(s))
202+
self.assertEqual(bin(struct.pack("Zd", math.pi+1j)), bin(s))
203203
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
204204
s = c_double_complex.__ctype_le__(math.pi+1j)
205205
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
206-
self.assertEqual(bin(struct.pack("<D", math.pi+1j)), bin(s))
206+
self.assertEqual(bin(struct.pack("<Zd", math.pi+1j)), bin(s))
207207
s = c_double_complex.__ctype_be__(math.pi+1j)
208208
self.assertAlmostEqual(s.value, math.pi+1j, places=6)
209-
self.assertEqual(bin(struct.pack(">D", math.pi+1j)), bin(s))
209+
self.assertEqual(bin(struct.pack(">Zd", math.pi+1j)), bin(s))
210210

211211
def test_endian_other(self):
212212
self.assertIs(c_byte.__ctype_le__, c_byte)

Lib/test/test_memoryview.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,8 +717,8 @@ def test_half_float(self):
717717
self.assertListEqual(half_view.tolist(), float_view.tolist())
718718

719719
def test_complex_types(self):
720-
float_complex_data = struct.pack('FFF', 0.0, -1.5j, 1+2j)
721-
double_complex_data = struct.pack('DDD', 0.0, -1.5j, 1+2j)
720+
float_complex_data = struct.pack('ZfZfZf', 0.0, -1.5j, 1+2j)
721+
double_complex_data = struct.pack('ZdZdZd', 0.0, -1.5j, 1+2j)
722722
float_complex_view = memoryview(float_complex_data).cast('Zf')
723723
double_complex_view = memoryview(double_complex_data).cast('Zd')
724724
self.assertEqual(float_complex_view.nbytes * 2, double_complex_view.nbytes)

Lib/test/test_struct.py

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
import unittest
88
import struct
99
import sys
10+
import warnings
1011
import weakref
1112

1213
from test import support
@@ -995,14 +996,26 @@ def test_c_complex_round_trip(self):
995996
values = [complex(*_) for _ in combinations([1, -1, 0.0, -0.0, 2,
996997
-3, INF, -INF, NAN], 2)]
997998
for z in values:
998-
for f in [
999-
'F', 'D', 'Zf', 'Zd',
1000-
'>F', '>D', '>Zf', '>Zd',
1001-
'<F', '<D', '<Zf', '<Zd',
1002-
]:
999+
for f in ['Zf', 'Zd', '>Zf', '>Zd', '<Zf', '<Zd']:
10031000
with self.subTest(z=z, format=f):
10041001
round_trip = struct.unpack(f, struct.pack(f, z))[0]
10051002
self.assertComplexesAreIdentical(z, round_trip)
1003+
z = 1+1j
1004+
for fmt in ['F', 'D', '>F', '>D', '<F', '<D']:
1005+
with self.subTest(format=fmt):
1006+
with warnings.catch_warnings():
1007+
warnings.simplefilter("error", DeprecationWarning)
1008+
self.assertRaises(DeprecationWarning, struct.pack, fmt, z)
1009+
with warnings.catch_warnings():
1010+
with self.assertWarns(DeprecationWarning):
1011+
b = struct.pack(fmt, z)
1012+
1013+
with warnings.catch_warnings():
1014+
warnings.simplefilter("error", DeprecationWarning)
1015+
self.assertRaises(DeprecationWarning, struct.unpack, fmt, b)
1016+
with self.assertWarns(DeprecationWarning):
1017+
round_trip = struct.unpack(fmt, b)[0]
1018+
self.assertComplexesAreIdentical(z, round_trip)
10061019

10071020
@unittest.skipIf(
10081021
support.is_android or support.is_apple_mobile,
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Deprecate using ``'F'`` and ``'D'`` type codes in the :mod:`struct` module.

Modules/_struct.c

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1697,6 +1697,21 @@ prepare_s(PyStructObject *self, PyObject *format)
16971697
if (e == NULL)
16981698
return -1;
16991699

1700+
if (strcmp(e->format, "F") == 0) {
1701+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
1702+
"The 'F' type code is deprecated, use 'Zf'", 1))
1703+
{
1704+
return -1;
1705+
}
1706+
}
1707+
if (strcmp(e->format, "D") == 0) {
1708+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
1709+
"The 'D' type code is deprecated, use 'Zd'", 1))
1710+
{
1711+
return -1;
1712+
}
1713+
}
1714+
17001715
switch (c) {
17011716
case 's': _Py_FALLTHROUGH;
17021717
case 'p':
@@ -2065,6 +2080,20 @@ s_unpack_internal(PyStructObject *soself, const char *startfrom,
20652080
}
20662081
v = PyBytes_FromStringAndSize(res + 1, n);
20672082
} else {
2083+
if (strcmp(e->format, "F") == 0) {
2084+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
2085+
"The 'F' type code is deprecated, use 'Zf'", 1))
2086+
{
2087+
goto fail;
2088+
}
2089+
}
2090+
if (strcmp(e->format, "D") == 0) {
2091+
if (PyErr_WarnEx(PyExc_DeprecationWarning,
2092+
"The 'D' type code is deprecated, use 'Zd'", 1))
2093+
{
2094+
goto fail;
2095+
}
2096+
}
20682097
v = e->unpack(state, res, e);
20692098
}
20702099
if (v == NULL)

0 commit comments

Comments
 (0)