diff -r 017e7391ab58 Lib/test/test_dictviews.py --- a/Lib/test/test_dictviews.py Wed Feb 04 08:37:02 2015 -0800 +++ b/Lib/test/test_dictviews.py Wed Feb 04 20:33:54 2015 +0200 @@ -1,5 +1,5 @@ import unittest -from test import support +import pickle class DictSetTest(unittest.TestCase): @@ -198,9 +198,30 @@ class DictSetTest(unittest.TestCase): d[42] = d.values() self.assertRaises(RuntimeError, repr, d) + def test_keys_pickle(self): + d = {'a': 1, 'b': 2, 'c': 3} + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + d2, keys = pickle.loads(pickle.dumps((d, d.keys()), proto)) + self.assertEqual(type(keys), type(d2.keys())) + self.assertEqual(sorted(keys), sorted(d2.keys())) -def test_main(): - support.run_unittest(DictSetTest) + def test_values_pickle(self): + d = {'a': 1, 'b': 2, 'c': 3} + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + d2, values = pickle.loads(pickle.dumps((d, d.values()), proto)) + self.assertEqual(type(values), type(d2.values())) + self.assertEqual(sorted(values), sorted(d2.values())) + + def test_items_pickle(self): + d = {'a': 1, 'b': 2, 'c': 3} + for proto in range(pickle.HIGHEST_PROTOCOL + 1): + with self.subTest(proto=proto): + d2, items = pickle.loads(pickle.dumps((d, d.items()), proto)) + self.assertEqual(type(items), type(d2.items())) + self.assertEqual(sorted(items), sorted(d2.items())) + if __name__ == "__main__": - test_main() + unittets.main() diff -r 017e7391ab58 Misc/NEWS --- a/Misc/NEWS Wed Feb 04 08:37:02 2015 -0800 +++ b/Misc/NEWS Wed Feb 04 20:33:54 2015 +0200 @@ -10,6 +10,8 @@ Release date: TBA Core and Builtins ----------------- +- Issue #23264: Added support for pickling dict views. + - Issue #22896: Avoid using PyObject_AsCharBuffer(), PyObject_AsReadBuffer() and PyObject_AsWriteBuffer(). diff -r 017e7391ab58 Objects/dictobject.c --- a/Objects/dictobject.c Wed Feb 04 08:37:02 2015 -0800 +++ b/Objects/dictobject.c Wed Feb 04 20:33:54 2015 +0200 @@ -3417,6 +3417,14 @@ dictkeys_contains(dictviewobject *dv, Py return PyDict_Contains((PyObject *)dv->dv_dict, obj); } +static PyObject* +dictkeys_reduce(dictviewobject *self) +{ + PyObject *m = PyObject_GetAttrString((PyObject *)Py_TYPE(self->dv_dict), + "keys"); + return Py_BuildValue("N(O)", m, self->dv_dict); +} + static PySequenceMethods dictkeys_as_sequence = { (lenfunc)dictview_len, /* sq_length */ 0, /* sq_concat */ @@ -3585,6 +3593,8 @@ PyDoc_STRVAR(isdisjoint_doc, static PyMethodDef dictkeys_methods[] = { {"isdisjoint", (PyCFunction)dictviews_isdisjoint, METH_O, isdisjoint_doc}, + {"__reduce__", (PyCFunction)dictkeys_reduce, METH_NOARGS, + reduce_doc}, {NULL, NULL} /* sentinel */ }; @@ -3657,6 +3667,14 @@ dictitems_contains(dictviewobject *dv, P return PyObject_RichCompareBool(value, found, Py_EQ); } +static PyObject* +dictitems_reduce(dictviewobject *self) +{ + PyObject *m = PyObject_GetAttrString((PyObject *)Py_TYPE(self->dv_dict), + "items"); + return Py_BuildValue("N(O)", m, self->dv_dict); +} + static PySequenceMethods dictitems_as_sequence = { (lenfunc)dictview_len, /* sq_length */ 0, /* sq_concat */ @@ -3671,6 +3689,8 @@ static PySequenceMethods dictitems_as_se static PyMethodDef dictitems_methods[] = { {"isdisjoint", (PyCFunction)dictviews_isdisjoint, METH_O, isdisjoint_doc}, + {"__reduce__", (PyCFunction)dictitems_reduce, METH_NOARGS, + reduce_doc}, {NULL, NULL} /* sentinel */ }; @@ -3724,6 +3744,14 @@ dictvalues_iter(dictviewobject *dv) return dictiter_new(dv->dv_dict, &PyDictIterValue_Type); } +static PyObject* +dictvalues_reduce(dictviewobject *self) +{ + PyObject *m = PyObject_GetAttrString((PyObject *)Py_TYPE(self->dv_dict), + "values"); + return Py_BuildValue("N(O)", m, self->dv_dict); +} + static PySequenceMethods dictvalues_as_sequence = { (lenfunc)dictview_len, /* sq_length */ 0, /* sq_concat */ @@ -3736,6 +3764,8 @@ static PySequenceMethods dictvalues_as_s }; static PyMethodDef dictvalues_methods[] = { + {"__reduce__", (PyCFunction)dictvalues_reduce, METH_NOARGS, + reduce_doc}, {NULL, NULL} /* sentinel */ };