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

This commit is contained in:
Stefan Krah 2019-02-02 18:57:41 +01:00 committed by GitHub
parent 4860f01ac0
commit d08ea70464
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 59 additions and 10 deletions

View File

@ -3600,7 +3600,7 @@ copying.
Previous versions compared the raw memory disregarding the item format Previous versions compared the raw memory disregarding the item format
and the logical array structure. and the logical array structure.
.. method:: tobytes() .. method:: tobytes(order=None)
Return the data in the buffer as a bytestring. This is equivalent to Return the data in the buffer as a bytestring. This is equivalent to
calling the :class:`bytes` constructor on the memoryview. :: calling the :class:`bytes` constructor on the memoryview. ::
@ -3616,6 +3616,13 @@ copying.
supports all format strings, including those that are not in supports all format strings, including those that are not in
:mod:`struct` module syntax. :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() .. method:: hex()
Return a string object containing two hexadecimal digits for each Return a string object containing two hexadecimal digits for each

View File

@ -893,6 +893,15 @@ class TestBufferProtocol(unittest.TestCase):
y = ndarray(initlst, shape=shape, flags=ro, format=fmt) y = ndarray(initlst, shape=shape, flags=ro, format=fmt)
self.assertEqual(memoryview(y), memoryview(result)) 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' # To 'F'
contig = py_buffer_to_contiguous(result, 'F', PyBUF_FULL_RO) contig = py_buffer_to_contiguous(result, 'F', PyBUF_FULL_RO)
self.assertEqual(len(contig), nmemb * itemsize) self.assertEqual(len(contig), nmemb * itemsize)
@ -905,6 +914,9 @@ class TestBufferProtocol(unittest.TestCase):
format=fmt) format=fmt)
self.assertEqual(memoryview(y), memoryview(result)) self.assertEqual(memoryview(y), memoryview(result))
contig_bytes = memoryview(result).tobytes(order='F')
self.assertEqual(contig_bytes, contig)
# To 'A' # To 'A'
contig = py_buffer_to_contiguous(result, 'A', PyBUF_FULL_RO) contig = py_buffer_to_contiguous(result, 'A', PyBUF_FULL_RO)
self.assertEqual(len(contig), nmemb * itemsize) self.assertEqual(len(contig), nmemb * itemsize)
@ -917,6 +929,9 @@ class TestBufferProtocol(unittest.TestCase):
y = ndarray(initlst, shape=shape, flags=f|ro, format=fmt) y = ndarray(initlst, shape=shape, flags=f|ro, format=fmt)
self.assertEqual(memoryview(y), memoryview(result)) self.assertEqual(memoryview(y), memoryview(result))
contig_bytes = memoryview(result).tobytes(order='A')
self.assertEqual(contig_bytes, contig)
if is_memoryview_format(fmt): if is_memoryview_format(fmt):
try: try:
m = memoryview(result) m = memoryview(result)

View File

@ -0,0 +1 @@
Add 'order' parameter to memoryview.tobytes().

View File

@ -2120,22 +2120,39 @@ memory_tolist(PyMemoryViewObject *mv, PyObject *noargs)
} }
static PyObject * 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); Py_buffer *src = VIEW_ADDR(self);
PyObject *bytes = NULL; char *order = NULL;
char ord = 'C';
PyObject *bytes;
CHECK_RELEASED(self); CHECK_RELEASED(self);
if (MV_C_CONTIGUOUS(self->flags)) { if (!PyArg_ParseTupleAndKeywords(args, kwds, "|z", kwlist, &order)) {
return PyBytes_FromStringAndSize(src->buf, src->len); 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); bytes = PyBytes_FromStringAndSize(NULL, src->len);
if (bytes == NULL) if (bytes == NULL)
return 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); Py_DECREF(bytes);
return NULL; return NULL;
} }
@ -2156,10 +2173,15 @@ memory_hex(PyMemoryViewObject *self, PyObject *dummy)
return _Py_strhex(src->buf, src->len); return _Py_strhex(src->buf, src->len);
} }
bytes = memory_tobytes(self, dummy); bytes = PyBytes_FromStringAndSize(NULL, src->len);
if (bytes == NULL) if (bytes == NULL)
return 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)); ret = _Py_strhex(PyBytes_AS_STRING(bytes), PyBytes_GET_SIZE(bytes));
Py_DECREF(bytes); Py_DECREF(bytes);
@ -3061,9 +3083,13 @@ PyDoc_STRVAR(memory_release_doc,
\n\ \n\
Release the underlying buffer exposed by the memoryview object."); Release the underlying buffer exposed by the memoryview object.");
PyDoc_STRVAR(memory_tobytes_doc, PyDoc_STRVAR(memory_tobytes_doc,
"tobytes($self, /)\n--\n\ "tobytes($self, /, order=None)\n--\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, PyDoc_STRVAR(memory_hex_doc,
"hex($self, /)\n--\n\ "hex($self, /)\n--\n\
\n\ \n\
@ -3083,7 +3109,7 @@ Return a readonly version of the memoryview.");
static PyMethodDef memory_methods[] = { static PyMethodDef memory_methods[] = {
{"release", (PyCFunction)memory_release, METH_NOARGS, memory_release_doc}, {"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}, {"hex", (PyCFunction)memory_hex, METH_NOARGS, memory_hex_doc},
{"tolist", (PyCFunction)memory_tolist, METH_NOARGS, memory_tolist_doc}, {"tolist", (PyCFunction)memory_tolist, METH_NOARGS, memory_tolist_doc},
{"cast", (PyCFunction)(void(*)(void))memory_cast, METH_VARARGS|METH_KEYWORDS, memory_cast_doc}, {"cast", (PyCFunction)(void(*)(void))memory_cast, METH_VARARGS|METH_KEYWORDS, memory_cast_doc},