diff -r 3537994fa43b Lib/test/test_struct.py --- a/Lib/test/test_struct.py Sat Nov 15 13:21:01 2014 +0200 +++ b/Lib/test/test_struct.py Tue Nov 18 15:34:05 2014 +0200 @@ -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) diff -r 3537994fa43b Modules/_struct.c --- a/Modules/_struct.c Sat Nov 15 13:21:01 2014 +0200 +++ b/Modules/_struct.c Tue Nov 18 15:34:05 2014 +0200 @@ -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 *ar } /* 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; }