[Python-checkins] bpo-35845: Add order={'C', 'F', 'A'} parameter to memoryview.tobytes(). (#11730)

Stefan Krah webhook-mailer at python.org
Sat Feb 2 12:57:44 EST 2019


https://github.com/python/cpython/commit/d08ea70464cb8a1f86134dcb4a5c2eac1a02bf1a
commit: d08ea70464cb8a1f86134dcb4a5c2eac1a02bf1a
branch: master
author: Stefan Krah <skrah at bytereef.org>
committer: GitHub <noreply at github.com>
date: 2019-02-02T18:57:41+01:00
summary:

bpo-35845: Add order={'C', 'F', 'A'} parameter to memoryview.tobytes(). (#11730)

files:
A Misc/NEWS.d/next/Library/2019-02-02-00-04-01.bpo-35845.1jx2wk.rst
M Doc/library/stdtypes.rst
M Lib/test/test_buffer.py
M Objects/memoryobject.c

diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index 887497852216..d1b1b8c636e9 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -3600,7 +3600,7 @@ copying.
          Previous versions compared the raw memory disregarding the item format
          and the logical array structure.
 
-   .. method:: tobytes()
+   .. method:: tobytes(order=None)
 
       Return the data in the buffer as a bytestring.  This is equivalent to
       calling the :class:`bytes` constructor on the memoryview. ::
@@ -3616,6 +3616,13 @@ copying.
       supports all format strings, including those that are not in
       :mod:`struct` module syntax.
 
+      .. versionadded:: 3.8
+         *Order* can be {'C', 'F', 'A'}.  When *order* is 'C' or 'F', the data
+         of the original array is converted to C or Fortran order. For contiguous
+         views, 'A' returns an exact copy of the physical memory. In particular,
+         in-memory Fortran order is preserved. For non-contiguous views, the
+         data is converted to C first. *order=None* is the same as *order='C'*.
+
    .. method:: hex()
 
       Return a string object containing two hexadecimal digits for each
diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py
index 761ed0a9a9bf..47413c03d663 100644
--- a/Lib/test/test_buffer.py
+++ b/Lib/test/test_buffer.py
@@ -893,6 +893,15 @@ def verify(self, result, *, obj,
                     y = ndarray(initlst, shape=shape, flags=ro, format=fmt)
                     self.assertEqual(memoryview(y), memoryview(result))
 
+                    contig_bytes = memoryview(result).tobytes()
+                    self.assertEqual(contig_bytes, contig)
+
+                    contig_bytes = memoryview(result).tobytes(order=None)
+                    self.assertEqual(contig_bytes, contig)
+
+                    contig_bytes = memoryview(result).tobytes(order='C')
+                    self.assertEqual(contig_bytes, contig)
+
                     # To 'F'
                     contig = py_buffer_to_contiguous(result, 'F', PyBUF_FULL_RO)
                     self.assertEqual(len(contig), nmemb * itemsize)
@@ -905,6 +914,9 @@ def verify(self, result, *, obj,
                                 format=fmt)
                     self.assertEqual(memoryview(y), memoryview(result))
 
+                    contig_bytes = memoryview(result).tobytes(order='F')
+                    self.assertEqual(contig_bytes, contig)
+
                     # To 'A'
                     contig = py_buffer_to_contiguous(result, 'A', PyBUF_FULL_RO)
                     self.assertEqual(len(contig), nmemb * itemsize)
@@ -917,6 +929,9 @@ def verify(self, result, *, obj,
                     y = ndarray(initlst, shape=shape, flags=f|ro, format=fmt)
                     self.assertEqual(memoryview(y), memoryview(result))
 
+                    contig_bytes = memoryview(result).tobytes(order='A')
+                    self.assertEqual(contig_bytes, contig)
+
         if is_memoryview_format(fmt):
             try:
                 m = memoryview(result)
diff --git a/Misc/NEWS.d/next/Library/2019-02-02-00-04-01.bpo-35845.1jx2wk.rst b/Misc/NEWS.d/next/Library/2019-02-02-00-04-01.bpo-35845.1jx2wk.rst
new file mode 100644
index 000000000000..755baf7b6154
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2019-02-02-00-04-01.bpo-35845.1jx2wk.rst
@@ -0,0 +1 @@
+Add 'order' parameter to memoryview.tobytes().
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c
index 40e6308c87ae..d835704bdaae 100644
--- a/Objects/memoryobject.c
+++ b/Objects/memoryobject.c
@@ -2120,22 +2120,39 @@ memory_tolist(PyMemoryViewObject *mv, PyObject *noargs)
 }
 
 static PyObject *
-memory_tobytes(PyMemoryViewObject *self, PyObject *dummy)
+memory_tobytes(PyMemoryViewObject *self, PyObject *args, PyObject *kwds)
 {
+    static char *kwlist[] = {"order", NULL};
     Py_buffer *src = VIEW_ADDR(self);
-    PyObject *bytes = NULL;
+    char *order = NULL;
+    char ord = 'C';
+    PyObject *bytes;
 
     CHECK_RELEASED(self);
 
-    if (MV_C_CONTIGUOUS(self->flags)) {
-        return PyBytes_FromStringAndSize(src->buf, src->len);
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|z", kwlist, &order)) {
+        return NULL;
+    }
+
+    if (order) {
+        if (strcmp(order, "F") == 0) {
+            ord = 'F';
+        }
+        else if (strcmp(order, "A") == 0) {
+            ord = 'A';
+        }
+        else if (strcmp(order, "C") != 0) {
+            PyErr_SetString(PyExc_ValueError,
+                "order must be 'C', 'F' or 'A'");
+            return NULL;
+        }
     }
 
     bytes = PyBytes_FromStringAndSize(NULL, src->len);
     if (bytes == NULL)
         return NULL;
 
-    if (buffer_to_contiguous(PyBytes_AS_STRING(bytes), src, 'C') < 0) {
+    if (PyBuffer_ToContiguous(PyBytes_AS_STRING(bytes), src, src->len, ord) < 0) {
         Py_DECREF(bytes);
         return NULL;
     }
@@ -2156,10 +2173,15 @@ memory_hex(PyMemoryViewObject *self, PyObject *dummy)
         return _Py_strhex(src->buf, src->len);
     }
 
-    bytes = memory_tobytes(self, dummy);
+    bytes = PyBytes_FromStringAndSize(NULL, src->len);
     if (bytes == NULL)
         return NULL;
 
+    if (PyBuffer_ToContiguous(PyBytes_AS_STRING(bytes), src, src->len, 'C') < 0) {
+        Py_DECREF(bytes);
+        return NULL;
+    }
+
     ret = _Py_strhex(PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes));
     Py_DECREF(bytes);
 
@@ -3061,9 +3083,13 @@ PyDoc_STRVAR(memory_release_doc,
 \n\
 Release the underlying buffer exposed by the memoryview object.");
 PyDoc_STRVAR(memory_tobytes_doc,
-"tobytes($self, /)\n--\n\
+"tobytes($self, /, order=None)\n--\n\
 \n\
-Return the data in the buffer as a byte string.");
+Return the data in the buffer as a byte string. Order can be {'C', 'F', 'A'}.\n\
+When order is 'C' or 'F', the data of the original array is converted to C or\n\
+Fortran order. For contiguous views, 'A' returns an exact copy of the physical\n\
+memory. In particular, in-memory Fortran order is preserved. For non-contiguous\n\
+views, the data is converted to C first. order=None is the same as order='C'.");
 PyDoc_STRVAR(memory_hex_doc,
 "hex($self, /)\n--\n\
 \n\
@@ -3083,7 +3109,7 @@ Return a readonly version of the memoryview.");
 
 static PyMethodDef memory_methods[] = {
     {"release",     (PyCFunction)memory_release, METH_NOARGS, memory_release_doc},
-    {"tobytes",     (PyCFunction)memory_tobytes, METH_NOARGS, memory_tobytes_doc},
+    {"tobytes",     (PyCFunction)memory_tobytes, METH_VARARGS|METH_KEYWORDS, memory_tobytes_doc},
     {"hex",         (PyCFunction)memory_hex, METH_NOARGS, memory_hex_doc},
     {"tolist",      (PyCFunction)memory_tolist, METH_NOARGS, memory_tolist_doc},
     {"cast",        (PyCFunction)(void(*)(void))memory_cast, METH_VARARGS|METH_KEYWORDS, memory_cast_doc},



More information about the Python-checkins mailing list