diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py index 6af90dfb871..c423f545488 100644 --- a/Lib/test/test_array.py +++ b/Lib/test/test_array.py @@ -2,6 +2,7 @@ Roger E. Masse """ +import collections.abc import unittest from test import support from test.support import os_helper @@ -29,6 +30,10 @@ typecodes = 'ubBhHiIlLfdqQ' class MiscTest(unittest.TestCase): + def test_array_is_sequence(self): + self.assertIsInstance(array.array("B"), collections.abc.MutableSequence) + self.assertIsInstance(array.array("B"), collections.abc.Reversible) + def test_bad_constructor(self): self.assertRaises(TypeError, array.array) self.assertRaises(TypeError, array.array, spam=42) @@ -331,6 +336,67 @@ class BaseTest: self.assertEqual(list(empit), [self.outside]) self.assertEqual(list(a), list(self.example) + [self.outside]) + def test_reverse_iterator(self): + a = array.array(self.typecode, self.example) + self.assertEqual(list(a), list(self.example)) + self.assertEqual(list(reversed(a)), list(iter(a))[::-1]) + + def test_reverse_iterator_picking(self): + orig = array.array(self.typecode, self.example) + data = list(orig) + data2 = [self.outside] + data + rev_data = data[len(data)-2::-1] + [self.outside] + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + # initial iterator + itorig = reversed(orig) + d = pickle.dumps((itorig, orig), proto) + it, a = pickle.loads(d) + a.insert(0, self.outside) + self.assertEqual(type(it), type(itorig)) + self.assertEqual(list(it), rev_data) + self.assertEqual(list(a), data2) + + # running iterator + next(itorig) + d = pickle.dumps((itorig, orig), proto) + it, a = pickle.loads(d) + a.insert(0, self.outside) + self.assertEqual(type(it), type(itorig)) + self.assertEqual(list(it), rev_data[1:]) + self.assertEqual(list(a), data2) + + # empty iterator + for i in range(1, len(data)): + next(itorig) + d = pickle.dumps((itorig, orig), proto) + it, a = pickle.loads(d) + a.insert(0, self.outside) + self.assertEqual(type(it), type(itorig)) + self.assertEqual(list(it), []) + self.assertEqual(list(a), data2) + + # exhausted iterator + self.assertRaises(StopIteration, next, itorig) + d = pickle.dumps((itorig, orig), proto) + it, a = pickle.loads(d) + a.insert(0, self.outside) + self.assertEqual(list(it), []) + self.assertEqual(list(a), data2) + + def test_exhausted_reverse_iterator(self): + a = array.array(self.typecode, self.example) + self.assertEqual(list(a), list(self.example)) + exhit = reversed(a) + empit = reversed(a) + for x in exhit: # exhaust the iterator + next(empit) # Pointing past the 0th position. + a.insert(0, self.outside) + self.assertEqual(list(exhit), []) + # The iterator index points past the 0th position so inserting + # an element in the beggining does not make it appear. + self.assertEqual(list(empit), []) + self.assertEqual(list(a), [self.outside] + list(self.example)) + def test_insert(self): a = array.array(self.typecode, self.example) a.insert(0, self.example[0]) diff --git a/Misc/NEWS.d/next/Library/2020-07-05-19-16-02.bpo-29727.Q6Z2rg.rst b/Misc/NEWS.d/next/Library/2020-07-05-19-16-02.bpo-29727.Q6Z2rg.rst new file mode 100644 index 00000000000..85cfa4f8938 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2020-07-05-19-16-02.bpo-29727.Q6Z2rg.rst @@ -0,0 +1,2 @@ +Register :class:`array.array` as a +:class:`~collections.abc.MutableSequence`. Patch by Pablo Galindo. diff --git a/Modules/arraymodule.c b/Modules/arraymodule.c index 2d498c7e829..2ba2ff43aa8 100644 --- a/Modules/arraymodule.c +++ b/Modules/arraymodule.c @@ -2989,6 +2989,26 @@ array_modexec(PyObject *m) Py_DECREF((PyObject *)&Arraytype); return -1; } + + PyObject *abc_mod = PyImport_ImportModule("collections.abc"); + if (!abc_mod) { + Py_DECREF((PyObject *)&Arraytype); + return -1; + } + PyObject *mutablesequence = PyObject_GetAttrString(abc_mod, "MutableSequence"); + Py_DECREF(abc_mod); + if (!mutablesequence) { + Py_DECREF((PyObject *)&Arraytype); + return -1; + } + PyObject *res = PyObject_CallMethod(mutablesequence, "register", "O", (PyObject *)&Arraytype); + Py_DECREF(mutablesequence); + if (!res) { + Py_DECREF((PyObject *)&Arraytype); + return -1; + } + Py_DECREF(res); + Py_INCREF((PyObject *)&Arraytype); if (PyModule_AddObject(m, "array", (PyObject *)&Arraytype) < 0) { Py_DECREF((PyObject *)&Arraytype);