[Python-checkins] bpo-29727: Register array.array as a MutableSequence (GH-21338)

Pablo Galindo webhook-mailer at python.org
Sun Jul 5 17:43:18 EDT 2020


https://github.com/python/cpython/commit/e51dd9dad6590bf3a940723fbbaaf4f64a3c9228
commit: e51dd9dad6590bf3a940723fbbaaf4f64a3c9228
branch: master
author: Pablo Galindo <Pablogsal at gmail.com>
committer: GitHub <noreply at github.com>
date: 2020-07-05T22:43:14+01:00
summary:

bpo-29727: Register array.array as a MutableSequence (GH-21338)

files:
A Misc/NEWS.d/next/Library/2020-07-05-19-16-02.bpo-29727.Q6Z2rg.rst
M Lib/test/test_array.py
M Modules/arraymodule.c

diff --git a/Lib/test/test_array.py b/Lib/test/test_array.py
index 6af90dfb871d7..c423f545488f8 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 @@ def __init__(self, typecode, newarg=None):
 
 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 @@ def test_exhausted_iterator(self):
         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 0000000000000..85cfa4f893811
--- /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 2d498c7e82941..2ba2ff43aa8b8 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);



More information about the Python-checkins mailing list