if not self.is_staticmethod and not self.is_classmethod:
rhs.binding = True
+ if self.decorators:
+ for decorator in self.decorators[::-1]:
+ rhs = ExprNodes.SimpleCallNode(
+ decorator.pos,
+ function = decorator.decorator,
+ args = [rhs])
+
self.assmt = SingleAssignmentNode(self.pos,
lhs = ExprNodes.NameNode(self.pos, name = self.name),
rhs = rhs)
# classobj ClassNode Class object
# target NameNode Variable to assign class object to
- child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "classobj", "target"]
+ child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "class_result", "target"]
decorators = None
+ class_result = None
py3_style_class = False # Python3 style class (bases+kwargs)
def __init__(self, pos, name, bases, doc, body, decorators = None,
return cenv
def analyse_declarations(self, env):
+ class_result = self.classobj
+ if self.decorators:
+ from ExprNodes import SimpleCallNode
+ for decorator in self.decorators[::-1]:
+ class_result = SimpleCallNode(
+ decorator.pos,
+ function = decorator.decorator,
+ args = [class_result])
+ self.class_result = class_result
+ self.class_result.analyse_declarations(env)
self.target.analyse_target_declaration(env)
cenv = self.create_scope(env)
cenv.directives = env.directives
self.metaclass.analyse_expressions(env)
self.mkw.analyse_expressions(env)
self.dict.analyse_expressions(env)
- self.classobj.analyse_expressions(env)
+ self.class_result.analyse_expressions(env)
genv = env.global_scope()
cenv = self.scope
self.body.analyse_expressions(cenv)
self.dict.generate_evaluation_code(code)
cenv.namespace_cname = cenv.class_obj_cname = self.dict.result()
self.body.generate_execution_code(code)
- self.classobj.generate_evaluation_code(code)
+ self.class_result.generate_evaluation_code(code)
cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result()
- self.target.generate_assignment_code(self.classobj, code)
+ self.target.generate_assignment_code(self.class_result, code)
self.dict.generate_disposal_code(code)
self.dict.free_temps(code)
if self.py3_style_class:
if env.in_cinclude and not self.objstruct_name:
error(self.pos, "Object struct name specification required for "
"C class defined in 'extern from' block")
+ if self.decorators:
+ error(self.pos,
+ "Decorators not allowed on cdef classes (used on type '%s')" % self.class_name)
self.base_type = None
# Now that module imports are cached, we need to
# import the modules for extern classes.
return node
-class DecoratorTransform(CythonTransform, SkipDeclarations):
+class DecoratorTransform(ScopeTrackingTransform, SkipDeclarations):
+ """Originally, this was the only place where decorators were
+ transformed into the corresponding calling code. Now, this is
+ done directly in DefNode and PyClassDefNode to avoid reassignments
+ to the function/class name - except for cdef class methods. For
+ those, the reassignment is required as methods are originally
+ defined in the PyMethodDef struct.
+ """
def visit_DefNode(self, func_node):
- self.visitchildren(func_node)
- if not func_node.decorators:
+ scope_type = self.scope_type
+ func_node = self.visit_FuncDefNode(func_node)
+ if scope_type is not 'cclass' or not func_node.decorators:
return func_node
return self._handle_decorators(
func_node, func_node.name)
- def visit_CClassDefNode(self, class_node):
- # This doesn't currently work, so it's disabled.
- #
- # Problem: assignments to cdef class names do not work. They
- # would require an additional check anyway, as the extension
- # type must not change its C type, so decorators cannot
- # replace an extension type, just alter it and return it.
-
- self.visitchildren(class_node)
- if not class_node.decorators:
- return class_node
- error(class_node.pos,
- "Decorators not allowed on cdef classes (used on type '%s')" % class_node.class_name)
- return class_node
- #return self._handle_decorators(
- # class_node, class_node.class_name)
-
- def visit_ClassDefNode(self, class_node):
- self.visitchildren(class_node)
- if not class_node.decorators:
- return class_node
- return self._handle_decorators(
- class_node, class_node.name)
-
def _handle_decorators(self, node, name):
decorator_result = ExprNodes.NameNode(node.pos, name = name)
for decorator in node.decorators[::-1]: