[Python-checkins] r70941 - in python/branches/py3k: Lib/test/test_functools.py Misc/ACKS Misc/NEWS Modules/_functoolsmodule.c

jack.diederich python-checkins at python.org
Wed Apr 1 06:27:09 CEST 2009


Author: jack.diederich
Date: Wed Apr  1 06:27:09 2009
New Revision: 70941

Log:
Merged revisions 70931 via svnmerge from 
svn+ssh://pythondev@svn.python.org/python/trunk

........
  r70931 | jack.diederich | 2009-03-31 19:46:48 -0400 (Tue, 31 Mar 2009) | 1 line
  
  #5228: add pickle support to functools.partial
........


Modified:
   python/branches/py3k/   (props changed)
   python/branches/py3k/Lib/test/test_functools.py
   python/branches/py3k/Misc/ACKS
   python/branches/py3k/Misc/NEWS
   python/branches/py3k/Modules/_functoolsmodule.c

Modified: python/branches/py3k/Lib/test/test_functools.py
==============================================================================
--- python/branches/py3k/Lib/test/test_functools.py	(original)
+++ python/branches/py3k/Lib/test/test_functools.py	Wed Apr  1 06:27:09 2009
@@ -2,6 +2,7 @@
 import unittest
 from test import support
 from weakref import proxy
+import pickle
 
 @staticmethod
 def PythonPartial(func, *args, **keywords):
@@ -19,6 +20,9 @@
     """capture all positional and keyword arguments"""
     return args, kw
 
+def signature(part):
+    """ return the signature of a partial object """
+    return (part.func, part.args, part.keywords, part.__dict__)
 
 class TestPartial(unittest.TestCase):
 
@@ -141,6 +145,12 @@
         join = self.thetype(''.join)
         self.assertEqual(join(data), '0123456789')
 
+    def test_pickle(self):
+        f = self.thetype(signature, 'asdf', bar=True)
+        f.add_something_to__dict__ = True
+        f_copy = pickle.loads(pickle.dumps(f))
+        self.assertEqual(signature(f), signature(f_copy))
+
 class PartialSubclass(functools.partial):
     pass
 
@@ -148,11 +158,13 @@
 
     thetype = PartialSubclass
 
-
 class TestPythonPartial(TestPartial):
 
     thetype = PythonPartial
 
+    # the python version isn't picklable
+    def test_pickle(self): pass
+
 class TestUpdateWrapper(unittest.TestCase):
 
     def check_wrapper(self, wrapper, wrapped,

Modified: python/branches/py3k/Misc/ACKS
==============================================================================
--- python/branches/py3k/Misc/ACKS	(original)
+++ python/branches/py3k/Misc/ACKS	Wed Apr  1 06:27:09 2009
@@ -167,6 +167,7 @@
 Raghuram Devarakonda
 Toby Dickenson
 Mark Dickinson
+Jack Diederich
 Humberto Diogenes
 Yves Dionne
 Daniel Dittmar

Modified: python/branches/py3k/Misc/NEWS
==============================================================================
--- python/branches/py3k/Misc/NEWS	(original)
+++ python/branches/py3k/Misc/NEWS	Wed Apr  1 06:27:09 2009
@@ -726,6 +726,8 @@
   buffer.
 
 
+- Issue #5228: Make functools.partial objects can now be pickled.
+
 Tests
 -----
 

Modified: python/branches/py3k/Modules/_functoolsmodule.c
==============================================================================
--- python/branches/py3k/Modules/_functoolsmodule.c	(original)
+++ python/branches/py3k/Modules/_functoolsmodule.c	Wed Apr  1 06:27:09 2009
@@ -196,6 +196,53 @@
 	{NULL} /* Sentinel */
 };
 
+/* Pickle strategy:
+   __reduce__ by itself doesn't support getting kwargs in the unpickle
+   operation so we define a __setstate__ that replaces all the information
+   about the partial.  If we only replaced part of it someone would use
+   it as a hook to do stange things.
+ */
+
+PyObject *
+partial_reduce(partialobject *pto, PyObject *unused)
+{
+	return Py_BuildValue("O(O)(OOOO)", Py_TYPE(pto), pto->fn, pto->fn, 
+			     pto->args, pto->kw,
+			     pto->dict ? pto->dict : Py_None);
+}
+
+PyObject *
+partial_setstate(partialobject *pto, PyObject *args)
+{
+	PyObject *fn, *fnargs, *kw, *dict;
+	if (!PyArg_ParseTuple(args, "(OOOO):__setstate__", 
+			      &fn, &fnargs, &kw, &dict))
+		return NULL;
+	Py_XDECREF(pto->fn);
+	Py_XDECREF(pto->args);
+	Py_XDECREF(pto->kw);
+	Py_XDECREF(pto->dict);
+	pto->fn = fn;
+	pto->args = fnargs;
+	pto->kw = kw;
+	if (dict != Py_None) {
+	  pto->dict = dict;
+	  Py_INCREF(dict);
+	} else {
+	  pto->dict = NULL;
+	}
+	Py_INCREF(fn);
+	Py_INCREF(fnargs);
+	Py_INCREF(kw);
+	Py_RETURN_NONE;
+}
+
+static PyMethodDef partial_methods[] = {
+	{"__reduce__", (PyCFunction)partial_reduce, METH_NOARGS},
+	{"__setstate__", (PyCFunction)partial_setstate, METH_VARARGS},
+	{NULL,		NULL}		/* sentinel */
+};
+
 static PyTypeObject partial_type = {
 	PyVarObject_HEAD_INIT(NULL, 0)
 	"functools.partial",		/* tp_name */
@@ -226,7 +273,7 @@
 	offsetof(partialobject, weakreflist),	/* tp_weaklistoffset */
 	0,				/* tp_iter */
 	0,				/* tp_iternext */
-	0,				/* tp_methods */
+	partial_methods,		/* tp_methods */
 	partial_memberlist,		/* tp_members */
 	partial_getsetlist,		/* tp_getset */
 	0,				/* tp_base */


More information about the Python-checkins mailing list