summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Krah <skrah@bytereef.org>2015-08-08 11:38:10 (GMT)
committerStefan Krah <skrah@bytereef.org>2015-08-08 11:38:10 (GMT)
commit0c51595a784787d8e198af910cb6d79172ee52bb (patch)
tree56d21e209ab26a91c65cad305097fdf6bd8f1b45
parent917c2c36542131dd81f2b5b4d185c50d3b15546f (diff)
downloadcpython-0c51595a784787d8e198af910cb6d79172ee52bb.zip
cpython-0c51595a784787d8e198af910cb6d79172ee52bb.tar.gz
cpython-0c51595a784787d8e198af910cb6d79172ee52bb.tar.bz2
Issue #15944: memoryview: Allow arbitrary formats when casting to bytes.
Original patch by Martin Panter.
-rw-r--r--Doc/library/stdtypes.rst5
-rw-r--r--Lib/test/test_buffer.py29
-rw-r--r--Lib/test/test_memoryview.py21
-rw-r--r--Misc/NEWS3
-rw-r--r--Objects/memoryobject.c10
5 files changed, 57 insertions, 11 deletions
diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index 1ae1693..f0cc56b 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -3564,7 +3564,7 @@ copying.
the buffer itself is not copied. Supported casts are 1D -> C-contiguous
and C-contiguous -> 1D.
- Both formats are restricted to single element native formats in
+ The destination format is restricted to a single element native format in
:mod:`struct` syntax. One of the formats must be a byte format
('B', 'b' or 'c'). The byte length of the result must be the same
as the original length.
@@ -3645,6 +3645,9 @@ copying.
.. versionadded:: 3.3
+ .. versionchanged:: 3.5
+ The source format is no longer restricted when casting to a byte view.
+
There are also several readonly attributes available:
.. attribute:: obj
diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py
index 6803156..a653390 100644
--- a/Lib/test/test_buffer.py
+++ b/Lib/test/test_buffer.py
@@ -2559,8 +2559,7 @@ class TestBufferProtocol(unittest.TestCase):
ex = ndarray(sitems, shape=[1], format=sfmt)
msrc = memoryview(ex)
for dfmt, _, _ in iter_format(1):
- if (not is_memoryview_format(sfmt) or
- not is_memoryview_format(dfmt)):
+ if not is_memoryview_format(dfmt):
self.assertRaises(ValueError, msrc.cast, dfmt,
[32//dsize])
else:
@@ -2773,6 +2772,32 @@ class TestBufferProtocol(unittest.TestCase):
ndim=ndim, shape=shape, strides=strides,
lst=lst, cast=True)
+ if ctypes:
+ # format: "T{>l:x:>d:y:}"
+ class BEPoint(ctypes.BigEndianStructure):
+ _fields_ = [("x", ctypes.c_long), ("y", ctypes.c_double)]
+ point = BEPoint(100, 200.1)
+ m1 = memoryview(point)
+ m2 = m1.cast('B')
+ self.assertEqual(m2.obj, point)
+ self.assertEqual(m2.itemsize, 1)
+ self.assertEqual(m2.readonly, 0)
+ self.assertEqual(m2.ndim, 1)
+ self.assertEqual(m2.shape, (m2.nbytes,))
+ self.assertEqual(m2.strides, (1,))
+ self.assertEqual(m2.suboffsets, ())
+
+ x = ctypes.c_double(1.2)
+ m1 = memoryview(x)
+ m2 = m1.cast('c')
+ self.assertEqual(m2.obj, x)
+ self.assertEqual(m2.itemsize, 1)
+ self.assertEqual(m2.readonly, 0)
+ self.assertEqual(m2.ndim, 1)
+ self.assertEqual(m2.shape, (m2.nbytes,))
+ self.assertEqual(m2.strides, (1,))
+ self.assertEqual(m2.suboffsets, ())
+
def test_memoryview_tolist(self):
# Most tolist() tests are in self.verify() etc.
diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py
index 6fe61a4..da01a84 100644
--- a/Lib/test/test_memoryview.py
+++ b/Lib/test/test_memoryview.py
@@ -492,5 +492,26 @@ class ArrayMemorySliceSliceTest(unittest.TestCase,
pass
+class OtherTest(unittest.TestCase):
+ def test_ctypes_cast(self):
+ # Issue 15944: Allow all source formats when casting to bytes.
+ ctypes = test.support.import_module("ctypes")
+ p6 = bytes(ctypes.c_double(0.6))
+
+ d = ctypes.c_double()
+ m = memoryview(d).cast("B")
+ m[:2] = p6[:2]
+ m[2:] = p6[2:]
+ self.assertEqual(d.value, 0.6)
+
+ for format in "Bbc":
+ with self.subTest(format):
+ d = ctypes.c_double()
+ m = memoryview(d).cast(format)
+ m[:2] = memoryview(p6).cast(format)[:2]
+ m[2:] = memoryview(p6).cast(format)[2:]
+ self.assertEqual(d.value, 0.6)
+
+
if __name__ == "__main__":
unittest.main()
diff --git a/Misc/NEWS b/Misc/NEWS
index 46ea632..4bcd2c8 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -98,6 +98,9 @@ Core and Builtins
- Issue #24687: Plug refleak on SyntaxError in function parameters
annotations.
+- Issue #15944: memoryview: Allow arbitrary formats when casting to bytes.
+ Patch by Martin Panter.
+
Library
-------
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c
index 54fd05f..74cad7d 100644
--- a/Objects/memoryobject.c
+++ b/Objects/memoryobject.c
@@ -1197,13 +1197,6 @@ cast_to_1D(PyMemoryViewObject *mv, PyObject *format)
assert(view->strides == mv->ob_array + view->ndim);
assert(view->suboffsets == mv->ob_array + 2*view->ndim);
- if (get_native_fmtchar(&srcchar, view->format) < 0) {
- PyErr_SetString(PyExc_ValueError,
- "memoryview: source format must be a native single character "
- "format prefixed with an optional '@'");
- return ret;
- }
-
asciifmt = PyUnicode_AsASCIIString(format);
if (asciifmt == NULL)
return ret;
@@ -1216,7 +1209,8 @@ cast_to_1D(PyMemoryViewObject *mv, PyObject *format)
goto out;
}
- if (!IS_BYTE_FORMAT(srcchar) && !IS_BYTE_FORMAT(destchar)) {
+ if ((get_native_fmtchar(&srcchar, view->format) < 0 ||
+ !IS_BYTE_FORMAT(srcchar)) && !IS_BYTE_FORMAT(destchar)) {
PyErr_SetString(PyExc_TypeError,
"memoryview: cannot cast between two non-byte formats");
goto out;