[py-svn] r33703 - in py/dist/py/apigen/rest: . testing

guido at codespeak.net guido at codespeak.net
Wed Oct 25 01:24:05 CEST 2006


Author: guido
Date: Wed Oct 25 01:24:04 2006
New Revision: 33703

Added:
   py/dist/py/apigen/rest/testing/somemodule.py
   py/dist/py/apigen/rest/testing/someothermodule.py
Modified:
   py/dist/py/apigen/rest/genrest.py
   py/dist/py/apigen/rest/testing/test_rest.py
Log:
Re-written the GenRest class, it's a bit cleaner now (but still quite a chunk
unfortunately), don't replace dots in file names anymore (since that may
cause name clashes), fixed underscore escaping.


Modified: py/dist/py/apigen/rest/genrest.py
==============================================================================
--- py/dist/py/apigen/rest/genrest.py	(original)
+++ py/dist/py/apigen/rest/genrest.py	Wed Oct 25 01:24:04 2006
@@ -108,99 +108,188 @@
 
 class RestGen(object):
     def __init__(self, ds, linkgen, writer=PipeWriter()):
-        #assert isinstance(linkgen, DirectPaste), "Cannot use different linkgen by now"
+        #assert isinstance(linkgen, DirectPaste), (
+        #                        "Cannot use different linkgen by now")
         self.dsa = DocStorageAccessor(ds)
         self.linkgen = linkgen
         self.writer = writer
-    
+
     def write(self):
         """write the data to the writer"""
-        # note that this builds up a list of Rest elements for the index as
-        # 'side effect', the list is passed along and filled, while the actual
-        # sections (also ReST elements) are returned by the write_* methods
-        # XXX this is quite icky! would be nice to have refactored
-        indexlst = [Title("Module: %s" % self.dsa.get_module_name(),
-                          belowchar="="),
-                    Paragraph(self.dsa.get_module_info()),
-                    Title("Exported functions:", belowchar="-")]
-        funclst = self.write_function_list(indexlst)
-        indexlst.append(Title("Exported classes:", belowchar="-"))
-        classlst = self.write_class_list(indexlst)
-        self.writer.write_section('index', Rest(*indexlst).text())
-        for sectionname, restitems in funclst:
-            self.writer.write_section(sectionname, Rest(*restitems).text())
-        for sectionname, classdata in classlst:
-            restitems, classfunclst = classdata
-            self.writer.write_section(sectionname, Rest(*restitems).text())
-            for fsectionname, frestitems in classfunclst:
-                self.writer.write_section(fsectionname,
-                                          Rest(*frestitems).text())
-    
-    def write_function_list(self, indexlst):
-        retlst = []
-        for name in self.dsa.get_function_names():
-            sectionname = 'function_%s' % (name,)
-            linktarget = self.writer.getlink('function', name,
-                                                  sectionname)
-            indexlst.append(ListItem(Text("Function: "),
-                                Link(name, linktarget)))
-            retlst.append((sectionname,
-                           self.write_function(sectionname, name)))
-        return retlst
+        modlist = self.get_module_list()
+        classlist = self.get_class_list(module='')
+        funclist = self.get_function_list()
+
+        indexrest = self.build_index([t[0] for t in modlist],
+                                     [t[0] for t in classlist],
+                                     funclist)
+        self.writer.write_section('index', Rest(*indexrest).text())
+        
+        self.build_modrest(modlist)
+        self.build_funcrest(funclist)
+        self.build_classrest(classlist)
+        
+    def build_modrest(self, modlist):
+        modrest = self.build_modules(modlist)
+        for name, rest, classlist, funclist in modrest:
+            self.writer.write_section('module_%s' % (name,),
+                                      Rest(*rest).text())
+            for cname, crest, cfunclist in classlist:
+                self.writer.write_section('class_%s' % (cname,),
+                                          Rest(*crest).text())
+                for fname, frest in cfunclist:
+                    self.writer.write_section('method_%s' % (fname,),
+                                              Rest(*frest).text())
+            for fname, frest in funclist:
+                self.writer.write_section('function_%s' % (fname,),
+                                          Rest(*frest).text())
     
