simplify auto __test__ dict generation:
authorStefan Behnel <scoder@users.berlios.de>
Sun, 31 Oct 2010 18:26:56 +0000 (19:26 +0100)
committerStefan Behnel <scoder@users.berlios.de>
Sun, 31 Oct 2010 18:26:56 +0000 (19:26 +0100)
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
tests/run/autotestdict.pyx

index 18ca5bd8ad240eaefd622044f8bbde08da5fe835..deaf2dfe6ef253b807e950307c0185b1114ea66e 100644 (file)
@@ -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
-
index 51e347eeded4ab54fe3652c47c0af51bbed954bb..0e3bc09ee285a703ec3560218c35efec97d4ae89 100644 (file)
@@ -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
     """