Skip to content

Commit 1ce3eb5

Browse files
committed
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.
1 parent 42cb462 commit 1ce3eb5

File tree

12 files changed

+167
-48
lines changed

12 files changed

+167
-48
lines changed

Doc/library/array.rst

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ The module defines the following type:
6060
appropriate type.
6161

6262
If given a list or string, the initializer is passed to the new array's
63-
:meth:`fromlist`, :meth:`fromstring`, or :meth:`fromunicode` method (see below)
63+
:meth:`fromlist`, :meth:`frombytes`, or :meth:`fromunicode` method (see below)
6464
to add initial items to the array. Otherwise, the iterable initializer is
6565
passed to the :meth:`extend` method.
6666

@@ -136,6 +136,15 @@ The following data items and methods are also supported:
136136
must be the right type to be appended to the array.
137137

138138

139+
.. method:: array.frombytes(s)
140+
141+
Appends items from the string, interpreting the string as an array of machine
142+
values (as if it had been read from a file using the :meth:`fromfile` method).
143+
144+
.. versionadded:: 3.2
145+
:meth:`fromstring` is renamed to :meth:`frombytes` for clarity.
146+
147+
139148
.. method:: array.fromfile(f, n)
140149

141150
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:
151160
a.append(x)`` except that if there is a type error, the array is unchanged.
152161

153162

154-
.. method:: array.fromstring(s)
163+
.. method:: array.fromstring()
155164

156-
Appends items from the string, interpreting the string as an array of machine
157-
values (as if it had been read from a file using the :meth:`fromfile` method).
165+
Deprecated alias for :meth:`frombytes`.
158166

159167

160168
.. method:: array.fromunicode(s)
161169

162170
Extends this array with data from the given unicode string. The array must
163171
be a type ``'u'`` array; otherwise a :exc:`ValueError` is raised. Use
164-
``array.fromstring(unicodestring.encode(enc))`` to append Unicode data to an
172+
``array.frombytes(unicodestring.encode(enc))`` to append Unicode data to an
165173
array of some other type.
166174

167175

@@ -194,6 +202,16 @@ The following data items and methods are also supported:
194202
Reverse the order of the items in the array.
195203

196204

205+
.. method:: array.tobytes()
206+
207+
Convert the array to an array of machine values and return the bytes
208+
representation (the same sequence of bytes that would be written to a file by
209+
the :meth:`tofile` method.)
210+
211+
.. versionadded:: 3.2
212+
:meth:`tostring` is renamed to :meth:`tobytes` for clarity.
213+
214+
197215
.. method:: array.tofile(f)
198216

199217
Write all items (as machine values) to the file object *f*.
@@ -206,15 +224,13 @@ The following data items and methods are also supported:
206224

207225
.. method:: array.tostring()
208226

209-
Convert the array to an array of machine values and return the string
210-
representation (the same sequence of bytes that would be written to a file by
211-
the :meth:`tofile` method.)
227+
Deprecated alias for :meth:`tobytes`.
212228

213229

214230
.. method:: array.tounicode()
215231

216232
Convert the array to a unicode string. The array must be a type ``'u'`` array;
217-
otherwise a :exc:`ValueError` is raised. Use ``array.tostring().decode(enc)`` to
233+
otherwise a :exc:`ValueError` is raised. Use ``array.tobytes().decode(enc)`` to
218234
obtain a unicode string from an array of some other type.
219235

220236

Lib/multiprocessing/managers.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
#
3333

3434
def reduce_array(a):
35-
return array.array, (a.typecode, a.tostring())
35+
return array.array, (a.typecode, a.tobytes())
3636
ForkingPickler.register(array.array, reduce_array)
3737

3838
view_types = [type(getattr({}, name)()) for name in ('items','keys','values')]

Lib/sre_compile.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -343,7 +343,7 @@ def _optimize_unicode(charset, fixup):
343343
else:
344344
code = 'I'
345345
# Convert block indices to byte array of 256 bytes
346-
mapping = array.array('b', mapping).tostring()
346+
mapping = array.array('b', mapping).tobytes()
347347
# Convert byte array to word array
348348
mapping = array.array(code, mapping)
349349
assert mapping.itemsize == _sre.CODESIZE

Lib/test/test_array.py

Lines changed: 48 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
import io
1212
import math
1313
import struct
14+
import warnings
1415

1516
import array
1617
from array import _array_reconstructor as array_reconstructor
@@ -367,15 +368,35 @@ def test_tofromlist(self):
367368
self.assertEqual(a, b)
368369

