summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSerhiy Storchaka <storchaka@gmail.com>2016-03-06 06:55:21 (GMT)
committerSerhiy Storchaka <storchaka@gmail.com>2016-03-06 06:55:21 (GMT)
commita0d416f0d186b5ee6ea6a898418871157a55b4f6 (patch)
tree026f19318df96522ce2dcca993f74e3dfa5a2538
parent841b930a41be90c6c05fb4bab8392f50e01d86b7 (diff)
downloadcpython-a0d416f0d186b5ee6ea6a898418871157a55b4f6.zip
cpython-a0d416f0d186b5ee6ea6a898418871157a55b4f6.tar.gz
cpython-a0d416f0d186b5ee6ea6a898418871157a55b4f6.tar.bz2
Issue #26482: Allowed pickling recursive dequeues.
-rw-r--r--Lib/test/test_deque.py68
-rw-r--r--Misc/NEWS2
-rw-r--r--Modules/_collectionsmodule.c36
3 files changed, 56 insertions, 50 deletions
diff --git a/Lib/test/test_deque.py b/Lib/test/test_deque.py
index e2c6b6c..634d71f 100644
--- a/Lib/test/test_deque.py
+++ b/Lib/test/test_deque.py
@@ -622,20 +622,22 @@ class TestBasic(unittest.TestCase):
self.assertEqual(list(d), list(e))
def test_pickle(self):
- d = deque(range(200))
- for i in range(pickle.HIGHEST_PROTOCOL + 1):
- s = pickle.dumps(d, i)
- e = pickle.loads(s)
- self.assertNotEqual(id(d), id(e))
- self.assertEqual(list(d), list(e))
-
-## def test_pickle_recursive(self):
-## d = deque('abc')
-## d.append(d)
-## for i in range(pickle.HIGHEST_PROTOCOL + 1):
-## e = pickle.loads(pickle.dumps(d, i))
-## self.assertNotEqual(id(d), id(e))
-## self.assertEqual(id(e), id(e[-1]))
+ for d in deque(range(200)), deque(range(200), 100):
+ for i in range(pickle.HIGHEST_PROTOCOL + 1):
+ s = pickle.dumps(d, i)
+ e = pickle.loads(s)
+ self.assertNotEqual(id(e), id(d))
+ self.assertEqual(list(e), list(d))
+ self.assertEqual(e.maxlen, d.maxlen)
+
+ def test_pickle_recursive(self):
+ for d in deque('abc'), deque('abc', 3):
+ d.append(d)
+ for i in range(pickle.HIGHEST_PROTOCOL + 1):
+ e = pickle.loads(pickle.dumps(d, i))
+ self.assertNotEqual(id(e), id(d))
+ self.assertEqual(id(e[-1]), id(e))
+ self.assertEqual(e.maxlen, d.maxlen)
def test_iterator_pickle(self):
data = deque(range(200))
@@ -827,24 +829,26 @@ class TestSubclass(unittest.TestCase):
self.assertEqual(type(d), type(e))
self.assertEqual(list(d), list(e))
-## def test_pickle(self):
-## d = Deque('abc')
-## d.append(d)
-##
-## e = pickle.loads(pickle.dumps(d))
-## self.assertNotEqual(id(d), id(e))
-## self.assertEqual(type(d), type(e))
-## dd = d.pop()
-## ee = e.pop()
-## self.assertEqual(id(e), id(ee))
-## self.assertEqual(d, e)
-##
-## d.x = d
-## e = pickle.loads(pickle.dumps(d))
-## self.assertEqual(id(e), id(e.x))
-##
-## d = DequeWithBadIter('abc')
-## self.assertRaises(TypeError, pickle.dumps, d)
+ def test_pickle_recursive(self):
+ for proto in range(pickle.HIGHEST_PROTOCOL + 1):
+ for d in Deque('abc'), Deque('abc', 3):
+ d.append(d)
+
+ e = pickle.loads(pickle.dumps(d, proto))
+ self.assertNotEqual(id(e), id(d))
+ self.assertEqual(type(e), type(d))
+ self.assertEqual(e.maxlen, d.maxlen)
+ dd = d.pop()
+ ee = e.pop()
+ self.assertEqual(id(ee), id(e))
+ self.assertEqual(e, d)
+
+ d.x = d
+ e = pickle.loads(pickle.dumps(d, proto))
+ self.assertEqual(id(e.x), id(e))
+
+ for d in DequeWithBadIter('abc'), DequeWithBadIter('abc', 2):
+ self.assertRaises(TypeError, pickle.dumps, d, proto)
def test_weakref(self):
d = deque('gallahad')
diff --git a/Misc/NEWS b/Misc/NEWS
index 3eee944..4ce8bf6 100644
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -201,6 +201,8 @@ Core and Builtins
Library
-------
+- Issue #26482: Allowed pickling recursive dequeues.
+
- Issue #26335: Make mmap.write() return the number of bytes written like
other write methods. Patch by Jakub Stasiak.
diff --git a/Modules/_collectionsmodule.c b/Modules/_collectionsmodule.c
index 19a86d1..d57f1ba 100644
--- a/Modules/_collectionsmodule.c
+++ b/Modules/_collectionsmodule.c
@@ -1296,31 +1296,31 @@ deque_traverse(dequeobject *deque, visitproc visit, void *arg)
static PyObject *
deque_reduce(dequeobject *deque)
{
- PyObject *dict, *result, *aslist;
+ PyObject *dict, *it;
_Py_IDENTIFIER(__dict__);
dict = _PyObject_GetAttrId((PyObject *)deque, &PyId___dict__);
- if (dict == NULL)
+ if (dict == NULL) {
+ if (!PyErr_ExceptionMatches(PyExc_AttributeError)) {
+ return NULL;
+ }
PyErr_Clear();
- aslist = PySequence_List((PyObject *)deque);
- if (aslist == NULL) {
- Py_XDECREF(dict);
+ dict = Py_None;
+ Py_INCREF(dict);
+ }
+
+ it = PyObject_GetIter((PyObject *)deque);
+ if (it == NULL) {
+ Py_DECREF(dict);
return NULL;
}
- if (dict == NULL) {
- if (deque->maxlen < 0)
- result = Py_BuildValue("O(O)", Py_TYPE(deque), aslist);
- else
- result = Py_BuildValue("O(On)", Py_TYPE(deque), aslist, deque->maxlen);
- } else {
- if (deque->maxlen < 0)
- result = Py_BuildValue("O(OO)O", Py_TYPE(deque), aslist, Py_None, dict);
- else
- result = Py_BuildValue("O(On)O", Py_TYPE(deque), aslist, deque->maxlen, dict);
+
+ if (deque->maxlen < 0) {
+ return Py_BuildValue("O()NN", Py_TYPE(deque), dict, it);
+ }
+ else {
+ return Py_BuildValue("O(()n)NN", Py_TYPE(deque), deque->maxlen, dict, it);
}
- Py_XDECREF(dict);
- Py_DECREF(aslist);
- return result;
}
PyDoc_STRVAR(reduce_doc, "Return state information for pickling.");