# HG changeset patch # Parent ed15f399a2922c96584a4e643b9a0ee0b360b64e diff -r ed15f399a292 Doc/library/stdtypes.rst --- a/Doc/library/stdtypes.rst Thu Aug 06 13:17:27 2015 +0300 +++ b/Doc/library/stdtypes.rst Thu Aug 06 16:47:44 2015 +0000 @@ -3561,12 +3561,15 @@ 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-contiguous - and C-contiguous -> 1D. - - Both formats are restricted to single element native formats 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 + the buffer itself is not copied. Casting is only supported for + C-contiguous views, and only when either the old or new shape is + one-dimensional. + + The new format is restricted to a single element native format in + :mod:`struct` syntax. Any C-contiguous view may be cast to a + one-dimensional byte view, using the 'B', 'b' or 'c' formats. + Otherwise, the original view must be in one of those byte formats. + The byte length of the result must be the same as the original length. Cast 1D/long to 1D/unsigned bytes:: @@ -3645,6 +3648,9 @@ .. versionadded:: 3.3 + .. versionchanged:: 3.6 + Original format no longer restricted when casting to a byte view. + There are also several readonly attributes available: .. attribute:: obj diff -r ed15f399a292 Lib/test/test_buffer.py --- a/Lib/test/test_buffer.py Thu Aug 06 13:17:27 2015 +0300 +++ b/Lib/test/test_buffer.py Thu Aug 06 16:47:44 2015 +0000 @@ -2559,14 +2559,17 @@ 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)): - self.assertRaises(ValueError, msrc.cast, dfmt, - [32//dsize]) - else: - if not is_byte_format(sfmt) and not is_byte_format(dfmt): - self.assertRaises(TypeError, msrc.cast, dfmt, - [32//dsize]) + with self.subTest(sfmt=sfmt, dfmt=dfmt): + if not is_memoryview_format(dfmt): + msg = ("destination format must be a " + "native single character") + self.assertRaisesRegex(ValueError, msg, + msrc.cast, dfmt, [32//dsize]) + else: + if not is_byte_format(sfmt) and not is_byte_format(dfmt): + msg = "cast between two non-byte formats" + self.assertRaisesRegex(TypeError, msg, + msrc.cast, dfmt, [32//dsize]) # invalid shape size_h = struct.calcsize('h') diff -r ed15f399a292 Lib/test/test_memoryview.py --- a/Lib/test/test_memoryview.py Thu Aug 06 13:17:27 2015 +0300 +++ b/Lib/test/test_memoryview.py Thu Aug 06 16:47:44 2015 +0000 @@ -492,5 +492,26 @@ pass +class OtherTest(unittest.TestCase): + def test_ctypes_cast(self): + # Issue 15944: Some "ctypes" were not usable + 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 -r ed15f399a292 Objects/memoryobject.c --- a/Objects/memoryobject.c Thu Aug 06 13:17:27 2015 +0300 +++ b/Objects/memoryobject.c Thu Aug 06 16:47:44 2015 +0000 @@ -1197,13 +1197,6 @@ 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 @@ 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;