369370
def test_tofromstring(self):
371+
nb_warnings = 4
372+
with warnings.catch_warnings(record=True) as r:
373+
warnings.filterwarnings("always",
374+
message=r"(to|from)string\(\) is deprecated",
375+
category=DeprecationWarning)
376+
a = array.array(self.typecode, 2*self.example)
377+
b = array.array(self.typecode)
378+
self.assertRaises(TypeError, a.tostring, 42)
379+
self.assertRaises(TypeError, b.fromstring)
380+
self.assertRaises(TypeError, b.fromstring, 42)
381+
b.fromstring(a.tostring())
382+
self.assertEqual(a, b)
383+
if a.itemsize>1:
384+
self.assertRaises(ValueError, b.fromstring, "x")
385+
nb_warnings += 1
386+
self.assertEqual(len(r), nb_warnings)
387+
388+
def test_tofrombytes(self):
370389
a = array.array(self.typecode, 2*self.example)
371390
b = array.array(self.typecode)
372-
self.assertRaises(TypeError, a.tostring, 42)
373-
self.assertRaises(TypeError, b.fromstring)
374-
self.assertRaises(TypeError, b.fromstring, 42)
375-
b.fromstring(a.tostring())
391+
self.assertRaises(TypeError, a.tobytes, 42)
392+
self.assertRaises(TypeError, b.frombytes)
393+
self.assertRaises(TypeError, b.frombytes, 42)
394+
b.frombytes(a.tobytes())
395+
c = array.array(self.typecode, bytearray(a.tobytes()))
376396
self.assertEqual(a, b)
397+
self.assertEqual(a, c)
377398
if a.itemsize>1:
378-
self.assertRaises(ValueError, b.fromstring, "x")
399+
self.assertRaises(ValueError, b.frombytes, b"x")
379400

380401
def test_repr(self):
381402
a = array.array(self.typecode, 2*self.example)
@@ -898,8 +919,8 @@ def test_buffer(self):
898919
a = array.array(self.typecode, self.example)
899920
m = memoryview(a)
900921
expected = m.tobytes()
901-
self.assertEqual(a.tostring(), expected)
902-
self.assertEqual(a.tostring()[0], expected[0])
922+
self.assertEqual(a.tobytes(), expected)
923+
self.assertEqual(a.tobytes()[0], expected[0])
903924
# Resizing is forbidden when there are buffer exports.
904925
# For issue 4509, we also check after each error that
905926
# the array was not modified.
@@ -913,7 +934,7 @@ def test_buffer(self):
913934
self.assertEqual(m.tobytes(), expected)
914935
self.assertRaises(BufferError, a.fromlist, a.tolist())
915936
self.assertEqual(m.tobytes(), expected)
916-
self.assertRaises(BufferError, a.fromstring, a.tostring())
937+
self.assertRaises(BufferError, a.frombytes, a.tobytes())
917938
self.assertEqual(m.tobytes(), expected)
918939
if self.typecode == 'u':
919940
self.assertRaises(BufferError, a.fromunicode, a.tounicode())
@@ -932,7 +953,7 @@ def test_buffer(self):
932953
def test_weakref(self):
933954
s = array.array(self.typecode, self.example)
934955
p = weakref.proxy(s)
935-
self.assertEqual(p.tostring(), s.tostring())
956+
self.assertEqual(p.tobytes(), s.tobytes())
936957
s = None
937958
self.assertRaises(ReferenceError, len, p)
938959

@@ -1110,6 +1131,23 @@ def test_overflow(self):
11101131
upper = int(pow(2, a.itemsize * 8)) - 1
11111132
self.check_overflow(lower, upper)
11121133

1134+
def test_bytes_extend(self):
1135+
s = bytes(self.example)
1136+
1137+
a = array.array(self.typecode, self.example)
1138+
a.extend(s)
1139+
self.assertEqual(
1140+
a,
1141+
array.array(self.typecode, self.example+self.example)
1142+
)
1143+
1144+
a = array.array(self.typecode, self.example)
1145+
a.extend(bytearray(reversed(s)))
1146+
self.assertEqual(
1147+
a,
1148+
array.array(self.typecode, self.example+self.example[::-1])
1149+
)
1150+
11131151

11141152
class ByteTest(SignedNumberTest):
11151153
typecode = 'b'
@@ -1172,7 +1210,7 @@ def test_byteswap(self):
11721210
# On alphas treating the byte swapped bit patters as
11731211
# floats/doubles results in floating point exceptions
11741212
# => compare the 8bit string values instead
1175-
self.assertNotEqual(a.tostring(), b.tostring())
1213+
self.assertNotEqual(a.tobytes(), b.tobytes())
11761214
b.byteswap()
11771215
self.assertEqual(a, b)
11781216

