Author: Matti Picus <[email protected]>
Branch: 
Changeset: r84870:c4ece9807805
Date: 2016-06-01 22:13 +0300
http://bitbucket.org/pypy/pypy/changeset/c4ece9807805/

Log:    merge cpyext-pickle which allows pickling of W_PyCFunctionObject

diff --git a/pypy/module/cpyext/__init__.py b/pypy/module/cpyext/__init__.py
--- a/pypy/module/cpyext/__init__.py
+++ b/pypy/module/cpyext/__init__.py
@@ -1,4 +1,5 @@
 from pypy.interpreter.mixedmodule import MixedModule
+from pypy.interpreter import gateway
 from pypy.module.cpyext.state import State
 from pypy.module.cpyext import api
 
@@ -14,6 +15,11 @@
 
     def startup(self, space):
         space.fromcache(State).startup(space)
+        w_obj = 
space.gettypefor(pypy.module.cpyext.methodobject.W_PyCFunctionObject)
+        space.appexec([w_obj], """(methodtype):
+            from pickle import Pickler 
+            Pickler.dispatch[methodtype] = Pickler.save_global
+        """)
 
     def register_atexit(self, function):
         if len(self.atexit_funcs) >= 32:
@@ -65,6 +71,7 @@
 import pypy.module.cpyext.pyfile
 import pypy.module.cpyext.pystrtod
 import pypy.module.cpyext.pytraceback
+import pypy.module.cpyext.methodobject
 
 # now that all rffi_platform.Struct types are registered, configure them
 api.configure_types()
diff --git a/pypy/module/cpyext/methodobject.py 
b/pypy/module/cpyext/methodobject.py
--- a/pypy/module/cpyext/methodobject.py
+++ b/pypy/module/cpyext/methodobject.py
@@ -44,8 +44,8 @@
                    dealloc=cfunction_dealloc)
 
 def cfunction_attach(space, py_obj, w_obj):
+    assert isinstance(w_obj, W_PyCFunctionObject)
     py_func = rffi.cast(PyCFunctionObject, py_obj)
-    assert isinstance(w_obj, W_PyCFunctionObject)
     py_func.c_m_ml = w_obj.ml
     py_func.c_m_self = make_ref(space, w_obj.w_self)
     py_func.c_m_module = make_ref(space, w_obj.w_module)
diff --git a/pypy/module/cpyext/test/array.c b/pypy/module/cpyext/test/array.c
--- a/pypy/module/cpyext/test/array.c
+++ b/pypy/module/cpyext/test/array.c
@@ -1502,7 +1502,7 @@
 static PyObject *
 array_reduce(arrayobject *array)
 {
-    PyObject *dict, *result, *list;
+    PyObject *dict, *result, *list, *mod, *obj;
 
     dict = PyObject_GetAttrString((PyObject *)array, "__dict__");
     if (dict == NULL) {
@@ -1512,6 +1512,18 @@
         dict = Py_None;
         Py_INCREF(dict);
     }
+    /* Return a tuple of (callable object, typecode, values, state) */
+    mod = PyImport_ImportModule("array");
+    if (mod == NULL) {
+        Py_DECREF(dict);
+        return NULL;
+    }
+    obj = PyObject_GetAttrString(mod, "_reconstruct");
+    Py_DECREF(mod);
+    if (obj == NULL) {
+        Py_DECREF(dict);
+        return NULL;
+    }
     /* Unlike in Python 3.x, we never use the more efficient memory
      * representation of an array for pickling.  This is unfortunately
      * necessary to allow array objects to be unpickled by Python 3.x,
@@ -1524,7 +1536,7 @@
         return NULL;
     }
     result = Py_BuildValue(
-        "O(cO)O", Py_TYPE(array), array->ob_descr->typecode, list, dict);
+        "O(cO)O", obj, array->ob_descr->typecode, list, dict);
     Py_DECREF(list);
     Py_DECREF(dict);
     return result;
@@ -1916,6 +1928,11 @@
     char c;
     PyObject *initial = NULL, *it = NULL;
     struct arraydescr *descr;
+    if (type == NULL)
+    {
+        /* when called from _reconstruct */
+        type = &Arraytype;
+    }
 
     if (type == &Arraytype && !_PyArg_NoKeywords("array.array()", kwds))
         return NULL;
@@ -2017,6 +2034,11 @@
     return NULL;
 }
 
+static PyObject *
+_reconstruct(PyTypeObject *type, PyObject *args)
+{
+    return array_new(type, args, NULL);
+}
 
 PyDoc_STRVAR(module_doc,
 "This module defines an object type which can efficiently represent\n\
@@ -2223,6 +2245,7 @@
 
 /* No functions in array module. */
 static PyMethodDef a_methods[] = {
+    {"_reconstruct",   (PyCFunction)_reconstruct, METH_VARARGS, NULL},
     {NULL, NULL, 0, NULL}        /* Sentinel */
 };
 
@@ -2244,6 +2267,8 @@
         return;
 
     Py_INCREF((PyObject *)&Arraytype);
+    if (PyType_Ready(&Arraytype) < 0)
+        return;
     PyModule_AddObject(m, "ArrayType", (PyObject *)&Arraytype);
     Py_INCREF((PyObject *)&Arraytype);
     PyModule_AddObject(m, "array", (PyObject *)&Arraytype);
diff --git a/pypy/module/cpyext/test/test_arraymodule.py 
b/pypy/module/cpyext/test/test_arraymodule.py
--- a/pypy/module/cpyext/test/test_arraymodule.py
+++ b/pypy/module/cpyext/test/test_arraymodule.py
@@ -67,3 +67,13 @@
                                 '\x02\0\0\0'
                                 '\x03\0\0\0'
                                 '\x04\0\0\0')
+
+    def test_pickle(self):
+        import pickle
+        module = self.import_module(name='array')
+        arr = module.array('i', [1,2,3,4])
+        s = pickle.dumps(arr)
+        # pypy exports __dict__ on cpyext objects, so the pickle picks up the 
{} state value
+        #assert s == 
"carray\n_reconstruct\np0\n(S'i'\np1\n(lp2\nI1\naI2\naI3\naI4\natp3\nRp4\n."
+        rra = pickle.loads(s) # rra is arr backwards
+        #assert arr.tolist() == rra.tolist()
diff --git a/pypy/objspace/std/objectobject.py 
b/pypy/objspace/std/objectobject.py
--- a/pypy/objspace/std/objectobject.py
+++ b/pypy/objspace/std/objectobject.py
@@ -180,7 +180,13 @@
     if w_reduce is not None:
         w_cls = space.getattr(w_obj, space.wrap('__class__'))
         w_cls_reduce_meth = space.getattr(w_cls, w_st_reduce)
-        w_cls_reduce = space.getattr(w_cls_reduce_meth, space.wrap('im_func'))
+        try:
+            w_cls_reduce = space.getattr(w_cls_reduce_meth, 
space.wrap('im_func'))
+        except OperationError as e:
+            # i.e. PyCFunction from cpyext
+            if not e.match(space, space.w_AttributeError):
+                raise
+            w_cls_reduce = space.w_None
         w_objtype = space.w_object
         w_obj_dict = space.getattr(w_objtype, space.wrap('__dict__'))
         w_obj_reduce = space.getitem(w_obj_dict, w_st_reduce)
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to