]> granicus.if.org Git - python/commitdiff
Issue #22113: struct.pack_into() now supports new buffer protocol (in
authorSerhiy Storchaka <storchaka@gmail.com>
Sat, 21 Feb 2015 17:51:17 +0000 (19:51 +0200)
committerSerhiy Storchaka <storchaka@gmail.com>
Sat, 21 Feb 2015 17:51:17 +0000 (19:51 +0200)
particular accepts writable memoryview).

Lib/test/test_struct.py
Misc/NEWS
Modules/_struct.c

index 4811974970ecf20a394cc5d94df3f0ecab57221b..fe56dcb18896df43a7aa905ff048abf5c291438c 100644 (file)
@@ -433,24 +433,24 @@ class StructTest(unittest.TestCase):
             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 @@ class StructTest(unittest.TestCase):
         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)
index bd96880ba9228f5239da15ebf9a7339eeee13791..7d8b7b9c1f64fd58f922f156660ec76288056ed7 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -18,6 +18,9 @@ Core and Builtins
 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.
index f035847b7ec905b0a6ab4a2c2a8615e3ec3274b0..bca7a2e7ca4af96482db1f50868364168b0d187f 100644 (file)
@@ -1657,8 +1657,8 @@ static PyObject *
 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 @@ s_pack_into(PyObject *self, PyObject *args)
     }
 
     /* 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;
 }