From: Stefan Behnel Date: Fri, 23 May 2008 20:11:00 +0000 (+0200) Subject: reverted last change, based on extended test case X-Git-Tag: 0.9.8rc1~11^2~10^2~15^2~16 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=e1a600b508467a5c0211b6c65eb15344f9001243;p=cython.git reverted last change, based on extended test case --- diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index 02ad826a..ba2e9d8c 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -1120,6 +1120,24 @@ class ClassScope(Scope): def add_string_const(self, value): return self.outer_scope.add_string_const(value) + + def lookup(self, name): + if name == "classmethod": + # We don't want to use the builtin classmethod here 'cause it won't do the + # right thing in this scope (as the class memebers aren't still functions). + # Don't want to add a cfunction to this scope 'cause that would mess with + # the type definition, so we just return the right entry. + self.use_utility_code(classmethod_utility_code) + entry = Entry( + "classmethod", + "__Pyx_Method_ClassMethod", + PyrexTypes.CFuncType( + py_object_type, + [PyrexTypes.CFuncTypeArg("", py_object_type, None)], 0, 0)) + entry.is_cfunction = 1 + return entry + else: + return Scope.lookup(self, name) class PyClassScope(ClassScope): @@ -1371,3 +1389,28 @@ class PropertyScope(Scope): error(pos, "Only __get__, __set__ and __del__ methods allowed " "in a property declaration") return None + + +# Should this go elsewhere (and then get imported)? +#------------------------------------------------------------------------------------ + +classmethod_utility_code = [ +""" +#include "descrobject.h" +static PyObject* __Pyx_Method_ClassMethod(PyObject *method); /*proto*/ +""",""" +static PyObject* __Pyx_Method_ClassMethod(PyObject *method) { + /* It appears that PyMethodDescr_Type is not anywhere exposed in the Python/C API */ + /* if (!PyObject_TypeCheck(method, &PyMethodDescr_Type)) { */ + if (strcmp(Py_TYPE(method)->tp_name, "method_descriptor") == 0) { /* cdef classes */ + PyMethodDescrObject *descr = (PyMethodDescrObject *)method; + return PyDescr_NewClassMethod(descr->d_type, descr->d_method); + } + else if (PyMethod_Check(method)) { /* python classes */ + return PyClassMethod_New(PyMethod_GET_FUNCTION(method)); + } + PyErr_Format(PyExc_TypeError, "Class-level classmethod() can only be called on a method_descriptor or instance method."); + return NULL; +} +""" +] diff --git a/tests/run/classmethod.pyx b/tests/run/classmethod.pyx index 2577934e..863d18b8 100644 --- a/tests/run/classmethod.pyx +++ b/tests/run/classmethod.pyx @@ -1,8 +1,14 @@ __doc__ = u""" +>>> class1.view() +class1 >>> class1.plus(1) 6 +>>> class2.view() +class2 >>> class2.plus(1) 7 +>>> class3.view() +class3 >>> class3.plus(1) 8 """ @@ -13,11 +19,20 @@ def f_plus(cls, a): class class1: a = 5 plus = classmethod(f_plus) + def view(cls): + print cls.__name__ + view = classmethod(view) class class2(object): a = 6 plus = classmethod(f_plus) + def view(cls): + print cls.__name__ + view = classmethod(view) cdef class class3: a = 7 plus = classmethod(f_plus) + def view(cls): + print cls.__name__ + view = classmethod(view)