Issue #8990: array.fromstring() and array.tostring() get renamed to

frombytes() and tobytes(), respectively, to avoid confusion.  Furthermore,
array.frombytes(), array.extend() as well as the array.array()
constructor now accept bytearray objects.  Patch by Thomas Jollans.
This commit is contained in:
Antoine Pitrou 2010-09-01 20:29:34 +00:00
parent 42cb462682
commit 1ce3eb5c5b
12 changed files with 167 additions and 48 deletions

View file

@ -60,7 +60,7 @@ The module defines the following type:
appropriate type.
If given a list or string, the initializer is passed to the new array's
:meth:`fromlist`, :meth:`fromstring`, or :meth:`fromunicode` method (see below)
:meth:`fromlist`, :meth:`frombytes`, or :meth:`fromunicode` method (see below)
to add initial items to the array. Otherwise, the iterable initializer is
passed to the :meth:`extend` method.
@ -136,6 +136,15 @@ The following data items and methods are also supported:
must be the right type to be appended to the array.
.. method:: array.frombytes(s)
Appends items from the string, interpreting the string as an array of machine
values (as if it had been read from a file using the :meth:`fromfile` method).
.. versionadded:: 3.2
:meth:`fromstring` is renamed to :meth:`frombytes` for clarity.
.. method:: array.fromfile(f, n)
Read *n* items (as machine values) from the file object *f* and append them to
@ -151,17 +160,16 @@ The following data items and methods are also supported:
a.append(x)`` except that if there is a type error, the array is unchanged.
.. method:: array.fromstring(s)
.. method:: array.fromstring()
Appends items from the string, interpreting the string as an array of machine
values (as if it had been read from a file using the :meth:`fromfile` method).
Deprecated alias for :meth:`frombytes`.
.. method:: array.fromunicode(s)
Extends this array with data from the given unicode string. The array must
be a type ``'u'`` array; otherwise a :exc:`ValueError` is raised. Use
``array.fromstring(unicodestring.encode(enc))`` to append Unicode data to an
``array.frombytes(unicodestring.encode(enc))`` to append Unicode data to an
array of some other type.
@ -194,6 +202,16 @@ The following data items and methods are also supported:
Reverse the order of the items in the array.
.. method:: array.tobytes()
Convert the array to an array of machine values and return the bytes
representation (the same sequence of bytes that would be written to a file by
the :meth:`tofile` method.)
.. versionadded:: 3.2
:meth:`tostring` is renamed to :meth:`tobytes` for clarity.
.. method:: array.tofile(f)
Write all items (as machine values) to the file object *f*.
@ -206,15 +224,13 @@ The following data items and methods are also supported:
.. method:: array.tostring()
Convert the array to an array of machine values and return the string
representation (the same sequence of bytes that would be written to a file by
the :meth:`tofile` method.)
Deprecated alias for :meth:`tobytes`.
.. method:: array.tounicode()
Convert the array to a unicode string. The array must be a type ``'u'`` array;
otherwise a :exc:`ValueError` is raised. Use ``array.tostring().decode(enc)`` to
otherwise a :exc:`ValueError` is raised. Use ``array.tobytes().decode(enc)`` to
obtain a unicode string from an array of some other type.

View file

@ -32,7 +32,7 @@
#
def reduce_array(a):
return array.array, (a.typecode, a.tostring())
return array.array, (a.typecode, a.tobytes())
ForkingPickler.register(array.array, reduce_array)
view_types = [type(getattr({}, name)()) for name in ('items','keys','values')]

View file

@ -343,7 +343,7 @@ def _optimize_unicode(charset, fixup):
else:
code = 'I'
# Convert block indices to byte array of 256 bytes
mapping = array.array('b', mapping).tostring()
mapping = array.array('b', mapping).tobytes()
# Convert byte array to word array
mapping = array.array(code, mapping)
assert mapping.itemsize == _sre.CODESIZE

View file

