Commit 1d6dbf9d authored by Robert Bradshaw's avatar Robert Bradshaw

Fix classmethod for use in cdef classes.

The issue here (as pointed out by Thomas Hunger) is that once the CClass
body gets executed the class is already constructed, and its methods
are actual methods not functions (as in Python).

The CClassScope now returns a utility function on lookup of "classmethod"
that creates a class method out of a method (rather than out of a function).
When added to the type dictionary, the result is exactly the same as setting
the METH_CLASS flag.
parent 1c9be2fc
...@@ -1372,9 +1372,6 @@ class CClassDefNode(StatNode): ...@@ -1372,9 +1372,6 @@ class CClassDefNode(StatNode):
def analyse_expressions(self, env): def analyse_expressions(self, env):
if self.body: if self.body:
scope = self.entry.type.scope scope = self.entry.type.scope
print "env", env
print "scope", scope
print scope.outer_scope
self.body.analyse_expressions(scope) self.body.analyse_expressions(scope)
def generate_function_definitions(self, env, code): def generate_function_definitions(self, env, code):
......
...@@ -344,7 +344,6 @@ class Scope: ...@@ -344,7 +344,6 @@ class Scope:
error(pos, "'%s' is not declared" % name) error(pos, "'%s' is not declared" % name)
def lookup(self, name): def lookup(self, name):
print "looking up", name, "in", self
# Look up name in this scope or an enclosing one. # Look up name in this scope or an enclosing one.
# Return None if not found. # Return None if not found.
return (self.lookup_here(name) return (self.lookup_here(name)
...@@ -980,10 +979,6 @@ class ClassScope(Scope): ...@@ -980,10 +979,6 @@ class ClassScope(Scope):
def add_string_const(self, value): def add_string_const(self, value):
return self.outer_scope.add_string_const(value) return self.outer_scope.add_string_const(value)
def lookup(self, name):
res = Scope.lookup(self, name)
return res
class PyClassScope(ClassScope): class PyClassScope(ClassScope):
# Namespace of a Python class. # Namespace of a Python class.
...@@ -1194,6 +1189,21 @@ class CClassScope(ClassScope): ...@@ -1194,6 +1189,21 @@ class CClassScope(ClassScope):
def release_temp(self, cname): def release_temp(self, cname):
return Scope.release_temp(self.global_scope(), 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): class PropertyScope(Scope):
# Scope holding the __get__, __set__ and __del__ methods for # Scope holding the __get__, __set__ and __del__ methods for
...@@ -1213,3 +1223,25 @@ class PropertyScope(Scope): ...@@ -1213,3 +1223,25 @@ class PropertyScope(Scope):
error(pos, "Only __get__, __set__ and __del__ methods allowed " error(pos, "Only __get__, __set__ and __del__ methods allowed "
"in a property declaration") "in a property declaration")
return None 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(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;
}
PyMethodDescrObject *descr = (PyMethodDescrObject *)method;
return PyDescr_NewClassMethod(descr->d_type, descr->d_method);
}
"""
]
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment