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):
def analyse_expressions(self, env):
if self.body:
scope = self.entry.type.scope
print "env", env
print "scope", scope
print scope.outer_scope
self.body.analyse_expressions(scope)
def generate_function_definitions(self, env, code):
......
......@@ -344,7 +344,6 @@ class Scope:
error(pos, "'%s' is not declared" % name)
def lookup(self, name):
print "looking up", name, "in", self
# Look up name in this scope or an enclosing one.
# Return None if not found.
return (self.lookup_here(name)
......@@ -980,10 +979,6 @@ class ClassScope(Scope):
def add_string_const(self, value):
return self.outer_scope.add_string_const(value)
def lookup(self, name):
res = Scope.lookup(self, name)
return res
class PyClassScope(ClassScope):
# Namespace of a Python class.
......@@ -1194,6 +1189,21 @@ 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
......@@ -1213,3 +1223,25 @@ 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(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