Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 0c51595

Browse files
author
Stefan Krah
committed
Issue #15944: memoryview: Allow arbitrary formats when casting to bytes.
Original patch by Martin Panter.
1 parent 917c2c3 commit 0c51595

5 files changed

Lines changed: 57 additions & 11 deletions

File tree

Doc/library/stdtypes.rst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3564,7 +3564,7 @@ copying.
35643564
the buffer itself is not copied. Supported casts are 1D -> C-contiguous
35653565
and C-contiguous -> 1D.
35663566

3567-
Both formats are restricted to single element native formats in
3567+
The destination format is restricted to a single element native format in
35683568
:mod:`struct` syntax. One of the formats must be a byte format
35693569
('B', 'b' or 'c'). The byte length of the result must be the same
35703570
as the original length.
@@ -3645,6 +3645,9 @@ copying.
36453645

36463646
.. versionadded:: 3.3
36473647

3648+
.. versionchanged:: 3.5
3649+
The source format is no longer restricted when casting to a byte view.
3650+
36483651
There are also several readonly attributes available:
36493652

36503653
.. attribute:: obj

Lib/test/test_buffer.py

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2559,8 +2559,7 @@ def test_memoryview_cast_invalid(self):
25592559
ex = ndarray(sitems, shape=[1], format=sfmt)
25602560
msrc = memoryview(ex)
25612561
for dfmt, _, _ in iter_format(1):
2562-
if (not is_memoryview_format(sfmt) or
2563-
not is_memoryview_format(dfmt)):
2562+
if not is_memoryview_format(dfmt):
25642563
self.assertRaises(ValueError, msrc.cast, dfmt,
25652564
[32//dsize])
25662565
else:
@@ -2773,6 +2772,32 @@ def test_memoryview_cast_1D_ND(self):
27732772
ndim=ndim, shape=shape, strides=strides,
27742773
lst=lst, cast=True)
27752774

2775+
if ctypes:
2776+
# format: "T{>l:x:>d:y:}"
2777+
class BEPoint(ctypes.BigEndianStructure):
2778+
_fields_ = [("x", ctypes.c_long), ("y", ctypes.c_double)]
2779+
point = BEPoint(100, 200.1)
2780+
m1 = memoryview(point)
2781+
m2 = m1.cast('B')
2782+
self.assertEqual(m2.obj, point)
2783+
self.assertEqual(m2.itemsize, 1)
2784+
self.assertEqual(m2.readonly, 0)
2785+
self.assertEqual(m2.ndim, 1)
2786+
self.assertEqual(m2.shape, (m2.nbytes,))
2787+
self.assertEqual(m2.strides, (1,))
2788+
self.assertEqual(m2.suboffsets, ())
2789+
2790+
x = ctypes.c_double(1.2)
2791+
m1 = memoryview(x)
2792+
m2 = m1.cast('c')
2793+
self.assertEqual(m2.obj, x)
2794+
self.assertEqual(m2.itemsize, 1)
2795+
self.assertEqual(m2.readonly, 0)
2796+
self.assertEqual(m2.ndim, 1)
2797+
self.assertEqual(m2.shape, (m2.nbytes,))
2798+
self.assertEqual(m2.strides, (1,))
2799+
self.assertEqual(m2.suboffsets, ())
2800+
27762801
def test_memoryview_tolist(self):
27772802

27782803
# Most tolist() tests are in self.verify() etc.

Lib/test/test_memoryview.py

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -492,5 +492,26 @@ class ArrayMemorySliceSliceTest(unittest.TestCase,
492492
pass
493493

494494

495+
class OtherTest(unittest.TestCase):
496+
def test_ctypes_cast(self):
497+
# Issue 15944: Allow all source formats when casting to bytes.
498+
ctypes = test.support.import_module("ctypes")
499+
p6 = bytes(ctypes.c_double(0.6))
500+
501+
d = ctypes.c_double()
502+
m = memoryview(d).cast("B")
503+
m[:2] = p6[:2]
504+
m[2:] = p6[2:]
505+
self.assertEqual(d.value, 0.6)
506+
507+
for format in "Bbc":
508+
with self.subTest(format):
509+
d = ctypes.c_double()
510+
m = memoryview(d).cast(format)
511+
m[:2] = memoryview(p6).cast(format)[:2]
512+
m[2:] = memoryview(p6).cast(format)[2:]
513+
self.assertEqual(d.value, 0.6)
514+
515+
495516
if __name__ == "__main__":
496517
unittest.main()

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ Core and Builtins
9898
- Issue #24687: Plug refleak on SyntaxError in function parameters
9999
annotations.
100100

101+
- Issue #15944: memoryview: Allow arbitrary formats when casting to bytes.
102+
Patch by Martin Panter.
103+
101104
Library
102105
-------
103106

Objects/memoryobject.c

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,13 +1197,6 @@ cast_to_1D(PyMemoryViewObject *mv, PyObject *format)
11971197
assert(view->strides == mv->ob_array + view->ndim);
11981198
assert(view->suboffsets == mv->ob_array + 2*view->ndim);
11991199

1200-
if (get_native_fmtchar(&srcchar, view->format) < 0) {
1201-
PyErr_SetString(PyExc_ValueError,
1202-
"memoryview: source format must be a native single character "
1203-
"format prefixed with an optional '@'");
1204-
return ret;
1205-
}
1206-
12071200
asciifmt = PyUnicode_AsASCIIString(format);
12081201
if (asciifmt == NULL)
12091202
return ret;
@@ -1216,7 +1209,8 @@ cast_to_1D(PyMemoryViewObject *mv, PyObject *format)
12161209
goto out;
12171210
}
12181211

1219-
if (!IS_BYTE_FORMAT(srcchar) && !IS_BYTE_FORMAT(destchar)) {
1212+
if ((get_native_fmtchar(&srcchar, view->format) < 0 ||
1213+
!IS_BYTE_FORMAT(srcchar)) && !IS_BYTE_FORMAT(destchar)) {
12201214
PyErr_SetString(PyExc_TypeError,
12211215
"memoryview: cannot cast between two non-byte formats");
12221216
goto out;

0 commit comments

Comments
 (0)