summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Doc/library/array.rst34
-rw-r--r--Lib/multiprocessing/managers.py2
-rw-r--r--Lib/sre_compile.py2
-rwxr-xr-xLib/test/test_array.py58
-rw-r--r--Lib/test/test_file.py4
-rw-r--r--Lib/test/test_io.py2
-rw-r--r--Lib/test/test_memoryio.py2
-rw-r--r--Lib/test/test_memoryview.py2
-rw-r--r--Lib/test/test_struct.py8
-rw-r--r--Lib/wave.py2
-rw-r--r--Misc/NEWS5
-rw-r--r--Modules/arraymodule.c94
12 files changed, 167 insertions, 48 deletions
diff --git a/Doc/library/array.rst b/Doc/library/array.rst
index 2235f08..e24a98b 100644
--- a/Doc/library/array.rst
+++ b/Doc/library/array.rst
@@ -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.
diff --git a/Lib/multiprocessing/managers.py b/Lib/multiprocessing/managers.py
index 8faf34e..44f749b 100644
--- a/Lib/multiprocessing/managers.py
+++ b/Lib/multiprocessing/managers.py
@@ -32,7 +32,7 @@ from multiprocessing.util import Finalize, info
#
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')]
diff --git a/Lib/sre_compile.py b/Lib/sre_compile.py
index 47e1701..f52ea01 100644
--- a/Lib/sre_compile.py
+++ b/Lib/sre_compile.py
@@ -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
diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
index d8d4ea7..d7b4fa8 100755
--- a/Lib/test/test_array.py
+++ b/Lib/test/test_array.py
@@ -11,6 +11,7 @@ import operator
import io
import math
import struct
+import warnings
import array
from array import _array_reconstructor as array_reconstructor
@@ -367,15 +368,35 @@ class BaseTest(unittest.TestCase):
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)
+ self.assertRaises(TypeError, b.fromstring)
+ self.assertRaises(TypeError, b.fromstring, 42)
+ b.fromstring(a.tostring())
+ 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.tostring, 42)
- self.assertRaises(TypeError, b.fromstring)
- self.assertRaises(TypeError, b.fromstring, 42)
- b.fromstring(a.tostring())
+ 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.fromstring, "x")
+ self.assertRaises(ValueError, b.frombytes, b"x")
def test_repr(self):
a = array.array(self.typecode, 2*self.example)
@@ -898,8 +919,8 @@ class BaseTest(unittest.TestCase):
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 @@ class BaseTest(unittest.TestCase):
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 @@ class BaseTest(unittest.TestCase):
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 @@ class UnsignedNumberTest(NumberTest):
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 @@ class FPTest(NumberTest):
# 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)
diff --git a/Lib/test/test_file.py b/Lib/test/test_file.py
index 6d51fd5..ebaa38b 100644
--- a/Lib/test/test_file.py
+++ b/Lib/test/test_file.py
@@ -44,7 +44,7 @@ class AutoFileTests(unittest.TestCase):
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 @@ class OtherFileTests(unittest.TestCase):
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))
diff --git a/Lib/test/test_io.py b/Lib/test/test_io.py
index fc109f3..76c8536 100644
--- a/Lib/test/test_io.py
+++ b/Lib/test/test_io.py
@@ -480,7 +480,7 @@ class IOTest(unittest.TestCase):
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:
diff --git a/Lib/test/test_memoryio.py b/Lib/test/test_memoryio.py
index 1e7d351..0decda5 100644
--- a/Lib/test/test_memoryio.py
+++ b/Lib/test/test_memoryio.py
@@ -425,7 +425,7 @@ class PyBytesIOTest(MemoryTestMixin, MemorySeekTestMixin, unittest.TestCase):
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)
diff --git a/Lib/test/test_memoryview.py b/Lib/test/test_memoryview.py
index 95071b5..6ca23fc 100644
--- a/Lib/test/test_memoryview.py
+++ b/Lib/test/test_memoryview.py
@@ -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'
diff --git a/Lib/test/test_struct.py b/Lib/test/test_struct.py
index 6ac8fdc..1151662 100644
--- a/Lib/test/test_struct.py
+++ b/Lib/test/test_struct.py
@@ -430,12 +430,12 @@ class StructTest(unittest.TestCase):
# 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 @@ class StructTest(unittest.TestCase):
# 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.
diff --git a/Lib/wave.py b/Lib/wave.py
index 950d8e2..57f9d17 100644
--- a/Lib/wave.py
+++ b/Lib/wave.py
@@ -248,7 +248,7 @@ class Wave_read:
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:
diff --git a/Misc/NEWS b/Misc/NEWS
index 11b5913..2a959a4 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -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.
diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c
index 548f303..6ece49f 100644
--- a/Modules/arraymodule.c
+++ b/Modules/arraymodule.c
@@ -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,45 +1331,84 @@ 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;
}
n = n / itemsize;
if (n > 0) {
- Py_ssize_t old_size = Py_SIZE(self);
+ 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);
+ 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) {