From 88d7665a6cecf316f93bc604219661db49b9502f Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Thu, 30 Dec 2010 01:22:20 +0100 Subject: [PATCH] Backed out changeset 291e2bdd20d5 - currently breaks Sage build --- Cython/Compiler/Nodes.py | 29 +++---------------- Cython/Compiler/ParseTreeTransforms.py | 38 ++++++++++++++++++------- Cython/Compiler/Tests/TestDecorators.py | 25 ++++++++++++++++ 3 files changed, 56 insertions(+), 36 deletions(-) create mode 100644 Cython/Compiler/Tests/TestDecorators.py diff --git a/Cython/Compiler/Nodes.py b/Cython/Compiler/Nodes.py index 0e7af2d4..92c051ac 100644 --- a/Cython/Compiler/Nodes.py +++ b/Cython/Compiler/Nodes.py @@ -2252,13 +2252,6 @@ class DefNode(FuncDefNode): 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) @@ -2974,9 +2967,8 @@ class PyClassDefNode(ClassDefNode): # classobj ClassNode Class object # target NameNode Variable to assign class object to - child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "class_result", "target"] + child_attrs = ["body", "dict", "metaclass", "mkw", "bases", "classobj", "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, @@ -3079,16 +3071,6 @@ class PyClassDefNode(ClassDefNode): 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 @@ -3101,7 +3083,7 @@ class PyClassDefNode(ClassDefNode): self.metaclass.analyse_expressions(env) self.mkw.analyse_expressions(env) self.dict.analyse_expressions(env) - self.class_result.analyse_expressions(env) + self.classobj.analyse_expressions(env) genv = env.global_scope() cenv = self.scope self.body.analyse_expressions(cenv) @@ -3121,9 +3103,9 @@ class PyClassDefNode(ClassDefNode): self.dict.generate_evaluation_code(code) cenv.namespace_cname = cenv.class_obj_cname = self.dict.result() self.body.generate_execution_code(code) - self.class_result.generate_evaluation_code(code) + self.classobj.generate_evaluation_code(code) cenv.namespace_cname = cenv.class_obj_cname = self.classobj.result() - self.target.generate_assignment_code(self.class_result, code) + self.target.generate_assignment_code(self.classobj, code) self.dict.generate_disposal_code(code) self.dict.free_temps(code) if self.py3_style_class: @@ -3182,9 +3164,6 @@ class CClassDefNode(ClassDefNode): 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. diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index 166ceec7..76e7ea97 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -945,23 +945,39 @@ class WithTransform(CythonTransform, SkipDeclarations): return node -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. - """ +class DecoratorTransform(CythonTransform, SkipDeclarations): def visit_DefNode(self, func_node): - scope_type = self.scope_type - func_node = self.visit_FuncDefNode(func_node) - if scope_type is not 'cclass' or not func_node.decorators: + self.visitchildren(func_node) + if 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]: diff --git a/Cython/Compiler/Tests/TestDecorators.py b/Cython/Compiler/Tests/TestDecorators.py new file mode 100644 index 00000000..5b9286f8 --- /dev/null +++ b/Cython/Compiler/Tests/TestDecorators.py @@ -0,0 +1,25 @@ +import unittest +from Cython.TestUtils import TransformTest +from Cython.Compiler.ParseTreeTransforms import DecoratorTransform + +class TestDecorator(TransformTest): + + def test_decorator(self): + t = self.run_pipeline([DecoratorTransform(None)], u""" + def decorator(fun): + return fun + @decorator + def decorated(): + pass + """) + + self.assertCode(u""" + def decorator(fun): + return fun + def decorated(): + pass + decorated = decorator(decorated) + """, t) + +if __name__ == '__main__': + unittest.main() -- 2.26.2