From c1690bf3d591f1b9e59005c9e7eedfa6b23341b4 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Sat, 22 Dec 2012 11:06:17 +0100 Subject: [PATCH] support @cython.final decorator in override .pxd files --- Cython/Compiler/ParseTreeTransforms.py | 21 ++++++----- tests/run/final_in_pxd.srctree | 68 ++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+), 10 deletions(-) create mode 100644 tests/run/final_in_pxd.srctree diff --git a/Cython/Compiler/ParseTreeTransforms.py b/Cython/Compiler/ParseTreeTransforms.py index d1c0b34..4bcfb30 100644 --- a/Cython/Compiler/ParseTreeTransforms.py +++ b/Cython/Compiler/ParseTreeTransforms.py @@ -909,16 +909,17 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): return self.visit_with_directives(body, directives) def visit_CVarDefNode(self, node): - if not node.decorators: + directives = self._extract_directives(node, 'function') + if not directives: return node - for dec in node.decorators: - for directive in self.try_to_parse_directives(dec.decorator) or (): - if directive is not None and directive[0] == u'locals': - node.directive_locals = directive[1] - else: - self.context.nonfatal_error(PostParseError(dec.pos, - "Cdef functions can only take cython.locals() decorator.")) - return node + for name, value in directives.iteritems(): + if name == 'locals': + node.directive_locals = value + elif name != 'final': + self.context.nonfatal_error(PostParseError(dec.pos, + "Cdef functions can only take cython.locals() or final decorators, got %s." % name)) + body = Nodes.StatListNode(node.pos, stats=[node]) + return self.visit_with_directives(body, directives) def visit_CClassDefNode(self, node): directives = self._extract_directives(node, 'cclass') @@ -948,7 +949,7 @@ class InterpretCompilerDirectives(CythonTransform, SkipDeclarations): directives.append(directive) else: realdecs.append(dec) - if realdecs and isinstance(node, (Nodes.CFuncDefNode, Nodes.CClassDefNode)): + if realdecs and isinstance(node, (Nodes.CFuncDefNode, Nodes.CClassDefNode, Nodes.CVarDefNode)): raise PostParseError(realdecs[0].pos, "Cdef functions/classes cannot take arbitrary decorators.") else: node.decorators = realdecs diff --git a/tests/run/final_in_pxd.srctree b/tests/run/final_in_pxd.srctree new file mode 100644 index 0000000..e0fe876 --- /dev/null +++ b/tests/run/final_in_pxd.srctree @@ -0,0 +1,68 @@ +PYTHON -c "import a; assert a.__file__.rstrip('co').endswith('.py'), a.__file__; a.test()" +PYTHON setup.py build_ext --inplace +PYTHON -c "import a; assert not a.__file__.rstrip('co').endswith('.py'), a.__file__; a.test()" + +######## setup.py ######## + +from Cython.Build.Dependencies import cythonize + +from distutils.core import setup + +setup( + ext_modules = cythonize("a.py"), + ) + +######## a.pxd ######## + +cimport cython + +cdef class ExtType: + @cython.final + cdef int final_func(self) + +@cython.final +cdef class FinalExtType: + cdef int func(self) + +@cython.final +cdef class FinalExtSubType(ExtType): + cdef int func(self) + +cdef class NonFinalSubType(ExtType): + cdef int func(self) + + +######## a.py ######## + +import cython + +class ExtType(object): + @cython.test_assert_path_exists("//CFuncDefNode[@entry.is_final_cmethod=True]") + def final_func(self): + return 1 + +class FinalExtType(object): + @cython.test_assert_path_exists("//CFuncDefNode[@entry.is_final_cmethod=True]") + def func(self): + return 2 + +class FinalExtSubType(ExtType): + @cython.test_assert_path_exists("//CFuncDefNode[@entry.is_final_cmethod=True]") + def func(self): + return 3 + +class NonFinalSubType(ExtType): + @cython.test_assert_path_exists("//CFuncDefNode[@entry.is_final_cmethod=True]") + @cython.final + def func(self): + return 4 + + +def test(): + assert ExtType().final_func() == 1 + assert FinalExtSubType().final_func() == 1 + assert NonFinalSubType().final_func() == 1 + + assert FinalExtType().func() == 2 + assert FinalExtSubType().func() == 3 + assert NonFinalSubType().func() == 4 -- 2.7.4