Lib/test/test_file.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ def testReadinto(self):
4444
a = array('b', b'x'*10)
4545
self.f = self.open(TESTFN, 'rb')
4646
n = self.f.readinto(a)
47-
self.assertEquals(b'12', a.tostring()[:n])
47+
self.assertEquals(b'12', a.tobytes()[:n])
4848

4949
def testReadinto_text(self):
5050
# verify readinto refuses text files
@@ -281,7 +281,7 @@ def testIteration(self):
281281
except ValueError:
282282
self.fail("readinto() after next() with supposedly empty "
283283
"iteration-buffer failed anyway")
284-
line = buf.tostring()
284+
line = buf.tobytes()
285285
if line != testline:
286286
self.fail("readinto() after next() with empty buffer "
287287
"failed. Got %r, expected %r" % (line, testline))

Lib/test/test_io.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -480,7 +480,7 @@ def test_close_flushes(self):
480480

481481
def test_array_writes(self):
482482
a = array.array('i', range(10))
483-
n = len(a.tostring())
483+
n = len(a.tobytes())
484484
with self.open(support.TESTFN, "wb", 0) as f:
485485
self.assertEqual(f.write(a), n)
486486
with self.open(support.TESTFN, "wb") as f:

Lib/test/test_memoryio.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -425,7 +425,7 @@ def test_readinto(self):
425425
a = array.array('b', b"hello world")
426426
memio = self.ioclass(buf)
427427
memio.readinto(a)
428-
self.assertEqual(a.tostring(), b"1234567890d")
428+
self.assertEqual(a.tobytes(), b"1234567890d")
429429
memio.close()
430430
self.assertRaises(ValueError, memio.readinto, b)
431431

Lib/test/test_memoryview.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,7 +231,7 @@ class BaseBytesMemoryTests(AbstractMemoryTests):
231231
class BaseArrayMemoryTests(AbstractMemoryTests):
232232
ro_type = None
233233
rw_type = lambda self, b: array.array('i', list(b))
234-
getitem_type = lambda self, b: array.array('i', list(b)).tostring()
234+
getitem_type = lambda self, b: array.array('i', list(b)).tobytes()
235235
itemsize = array.array('i').itemsize
236236
format = 'i'
237237

Lib/test/test_struct.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -430,12 +430,12 @@ def test_pack_into(self):
430430

431431
# Test without offset
432432
s.pack_into(writable_buf, 0, test_string)
433-
from_buf = writable_buf.tostring()[:len(test_string)]
433+
from_buf = writable_buf.tobytes()[:len(test_string)]
434434
self.assertEqual(from_buf, test_string)
435435

436436
# Test with offset.
437437
s.pack_into(writable_buf, 10, test_string)
438-
from_buf = writable_buf.tostring()[:len(test_string)+10]
438+
from_buf = writable_buf.tobytes()[:len(test_string)+10]
439439
self.assertEqual(from_buf, test_string[:10] + test_string)
440440

441441
# Go beyond boundaries.
@@ -458,12 +458,12 @@ def test_pack_into_fn(self):
458458

459459
# Test without offset.
460460
pack_into(writable_buf, 0, test_string)
461-
from_buf = writable_buf.tostring()[:len(test_string)]
461+
from_buf = writable_buf.tobytes()[:len(test_string)]
462462
self.assertEqual(from_buf, test_string)
463463

464464
# Test with offset.
465465
pack_into(writable_buf, 10, test_string)
466-
from_buf = writable_buf.tostring()[:len(test_string)+10]
466+
from_buf = writable_buf.tobytes()[:len(test_string)+10]
467467
self.assertEqual(from_buf, test_string[:10] + test_string)
468468

469469
# Go beyond boundaries.

Lib/wave.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,7 @@ def readframes(self, nframes):
248248
chunk = chunk.file
249249
chunk.size_read = chunk.size_read + nitems * self._sampwidth
250250
data.byteswap()
251-
data = data.tostring()
251+
data = data.tobytes()
252252
else:
253253
data = self._data_chunk.read(nframes * self._framesize)
254254
if self._convert and data:

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -149,6 +149,11 @@ Extensions
149149
Library
150150
-------
151151

152+
- Issue #8990: array.fromstring() and array.tostring() get renamed to
153+
frombytes() and tobytes(), respectively, to avoid confusion. Furthermore,
154+
array.frombytes(), array.extend() as well as the array.array()
155+
constructor now accept bytearray objects. Patch by Thomas Jollans.
156+
152157
- Issue #808164: Fixed socket.close to avoid references to globals, to
153158
avoid issues when socket.close is called from a __del__ method.
154159

0 commit comments

Comments
 (0)