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