@ -11,6 +11,7 @@
import io
import math
import struct
import warnings
import array
from array import _array_reconstructor as array_reconstructor
@ -367,6 +368,11 @@ def test_tofromlist(self):
self.assertEqual(a, b)
def test_tofromstring(self):
nb_warnings = 4
with warnings.catch_warnings(record=True) as r:
warnings.filterwarnings("always",
message=r"(to|from)string\(\) is deprecated",
category=DeprecationWarning)
a = array.array(self.typecode, 2*self.example)
b = array.array(self.typecode)
self.assertRaises(TypeError, a.tostring, 42)
@ -376,6 +382,21 @@ def test_tofromstring(self):
self.assertEqual(a, b)
if a.itemsize>1:
self.assertRaises(ValueError, b.fromstring, "x")
nb_warnings += 1
self.assertEqual(len(r), nb_warnings)
def test_tofrombytes(self):
a = array.array(self.typecode, 2*self.example)
b = array.array(self.typecode)
self.assertRaises(TypeError, a.tobytes, 42)
self.assertRaises(TypeError, b.frombytes)
self.assertRaises(TypeError, b.frombytes, 42)
b.frombytes(a.tobytes())
c = array.array(self.typecode, bytearray(a.tobytes()))
self.assertEqual(a, b)
self.assertEqual(a, c)
if a.itemsize>1:
self.assertRaises(ValueError, b.frombytes, b"x")
def test_repr(self):
a = array.array(self.typecode, 2*self.example)
@ -898,8 +919,8 @@ def test_buffer(self):
a = array.array(self.typecode, self.example)
m = memoryview(a)
expected = m.tobytes()
self.assertEqual(a.tostring(), expected)
self.assertEqual(a.tostring()[0], expected[0])
self.assertEqual(a.tobytes(), expected)
self.assertEqual(a.tobytes()[0], expected[0])
# Resizing is forbidden when there are buffer exports.
# For issue 4509, we also check after each error that
# the array was not modified.
@ -913,7 +934,7 @@ def test_buffer(self):
self.assertEqual(m.tobytes(), expected)
self.assertRaises(BufferError, a.fromlist, a.tolist())
self.assertEqual(m.tobytes(), expected)
self.assertRaises(BufferError, a.fromstring, a.tostring())
self.assertRaises(BufferError, a.frombytes, a.tobytes())
self.assertEqual(m.tobytes(), expected)
if self.typecode == 'u':
self.assertRaises(BufferError, a.fromunicode, a.tounicode())
@ -932,7 +953,7 @@ def test_buffer(self):
def test_weakref(self):
s = array.array(self.typecode, self.example)
p = weakref.proxy(s)
self.assertEqual(p.tostring(), s.tostring())
self.assertEqual(p.tobytes(), s.tobytes())
s = None
self.assertRaises(ReferenceError, len, p)
@ -1110,6 +1131,23 @@ def test_overflow(self):
upper = int(pow(2, a.itemsize * 8)) - 1
self.check_overflow(lower, upper)
def test_bytes_extend(self):
s = bytes(self.example)
a = array.array(self.typecode, self.example)
a.extend(s)
self.assertEqual(
a,
array.array(self.typecode, self.example+self.example)
)
a = array.array(self.typecode, self.example)
a.extend(bytearray(reversed(s)))
self.assertEqual(
a,
array.array(self.typecode, self.example+self.example[::-1])
)
class ByteTest(SignedNumberTest):
typecode = 'b'
@ -1172,7 +1210,7 @@ def test_byteswap(self):
# On alphas treating the byte swapped bit patters as
# floats/doubles results in floating point exceptions
# => compare the 8bit string values instead
self.assertNotEqual(a.tostring(), b.tostring())
self.assertNotEqual(a.tobytes(), b.tobytes())
b.byteswap()
self.assertEqual(a, b)

View file

@ -44,7 +44,7 @@ def testReadinto(self):
a = array('b', b'x'*10)
self.f = self.open(TESTFN, 'rb')
n = self.f.readinto(a)
self.assertEquals(b'12', a.tostring()[:n])
self.assertEquals(b'12', a.tobytes()[:n])
def testReadinto_text(self):
# verify readinto refuses text files
@ -281,7 +281,7 @@ def testIteration(self):
except ValueError:
self.fail("readinto() after next() with supposedly empty "
"iteration-buffer failed anyway")
line = buf.tostring()
line = buf.tobytes()
if line != testline:
self.fail("readinto() after next() with empty buffer "
"failed. Got %r, expected %r" % (line, testline))

View file

@ -480,7 +480,7 @@ def test_close_flushes(self):
def test_array_writes(self):
a = array.array('i', range(10))
n = len(a.tostring())
n = len(a.tobytes())
with self.open(support.TESTFN, "wb", 0) as f:
self.assertEqual(f.write(a), n)
with self.open(support.TESTFN, "wb") as f:

View file

@ -425,7 +425,7 @@ def test_readinto(self):
a = array.array('b', b"hello world")
memio = self.ioclass(buf)
memio.readinto(a)
self.assertEqual(a.tostring(), b"1234567890d")
self.assertEqual(a.tobytes(), b"1234567890d")
memio.close()
self.assertRaises(ValueError, memio.readinto, b)

View file

@ -231,7 +231,7 @@ class BaseBytesMemoryTests(AbstractMemoryTests):
class BaseArrayMemoryTests(AbstractMemoryTests):
ro_type = None
rw_type = lambda self, b: array.array('i', list(b))
getitem_type = lambda self, b: array.array('i', list(b)).tostring()
getitem_type = lambda self, b: array.array('i', list(b)).tobytes()
itemsize = array.array('i').itemsize
format = 'i'

View file

@ -430,12 +430,12 @@ def test_pack_into(self):
# Test without offset
s.pack_into(writable_buf, 0, test_string)
from_buf = writable_buf.tostring()[:len(test_string)]
from_buf = writable_buf.tobytes()[: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 = writable_buf.tobytes()[:len(test_string)+10]
self.assertEqual(from_buf, test_string[:10] + test_string)
# Go beyond boundaries.
@ -458,12 +458,12 @@ def test_pack_into_fn(self):
# Test without offset.
pack_into(writable_buf, 0, test_string)
from_buf = writable_buf.tostring()[:len(test_string)]
from_buf = writable_buf.tobytes()[:len(test_string)]
self.assertEqual(from_buf, test_string)
# Test with offset.
pack_into(writable_buf, 10, test_string)
from_buf = writable_buf.tostring()[:len(test_string)+10]
from_buf = writable_buf.tobytes()[:len(test_string)+10]
self.assertEqual(from_buf, test_string[:10] + test_string)
# Go beyond boundaries.

View file

@ -248,7 +248,7 @@ def readframes(self, nframes):
chunk = chunk.file
chunk.size_read = chunk.size_read + nitems * self._sampwidth
data.byteswap()
data = data.tostring()
data = data.tobytes()
else:
data = self._data_chunk.read(nframes * self._framesize)
if self._convert and data:

View file

@ -149,6 +149,11 @@ Extensions
Library
-------
- Issue #8990: array.fromstring() and array.tostring() get renamed to
frombytes() and tobytes(), respectively, to avoid confusion. Furthermore,
array.frombytes(), array.extend() as well as the array.array()
constructor now accept bytearray objects. Patch by Thomas Jollans.
- Issue #808164: Fixed socket.close to avoid references to globals, to
avoid issues when socket.close is called from a __del__ method.

View file

@ -1175,7 +1175,7 @@ Reverse the order of the items in the array.");
/* Forward */
static PyObject *array_fromstring(arrayobject *self, PyObject *args);
static PyObject *array_frombytes(arrayobject *self, PyObject *args);
static PyObject *
array_fromfile(arrayobject *self, PyObject *args)
@ -1212,7 +1212,7 @@ array_fromfile(arrayobject *self, PyObject *args)
if (args == NULL)
return NULL;
res = array_fromstring(self, args);
res = array_frombytes(self, args);
Py_DECREF(args);
if (res == NULL)
return NULL;
@ -1331,16 +1331,19 @@ PyDoc_STRVAR(tolist_doc,
\n\
Convert array to an ordinary list with the same items.");
static PyObject *
array_fromstring(arrayobject *self, PyObject *args)
frombytes(arrayobject *self, Py_buffer *buffer)
{
char *str;
Py_ssize_t n;
int itemsize = self->ob_descr->itemsize;
if (!PyArg_ParseTuple(args, "s#:fromstring", &str, &n))
Py_ssize_t n;
if (buffer->itemsize != 1) {
PyBuffer_Release(buffer);
PyErr_SetString(PyExc_TypeError, "string/buffer of bytes required.");
return NULL;
}
n = buffer->len;
if (n % itemsize != 0) {
PyBuffer_Release(buffer);
PyErr_SetString(PyExc_ValueError,
"string length not a multiple of item size");
return NULL;
@ -1350,26 +1353,62 @@ array_fromstring(arrayobject *self, PyObject *args)
Py_ssize_t old_size = Py_SIZE(self);
if ((n > PY_SSIZE_T_MAX - old_size) ||
((old_size + n) > PY_SSIZE_T_MAX / itemsize)) {
PyBuffer_Release(buffer);
return PyErr_NoMemory();
}
if (array_resize(self, old_size + n) == -1)
if (array_resize(self, old_size + n) == -1) {
PyBuffer_Release(buffer);
return NULL;
memcpy(self->ob_item + old_size * itemsize,
str, n * itemsize);
}
memcpy(self->ob_item + old_size * itemsize,
buffer->buf, n * itemsize);
}
PyBuffer_Release(buffer);
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *
array_fromstring(arrayobject *self, PyObject *args)
{
Py_buffer buffer;
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"fromstring() is deprecated. Use frombytes() instead.", 2) != 0)
return NULL;
if (!PyArg_ParseTuple(args, "s*:fromstring", &buffer))
return NULL;
else
return frombytes(self, &buffer);
}
PyDoc_STRVAR(fromstring_doc,
"fromstring(string)\n\
\n\
Appends items from the string, interpreting it as an array of machine\n\
values, as if it had been read from a file using the fromfile() method).\n\
\n\
This method is deprecated. Use frombytes instead.");
static PyObject *
array_frombytes(arrayobject *self, PyObject *args)
{
Py_buffer buffer;
if (!PyArg_ParseTuple(args, "y*:frombytes", &buffer))
return NULL;
else
return frombytes(self, &buffer);
}
PyDoc_STRVAR(frombytes_doc,
"frombytes(bytestring)\n\
\n\
Appends items from the string, interpreting it as an array of machine\n\
values, as if it had been read from a file using the fromfile() method).");
static PyObject *
array_tostring(arrayobject *self, PyObject *unused)
array_tobytes(arrayobject *self, PyObject *unused)
{
if (Py_SIZE(self) <= PY_SSIZE_T_MAX / self->ob_descr->itemsize) {
return PyBytes_FromStringAndSize(self->ob_item,
@ -1379,13 +1418,30 @@ array_tostring(arrayobject *self, PyObject *unused)
}
}
PyDoc_STRVAR(tostring_doc,
"tostring() -> string\n\
PyDoc_STRVAR(tobytes_doc,
"tobytes() -> bytes\n\
\n\
Convert the array to an array of machine values and return the string\n\
Convert the array to an array of machine values and return the bytes\n\
representation.");
static PyObject *
array_tostring(arrayobject *self, PyObject *unused)
{
if (PyErr_WarnEx(PyExc_DeprecationWarning,
"tostring() is deprecated. Use tobytes() instead.", 2) != 0)
return NULL;
return array_tobytes(self, unused);
}
PyDoc_STRVAR(tostring_doc,
"tostring() -> bytes\n\
\n\
Convert the array to an array of machine values and return the bytes\n\
representation.\n\
\n\
This method is deprecated. Use tobytes instead.");
static PyObject *
array_fromunicode(arrayobject *self, PyObject *args)
@ -1420,7 +1476,7 @@ PyDoc_STRVAR(fromunicode_doc,
\n\
Extends this array with data from the unicode string ustr.\n\
The array must be a unicode type array; otherwise a ValueError\n\
is raised. Use array.fromstring(ustr.decode(...)) to\n\
is raised. Use array.frombytes(ustr.decode(...)) to\n\
append Unicode data to an array of some other type.");
@ -1927,7 +1983,7 @@ array_reduce_ex(arrayobject *array, PyObject *value)
return result;
}
array_str = array_tostring(array, NULL);
array_str = array_tobytes(array, NULL);
if (array_str == NULL) {
Py_DECREF(dict);
return NULL;
@ -1983,6 +2039,8 @@ static PyMethodDef array_methods[] = {
fromlist_doc},
{"fromstring", (PyCFunction)array_fromstring, METH_VARARGS,
fromstring_doc},
{"frombytes", (PyCFunction)array_frombytes, METH_VARARGS,
frombytes_doc},
{"fromunicode", (PyCFunction)array_fromunicode, METH_VARARGS,
fromunicode_doc},
{"index", (PyCFunction)array_index, METH_O,
@ -2005,6 +2063,8 @@ static PyMethodDef array_methods[] = {
tolist_doc},
{"tostring", (PyCFunction)array_tostring, METH_NOARGS,
tostring_doc},
{"tobytes", (PyCFunction)array_tobytes, METH_NOARGS,
tobytes_doc},
{"tounicode", (PyCFunction)array_tounicode, METH_NOARGS,
tounicode_doc},
{NULL, NULL} /* sentinel */
@ -2386,7 +2446,7 @@ array_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
Py_DECREF(a);
return NULL;
}
v = array_fromstring((arrayobject *)a,
v = array_frombytes((arrayobject *)a,
t_initial);
Py_DECREF(t_initial);
if (v == NULL) {