-    def write_class_list(self, indexlst):
-        retlst = []
-        for name in self.dsa.get_class_names():
-            sectionname = 'class_%s' % (name,)
-            linktarget = self.writer.getlink('class', name, sectionname)
-            indexlst.append(ListItem(Text("Class: "), Link(name, linktarget)))
-            retlst.append((sectionname, self.write_class(sectionname, name)))
-        return retlst
+    def build_classrest(self, classlist):
+        classrest = self.build_classes(classlist)
+        for cname, rest, cfunclist in classrest:
+            self.writer.write_section('class_%s' % (cname,),
+                                      Rest(*rest).text())
+            for fname, rest in cfunclist:
+                self.writer.write_section('method_%s' % (fname,),
+                                          Rest(*rest).text())
+
+    def build_funcrest(self, funclist):
+        funcrest = self.build_functions(funclist)
+        for fname, rest in funcrest:
+            self.writer.write_section('function_%s' % (fname,),
+                                      Rest(*rest).text())
+
+    def build_index(self, modules, classes, functions):
+        rest = [Title('Index', abovechar='=', belowchar='=')]
+        rest.append(Title('Exported modules:', belowchar='='))
+        for module in modules:
+            linktarget = self.writer.getlink('module', module,
+                                             'module_%s' % (module,))
+            rest.append(ListItem(Link(module, linktarget)))
+        rest.append(Title('Exported classes:', belowchar='='))
+        for cls in classes:
+            linktarget = self.writer.getlink('class', cls, 'class_%s' % (cls,))
+            rest.append(ListItem(Link(cls, linktarget)))
+        rest.append(Title('Exported functions:', belowchar='='))
+        for func in functions:
+            linktarget = self.writer.getlink('function', func,
+                                             'function_%s' % (func,))
+            rest.append(ListItem(Link(func, linktarget)))
+        return rest
+
+    def build_modules(self, modules):
+        ret = []
+        for module, classes, functions in modules:
+            rest = [Title('Module: %s' % (module,), belowchar='-')]
+            rest.append(Title('Classes:', belowchar='^'))
+            for cls, cfunclist in classes:
+                linktarget = self.writer.getlink('class', cls,
+                                                 'class_%s' % (cls,))
+                rest.append(ListItem(Link(cls, linktarget)))
+            classrest = self.build_classes(classes)
+            rest.append(Title('Functions:', belowchar='^'))
+            for func in functions:
+                linktarget = self.writer.getlink('function',
+                                                 '%s.%s' % (module, func),
+                                                 'function_%s.%s' % (module,
+                                                                     func))
+                rest.append(ListItem(Link(func, linktarget)))
+            funcrest = self.build_functions(functions, module)
+            ret.append((module, rest, classrest, funcrest))
+        return ret
     
-    def write_class(self, section_name, class_name):
-        classlst = [Title("Class: %s" % class_name, belowchar='-'),
-                    LiteralBlock(self.dsa.get_function_doc(class_name))]
-        
-        # write down exported methods
-        classlst.append(Title("Exported methods:", belowchar="^"))
-        funclist = []
-        for method in self.dsa.get_class_methods(class_name):
-            sectionname = 'method_%s_%s' % (class_name, method)
-            linktext = '%s.%s' % (class_name, method)
-            linktarget = self.writer.getlink('function', linktext,
-                                                  sectionname)
-            classlst.append(ListItem(Link(linktext, linktarget)))
-            # XXX assuming a function is always part of a class section
-            funclist.append((sectionname,
-                             self.write_function(sectionname,
-                                                 class_name + "." + method,
-                                                 '^')))
-        return classlst, funclist
+    def build_classes(self, classes):
+        ret = []
+        for cls, functions in classes:
+            rest = [Title('Class: %s' % (cls,), belowchar='-'),
+                    Title('Functions:', belowchar='^')]
+            for func in functions:
+                linktarget = self.writer.getlink('method',
+                                                 '%s.%s' % (cls, func),
+                                                 'method_%s.%s' % (cls, func))
+                rest.append(ListItem(Link(func, linktarget)))
+            funcrest = self.build_functions(functions, cls)
+            ret.append((cls, rest, funcrest))
+        return ret
     
-    def write_function(self, section_name, fun_name, belowchar='-'):
+    def build_functions(self, functions, parent=''):
+        ret = []
+        for function in functions:
+            if parent:
+                function = '%s.%s' % (parent, function)
+            rest = self.write_function(function)
+            ret.append((function, rest))
+        return ret
+
+    def get_module_list(self):
+        visited = []
+        ret = []
+        for name in self.dsa.get_class_names():
+            if '.' in name:
+                module, classname = name.rsplit('.', 1)
+                if module in visited:
+                    continue
+                visited.append(module)
+                ret.append((module, self.get_class_list(module),
+                                    self.get_function_list(module)))
+        return ret
+
+    def get_class_list(self, module):
+        ret = []
+        for name in self.dsa.get_class_names():
+            classname = name
+            if '.' in name:
+                classmodule, classname = name.rsplit('.', 1)
+                if classmodule != module:
+                    continue
+            elif module != '':
+                continue
+            print 'retrieving method list for', name
+            print 'method list:', self.get_method_list(name)
+            ret.append((name, self.get_method_list(name)))
+        return ret
+
+    def get_function_list(self, module=''):
+        ret = []
+        for name in self.dsa.get_function_names():
+            funcname = name
+            if '.' in name:
+                funcpath, funcname = name.rsplit('.', 1)
+                if funcpath != module:
+                    continue
+            elif module != '':
+                continue
+            ret.append(funcname)
+        return ret
+
+    def get_method_list(self, classname):
+        return self.dsa.get_class_methods(classname)
+
+    def write_function(self, functionname, belowchar='-'):
         # XXX I think the docstring should either be split on \n\n and cleaned
         # from indentation, or treated as ReST too (although this is obviously
         # dangerous for non-ReST docstrings)...
-        lst = [Title("Function: %s" % fun_name, belowchar=belowchar),
-               LiteralBlock(self.dsa.get_function_doc(fun_name)),
-               LiteralBlock(self.dsa.get_function_definition(fun_name))]
+        lst = [Title("Function: %s" % (functionname,), belowchar=belowchar),
+               LiteralBlock(self.dsa.get_function_doc(functionname)),
+               LiteralBlock(self.dsa.get_function_definition(functionname))]
         
         
-        args, retval = self.dsa.get_function_signature(fun_name)
-        arg_str = "\n".join(["%s :: %s" % (str(name), str(type)) for name, type in args])
+        args, retval = self.dsa.get_function_signature(functionname)
+        arg_str = "\n".join(["%s :: %s" % (str(name), str(type))
+                             for name, type in args])
         arg_str += "\n" + "Return value :: %s" % str(retval)
         lst.append(Paragraph("where:"))
         lst.append(LiteralBlock(arg_str))
         
         # XXX missing implementation of dsa.get_function_location()
-        #filename, lineno = self.dsa.get_function_location(fun_name)
+        #filename, lineno = self.dsa.get_function_location(functionname)
         #linkname, linktarget = self.linkgen.getlink(filename, lineno)
         #if linktarget:
         #    lst.append(Paragraph("Function source: ",
         #               Link(linkname, linktarget)))
         #else:
         lst.append(Paragraph('Function source:'))
-        lst.append(LiteralBlock(self.dsa.get_function_source(fun_name)))
+        lst.append(LiteralBlock(self.dsa.get_function_source(functionname)))
         
         #arg_str = "(%s)" % (",".join([str(i) for i in args]))
         #ret_str = str(retval)
@@ -213,7 +302,7 @@
         lst.append(call_site_title)
         call_sites = lst
         
-        for call_site, frame in self.dsa.get_function_callpoints(fun_name):
+        for call_site, frame in self.dsa.get_function_callpoints(functionname):
             link_str = "File %s:%s" % (call_site.filename,
                                        call_site.lineno)
             link_str, link_target = self.linkgen.getlink(call_site.filename,
@@ -230,7 +319,7 @@
             except KeyboardInterrupt, SystemError:
                 raise
             except:
-                source = ["*Cannot get source*"]
+                source = "*Cannot get source*"
             lines = []
             for num, line in enumerate(source):
                 if num == call_site.lineno - frame.code.firstlineno - 1:

Added: py/dist/py/apigen/rest/testing/somemodule.py
==============================================================================
--- (empty file)
+++ py/dist/py/apigen/rest/testing/somemodule.py	Wed Oct 25 01:24:04 2006
@@ -0,0 +1,10 @@
+class SomeClass(object):
+    """Some class definition"""
+    
+    def __init__(self, a):
+        self.a = a
+    
+    def method(self, a, b, c):
+        """method docstring"""
+        return a + b + c
+

Added: py/dist/py/apigen/rest/testing/someothermodule.py
==============================================================================
--- (empty file)
+++ py/dist/py/apigen/rest/testing/someothermodule.py	Wed Oct 25 01:24:04 2006
@@ -0,0 +1,21 @@
+from somemodule import SomeClass
+
+class SomeSubClass(SomeClass):
+    """Some subclass definition"""
+
+def fun(a, b, c):
+    """Some docstring
+    
+        Let's make it span a couple of lines to be interesting...
+
+        Note:
+
+         * rest
+         * should
+         * be
+         * supported
+         * or
+         * ignored...
+    """
+    return "d"
+

Modified: py/dist/py/apigen/rest/testing/test_rest.py
==============================================================================
--- py/dist/py/apigen/rest/testing/test_rest.py	(original)
+++ py/dist/py/apigen/rest/testing/test_rest.py	Wed Oct 25 01:24:04 2006
@@ -133,6 +133,25 @@
         fun(1, 3, s2)
         t.end_tracing()
         return ds
+
+    def get_filled_docstorage_modules(self):
+        import somemodule
+        import someothermodule
+        descs = {
+            'somemodule.SomeClass': somemodule,
+            'someothermodule.SomeOtherClass': someothermodule,
+            'someothermodule.fun': someothermodule.fun,
+        }
+        ds = DocStorage().from_dict(descs)
+        t = Tracer(ds)
+        t.start_tracing()
+        s1 = somemodule.SomeClass("a")
+        someothermodule.fun(1, 2, s1)
+        s2 = someothermodule.SomeSubClass("b")
+        s2.method(1, 2, 3)
+        someothermodule.fun(1, 3, s2)
+        t.end_tracing()
+        return ds
     
     def check_rest(self, tempdir):
         from py.__.misc import rest
@@ -151,14 +170,36 @@
             'class_SomeSubClass.txt',
             'function_fun.txt',
             'index.txt',
-            'method_SomeClass___init__.txt',
-            'method_SomeClass_method.txt',
-            'method_SomeSubClass___init__.txt',
-            'method_SomeSubClass_method.txt',
+            'method_SomeClass.__init__.txt',
+            'method_SomeClass.method.txt',
+            'method_SomeSubClass.__init__.txt',
+            'method_SomeSubClass.method.txt',
         ]
         # now we check out...
         self.check_rest(tempdir)
 
+    def test_generation_modules(self):
+        py.test.skip('borken - fijal, somehow the methods for classes in '
+                     'modules don\'t get picked up... any idea?')
+        ds = self.get_filled_docstorage_modules()
+        lg = DirectPaste()
+        tempdir = temppath.ensure('module_api', dir=True)
+        r = RestGen(ds, lg, DirWriter(tempdir))
+        r.write()
+        basenames = [p.basename for p in tempdir.listdir('*.txt')]
+        assert sorted(basenames) == [
+            'class_somemodule.SomeClass.txt',
+            'class_someothermodule.SomeOtherClass.txt',
+            'function_someothermodule.fun.txt',
+            'index.txt',
+            'method_somemodule.SomeClass.__init__.txt',
+            'method_somemodule.SomeClass.method.txt',
+            'method_somemodule.SomeSubClass.__init__.txt',
+            'method_somemodule.SomeSubClass.method.txt',
+            'module_somemodule.txt',
+            'module_someothermodule.txt',
+        ]
+
     def test_check_internal_links(self):
         ds = self.get_filled_docstorage()
         lg = DirectFS()
@@ -185,7 +226,6 @@
         if not tempfile.check():
             py.test.skip('depends on previous test, which failed')
         data = tempfile.read()
-        print data
         # index should be above the rest
         assert data.find('Exported classes\\:') > -1
         assert data.find('Exported classes\\:') < data.find('Function\\: fun')
@@ -197,13 +237,11 @@
         assert data.find('Class\\: SomeClass') < data.find(
                                             'Function\\: SomeClass.method')
         # __init__ should be above other methods
-        assert data.find('Function\\: SomeClass.__init__') > -1
-        # XXX in the future... 
-        # assert data.find('Function: SomeClass.__init__') < data.find(
-        #                                     'Function: SomeClass.method')
+        assert data.find('Function\\: SomeClass.\\_\\_init\\_\\_') > -1
+        assert data.find('Function\\: SomeClass.\\_\\_init\\_\\_') < data.find(
+                                                'Function\\: SomeClass.method')
 
     def test_som_fun(self):
-        py.test.skip("Failing")
         descs = {'fun_':fun_}
         ds = DocStorage().from_dict(descs)
         t = Tracer(ds)
@@ -232,7 +270,7 @@
         tempdir = temppath.ensure("function_source", dir=True)
         r = RestGen(ds, lg, DirWriter(tempdir))
         r.write()
-        assert tempdir.join("function_blah.txt").open().read().find("a = 3") != -1
+        assert tempdir.join("function_blah.txt").read().find("a = 3") != -1
         self.check_rest(tempdir)
 
     def test_function_arguments(self):
@@ -252,7 +290,7 @@
         tempdir = temppath.ensure("function_args", dir=True)
         r = RestGen(ds, lg, DirWriter(tempdir))
         r.write()
-        source = tempdir.join("function_blah.txt").open().read()
+        source = tempdir.join("function_blah.txt").read()
         call_point = source.find("Call sites\:")
         assert call_point != -1
         assert source.find("a :: <Int>") < call_point



More information about the pytest-commit mailing list