[pypy-commit] pypy default: cpyext: implement built-in classmethods: METH_CLASS flag.
amauryfa
noreply at buildbot.pypy.org
Mon Oct 22 00:33:25 CEST 2012
Author: Amaury Forgeot d'Arc <amauryfa at gmail.com>
Branch:
Changeset: r58331:297db88c1327
Date: 2012-10-21 15:12 +0200
http://bitbucket.org/pypy/pypy/changeset/297db88c1327/
Log: cpyext: implement built-in classmethods: METH_CLASS flag.
diff --git a/pypy/module/cpyext/funcobject.py b/pypy/module/cpyext/funcobject.py
--- a/pypy/module/cpyext/funcobject.py
+++ b/pypy/module/cpyext/funcobject.py
@@ -116,10 +116,6 @@
assert isinstance(w_method, Method)
return borrow_from(w_method, w_method.w_class)
- at cpython_api([PyObject], PyObject)
-def PyClassMethod_New(space, w_function):
- return space.call_method(space.builtin, "classmethod", w_function)
-
def unwrap_list_of_strings(space, w_list):
return [space.str_w(w_item) for w_item in space.fixedview(w_list)]
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
@@ -4,7 +4,8 @@
from pypy.interpreter.typedef import interp_attrproperty, interp_attrproperty_w
from pypy.interpreter.gateway import interp2app
from pypy.interpreter.error import OperationError, operationerrfmt
-from pypy.interpreter.function import BuiltinFunction, Method, StaticMethod
+from pypy.interpreter.function import (
+ BuiltinFunction, Method, StaticMethod, ClassMethod)
from pypy.rpython.lltypesystem import rffi, lltype
from pypy.module.cpyext.pyobject import (PyObject, from_ref, make_ref,
make_typedescr, Py_DecRef)
@@ -128,6 +129,21 @@
PyCFunction_Check, PyCFunction_CheckExact = build_type_checkers("CFunction", W_PyCFunctionObject)
+class W_PyCClassMethodObject(W_PyCFunctionObject):
+ w_self = None
+ def __init__(self, space, ml, w_type):
+ self.space = space
+ self.ml = ml
+ self.name = rffi.charp2str(ml.c_ml_name)
+ self.w_objclass = w_type
+
+ def __repr__(self):
+ return self.space.unwrap(self.descr_method_repr())
+
+ def descr_method_repr(self):
+ return self.getrepr(self.space, "built-in method '%s' of '%s' object" % (self.name, self.w_objclass.getname(self.space)))
+
+
class W_PyCWrapperObject(Wrappable):
def __init__(self, space, pto, method_name, wrapper_func, wrapper_func_kwds,
doc, func):
@@ -196,6 +212,11 @@
else:
return w_function
+def cclassmethod_descr_get(space, w_function, w_obj, w_cls=None):
+ if not w_cls:
+ w_cls = space.type(w_obj)
+ return space.wrap(Method(space, w_function, w_cls, space.w_None))
+
W_PyCFunctionObject.typedef = TypeDef(
'builtin_function_or_method',
@@ -216,6 +237,16 @@
)
W_PyCMethodObject.typedef.acceptable_as_base_class = False
+W_PyCClassMethodObject.typedef = TypeDef(
+ 'classmethod',
+ __get__ = interp2app(cclassmethod_descr_get),
+ __call__ = interp2app(cmethod_descr_call),
+ __name__ = interp_attrproperty('name', cls=W_PyCClassMethodObject),
+ __objclass__ = interp_attrproperty_w('w_objclass', cls=W_PyCClassMethodObject),
+ __repr__ = interp2app(W_PyCClassMethodObject.descr_method_repr),
+ )
+W_PyCClassMethodObject.typedef.acceptable_as_base_class = False
+
W_PyCWrapperObject.typedef = TypeDef(
'wrapper_descriptor',
@@ -243,10 +274,18 @@
def PyStaticMethod_New(space, w_func):
return space.wrap(StaticMethod(w_func))
+ at cpython_api([PyObject], PyObject)
+def PyClassMethod_New(space, w_func):
+ return space.wrap(ClassMethod(w_func))
+
@cpython_api([PyObject, lltype.Ptr(PyMethodDef)], PyObject)
def PyDescr_NewMethod(space, w_type, method):
return space.wrap(W_PyCMethodObject(space, method, w_type))
+ at cpython_api([PyObject, lltype.Ptr(PyMethodDef)], PyObject)
+def PyDescr_NewClassMethod(space, w_type, method):
+ return space.wrap(W_PyCClassMethodObject(space, method, w_type))
+
def PyDescr_NewWrapper(space, pto, method_name, wrapper_func, wrapper_func_kwds,
doc, func):
# not exactly the API sig
diff --git a/pypy/module/cpyext/modsupport.py b/pypy/module/cpyext/modsupport.py
--- a/pypy/module/cpyext/modsupport.py
+++ b/pypy/module/cpyext/modsupport.py
@@ -5,7 +5,7 @@
from pypy.interpreter.module import Module
from pypy.module.cpyext.methodobject import (
W_PyCFunctionObject, PyCFunction_NewEx, PyDescr_NewMethod,
- PyMethodDef, PyStaticMethod_New)
+ PyMethodDef, PyDescr_NewClassMethod, PyStaticMethod_New)
from pypy.module.cpyext.pyerrors import PyErr_BadInternalCall
from pypy.module.cpyext.state import State
from pypy.interpreter.error import OperationError
@@ -97,8 +97,7 @@
if flags & METH_STATIC:
raise OperationError(space.w_ValueError,
space.wrap("method cannot be both class and static"))
- #w_obj = PyDescr_NewClassMethod(space, w_type, method)
- w_obj = space.w_Ellipsis # XXX
+ w_obj = PyDescr_NewClassMethod(space, w_type, method)
elif flags & METH_STATIC:
w_func = PyCFunction_NewEx(space, method, None, None)
w_obj = PyStaticMethod_New(space, w_func)
diff --git a/pypy/module/cpyext/stubs.py b/pypy/module/cpyext/stubs.py
--- a/pypy/module/cpyext/stubs.py
+++ b/pypy/module/cpyext/stubs.py
@@ -434,10 +434,6 @@
def PyDescr_NewWrapper(space, type, wrapper, wrapped):
raise NotImplementedError
- at cpython_api([PyTypeObjectPtr, PyMethodDef], PyObject)
-def PyDescr_NewClassMethod(space, type, method):
- raise NotImplementedError
-
@cpython_api([PyObject], rffi.INT_real, error=CANNOT_FAIL)
def PyDescr_IsData(space, descr):
"""Return true if the descriptor objects descr describes a data attribute, or
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
@@ -72,6 +72,13 @@
}
static PyObject *
+foo_classmeth(PyObject *cls)
+{
+ Py_INCREF(cls);
+ return cls;
+}
+
+static PyObject *
foo_unset(fooobject *self)
{
self->foo_string = NULL;
@@ -82,6 +89,7 @@
static PyMethodDef foo_methods[] = {
{"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},
{"unset_string_member", (PyCFunction)foo_unset, METH_NOARGS, NULL},
{NULL, NULL} /* sentinel */
};
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
@@ -117,6 +117,11 @@
obj2 = obj.create()
assert obj2.foo == 42
+ def test_classmethod(self):
+ module = self.import_module(name="foo")
+ obj = module.fooType.classmeth()
+ assert obj is module.fooType
+
def test_new(self):
module = self.import_module(name='foo')
obj = module.new()
More information about the pypy-commit
mailing list