Fix classmethod for non-cdef classes.
authorRobert Bradshaw <robertwb@math.washington.edu>
Thu, 29 Nov 2007 08:09:42 +0000 (00:09 -0800)
committerRobert Bradshaw <robertwb@math.washington.edu>
Thu, 29 Nov 2007 08:09:42 +0000 (00:09 -0800)
Cython/Compiler/Parsing.py
Cython/Compiler/Symtab.py

index 47f8c4756ac2cbc1540ca945f03187030cd8a02f..5df24922d470df34a51d963110db2f5d92d1154d 100644 (file)
@@ -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)
index f680763a16c461972265967e86f8fd7dc5de3e2c..66787d1ce436c99e439380f29aaba5496beb3c30 100644 (file)
@@ -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;
 }
 """
 ]