[Python-checkins] cpython (2.7): Issue #22113: struct.pack_into() now supports new buffer protocol (in

serhiy.storchaka python-checkins at python.org
Sat Feb 21 18:57:14 CET 2015


https://hg.python.org/cpython/rev/4d8e37e54a7d
changeset:   94719:4d8e37e54a7d
branch:      2.7
parent:      94715:5387095b8675
user:        Serhiy Storchaka <storchaka at gmail.com>
date:        Sat Feb 21 19:51:17 2015 +0200
summary:
  Issue #22113: struct.pack_into() now supports new buffer protocol (in
particular accepts writable memoryview).

files:
  Lib/test/test_struct.py |  19 ++++++++++++++-----
  Misc/NEWS               |   3 +++
  Modules/_struct.c       |  22 ++++++++++++----------
  3 files changed, 29 insertions(+), 15 deletions(-)


diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py
--- a/Lib/test/test_struct.py
+++ b/Lib/test/test_struct.py
@@ -433,24 +433,24 @@
             self.assertRaises(struct.error, s.unpack_from, data, i)
             self.assertRaises(struct.error, struct.unpack_from, fmt, data, i)
 
-    def test_pack_into(self):
+    def test_pack_into(self, cls=bytearray, tobytes=str):
         test_string = 'Reykjavik rocks, eow!'
-        writable_buf = array.array('c', ' '*100)
+        writable_buf = cls(' '*100)
         fmt = '21s'
         s = struct.Struct(fmt)
 
         # Test without offset
         s.pack_into(writable_buf, 0, test_string)
-        from_buf = writable_buf.tostring()[:len(test_string)]
+        from_buf = tobytes(writable_buf)[:len(test_string)]
         self.assertEqual(from_buf, test_string)
 
         # Test with offset.
         s.pack_into(writable_buf, 10, test_string)
-        from_buf = writable_buf.tostring()[:len(test_string)+10]
+        from_buf = tobytes(writable_buf)[:len(test_string)+10]
         self.assertEqual(from_buf, test_string[:10] + test_string)
 
         # Go beyond boundaries.
-        small_buf = array.array('c', ' '*10)
+        small_buf = cls(' '*10)
         self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
                           test_string)
         self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
@@ -461,6 +461,15 @@
         self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
                           None)
 
+    def test_pack_into_array(self):
+        self.test_pack_into(cls=lambda b: array.array('c', b),
+                            tobytes=array.array.tostring)
+
+    def test_pack_into_memoryview(self):
+        # Issue #22113
+        self.test_pack_into(cls=lambda b: memoryview(bytearray(b)),
+                            tobytes=memoryview.tobytes)
+
     def test_pack_into_fn(self):
         test_string = 'Reykjavik rocks, eow!'
         writable_buf = array.array('c', ' '*100)
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -18,6 +18,9 @@
 Library
 -------
 
+- Issue #22113: struct.pack_into() now supports new buffer protocol (in
+  particular accepts writable memoryview).
+
 - Issues #814253, #9179: Warnings now are raised when group references and
   conditional group references are used in lookbehind assertions in regular
   expressions.
diff --git a/Modules/_struct.c b/Modules/_struct.c
--- a/Modules/_struct.c
+++ b/Modules/_struct.c
@@ -1657,8 +1657,8 @@
 s_pack_into(PyObject *self, PyObject *args)
 {
     PyStructObject *soself;
-    char *buffer;
-    Py_ssize_t buffer_len, offset;
+    Py_buffer buf;
+    Py_ssize_t offset;
 
     /* Validate arguments.  +1 is for the first arg as buffer. */
     soself = (PyStructObject *)self;
@@ -1683,33 +1683,35 @@
     }
 
     /* Extract a writable memory buffer from the first argument */
-    if ( PyObject_AsWriteBuffer(PyTuple_GET_ITEM(args, 0),
-                                                            (void**)&buffer, &buffer_len) == -1 ) {
+    if (!PyArg_Parse(PyTuple_GET_ITEM(args, 0), "w*", &buf))
         return NULL;
-    }
-    assert( buffer_len >= 0 );
 
     /* Extract the offset from the first argument */
     offset = PyInt_AsSsize_t(PyTuple_GET_ITEM(args, 1));
-    if (offset == -1 && PyErr_Occurred())
+    if (offset == -1 && PyErr_Occurred()) {
+        PyBuffer_Release(&buf);
         return NULL;
+    }
 
     /* Support negative offsets. */
     if (offset < 0)
-        offset += buffer_len;
+        offset += buf.len;
 
     /* Check boundaries */
-    if (offset < 0 || (buffer_len - offset) < soself->s_size) {
+    if (offset < 0 || (buf.len - offset) < soself->s_size) {
         PyErr_Format(StructError,
                      "pack_into requires a buffer of at least %zd bytes",
                      soself->s_size);
+        PyBuffer_Release(&buf);
         return NULL;
     }
 
     /* Call the guts */
-    if ( s_pack_internal(soself, args, 2, buffer + offset) != 0 ) {
+    if (s_pack_internal(soself, args, 2, (char *)buf.buf + offset) != 0) {
+        PyBuffer_Release(&buf);
         return NULL;
     }
+    PyBuffer_Release(&buf);
 
     Py_RETURN_NONE;
 }

-- 
Repository URL: https://hg.python.org/cpython


More information about the Python-checkins mailing list