Commit faa02376 authored by Serhiy Storchaka's avatar Serhiy Storchaka

Issue #22113: struct.pack_into() now supports new buffer protocol (in

particular accepts writable memoryview).
parent 6085be3c
...@@ -433,24 +433,24 @@ class StructTest(unittest.TestCase): ...@@ -433,24 +433,24 @@ class StructTest(unittest.TestCase):
self.assertRaises(struct.error, s.unpack_from, data, i) self.assertRaises(struct.error, s.unpack_from, data, i)
self.assertRaises(struct.error, struct.unpack_from, fmt, 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!' test_string = 'Reykjavik rocks, eow!'
writable_buf = array.array('c', ' '*100) writable_buf = cls(' '*100)
fmt = '21s' fmt = '21s'
s = struct.Struct(fmt) s = struct.Struct(fmt)
# Test without offset # Test without offset
s.pack_into(writable_buf, 0, test_string) 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) self.assertEqual(from_buf, test_string)
# Test with offset. # Test with offset.
s.pack_into(writable_buf, 10, test_string) 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) self.assertEqual(from_buf, test_string[:10] + test_string)
# Go beyond boundaries. # Go beyond boundaries.
small_buf = array.array('c', ' '*10) small_buf = cls(' '*10)
self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0, self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 0,
test_string) test_string)
self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2, self.assertRaises((ValueError, struct.error), s.pack_into, small_buf, 2,
...@@ -461,6 +461,15 @@ class StructTest(unittest.TestCase): ...@@ -461,6 +461,15 @@ class StructTest(unittest.TestCase):
self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb, self.assertRaises((TypeError, struct.error), struct.pack_into, b'', sb,
None) 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): def test_pack_into_fn(self):
test_string = 'Reykjavik rocks, eow!' test_string = 'Reykjavik rocks, eow!'
writable_buf = array.array('c', ' '*100) writable_buf = array.array('c', ' '*100)
......
...@@ -18,6 +18,9 @@ Core and Builtins ...@@ -18,6 +18,9 @@ Core and Builtins
Library 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 - Issues #814253, #9179: Warnings now are raised when group references and
conditional group references are used in lookbehind assertions in regular conditional group references are used in lookbehind assertions in regular
expressions. expressions.
......
...@@ -1657,8 +1657,8 @@ static PyObject * ...@@ -1657,8 +1657,8 @@ static PyObject *
s_pack_into(PyObject *self, PyObject *args) s_pack_into(PyObject *self, PyObject *args)
{ {
PyStructObject *soself; PyStructObject *soself;
char *buffer; Py_buffer buf;
Py_ssize_t buffer_len, offset; Py_ssize_t offset;
/* Validate arguments. +1 is for the first arg as buffer. */ /* Validate arguments. +1 is for the first arg as buffer. */
soself = (PyStructObject *)self; soself = (PyStructObject *)self;
...@@ -1683,33 +1683,35 @@ s_pack_into(PyObject *self, PyObject *args) ...@@ -1683,33 +1683,35 @@ s_pack_into(PyObject *self, PyObject *args)
} }
/* Extract a writable memory buffer from the first argument */ /* Extract a writable memory buffer from the first argument */
if ( PyObject_AsWriteBuffer(PyTuple_GET_ITEM(args, 0), if (!PyArg_Parse(PyTuple_GET_ITEM(args, 0), "w*", &buf))
(void**)&buffer, &buffer_len) == -1 ) {
return NULL; return NULL;
}
assert( buffer_len >= 0 );
/* Extract the offset from the first argument */ /* Extract the offset from the first argument */
offset = PyInt_AsSsize_t(PyTuple_GET_ITEM(args, 1)); offset = PyInt_AsSsize_t(PyTuple_GET_ITEM(args, 1));
if (offset == -1 && PyErr_Occurred()) if (offset == -1 && PyErr_Occurred()) {
PyBuffer_Release(&buf);
return NULL; return NULL;
}
/* Support negative offsets. */ /* Support negative offsets. */
if (offset < 0) if (offset < 0)
offset += buffer_len; offset += buf.len;
/* Check boundaries */ /* Check boundaries */
if (offset < 0 || (buffer_len - offset) < soself->s_size) { if (offset < 0 || (buf.len - offset) < soself->s_size) {
PyErr_Format(StructError, PyErr_Format(StructError,
"pack_into requires a buffer of at least %zd bytes", "pack_into requires a buffer of at least %zd bytes",
soself->s_size); soself->s_size);
PyBuffer_Release(&buf);
return NULL; return NULL;
} }
/* Call the guts */ /* 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; return NULL;
} }
PyBuffer_Release(&buf);
Py_RETURN_NONE; Py_RETURN_NONE;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment