bpo-29727: Register array.array as a MutableSequence (GH-21338)
This commit is contained in:
parent
b3dd5cd4a3
commit
e51dd9dad6
|
@ -2,6 +2,7 @@
|
||||||
Roger E. Masse
|
Roger E. Masse
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import collections.abc
|
||||||
import unittest
|
import unittest
|
||||||
from test import support
|
from test import support
|
||||||
from test.support import os_helper
|
from test.support import os_helper
|
||||||
|
@ -29,6 +30,10 @@ typecodes = 'ubBhHiIlLfdqQ'
|
||||||
|
|
||||||
class MiscTest(unittest.TestCase):
|
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):
|
def test_bad_constructor(self):
|
||||||
self.assertRaises(TypeError, array.array)
|
self.assertRaises(TypeError, array.array)
|
||||||
self.assertRaises(TypeError, array.array, spam=42)
|
self.assertRaises(TypeError, array.array, spam=42)
|
||||||
|
@ -331,6 +336,67 @@ class BaseTest:
|
||||||
self.assertEqual(list(empit), [self.outside])
|
self.assertEqual(list(empit), [self.outside])
|
||||||
self.assertEqual(list(a), list(self.example) + [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):
|
def test_insert(self):
|
||||||
a = array.array(self.typecode, self.example)
|
a = array.array(self.typecode, self.example)
|
||||||
a.insert(0, self.example[0])
|
a.insert(0, self.example[0])
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
Register :class:`array.array` as a
|
||||||
|
:class:`~collections.abc.MutableSequence`. Patch by Pablo Galindo.
|
|
@ -2989,6 +2989,26 @@ array_modexec(PyObject *m)
|
||||||
Py_DECREF((PyObject *)&Arraytype);
|
Py_DECREF((PyObject *)&Arraytype);
|
||||||
return -1;
|
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);
|
Py_INCREF((PyObject *)&Arraytype);
|
||||||
if (PyModule_AddObject(m, "array", (PyObject *)&Arraytype) < 0) {
|
if (PyModule_AddObject(m, "array", (PyObject *)&Arraytype) < 0) {
|
||||||
Py_DECREF((PyObject *)&Arraytype);
|
Py_DECREF((PyObject *)&Arraytype);
|
||||||
|
|
Loading…
Reference in New Issue