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')
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
--- /dev/null
+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