From 597ae6ae08e21b79aa02cb8099092b4e82ca2d31 Mon Sep 17 00:00:00 2001 From: jamie2779 Date: Fri, 15 Aug 2025 15:05:22 +0900 Subject: [PATCH 1/5] allow memoryview cast for F-contiguous --- Lib/test/test_buffer.py | 26 ++++++++++++++++++++++++++ Objects/memoryobject.c | 8 +++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 19582e757161fc..cdb1f575ff573c 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -2846,6 +2846,32 @@ class BEPoint(ctypes.BigEndianStructure): self.assertEqual(m2.strides, (1,)) self.assertEqual(m2.suboffsets, ()) + def test_memoryview_cast_f_contiguous_ND_1D(self): + nd = ndarray(list(range(12)),shape=[3, 4], format='B', flags=ND_FORTRAN) + m = memoryview(nd) + self.assertTrue(m.f_contiguous) + self.assertTrue(m.contiguous) + + m1 = m.cast('B') + self.assertEqual(m1.ndim, 1) + self.assertEqual(m1.shape, (m.nbytes,)) + self.assertEqual(m1.strides, (1,)) + self.assertTrue(m1.c_contiguous) + self.assertTrue(m1.contiguous) + self.assertEqual(m1.tobytes(), memoryview(nd).tobytes(order='F')) + + for fmt in ('B', 'b', 'c', 'H', 'I'): + size = struct.calcsize(fmt) + if m.nbytes % size == 0: + m2 = m.cast(fmt) + self.assertEqual(m2.ndim, 1) + self.assertEqual(m2.shape, (m.nbytes // size,)) + self.assertTrue(m2.contiguous) + + m3 = m[::-1] + with self.assertRaises(TypeError): + m3.cast('B') + def test_memoryview_tolist(self): # Most tolist() tests are in self.verify() etc. diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index cf673fb379edcd..c5971eb82ad5ff 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -1456,9 +1456,11 @@ memoryview_cast_impl(PyMemoryViewObject *self, PyObject *format, CHECK_RESTRICTED(self); if (!MV_C_CONTIGUOUS(self->flags)) { - PyErr_SetString(PyExc_TypeError, - "memoryview: casts are restricted to C-contiguous views"); - return NULL; + if(shape || self->view.ndim == 1 || !MV_F_CONTIGUOUS(self->flags)) { + PyErr_SetString(PyExc_TypeError, + "memoryview: casts are restricted to C-contiguous views"); + return NULL; + } } if ((shape || self->view.ndim != 1) && zero_in_shape(self)) { PyErr_SetString(PyExc_TypeError, From 3cc8a7ec723fa66d64cb5b59a82da30280d97eee Mon Sep 17 00:00:00 2001 From: "blurb-it[bot]" <43283697+blurb-it[bot]@users.noreply.github.com> Date: Fri, 15 Aug 2025 06:28:46 +0000 Subject: [PATCH 2/5] =?UTF-8?q?=F0=9F=93=9C=F0=9F=A4=96=20Added=20by=20blu?= =?UTF-8?q?rb=5Fit.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../2025-08-15-06-28-45.gh-issue-91484.huCgHt.rst | 1 + 1 file changed, 1 insertion(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-08-15-06-28-45.gh-issue-91484.huCgHt.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-15-06-28-45.gh-issue-91484.huCgHt.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-15-06-28-45.gh-issue-91484.huCgHt.rst new file mode 100644 index 00000000000000..0131095ac44b3e --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-15-06-28-45.gh-issue-91484.huCgHt.rst @@ -0,0 +1 @@ +memoryview.cast() now allows casting from N-D to 1-D for F-contiguous. From 20df3ab5cd12336d1daae16a23791bb55b40c762 Mon Sep 17 00:00:00 2001 From: jamie2779 Date: Fri, 15 Aug 2025 15:47:16 +0900 Subject: [PATCH 3/5] fix lint issue --- Lib/test/test_buffer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index cdb1f575ff573c..cac2f801e6dd45 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -2867,7 +2867,7 @@ def test_memoryview_cast_f_contiguous_ND_1D(self): self.assertEqual(m2.ndim, 1) self.assertEqual(m2.shape, (m.nbytes // size,)) self.assertTrue(m2.contiguous) - + m3 = m[::-1] with self.assertRaises(TypeError): m3.cast('B') From 6678890e4969cf11f5b5facd66a534c2c7756670 Mon Sep 17 00:00:00 2001 From: jamie2779 Date: Fri, 24 Jul 2026 20:59:52 +0900 Subject: [PATCH 4/5] gh-91484: Address review comments --- Doc/library/stdtypes.rst | 9 +++++++-- Doc/whatsnew/3.16.rst | 4 ++++ .../2025-08-15-06-28-45.gh-issue-91484.huCgHt.rst | 2 +- Objects/memoryobject.c | 4 ++-- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst index 9df5eb78d286a5..0b6a1b488fb64f 100644 --- a/Doc/library/stdtypes.rst +++ b/Doc/library/stdtypes.rst @@ -4876,8 +4876,9 @@ copying. Cast a memoryview to a new format or shape. *shape* defaults to ``[byte_length//new_itemsize]``, which means that the result view will be one-dimensional. The return value is a new memoryview, but - the buffer itself is not copied. Supported casts are 1D -> C-:term:`contiguous` - and C-contiguous -> 1D. + the buffer itself is not copied. Supported casts are + 1D -> C-:term:`contiguous`, C-contiguous -> 1D, and + F-contiguous -> 1D. The destination format is restricted to a single element native format in :mod:`struct` syntax. One of the formats must be a byte format @@ -4964,6 +4965,10 @@ copying. .. versionchanged:: 3.5 The source format is no longer restricted when casting to a byte view. + .. versionchanged:: next + Casting a multi-dimensional F-contiguous view to a one-dimensional + view is now supported. + .. method:: count(value, /) Count the number of occurrences of *value*. diff --git a/Doc/whatsnew/3.16.rst b/Doc/whatsnew/3.16.rst index 662defa709a246..06e831ea1e3463 100644 --- a/Doc/whatsnew/3.16.rst +++ b/Doc/whatsnew/3.16.rst @@ -75,6 +75,10 @@ New features Other language changes ====================== +* :meth:`memoryview.cast` now allows casting a multidimensional + F-contiguous view to a one-dimensional view. + (Contributed by Jaemin Park in :gh:`91484`.) + * :ref:`Frame objects ` now support :mod:`weak references `. This allows associating extra data with active frames, for example in debuggers, without keeping the frames (and everything diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-15-06-28-45.gh-issue-91484.huCgHt.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-15-06-28-45.gh-issue-91484.huCgHt.rst index 0131095ac44b3e..7bba0da22d1c4d 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-08-15-06-28-45.gh-issue-91484.huCgHt.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-08-15-06-28-45.gh-issue-91484.huCgHt.rst @@ -1 +1 @@ -memoryview.cast() now allows casting from N-D to 1-D for F-contiguous. +:meth:`memoryview.cast` now allows casting from N-D to 1-D for F-contiguous. diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c index f4cfc38a0b9d76..f6ffa337c632a0 100644 --- a/Objects/memoryobject.c +++ b/Objects/memoryobject.c @@ -1485,9 +1485,9 @@ memoryview_cast_impl(PyMemoryViewObject *self, PyObject *format, CHECK_RESTRICTED(self); if (!MV_C_CONTIGUOUS(self->flags)) { - if(shape || self->view.ndim == 1 || !MV_F_CONTIGUOUS(self->flags)) { + if (shape || !MV_F_CONTIGUOUS(self->flags)) { PyErr_SetString(PyExc_TypeError, - "memoryview: casts are restricted to C-contiguous views"); + "memoryview: casts are restricted to contiguous views"); return NULL; } } From d215db1bf8d56406a1f6c0b0a1fa980a95ba8450 Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Fri, 24 Jul 2026 15:45:31 +0300 Subject: [PATCH 5/5] Update Lib/test/test_buffer.py --- Lib/test/test_buffer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py index 69e00295f874aa..579e680448e94e 100644 --- a/Lib/test/test_buffer.py +++ b/Lib/test/test_buffer.py @@ -2878,7 +2878,7 @@ class BEPoint: self.assertEqual(m2.suboffsets, ()) def test_memoryview_cast_f_contiguous_ND_1D(self): - nd = ndarray(list(range(12)),shape=[3, 4], format='B', flags=ND_FORTRAN) + nd = ndarray(list(range(12)), shape=[3, 4], format='B', flags=ND_FORTRAN) m = memoryview(nd) self.assertTrue(m.f_contiguous) self.assertTrue(m.contiguous)