bpo-33176: Add a toreadonly() method to memoryviews. (GH-6466)
This commit is contained in:
parent
b1dc07509f
commit
480ab05d5f
|
@ -3591,6 +3591,25 @@ copying.
|
||||||
:mod:`struct` module syntax as well as multi-dimensional
|
:mod:`struct` module syntax as well as multi-dimensional
|
||||||
representations.
|
representations.
|
||||||
|
|
||||||
|
.. method:: toreadonly()
|
||||||
|
|
||||||
|
Return a readonly version of the memoryview object. The original
|
||||||
|
memoryview object is unchanged. ::
|
||||||
|
|
||||||
|
>>> m = memoryview(bytearray(b'abc'))
|
||||||
|
>>> mm = m.toreadonly()
|
||||||
|
>>> mm.tolist()
|
||||||
|
[89, 98, 99]
|
||||||
|
>>> mm[0] = 42
|
||||||
|
Traceback (most recent call last):
|
||||||
|
File "<stdin>", line 1, in <module>
|
||||||
|
TypeError: cannot modify read-only memory
|
||||||
|
>>> m[0] = 43
|
||||||
|
>>> mm.tolist()
|
||||||
|
[43, 98, 99]
|
||||||
|
|
||||||
|
.. versionadded:: 3.8
|
||||||
|
|
||||||
.. method:: release()
|
.. method:: release()
|
||||||
|
|
||||||
Release the underlying buffer exposed by the memoryview object. Many
|
Release the underlying buffer exposed by the memoryview object. Many
|
||||||
|
|
|
@ -924,23 +924,30 @@ class TestBufferProtocol(unittest.TestCase):
|
||||||
except BufferError: # re-exporter does not provide full information
|
except BufferError: # re-exporter does not provide full information
|
||||||
return
|
return
|
||||||
ex = result.obj if isinstance(result, memoryview) else result
|
ex = result.obj if isinstance(result, memoryview) else result
|
||||||
self.assertIs(m.obj, ex)
|
|
||||||
self.assertEqual(m.nbytes, expected_len)
|
|
||||||
self.assertEqual(m.itemsize, itemsize)
|
|
||||||
self.assertEqual(m.format, fmt)
|
|
||||||
self.assertEqual(m.readonly, readonly)
|
|
||||||
self.assertEqual(m.ndim, ndim)
|
|
||||||
self.assertEqual(m.shape, tuple(shape))
|
|
||||||
if not (sliced and suboffsets):
|
|
||||||
self.assertEqual(m.strides, tuple(strides))
|
|
||||||
self.assertEqual(m.suboffsets, tuple(suboffsets))
|
|
||||||
|
|
||||||
n = 1 if ndim == 0 else len(lst)
|
def check_memoryview(m, expected_readonly=readonly):
|
||||||
self.assertEqual(len(m), n)
|
self.assertIs(m.obj, ex)
|
||||||
|
self.assertEqual(m.nbytes, expected_len)
|
||||||
|
self.assertEqual(m.itemsize, itemsize)
|
||||||
|
self.assertEqual(m.format, fmt)
|
||||||
|
self.assertEqual(m.readonly, expected_readonly)
|
||||||
|
self.assertEqual(m.ndim, ndim)
|
||||||
|
self.assertEqual(m.shape, tuple(shape))
|
||||||
|
if not (sliced and suboffsets):
|
||||||
|
self.assertEqual(m.strides, tuple(strides))
|
||||||
|
self.assertEqual(m.suboffsets, tuple(suboffsets))
|
||||||
|
|
||||||
rep = result.tolist() if fmt else result.tobytes()
|
n = 1 if ndim == 0 else len(lst)
|
||||||
self.assertEqual(rep, lst)
|
self.assertEqual(len(m), n)
|
||||||
self.assertEqual(m, result)
|
|
||||||
|
rep = result.tolist() if fmt else result.tobytes()
|
||||||
|
self.assertEqual(rep, lst)
|
||||||
|
self.assertEqual(m, result)
|
||||||
|
|
||||||
|
check_memoryview(m)
|
||||||
|
with m.toreadonly() as mm:
|
||||||
|
check_memoryview(mm, expected_readonly=True)
|
||||||
|
m.tobytes() # Releasing mm didn't release m
|
||||||
|
|
||||||
def verify_getbuf(self, orig_ex, ex, req, sliced=False):
|
def verify_getbuf(self, orig_ex, ex, req, sliced=False):
|
||||||
def simple_fmt(ex):
|
def simple_fmt(ex):
|
||||||
|
|
|
@ -362,6 +362,17 @@ class AbstractMemoryTests:
|
||||||
self.assertEqual(list(reversed(m)), aslist)
|
self.assertEqual(list(reversed(m)), aslist)
|
||||||
self.assertEqual(list(reversed(m)), list(m[::-1]))
|
self.assertEqual(list(reversed(m)), list(m[::-1]))
|
||||||
|
|
||||||
|
def test_toreadonly(self):
|
||||||
|
for tp in self._types:
|
||||||
|
b = tp(self._source)
|
||||||
|
m = self._view(b)
|
||||||
|
mm = m.toreadonly()
|
||||||
|
self.assertTrue(mm.readonly)
|
||||||
|
self.assertTrue(memoryview(mm).readonly)
|
||||||
|
self.assertEqual(mm.tolist(), m.tolist())
|
||||||
|
mm.release()
|
||||||
|
m.tolist()
|
||||||
|
|
||||||
def test_issue22668(self):
|
def test_issue22668(self):
|
||||||
a = array.array('H', [256, 256, 256, 256])
|
a = array.array('H', [256, 256, 256, 256])
|
||||||
x = memoryview(a)
|
x = memoryview(a)
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Add a ``toreadonly()`` method to memoryviews.
|
|
@ -1398,6 +1398,20 @@ error:
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static PyObject *
|
||||||
|
memory_toreadonly(PyMemoryViewObject *self, PyObject *noargs)
|
||||||
|
{
|
||||||
|
CHECK_RELEASED(self);
|
||||||
|
/* Even if self is already readonly, we still need to create a new
|
||||||
|
* object for .release() to work correctly.
|
||||||
|
*/
|
||||||
|
self = (PyMemoryViewObject *) mbuf_add_view(self->mbuf, &self->view);
|
||||||
|
if (self != NULL) {
|
||||||
|
self->view.readonly = 1;
|
||||||
|
};
|
||||||
|
return (PyObject *) self;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**************************************************************************/
|
/**************************************************************************/
|
||||||
/* getbuffer */
|
/* getbuffer */
|
||||||
|
@ -3061,6 +3075,10 @@ PyDoc_STRVAR(memory_cast_doc,
|
||||||
"cast($self, /, format, *, shape)\n--\n\
|
"cast($self, /, format, *, shape)\n--\n\
|
||||||
\n\
|
\n\
|
||||||
Cast a memoryview to a new format or shape.");
|
Cast a memoryview to a new format or shape.");
|
||||||
|
PyDoc_STRVAR(memory_toreadonly_doc,
|
||||||
|
"toreadonly($self, /)\n--\n\
|
||||||
|
\n\
|
||||||
|
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},
|
||||||
|
@ -3068,6 +3086,7 @@ static PyMethodDef memory_methods[] = {
|
||||||
{"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)memory_cast, METH_VARARGS|METH_KEYWORDS, memory_cast_doc},
|
{"cast", (PyCFunction)memory_cast, METH_VARARGS|METH_KEYWORDS, memory_cast_doc},
|
||||||
|
{"toreadonly", (PyCFunction)memory_toreadonly, METH_NOARGS, memory_toreadonly_doc},
|
||||||
{"__enter__", memory_enter, METH_NOARGS, NULL},
|
{"__enter__", memory_enter, METH_NOARGS, NULL},
|
||||||
{"__exit__", memory_exit, METH_VARARGS, NULL},
|
{"__exit__", memory_exit, METH_VARARGS, NULL},
|
||||||
{NULL, NULL}
|
{NULL, NULL}
|
||||||
|
|
Loading…
Reference in New Issue