Skip to content

Commit e51dd9d

Browse files
authored
bpo-29727: Register array.array as a MutableSequence (GH-21338)
1 parent b3dd5cd commit e51dd9d

File tree

3 files changed

+88
-0
lines changed

3 files changed

+88
-0
lines changed

Lib/test/test_array.py

+66
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
Roger E. Masse
33
"""
44

5+
import collections.abc
56
import unittest
67
from test import support
78
from test.support import os_helper
@@ -29,6 +30,10 @@ def __init__(self, typecode, newarg=None):
2930

3031
class MiscTest(unittest.TestCase):
3132

33+
def test_array_is_sequence(self):
34+
self.assertIsInstance(array.array("B"), collections.abc.MutableSequence)
35+
self.assertIsInstance(array.array("B"), collections.abc.Reversible)
36+
3237
def test_bad_constructor(self):
3338
self.assertRaises(TypeError, array.array)
3439
self.assertRaises(TypeError, array.array, spam=42)
@@ -331,6 +336,67 @@ def test_exhausted_iterator(self):
331336
self.assertEqual(list(empit), [self.outside])
332337
self.assertEqual(list(a), list(self.example) + [self.outside])
333338

339+
def test_reverse_iterator(self):
340+
a = array.array(self.typecode, self.example)
341+
self.assertEqual(list(a), list(self.example))
342+
self.assertEqual(list(reversed(a)), list(iter(a))[::-1])
343+
344+
def test_reverse_iterator_picking(self):
345+
orig = array.array(self.typecode, self.example)
346+
data = list(orig)
347+
data2 = [self.outside] + data
348+
rev_data = data[len(data)-2::-1] + [self.outside]
349+
for proto in range(pickle.HIGHEST_PROTOCOL + 1):
350+
# initial iterator
351+
itorig = reversed(orig)
352+
d = pickle.dumps((itorig, orig), proto)
353+
it, a = pickle.loads(d)
354+
a.insert(0, self.outside)
355+
self.assertEqual(type(it), type(itorig))
356+
self.assertEqual(list(it), rev_data)
357+
self.assertEqual(list(a), data2)
358+
359+
# running iterator
360+
next(itorig)
361+
d = pickle.dumps((itorig, orig), proto)
362+
it, a = pickle.loads(d)
363+
a.insert(0, self.outside)
364+
self.assertEqual(type(it), type(itorig))
365+
self.assertEqual(list(it), rev_data[1:])
366+
self.assertEqual(list(a), data2)
367+
368+
# empty iterator
369+
for i in range(1, len(data)):
370+
next(itorig)
371+
d = pickle.dumps((itorig, orig), proto)
372+
it, a = pickle.loads(d)
373+
a.insert(0, self.outside)
374+
self.assertEqual(type(it), type(itorig))
375+
self.assertEqual(list(it), [])
376+
self.assertEqual(list(a), data2)
377+
378+
# exhausted iterator
379+
self.assertRaises(StopIteration, next, itorig)
380+
d = pickle.dumps((itorig, orig), proto)
381+
it, a = pickle.loads(d)
382+
a.insert(0, self.outside)
383+
self.assertEqual(list(it), [])
384+
self.assertEqual(list(a), data2)
385+
386+
def test_exhausted_reverse_iterator(self):
387+
a = array.array(self.typecode, self.example)
388+
self.assertEqual(list(a), list(self.example))
389+
exhit = reversed(a)
390+
empit = reversed(a)
391+
for x in exhit: # exhaust the iterator
392+
next(empit) # Pointing past the 0th position.
393+
a.insert(0, self.outside)
394+
self.assertEqual(list(exhit), [])
395+
# The iterator index points past the 0th position so inserting
396+
# an element in the beggining does not make it appear.
397+
self.assertEqual(list(empit), [])
398+
self.assertEqual(list(a), [self.outside] + list(self.example))
399+
334400
def test_insert(self):
335401
a = array.array(self.typecode, self.example)
336402
a.insert(0, self.example[0])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Register :class:`array.array` as a
2+
:class:`~collections.abc.MutableSequence`. Patch by Pablo Galindo.

Modules/arraymodule.c

+20
Original file line numberDiff line numberDiff line change
@@ -2989,6 +2989,26 @@ array_modexec(PyObject *m)
29892989
Py_DECREF((PyObject *)&Arraytype);
29902990
return -1;
29912991
}
2992+
2993+
PyObject *abc_mod = PyImport_ImportModule("collections.abc");
2994+
if (!abc_mod) {
2995+
Py_DECREF((PyObject *)&Arraytype);
2996+
return -1;
2997+
}
2998+
PyObject *mutablesequence = PyObject_GetAttrString(abc_mod, "MutableSequence");
2999+
Py_DECREF(abc_mod);
3000+
if (!mutablesequence) {
3001+
Py_DECREF((PyObject *)&Arraytype);
3002+
return -1;
3003+
}
3004+
PyObject *res = PyObject_CallMethod(mutablesequence, "register", "O", (PyObject *)&Arraytype);
3005+
Py_DECREF(mutablesequence);
3006+
if (!res) {
3007+
Py_DECREF((PyObject *)&Arraytype);
3008+
return -1;
3009+
}
3010+
Py_DECREF(res);
3011+
29923012
Py_INCREF((PyObject *)&Arraytype);
29933013
if (PyModule_AddObject(m, "array", (PyObject *)&Arraytype) < 0) {
29943014
Py_DECREF((PyObject *)&Arraytype);

0 commit comments

Comments
 (0)