Index: Objects/setobject.c =================================================================== RCS file: /cvsroot/python/python/dist/src/Objects/setobject.c,v retrieving revision 1.30 diff -u -r1.30 setobject.c --- Objects/setobject.c 28 Sep 2004 01:51:34 -0000 1.30 +++ Objects/setobject.c 8 Nov 2004 10:56:45 -0000 @@ -844,23 +844,48 @@ static PyObject * set_reduce(PySetObject *so) { - PyObject *keys=NULL, *args=NULL, *result=NULL; + PyObject *dict, *result; - keys = PyDict_Keys(so->data); - if (keys == NULL) - goto done; - args = PyTuple_Pack(1, keys); - if (args == NULL) - goto done; - result = PyTuple_Pack(2, so->ob_type, args); -done: - Py_XDECREF(args); - Py_XDECREF(keys); + dict = PyObject_GetAttrString((PyObject *)so, "__dict__"); + if (dict == NULL) { + PyErr_Clear(); + dict = Py_None; + Py_INCREF(dict); + } + result = Py_BuildValue("O()(ON)", so->ob_type, dict, + PyDict_Keys(so->data)); + Py_DECREF(dict); return result; } PyDoc_STRVAR(reduce_doc, "Return state information for pickling."); +static PyObject * +set_setstate(PySetObject *so, PyObject *state) +{ + PyObject *dict, *keys, *result; + + if (!PyArg_UnpackTuple(state, "__setstate__", 2, 2, &dict, &keys)) + return NULL; + if (PyDict_Check(dict)) { + PyObject *k, *v; + int i = 0; + while (PyDict_Next(dict, &i, &k, &v)) + if (PyObject_SetAttr((PyObject *)so, k, v) == -1) + return NULL; + } else if (dict != Py_None) { + PyErr_SetString(PyExc_ValueError, + "attribute state must be dictionary"); + return NULL; + } + PyDict_Clear(so->data); + result = set_update(so, keys); + so->hash = -1; + return result; +} + +PyDoc_STRVAR(setstate_doc, "Process state for unpickling."); + static int set_init(PySetObject *self, PyObject *args, PyObject *kwds) { @@ -925,6 +950,8 @@ reduce_doc}, {"remove", (PyCFunction)set_remove, METH_O, remove_doc}, + {"__setstate__",(PyCFunction)set_setstate, METH_O, + setstate_doc}, {"symmetric_difference",(PyCFunction)set_symmetric_difference, METH_O, symmetric_difference_doc}, {"symmetric_difference_update",(PyCFunction)set_symmetric_difference_update, METH_O, @@ -1041,6 +1068,8 @@ issuperset_doc}, {"__reduce__", (PyCFunction)set_reduce, METH_NOARGS, reduce_doc}, + {"__setstate__",(PyCFunction)set_setstate, METH_O, + setstate_doc}, {"symmetric_difference",(PyCFunction)set_symmetric_difference, METH_O, symmetric_difference_doc}, {"union", (PyCFunction)set_union, METH_O, Index: Lib/test/test_set.py =================================================================== RCS file: /cvsroot/python/python/dist/src/Lib/test/test_set.py,v retrieving revision 1.15 diff -u -r1.15 test_set.py --- Lib/test/test_set.py 28 Sep 2004 01:51:35 -0000 1.15 +++ Lib/test/test_set.py 8 Nov 2004 10:56:46 -0000 @@ -179,6 +179,15 @@ dup = pickle.loads(p) self.assertEqual(self.s, dup, "%s != %s" % (self.s, dup)) + def test_pickling_recursive(self): + a = FrozenSetSubclass() # Anything hashable with a __dict__ will do + s = self.thetype([a]) + a.s = s + p = pickle.dumps(s) + dup = pickle.loads(p) + adup = iter(dup).next() + self.assert_(dup is adup.s) + def test_deepcopy(self): class Tracer: def __init__(self, value): @@ -363,7 +372,17 @@ class SetSubclass(set): pass -class TestSetSubclass(TestSet): +class TestSubclassOps: + + def test_pickleinst(self): + s = self.thetype() + s.s = s + p = pickle.dumps(s) + dup = pickle.loads(p) + self.assertNotEqual(id(s), id(dup)) + self.assertEqual(id(dup), id(dup.s)) + +class TestSetSubclass(TestSet, TestSubclassOps): thetype = SetSubclass class TestFrozenSet(TestJointOps): @@ -413,7 +432,7 @@ class FrozenSetSubclass(frozenset): pass -class TestFrozenSetSubclass(TestFrozenSet): +class TestFrozenSetSubclass(TestFrozenSet, TestSubclassOps): thetype = FrozenSetSubclass def test_constructor_identity(self):