diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index c931be6df5fdaa..71f4f586b97489 100755 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -254,20 +254,24 @@ def test_float16_endianness(self): self.assertEqual(b_be.tolist(), [1.5]) def test_unicode(self): - teststr = "Bonne Journ\xe9e \U0002030a\U00020347" testcases = ( (UTF16_LE, "UTF-16-LE"), (UTF16_BE, "UTF-16-BE"), (UTF32_LE, "UTF-32-LE"), (UTF32_BE, "UTF-32-BE") ) - for testcase in testcases: - mformat_code, encoding = testcase - a = array.array('w', teststr) - b = array_reconstructor( - array.array, 'w', mformat_code, teststr.encode(encoding)) - self.assertEqual(a, b, - msg="{0!r} != {1!r}; testcase={2!r}".format(a, b, testcase)) + # An even and an odd length; odd lengths were wrongly rejected. + for teststr in ("Bonne Journ\xe9e \U0002030a\U00020347", + "Bonne Journ\xe9e \U0002030a\U00020347!"): + for testcase in testcases: + mformat_code, encoding = testcase + a = array.array('w', teststr) + b = array_reconstructor( + array.array, 'w', mformat_code, teststr.encode(encoding)) + self.assertEqual( + a, b, + msg="{0!r} != {1!r}; testcase={2!r}".format( + a, b, testcase)) class BaseTest: diff --git a/Misc/NEWS.d/next/Library/2026-08-15-15-00-00.gh-issue-155850.ArrUtf.rst b/Misc/NEWS.d/next/Library/2026-08-15-15-00-00.gh-issue-155850.ArrUtf.rst new file mode 100644 index 00000000000000..9da84b3f1ccfe4 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2026-08-15-15-00-00.gh-issue-155850.ArrUtf.rst @@ -0,0 +1,3 @@ +Fix :mod:`array` unpickling of an odd-length ``'w'`` array pickled on a +machine of the opposite endianness; a wrong item size for the UTF-16 and +UTF-32 machine formats made it raise :exc:`ValueError`. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index a0181c083a6036..ebc8bfd667c2a8 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -2050,10 +2050,10 @@ static const struct mformatdescr { {4, 0, 1}, /* 15: IEEE_754_FLOAT_BE */ {8, 0, 0}, /* 16: IEEE_754_DOUBLE_LE */ {8, 0, 1}, /* 17: IEEE_754_DOUBLE_BE */ - {4, 0, 0}, /* 18: UTF16_LE */ - {4, 0, 1}, /* 19: UTF16_BE */ - {8, 0, 0}, /* 20: UTF32_LE */ - {8, 0, 1}, /* 21: UTF32_BE */ + {2, 0, 0}, /* 18: UTF16_LE */ + {2, 0, 1}, /* 19: UTF16_BE */ + {4, 0, 0}, /* 20: UTF32_LE */ + {4, 0, 1}, /* 21: UTF32_BE */ {8, 0, 0}, /* 22: IEEE_754_FLOAT_COMPLEX_LE */ {8, 0, 1}, /* 23: IEEE_754_FLOAT_COMPLEX_BE */ {16, 0, 0}, /* 24: IEEE_754_DOUBLE_COMPLEX_LE */