Author: Ronan Lamy <[email protected]>
Branch: py3.5
Changeset: r92500:3c8212fb97a5
Date: 2017-09-29 12:17 +0200
http://bitbucket.org/pypy/pypy/changeset/3c8212fb97a5/
Log: fix Cython issue with classmethods in cdef classes
diff --git a/pypy/module/cpyext/api.py b/pypy/module/cpyext/api.py
--- a/pypy/module/cpyext/api.py
+++ b/pypy/module/cpyext/api.py
@@ -669,7 +669,7 @@
'PySlice_Type': 'space.gettypeobject(W_SliceObject.typedef)',
'PyStaticMethod_Type': 'space.gettypeobject(StaticMethod.typedef)',
'PyCFunction_Type':
'space.gettypeobject(cpyext.methodobject.W_PyCFunctionObject.typedef)',
- 'PyWrapperDescr_Type':
'space.gettypeobject(cpyext.methodobject.W_PyCMethodObject.typedef)',
+ 'PyWrapperDescr_Type':
'space.gettypeobject(cpyext.methodobject.W_PyCWrapperObject.typedef)',
'PyInstanceMethod_Type':
'space.gettypeobject(cpyext.classobject.InstanceMethod.typedef)',
}.items():
register_global(cpyname, 'PyTypeObject*', pypyexpr, header=pypy_decl)
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
@@ -1,4 +1,4 @@
-from rpython.rtyper.lltypesystem import lltype, rffi, llmemory
+from rpython.rtyper.lltypesystem import lltype, rffi
from pypy.interpreter.baseobjspace import W_Root
from pypy.interpreter.error import OperationError, oefmt
@@ -10,8 +10,7 @@
from pypy.module.cpyext.api import (
CONST_STRING, METH_CLASS, METH_COEXIST, METH_KEYWORDS, METH_NOARGS, METH_O,
METH_STATIC, METH_VARARGS, PyObject, bootstrap_function,
- cpython_api, generic_cpy_call, CANNOT_FAIL,
- PyTypeObjectPtr, slot_function, cts)
+ cpython_api, generic_cpy_call, CANNOT_FAIL, slot_function, cts)
from pypy.module.cpyext.pyobject import (
Py_DecRef, from_ref, make_ref, as_pyobj, make_typedescr)
@@ -102,7 +101,7 @@
return self.space.unwrap(self.descr_method_repr())
def descr_method_repr(self):
- w_objclass = self.w_objclass
+ w_objclass = self.w_objclass
assert isinstance(w_objclass, W_TypeObject)
return self.space.newtext("<method '%s' of '%s' objects>" % (
self.name, w_objclass.name))
@@ -110,7 +109,7 @@
def descr_call(self, space, __args__):
args_w, kw_w = __args__.unpack()
if len(args_w) < 1:
- w_objclass = self.w_objclass
+ w_objclass = self.w_objclass
assert isinstance(w_objclass, W_TypeObject)
raise oefmt(space.w_TypeError,
"descriptor '%8' of '%s' object needs an argument",
@@ -118,7 +117,7 @@
w_instance = args_w[0]
# XXX: needs a stricter test
if not space.isinstance_w(w_instance, self.w_objclass):
- w_objclass = self.w_objclass
+ w_objclass = self.w_objclass
assert isinstance(w_objclass, W_TypeObject)
raise oefmt(space.w_TypeError,
"descriptor '%8' requires a '%s' object but received a '%T'",
@@ -323,11 +322,15 @@
def PyClassMethod_New(space, w_func):
return ClassMethod(w_func)
-@cpython_api([PyTypeObjectPtr, lltype.Ptr(PyMethodDef)], PyObject)
[email protected]("""
+ PyObject *
+ PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)""")
def PyDescr_NewMethod(space, w_type, method):
return W_PyCMethodObject(space, method, w_type)
-@cpython_api([PyObject, lltype.Ptr(PyMethodDef)], PyObject)
[email protected]("""
+ PyObject *
+ PyDescr_NewClassMethod(PyTypeObject *type, PyMethodDef *method)""")
def PyDescr_NewClassMethod(space, w_type, method):
return W_PyCClassMethodObject(space, method, w_type)
diff --git a/pypy/module/cpyext/test/foo.c b/pypy/module/cpyext/test/foo.c
--- a/pypy/module/cpyext/test/foo.c
+++ b/pypy/module/cpyext/test/foo.c
@@ -83,6 +83,22 @@
return cls;
}
+PyObject* make_classmethod(PyObject* method)
+{
+ // adapted from __Pyx_Method_ClassMethod
+ if (PyObject_TypeCheck(method, &PyWrapperDescr_Type)) {
+ return PyClassMethod_New(method);
+ }
+ else if (PyMethod_Check(method)) {
+ return PyClassMethod_New(PyMethod_GET_FUNCTION(method));
+ }
+ else {
+ PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
+ PyTypeObject *d_type = descr->d_common.d_type;
+ return PyDescr_NewClassMethod(d_type, descr->d_method);
+ }
+}
+
static PyObject *
foo_unset(fooobject *self)
{
@@ -95,6 +111,7 @@
{"copy", (PyCFunction)foo_copy, METH_NOARGS, NULL},
{"create", (PyCFunction)foo_create, METH_NOARGS|METH_STATIC, NULL},
{"classmeth", (PyCFunction)foo_classmeth, METH_NOARGS|METH_CLASS, NULL},
+ {"fake_classmeth", (PyCFunction)foo_classmeth, METH_NOARGS, NULL},
{"unset_string_member", (PyCFunction)foo_unset, METH_NOARGS, NULL},
{NULL, NULL} /* sentinel */
};
@@ -167,19 +184,19 @@
/* copied from numpy scalartypes.c for inherited classes */
if (t->tp_bases && (PyTuple_GET_SIZE(t->tp_bases) > 1))
{
- PyTypeObject *sup;
- /* We are inheriting from a Python type as well so
+ PyTypeObject *sup;
+ /* We are inheriting from a Python type as well so
give it first dibs on conversion */
sup = (PyTypeObject *)PyTuple_GET_ITEM(t->tp_bases, 1);
- /* Prevent recursion */
- if (new_fooType != sup->tp_new)
+ /* Prevent recursion */
+ if (new_fooType != sup->tp_new)
{
o = sup->tp_new(t, args, kwds);
return o;
}
}
o = t->tp_alloc(t, 0);
- return o;
+ return o;
};
static PyMemberDef foo_members[] = {
@@ -717,7 +734,7 @@
"foo",
"Module Doc",
-1,
- foo_functions,
+ foo_functions,
NULL,
NULL,
NULL,
@@ -751,6 +768,7 @@
#endif
{
PyObject *d;
+ PyObject *fake_classmeth, *classmeth;
#if PY_MAJOR_VERSION >= 3
PyObject *module = PyModule_Create(&moduledef);
#else
@@ -808,6 +826,10 @@
INITERROR;
gettype2 = PyObject_New(PyObject, &GetType2);
+ fake_classmeth = PyDict_GetItemString((PyObject *)fooType.tp_dict,
"fake_classmeth");
+ classmeth = make_classmethod(fake_classmeth);
+ if (PyDict_SetItemString((PyObject *)fooType.tp_dict, "fake_classmeth",
classmeth) < 0)
+ INITERROR;
d = PyModule_GetDict(module);
if (d == NULL)
diff --git a/pypy/module/cpyext/test/test_typeobject.py
b/pypy/module/cpyext/test/test_typeobject.py
--- a/pypy/module/cpyext/test/test_typeobject.py
+++ b/pypy/module/cpyext/test/test_typeobject.py
@@ -135,6 +135,12 @@
"<method 'copy' of 'foo' objects>")
raises(TypeError, descr, None)
+ def test_cython_fake_classmethod(self):
+ module = self.import_module(name='foo')
+ print(module.fooType.fake_classmeth)
+ print(type(module.fooType.fake_classmeth))
+ assert module.fooType.fake_classmeth() is module.fooType
+
def test_new(self):
# XXX cpython segfaults but if run singly (with -k test_new) this
passes
module = self.import_module(name='foo')
_______________________________________________
pypy-commit mailing list
[email protected]
https://mail.python.org/mailman/listinfo/pypy-commit