From 08a9b9392d51b662349c2fd16e2f9a0ce0f5bfd7 Mon Sep 17 00:00:00 2001 From: Robert Bradshaw Date: Thu, 29 Nov 2007 00:09:42 -0800 Subject: [PATCH] Fix classmethod for non-cdef classes. --- Cython/Compiler/Parsing.py | 2 +- Cython/Compiler/Symtab.py | 43 ++++++++++++++++++++------------------ 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/Cython/Compiler/Parsing.py b/Cython/Compiler/Parsing.py index 47f8c475..5df24922 100644 --- a/Cython/Compiler/Parsing.py +++ b/Cython/Compiler/Parsing.py @@ -1343,7 +1343,7 @@ def p_statement(s, level, cdef_flag = 0, visibility = 'private', api = 0): elif s.sy == 'pass' and level <> 'property': return p_pass_statement(s, with_newline = 1) else: - if level in ('c_class', 'c_class_pxd', 'property'): + if level in ('c_class_pxd', 'property'): s.error("Executable statement not allowed here") if s.sy == 'if': return p_if_statement(s) diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index f680763a..66787d1c 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -1071,6 +1071,21 @@ 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", + CFuncType(py_object_type, [CFuncTypeArg("", py_object_type, None)], 0, 0)) + entry.is_cfunction = 1 + return entry + else: + return Scope.lookup(self, name) + class PyClassScope(ClassScope): # Namespace of a Python class. @@ -1290,21 +1305,6 @@ class CClassScope(ClassScope): def release_temp(self, cname): return Scope.release_temp(self.global_scope(), cname) - 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", - CFuncType(py_object_type, [CFuncTypeArg("", py_object_type, None)], 0, 0)) - entry.is_cfunction = 1 - return entry - else: - return Scope.lookup(self, name) - class PropertyScope(Scope): # Scope holding the __get__, __set__ and __del__ methods for @@ -1337,12 +1337,15 @@ 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(method->ob_type->tp_name, "method_descriptor") != 0) { - PyErr_Format(PyExc_TypeError, "Extension type classmethod() can only be called on a method_descriptor."); - return NULL; + if (strcmp(method->ob_type->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)); } - PyMethodDescrObject *descr = (PyMethodDescrObject *)method; - return PyDescr_NewClassMethod(descr->d_type, descr->d_method); + PyErr_Format(PyExc_TypeError, "Class-level classmethod() can only be called on a method_descriptor or instance method."); + return NULL; } """ ] -- 2.26.2