https://github.com/python/cpython/commit/f3be08aa6f6f8fbb48b532dc75845be5b3c83a8b
commit: f3be08aa6f6f8fbb48b532dc75845be5b3c83a8b
branch: main
author: PhysicistJohn <[email protected]>
committer: vstinner <[email protected]>
date: 2026-08-11T15:41:05+02:00
summary:
gh-154568: Fix array unpickling of little-endian float16 (#154569)
Fix array._array_reconstructor() ignoring requested byte order for float16.
The slow-path decoder for IEEE_754_FLOAT16_LE/BE computed the
byte-order flag by comparing mformat_code against IEEE_754_FLOAT_LE
(the 32-bit float constant) instead of IEEE_754_FLOAT16_LE. Since the
float16 mformat codes are never equal to that constant, the comparison
was always false, so the decoder always treated input as big-endian
regardless of what was requested.
Adds a regression test.
files:
A
Misc/NEWS.d/next/Library/2026-07-23-21-00-00.gh-issue-154568.float16-reconstructor.rst
M Lib/test/test_array.py
M Modules/arraymodule.c
diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
index b5f6603defde5c..d9b608fb23d0c6 100755
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -209,6 +209,10 @@ def test_numbers(self):
[-1<<63, (1<<63)-1, 0]),
(['l'], SIGNED_INT64_BE, '>qqq',
[-1<<63, (1<<63)-1, 0]),
+ (['e'], IEEE_754_FLOAT16_LE, '<eeee',
+ [1.0, float('inf'), float('-inf'), -0.0]),
+ (['e'], IEEE_754_FLOAT16_BE, '>eeee',
+ [1.0, float('inf'), float('-inf'), -0.0]),
(['f'], IEEE_754_FLOAT_LE, '<ffff',
[16711938.0, float('inf'), float('-inf'), -0.0]),
(['f'], IEEE_754_FLOAT_BE, '>ffff',
@@ -239,6 +243,16 @@ def test_numbers(self):
self.assertEqual(a, b,
msg="{0!r} != {1!r}; testcase={2!r}".format(a, b,
testcase))
+ def test_float16_endianness(self):
+ # gh-154568: array_reconstructor() slow-path decoder for
+ # IEEE_754_FLOAT16_LE ignored the encoding.
+ le_bytes = struct.pack('<e', 1.5)
+ be_bytes = struct.pack('>e', 1.5)
+ b_le = array_reconstructor(array.array, 'd', IEEE_754_FLOAT16_LE,
le_bytes)
+ b_be = array_reconstructor(array.array, 'd', IEEE_754_FLOAT16_BE,
be_bytes)
+ self.assertEqual(b_le.tolist(), [1.5])
+ self.assertEqual(b_be.tolist(), [1.5])
+
def test_unicode(self):
teststr = "Bonne Journ\xe9e \U0002030a\U00020347"
testcases = (
diff --git
a/Misc/NEWS.d/next/Library/2026-07-23-21-00-00.gh-issue-154568.float16-reconstructor.rst
b/Misc/NEWS.d/next/Library/2026-07-23-21-00-00.gh-issue-154568.float16-reconstructor.rst
new file mode 100644
index 00000000000000..85c0c81231b6ae
--- /dev/null
+++
b/Misc/NEWS.d/next/Library/2026-07-23-21-00-00.gh-issue-154568.float16-reconstructor.rst
@@ -0,0 +1 @@
+Fix :mod:`array` unpickling of little-endian float16.
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 68486c66575933..39a399d7a49cf5 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -2281,7 +2281,7 @@ array__array_reconstructor_impl(PyObject *module,
PyTypeObject *arraytype,
case IEEE_754_FLOAT16_LE:
case IEEE_754_FLOAT16_BE: {
Py_ssize_t i;
- int le = (mformat_code == IEEE_754_FLOAT_LE) ? 1 : 0;
+ int le = (mformat_code == IEEE_754_FLOAT16_LE) ? 1 : 0;
Py_ssize_t itemcount = Py_SIZE(items) / 2;
const char *memstr = PyBytes_AS_STRING(items);
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]