From 4978fea0caf2d48fbce44474fd8830824cf4c370 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Sun, 31 Oct 2010 19:26:56 +0100 Subject: [PATCH] simplify auto __test__ dict generation: store docstrings directly in the dict instead of looking them up at module init time => much faster, a lot less code, fewer redundant string constants (duplicate strings are unified anyway), and just as good, as docstrings of Cython functions/methods can't currently be changed anyway --- Cython/Compiler/AnalysedTreeTransforms.py | 127 +++++++++------------- tests/run/autotestdict.pyx | 9 +- 2 files changed, 59 insertions(+), 77 deletions(-) diff --git a/Cython/Compiler/AnalysedTreeTransforms.py b/Cython/Compiler/AnalysedTreeTransforms.py index 18ca5bd8..deaf2dfe 100644 --- a/Cython/Compiler/AnalysedTreeTransforms.py +++ b/Cython/Compiler/AnalysedTreeTransforms.py @@ -18,91 +18,72 @@ class AutoTestDictTransform(ScopeTrackingTransform): def visit_ModuleNode(self, node): if node.is_pxd: return node + self.scope_type = 'module' self.scope_node = node - if self.current_directives['autotestdict']: - assert isinstance(node.body, StatListNode) - # First see if __test__ is already created - if u'__test__' in node.scope.entries: - # Do nothing - return node - - pos = node.pos + if not self.current_directives['autotestdict']: + return node + + assert isinstance(node.body, StatListNode) - self.tests = [] - self.testspos = node.pos + # First see if __test__ is already created + if u'__test__' in node.scope.entries: + # Do nothing + return node + + pos = node.pos - test_dict_entry = node.scope.declare_var(EncodedString(u'__test__'), - py_object_type, - pos, - visibility='public') - create_test_dict_assignment = SingleAssignmentNode(pos, - lhs=NameNode(pos, name=EncodedString(u'__test__'), - entry=test_dict_entry), - rhs=DictNode(pos, key_value_pairs=self.tests)) - self.visitchildren(node) - node.body.stats.append(create_test_dict_assignment) + self.tests = [] + self.testspos = node.pos - + test_dict_entry = node.scope.declare_var(EncodedString(u'__test__'), + py_object_type, + pos, + visibility='public') + create_test_dict_assignment = SingleAssignmentNode(pos, + lhs=NameNode(pos, name=EncodedString(u'__test__'), + entry=test_dict_entry), + rhs=DictNode(pos, key_value_pairs=self.tests)) + self.visitchildren(node) + node.body.stats.append(create_test_dict_assignment) return node - def add_test(self, testpos, name, func_ref_node): - # func_ref_node must evaluate to the function object containing - # the docstring, BUT it should not be the function itself (which - # would lead to a new *definition* of the function) + def add_test(self, testpos, path, doctest): pos = self.testspos - keystr = u'%s (line %d)' % (name, testpos[1]) + keystr = u'%s (line %d)' % (path, testpos[1]) key = UnicodeNode(pos, value=EncodedString(keystr)) - - value = DocstringRefNode(pos, func_ref_node) + value = UnicodeNode(pos, value=EncodedString(doctest)) self.tests.append(DictItemNode(pos, key=key, value=value)) - + def visit_FuncDefNode(self, node): - if node.doc: - if isinstance(node, CFuncDefNode) and not node.py_func: - # skip non-cpdef cdef functions + if not node.doc: + return node + if isinstance(node, CFuncDefNode) and not node.py_func: + # skip non-cpdef cdef functions + return node + + pos = self.testspos + if self.scope_type == 'module': + path = node.entry.name + elif self.scope_type in ('pyclass', 'cclass'): + if isinstance(node, CFuncDefNode): + name = node.py_func.name + else: + name = node.name + if self.scope_type == 'cclass' and name in self.blacklist: return node - - pos = self.testspos - if self.scope_type == 'module': - parent = ModuleRefNode(pos) - name = node.entry.name - elif self.scope_type in ('pyclass', 'cclass'): - if isinstance(node, CFuncDefNode): - name = node.py_func.name - else: - name = node.name - if self.scope_type == 'cclass' and name in self.blacklist: - return node - mod = ModuleRefNode(pos) - if self.scope_type == 'pyclass': - clsname = self.scope_node.name - else: - clsname = self.scope_node.class_name - parent = AttributeNode(pos, obj=mod, - attribute=clsname, - type=py_object_type, - is_py_attr=True, - is_temp=True) - if isinstance(node.entry.scope, Symtab.PropertyScope): - new_node = AttributeNode(pos, obj=parent, - attribute=node.entry.scope.name, - type=py_object_type, - is_py_attr=True, - is_temp=True) - parent = new_node - name = "%s.%s.%s" % (clsname, node.entry.scope.name, - node.entry.name) - else: - name = "%s.%s" % (clsname, node.entry.name) + if self.scope_type == 'pyclass': + class_name = self.scope_node.name + else: + class_name = self.scope_node.class_name + if isinstance(node.entry.scope, Symtab.PropertyScope): + property_method_name = node.entry.scope.name + path = "%s.%s.%s" % (class_name, node.entry.scope.name, + node.entry.name) else: - assert False - getfunc = AttributeNode(pos, obj=parent, - attribute=node.entry.name, - type=py_object_type, - is_py_attr=True, - is_temp=True) - self.add_test(node.pos, name, getfunc) + path = "%s.%s" % (class_name, node.entry.name) + else: + assert False + self.add_test(node.pos, path, node.doc) return node - diff --git a/tests/run/autotestdict.pyx b/tests/run/autotestdict.pyx index 51e347ee..0e3bc09e 100644 --- a/tests/run/autotestdict.pyx +++ b/tests/run/autotestdict.pyx @@ -12,8 +12,8 @@ all_tests_run() is executed which does final validation. >>> items.sort() >>> for key, value in items: ... print('%s ; %s' % (key, value)) -MyCdefClass.cpdef_method (line 78) ; >>> add_log("cpdef class method") -MyCdefClass.method (line 75) ; >>> add_log("cdef class method") +MyCdefClass.cpdef_method (line 79) ; >>> add_log("cpdef class method") +MyCdefClass.method (line 76) ; >>> add_log("cdef class method") MyClass.method (line 65) ; >>> add_log("class method") doc_without_test (line 47) ; Some docs mycpdeffunc (line 53) ; >>> add_log("cpdef") @@ -33,7 +33,7 @@ cdef cdeffunc(): def all_tests_run(): log.sort() - assert log == [u'cdef class method', u'class method', u'cpdef', u'def'], log + assert log == [u'cdef class', u'cdef class method', u'class method', u'cpdef', u'cpdef class method', u'def'], log def add_log(s): log.append(unicode(s)) @@ -68,7 +68,8 @@ class MyClass: cdef class MyCdefClass: """ Needs no hack - + + >>> add_log("cdef class") >>> True True """ -- 2.26.2