Commit e0d366d9 authored by Stefan Behnel's avatar Stefan Behnel

merged reverted patches from cython-devel

parents a67d1a16 b30d2f40
......@@ -1975,7 +1975,6 @@ class DefNode(FuncDefNode):
# when the def statement is inside a Python class definition.
#
# assmt AssignmentNode Function construction/assignment
# py_cfunc_node PyCFunctionNode/InnerFunctionNode The PyCFunction to create and assign
child_attrs = ["args", "star_arg", "starstar_arg", "body", "decorators"]
......@@ -1990,7 +1989,6 @@ class DefNode(FuncDefNode):
entry = None
acquire_gil = 0
self_in_stararg = 0
py_cfunc_node = None
def __init__(self, pos, **kwds):
FuncDefNode.__init__(self, pos, **kwds)
......@@ -2342,23 +2340,15 @@ class DefNode(FuncDefNode):
genv = genv.outer_scope
if genv.is_closure_scope:
self.py_cfunc_node = ExprNodes.InnerFunctionNode(
rhs = ExprNodes.InnerFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname)
else:
self.py_cfunc_node = ExprNodes.PyCFunctionNode(
rhs = ExprNodes.PyCFunctionNode(
self.pos, pymethdef_cname = self.entry.pymethdef_cname, binding = env.directives['binding'])
if env.is_py_class_scope:
if not self.is_staticmethod and not self.is_classmethod:
self.py_cfunc_node.binding = True
rhs = self.py_cfunc_node
if self.decorators:
for decorator in self.decorators[::-1]:
rhs = ExprNodes.SimpleCallNode(
decorator.pos,
function = decorator.decorator,
args = [rhs])
rhs.binding = True
self.assmt = SingleAssignmentNode(self.pos,
lhs = ExprNodes.NameNode(self.pos, name = self.name),
......@@ -3092,9 +3082,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,
......@@ -3197,16 +3186,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
......@@ -3219,7 +3198,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)
......@@ -3239,9 +3218,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:
......@@ -3300,9 +3279,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.
......
......@@ -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 != '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]:
......@@ -1451,9 +1467,9 @@ class CreateClosureClasses(CythonTransform):
if not from_closure and (self.path or inner_node):
if not inner_node:
if not node.py_cfunc_node:
if not node.assmt:
raise InternalError, "DefNode does not have assignment node"
inner_node = node.py_cfunc_node
inner_node = node.assmt.rhs
inner_node.needs_self_code = False
node.needs_outer_scope = False
......
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()
......@@ -18,6 +18,7 @@ ipow_crash_T562
pure_mode_cmethod_inheritance_T583
genexpr_iterable_lookup_T600
for_from_pyvar_loop_T601
decorators_T593
# CPython regression tests that don't current work:
pyregr.test_threadsignals
......
......@@ -10,6 +10,7 @@ def testme(func):
return True
except NameError:
return False
@testme
def am_i_buggy():
pass
......@@ -24,6 +25,30 @@ def testclass(klass):
class Foo:
pass
def called_deco(a,b,c):
def count(f):
a.append( (b,c) )
return f
return count
L = []
@called_deco(L, 5, c=6)
@called_deco(L, c=3, b=4)
@called_deco(L, 1, 2)
def wrapped_func(x):
"""
>>> L
[(1, 2), (4, 3), (5, 6)]
>>> wrapped_func(99)
99
>>> L
[(1, 2), (4, 3), (5, 6)]
"""
return x
def class_in_closure(x):
"""
>>> C1, c0 = class_in_closure(5)
......
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