Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 480ab05

Browse files
authored
bpo-33176: Add a toreadonly() method to memoryviews. (GH-6466)
1 parent b1dc075 commit 480ab05

5 files changed

Lines changed: 73 additions & 16 deletions

File tree

Doc/library/stdtypes.rst

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3591,6 +3591,25 @@ copying.
35913591
:mod:`struct` module syntax as well as multi-dimensional
35923592
representations.
35933593

3594+
.. method:: toreadonly()
3595+
3596+
Return a readonly version of the memoryview object. The original
3597+
memoryview object is unchanged. ::
3598+
3599+
>>> m = memoryview(bytearray(b'abc'))
3600+
>>> mm = m.toreadonly()
3601+
>>> mm.tolist()
3602+
[89, 98, 99]
3603+
>>> mm[0] = 42
3604+
Traceback (most recent call last):
3605+
File "<stdin>", line 1, in <module>
3606+
TypeError: cannot modify read-only memory
3607+
>>> m[0] = 43
3608+
>>> mm.tolist()
3609+
[43, 98, 99]
3610+
3611+
.. versionadded:: 3.8
3612+
35943613
.. method:: release()
35953614

35963615
Release the underlying buffer exposed by the memoryview object. Many

Lib/test/test_buffer.py

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -924,23 +924,30 @@ def verify(self, result, obj=-1,
924924
except BufferError: # re-exporter does not provide full information
925925
return
926926
ex = result.obj if isinstance(result, memoryview) else result
927-
self.assertIs(m.obj, ex)
928-
self.assertEqual(m.nbytes, expected_len)
929-
self.assertEqual(m.itemsize, itemsize)
930-
self.assertEqual(m.format, fmt)
931-
self.assertEqual(m.readonly, readonly)
932-
self.assertEqual(m.ndim, ndim)
933-
self.assertEqual(m.shape, tuple(shape))
934-
if not (sliced and suboffsets):
935-
self.assertEqual(m.strides, tuple(strides))
936-
self.assertEqual(m.suboffsets, tuple(suboffsets))
937-
938-
n = 1 if ndim == 0 else len(lst)
939-
self.assertEqual(len(m), n)
940927

941-
rep = result.tolist() if fmt else result.tobytes()
942-
self.assertEqual(rep, lst)
943-
self.assertEqual(m, result)
928+
def check_memoryview(m, expected_readonly=readonly):
929+
self.assertIs(m.obj, ex)
930+
self.assertEqual(m.nbytes, expected_len)
931+
self.assertEqual(m.itemsize, itemsize)
932+
self.assertEqual(m.format, fmt)
933+
self.assertEqual(m.readonly, expected_readonly)
934+
self.assertEqual(m.ndim, ndim)
935+
self.assertEqual(m.shape, tuple(shape))
936+
if not (sliced and suboffsets):
937+
self.assertEqual(m.strides, tuple(strides))
938+
self.assertEqual(m.suboffsets, tuple(suboffsets))
939+
940+
n = 1 if ndim == 0 else len(lst)
941+
self.assertEqual(len(m), n)
942+
943+
rep = result.tolist() if fmt else result.tobytes()
944+
self.assertEqual(rep, lst)
945+
self.assertEqual(m, result)
946+
947+
check_memoryview(m)
948+
with m.toreadonly() as mm:
949+
check_memoryview(mm, expected_readonly=True)
950+
m.tobytes() # Releasing mm didn't release m
944951

945952
def verify_getbuf(self, orig_ex, ex, req, sliced=False):
946953
def simple_fmt(ex):

Lib/test/test_memoryview.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -362,6 +362,17 @@ def test_reversed(self):
362362
self.assertEqual(list(reversed(m)), aslist)
363363
self.assertEqual(list(reversed(m)), list(m[::-1]))
364364

365+
def test_toreadonly(self):
366+
for tp in self._types:
367+
b = tp(self._source)
368+
m = self._view(b)
369+
mm = m.toreadonly()
370+
self.assertTrue(mm.readonly)
371+
self.assertTrue(memoryview(mm).readonly)
372+
self.assertEqual(mm.tolist(), m.tolist())
373+
mm.release()
374+
m.tolist()
375+
365376
def test_issue22668(self):
366377
a = array.array('H', [256, 256, 256, 256])
367378
x = memoryview(a)
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add a ``toreadonly()`` method to memoryviews.

Objects/memoryobject.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1398,6 +1398,20 @@ memory_cast(PyMemoryViewObject *self, PyObject *args, PyObject *kwds)
13981398
return NULL;
13991399
}
14001400

1401+
static PyObject *
1402+
memory_toreadonly(PyMemoryViewObject *self, PyObject *noargs)
1403+
{
1404+
CHECK_RELEASED(self);
1405+
/* Even if self is already readonly, we still need to create a new
1406+
* object for .release() to work correctly.
1407+
*/
1408+
self = (PyMemoryViewObject *) mbuf_add_view(self->mbuf, &self->view);
1409+
if (self != NULL) {
1410+
self->view.readonly = 1;
1411+
};
1412+
return (PyObject *) self;
1413+
}
1414+
14011415

14021416
/**************************************************************************/
14031417
/* getbuffer */
@@ -3061,13 +3075,18 @@ PyDoc_STRVAR(memory_cast_doc,
30613075
"cast($self, /, format, *, shape)\n--\n\
30623076
\n\
30633077
Cast a memoryview to a new format or shape.");
3078+
PyDoc_STRVAR(memory_toreadonly_doc,
3079+
"toreadonly($self, /)\n--\n\
3080+
\n\
3081+
Return a readonly version of the memoryview.");
30643082

30653083
static PyMethodDef memory_methods[] = {
30663084
{"release", (PyCFunction)memory_release, METH_NOARGS, memory_release_doc},
30673085
{"tobytes", (PyCFunction)memory_tobytes, METH_NOARGS, memory_tobytes_doc},
30683086
{"hex", (PyCFunction)memory_hex, METH_NOARGS, memory_hex_doc},
30693087
{"tolist", (PyCFunction)memory_tolist, METH_NOARGS, memory_tolist_doc},
30703088
{"cast", (PyCFunction)memory_cast, METH_VARARGS|METH_KEYWORDS, memory_cast_doc},
3089+
{"toreadonly", (PyCFunction)memory_toreadonly, METH_NOARGS, memory_toreadonly_doc},
30713090
{"__enter__", memory_enter, METH_NOARGS, NULL},
30723091
{"__exit__", memory_exit, METH_VARARGS, NULL},
30733092
{NULL, NULL}

0 commit comments

Comments
 (0)