[Python-checkins] bpo-33176: Add a toreadonly() method to memoryviews. (GH-6466)

Antoine Pitrou webhook-mailer at python.org
Sat Apr 14 13:49:24 EDT 2018


https://github.com/python/cpython/commit/480ab05d5fee2b8fa161f799af33086a4e68c7dd
commit: 480ab05d5fee2b8fa161f799af33086a4e68c7dd
branch: master
author: Antoine Pitrou <pitrou at free.fr>
committer: GitHub <noreply at github.com>
date: 2018-04-14T19:49:21+02:00
summary:

bpo-33176: Add a toreadonly() method to memoryviews. (GH-6466)

files:
A Misc/NEWS.d/next/Core and Builtins/2018-04-13-22-31-09.bpo-33176.PB9com.rst
M Doc/library/stdtypes.rst
M Lib/test/test_buffer.py
M Lib/test/test_memoryview.py
M Objects/memoryobject.c

diff --git a/Doc/library/stdtypes.rst b/Doc/library/stdtypes.rst
index a213189a3407..af2b4e1cb66a 100644
--- a/Doc/library/stdtypes.rst
+++ b/Doc/library/stdtypes.rst
@@ -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
diff --git a/Lib/test/test_buffer.py b/Lib/test/test_buffer.py
index f302da415d33..a3f3ef098a61 100644
--- a/Lib/test/test_buffer.py
+++ b/Lib/test/test_buffer.py
@@ -924,23 +924,30 @@ def verify(self, result, obj=-1,
             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)
 
-            rep = result.tolist() if fmt else result.tobytes()
-            self.assertEqual(rep, lst)
-            self.assertEqual(m, result)
+            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))
+
+                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):
diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py
index ddd5b9a8e2f2..ca307d8342f3 100644
--- a/Lib/test/test_memoryview.py
+++ b/Lib/test/test_memoryview.py
@@ -362,6 +362,17 @@ def test_reversed(self):
             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)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-04-13-22-31-09.bpo-33176.PB9com.rst b/Misc/NEWS.d/next/Core and Builtins/2018-04-13-22-31-09.bpo-33176.PB9com.rst
new file mode 100644
index 000000000000..68785b3cb6a1
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2018-04-13-22-31-09.bpo-33176.PB9com.rst	
@@ -0,0 +1 @@
+Add a ``toreadonly()`` method to memoryviews.
diff --git a/Objects/memoryobject.c b/Objects/memoryobject.c
index ccf45ffc5826..adaa67c06446 100644
--- a/Objects/memoryobject.c
+++ b/Objects/memoryobject.c
@@ -1398,6 +1398,20 @@ memory_cast(PyMemoryViewObject *self, PyObject *args, PyObject *kwds)
     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}



More information about the Python-checkins mailing list