mirror of https://github.com/python/cpython
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
|
||||
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()
|
||||
|
||||
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
|
||||
return
|
||||
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)
|
||||
self.assertEqual(len(m), n)
|
||||
def check_memoryview(m, expected_readonly=readonly):
|
||||
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()
|
||||
self.assertEqual(rep, lst)
|
||||
self.assertEqual(m, result)
|
||||
n = 1 if ndim == 0 else len(lst)
|
||||
self.assertEqual(len(m), n)
|
||||
|
||||
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 simple_fmt(ex):
|
||||
|
|
|
@ -362,6 +362,17 @@ class AbstractMemoryTests:
|
|||
self.assertEqual(list(reversed(m)), aslist)
|
||||
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):
|
||||
a = array.array('H', [256, 256, 256, 256])
|
||||
x = memoryview(a)
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Add a ``toreadonly()`` method to memoryviews.
|
|
@ -1398,6 +1398,20 @@ error:
|
|||
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 */
|
||||
|
@ -3061,6 +3075,10 @@ PyDoc_STRVAR(memory_cast_doc,
|
|||
"cast($self, /, format, *, shape)\n--\n\
|
||||
\n\
|
||||
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[] = {
|
||||
{"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},
|
||||
{"tolist", (PyCFunction)memory_tolist, METH_NOARGS, memory_tolist_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},
|
||||
{"__exit__", memory_exit, METH_VARARGS, NULL},
|
||||
{NULL, NULL}
|
||||
|
|
Loading…
Reference in New Issue