Skip to content

Commit a400767

Browse files
authored
gh-91484: Allow memoryview cast for F-contiguous (GH-137803)
1 parent b1e530e commit a400767

5 files changed

Lines changed: 43 additions & 5 deletions

File tree

Doc/library/stdtypes.rst

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4876,8 +4876,9 @@ copying.
48764876
Cast a memoryview to a new format or shape. *shape* defaults to
48774877
``[byte_length//new_itemsize]``, which means that the result view
48784878
will be one-dimensional. The return value is a new memoryview, but
4879-
the buffer itself is not copied. Supported casts are 1D -> C-:term:`contiguous`
4880-
and C-contiguous -> 1D.
4879+
the buffer itself is not copied. Supported casts are
4880+
1D -> C-:term:`contiguous`, C-contiguous -> 1D, and
4881+
F-contiguous -> 1D.
48814882

48824883
The destination format is restricted to a single element native format in
48834884
:mod:`struct` syntax. One of the formats must be a byte format
@@ -4964,6 +4965,10 @@ copying.
49644965
.. versionchanged:: 3.5
49654966
The source format is no longer restricted when casting to a byte view.
49664967

4968+
.. versionchanged:: next
4969+
Casting a multi-dimensional F-contiguous view to a one-dimensional
4970+
view is now supported.
4971+
49674972
.. method:: count(value, /)
49684973

49694974
Count the number of occurrences of *value*.

Doc/whatsnew/3.16.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,10 @@ New features
7575
Other language changes
7676
======================
7777

78+
* :meth:`memoryview.cast` now allows casting a multidimensional
79+
F-contiguous view to a one-dimensional view.
80+
(Contributed by Jaemin Park in :gh:`91484`.)
81+
7882
* :ref:`Frame objects <frame-objects>` now support :mod:`weak references
7983
<weakref>`. This allows associating extra data with active frames,
8084
for example in debuggers, without keeping the frames (and everything

Lib/test/test_buffer.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2877,6 +2877,32 @@ class BEPoint:
28772877
self.assertEqual(m2.strides, (1,))
28782878
self.assertEqual(m2.suboffsets, ())
28792879

2880+
def test_memoryview_cast_f_contiguous_ND_1D(self):
2881+
nd = ndarray(list(range(12)), shape=[3, 4], format='B', flags=ND_FORTRAN)
2882+
m = memoryview(nd)
2883+
self.assertTrue(m.f_contiguous)
2884+
self.assertTrue(m.contiguous)
2885+
2886+
m1 = m.cast('B')
2887+
self.assertEqual(m1.ndim, 1)
2888+
self.assertEqual(m1.shape, (m.nbytes,))
2889+
self.assertEqual(m1.strides, (1,))
2890+
self.assertTrue(m1.c_contiguous)
2891+
self.assertTrue(m1.contiguous)
2892+
self.assertEqual(m1.tobytes(), memoryview(nd).tobytes(order='F'))
2893+
2894+
for fmt in ('B', 'b', 'c', 'H', 'I'):
2895+
size = struct.calcsize(fmt)
2896+
if m.nbytes % size == 0:
2897+
m2 = m.cast(fmt)
2898+
self.assertEqual(m2.ndim, 1)
2899+
self.assertEqual(m2.shape, (m.nbytes // size,))
2900+
self.assertTrue(m2.contiguous)
2901+
2902+
m3 = m[::-1]
2903+
with self.assertRaises(TypeError):
2904+
m3.cast('B')
2905+
28802906
def test_memoryview_tolist(self):
28812907

28822908
# Most tolist() tests are in self.verify() etc.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
:meth:`memoryview.cast` now allows casting from N-D to 1-D for F-contiguous.

Objects/memoryobject.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1485,9 +1485,11 @@ memoryview_cast_impl(PyMemoryViewObject *self, PyObject *format,
14851485
CHECK_RESTRICTED(self);
14861486

14871487
if (!MV_C_CONTIGUOUS(self->flags)) {
1488-
PyErr_SetString(PyExc_TypeError,
1489-
"memoryview: casts are restricted to C-contiguous views");
1490-
return NULL;
1488+
if (shape || !MV_F_CONTIGUOUS(self->flags)) {
1489+
PyErr_SetString(PyExc_TypeError,
1490+
"memoryview: casts are restricted to contiguous views");
1491+
return NULL;
1492+
}
14911493
}
14921494
if ((shape || self->view.ndim != 1) && zero_in_shape(self)) {
14931495
PyErr_SetString(PyExc_TypeError,

0 commit comments

Comments
 (0)