[py-svn] r36589 - in py/dist/py/apigen: . source testing

guido at codespeak.net guido at codespeak.net
Fri Jan 12 17:21:48 CET 2007


Author: guido
Date: Fri Jan 12 17:21:16 2007
New Revision: 36589

Modified:
   py/dist/py/apigen/htmlgen.py
   py/dist/py/apigen/layout.py
   py/dist/py/apigen/source/browser.py
   py/dist/py/apigen/testing/test_apigen_example.py
Log:
First source pages get built and linked to.


Modified: py/dist/py/apigen/htmlgen.py
==============================================================================
--- py/dist/py/apigen/htmlgen.py	(original)
+++ py/dist/py/apigen/htmlgen.py	Fri Jan 12 17:21:16 2007
@@ -1,7 +1,12 @@
 import py
+import inspect
 from py.__.apigen.layout import LayoutPage
+from py.__.apigen.source import browser as source_browser
+from py.__.apigen.source import html as source_html
 
 html = py.xml.html
+raw = py.xml.raw
+
 class H(html):
     class ClassDescription(html.div):
         pass
@@ -30,13 +35,16 @@
     class BaseDescription(html.a):
         pass
 
+    class SourceDef(html.pre):
+        style = html.Style(whitespace='pre')
+
 def get_param_htmldesc(linker, func):
     """ get the html for the parameters of a function """
     import inspect
     # XXX copy and modify formatargspec to produce html
     return H.em(inspect.formatargspec(*inspect.getargspec(func)))
 
-def build_full_method_view(linker, dsa, dotted_name):
+def build_full_method_view(base, linker, dsa, dotted_name):
     """ build the html for a class method """
     func = dsa.get_obj(dotted_name)
     params = get_param_htmldesc(linker, func)
@@ -48,7 +56,7 @@
     )
     return snippet
 
-def build_short_method_view(linker, dsa, dotted_name):
+def build_short_method_view(base, linker, dsa, dotted_name):
     """ build the html for a class method """
     func = dsa.get_obj(dotted_name)
     params = get_param_htmldesc(linker, func)
@@ -61,9 +69,12 @@
     )
     return snippet
 
-def build_class_view(linker, dsa, dotted_name):
+def build_class_view(base, linker, dsa, dotted_name):
     """ build the html for a class """
     cls = dsa.get_obj(dotted_name)
+    sourcefile = inspect.getsourcefile(cls)
+    if sourcefile[-1] in ['o', 'c']:
+        sourcefile = sourcefile[:-1]
     docstring = cls.__doc__
     methods = dsa.get_class_methods(dotted_name)
     basehtml = []
@@ -82,17 +93,19 @@
     snippet = H.ClassDescription(
         # XXX bases HTML
         H.ClassDef('%s(' % (cls.__name__,), *basehtml),
+        H.a('source', href=linker.get_lazyhref(sourcefile)),
         H.Docstring(docstring),
     )
     snippet.append(H.h2('Functions:'))
     for method in methods:
-        snippet += build_short_method_view(linker, dsa, '%s.%s' % (dotted_name,
-                                                                   method))
+        snippet += build_short_method_view(base, linker, dsa,
+                                           '%s.%s' % (dotted_name, method))
     return snippet
 
-def build_method_view(linker, dsa, dotted_name):
+def build_method_view(base, linker, dsa, dotted_name):
     pass
 
+# XXX nav functions need cleanup!!
 def build_package_navigation(linker, dotted_name):
     # import dotted name
     # build nav from sub items
@@ -175,26 +188,61 @@
                 navitems.append(H.br())
     return H.Navigation(*navitems)
 
+re = py.std.re
+_reg_body = re.compile(r'<body[^>]*>(.*)</body>', re.S)
+def build_source_python_page(fspath):
+    mod = source_browser.parse_path(fspath)
+    # XXX let's cheat a bit here... there should be a different function using
+    # the linker, and returning a proper py.xml.html element, at some point
+    html = source_html.create_html(mod)
+    snippet = _reg_body.search(html).group(1)
+    tag = H.SourceDef(raw(snippet))
+    nav = H.Navigation('navigation')
+    return tag, nav
+
+def build_source_dir_page(fspath):
+    tag = H.div('content')
+    nav = H.Navigation('navigation')
+    return tag, nav
+
+def build_source_nonpython_page(fspath):
+    tag = H.div('content')
+    nav = H.Navigation('navigation')
+    return tag, nav
+
 # the build_*_pages methods all do two-pass page generation (first pass builds
 # the link db, second uses it)
-def build_source_pages(linker, base):
-    """ build syntax-colored source views """
+def prepare_source_pages(linker, base, outputbase):
     passed = []
-    for fspath in base.visit("*.py"):
+    for fspath in base.visit():
         relfspath = fspath.relto(base)
-        reloutputpath = "source/" + relfspath + ".html"
-        linker.set_link(relfspath, reloutputpath)
-        passed.append((fspath, reloutputpath))
-    for fspath, reloutputpath in passed:
-        targetpath = outputbase.join(reloutputpath)
-        page = build_source_page(fspath)
-        targetpath.write(page.unicode().encode("utf8"))
+        if fspath.check(dir=True):
+            reloutputpath = 'source/%s/index.html' % (relfspath,)
+        else:
+            reloutputpath = "source/%s.html" % (relfspath,)
+        print reloutputpath
+        outputpath = outputbase.join(reloutputpath)
+        linker.set_link(str(fspath), reloutputpath)
+        passed.append((fspath, outputpath))
+    return passed
 
-def build_class_api_pages(project, linker, dsa, base, classes_dotted_names):
-    """ build the full api pages for a set of classes """
+def build_source_pages(data, project, outputbase):
+    """ build syntax-colored source views """
+    for fspath, outputpath in data:
+        if fspath.check(ext='.py'):
+            tag, nav = build_source_python_page(fspath)
+        elif fspath.check(dir=True):
+            tag, nav = build_source_dir_page(fspath)
+        else:
+            tag, nav = build_source_nonpython_page(fspath)
+        page = wrap_page(project, 'sources for %s' % (fspath,), tag, nav)
+        outputpath.ensure()
+        outputpath.write(page.unicode().encode("utf8"))
+
+def prepare_class_api_pages(linker, dsa, base, classes_dotted_names):
     passed = []
     for dotted_name in classes_dotted_names:
-        tag = build_class_view(linker, dsa, dotted_name)
+        tag = build_class_view(base, linker, dsa, dotted_name)
         nav = build_class_navigation(linker, dsa, dotted_name)
         reltargetpath = "api/%s.html" % (dotted_name,)
         linker.set_link(dotted_name, reltargetpath)
@@ -202,51 +250,59 @@
         method_dotted_names = ['%s.%s' % (dotted_name, method_name) for
                                method_name in
                                dsa.get_class_methods(dotted_name)]
-        build_method_api_pages(project, linker, dsa, base, method_dotted_names)
-    for dotted_name, tag, nav, reltargetpath in passed:
-        page = wrap_page(project, linker,
-                         'api documentation for %s' % (dotted_name,), tag, nav)
+        methodsdata = prepare_method_api_pages(linker, dsa, base,
+                                               method_dotted_names)
+    return passed, methodsdata
+    
+def build_class_api_pages(data, project, outputbase):
+    """ build the full api pages for a set of classes """
+    for dotted_name, tag, nav, reltargetpath in data:
+        page = wrap_page(project, 'api documentation for %s' % (dotted_name,), tag, nav)
         content = page.unicode()
-        targetpath = base.ensure(reltargetpath)
+        targetpath = outputbase.ensure(reltargetpath)
         targetpath.write(content.encode("utf8"))
 
-def build_method_api_pages(project, linker, dsa, base, methods_dotted_names):
+def prepare_method_api_pages(linker, dsa, base, methods_dotted_names):
     passed = []
     for dotted_name in methods_dotted_names:
-        print 'building full method view for', dotted_name
-        tag = build_full_method_view(linker, dsa, dotted_name)
+        tag = build_full_method_view(base, linker, dsa, dotted_name)
         nav = build_class_navigation(linker, dsa,
                                      '.'.join(dotted_name.split('.')[:-1]))
         reltargetpath = "api/%s.html" % (dotted_name,)
         linker.set_link(dotted_name, reltargetpath)
         passed.append((dotted_name, tag, nav, reltargetpath))
-    for dotted_name, tag, nav, reltargetpath in passed:
-        page = wrap_page(project, linker,
-                         'api documentation for %s' % (dotted_name,), tag, nav)
+    return passed
+
+def build_method_api_pages(data, project, outputbase):
+    for dotted_name, tag, nav, reltargetpath in data:
+        page = wrap_page(project, 'api documentation for %s' % (dotted_name,),
+                         tag, nav)
         content = page.unicode()
-        targetpath = base.join(reltargetpath)
+        targetpath = outputbase.join(reltargetpath)
         targetpath.ensure()
         targetpath.write(content.encode("utf8"))
 
-def build_function_api_pages(project, linker, dsa, base, methods_dotted_names):
+def prepare_function_api_pages(linker, dsa, base, methods_dotted_names):
     passed = []
     for dotted_name in methods_dotted_names:
-        print 'building function view for', dotted_name
-        # XXX should we call build_full_function_view instead?
-        tag = build_full_method_view(linker, dsa, dotted_name)
+        # XXX should we create a build_full_function_view instead?
+        tag = build_full_method_view(base, linker, dsa, dotted_name)
         nav = build_function_navigation(linker, dsa, dotted_name)
         reltargetpath = "api/%s.html" % (dotted_name,)
         linker.set_link(dotted_name, reltargetpath)
         passed.append((dotted_name, tag, nav, reltargetpath))
-    for dotted_name, tag, nav, reltargetpath in passed:
-        page = wrap_page(project, linker,
-                         'api documentation for %s' % (dotted_name,), tag, nav)
+    return passed
+
+def build_function_api_pages(data, project, outputbase):
+    for dotted_name, tag, nav, reltargetpath in data:
+        page = wrap_page(project, 'api documentation for %s' % (dotted_name,),
+                         tag, nav)
         content = page.unicode()
-        targetpath = base.join(reltargetpath)
+        targetpath = outputbase.join(reltargetpath)
         targetpath.ensure()
         targetpath.write(content.encode("utf8"))
 
-def wrap_page(project, linker, title, contentel, navel):
+def wrap_page(project, title, contentel, navel):
     page = LayoutPage(project, title, nav=navel)
     page.set_content(contentel)
     return page

Modified: py/dist/py/apigen/layout.py
==============================================================================
--- py/dist/py/apigen/layout.py	(original)
+++ py/dist/py/apigen/layout.py	Fri Jan 12 17:21:16 2007
@@ -13,7 +13,7 @@
         super(LayoutPage, self).__init__(*args, **kwargs)
 
     def set_content(self, contentel):
-        self.contentspace += contentel
+        self.contentspace.append(contentel)
 
     def fill(self):
         super(LayoutPage, self).fill()

Modified: py/dist/py/apigen/source/browser.py
==============================================================================
--- py/dist/py/apigen/source/browser.py	(original)
+++ py/dist/py/apigen/source/browser.py	Fri Jan 12 17:21:16 2007
@@ -135,3 +135,4 @@
     except (ImportError, AttributeError):
         pass
     return Module(path, mod_dict)
+

Modified: py/dist/py/apigen/testing/test_apigen_example.py
==============================================================================
--- py/dist/py/apigen/testing/test_apigen_example.py	(original)
+++ py/dist/py/apigen/testing/test_apigen_example.py	Fri Jan 12 17:21:16 2007
@@ -10,11 +10,11 @@
 
 def setup_fs_project():
     temp = py.test.ensuretemp('apigen_example')
-    temp.ensure("pkg/func.py").write(py.code.Source("""
+    temp.ensure("pkg/func.py").write(py.code.Source("""\
         def func(arg1):
             "docstring"
     """))
-    temp.ensure('pkg/someclass.py').write(py.code.Source("""
+    temp.ensure('pkg/someclass.py').write(py.code.Source("""\
         class SomeClass(object):
             " docstring someclass "
             def __init__(self, somevar):
@@ -24,14 +24,14 @@
                 " get_somevar docstring "
                 return self.somevar
     """))
-    temp.ensure('pkg/somesubclass.py').write(py.code.Source("""
+    temp.ensure('pkg/somesubclass.py').write(py.code.Source("""\
         from someclass import SomeClass
         class SomeSubClass(SomeClass):
             " docstring somesubclass "
             def get_somevar(self):
                 return self.somevar + 1
     """))
-    temp.ensure("pkg/__init__.py").write(py.code.Source("""
+    temp.ensure("pkg/__init__.py").write(py.code.Source("""\
         from py.initpkg import initpkg
         initpkg(__name__, exportdefs = {
             'pkg.sub.func': ("./func.py", "func"),
@@ -60,15 +60,18 @@
         self.linker.set_root(self.fs_root.strpath)
 
     def test_build_full_method_view(self):
-        snippet = build_full_method_view(self.linker, self.dsa, 'pkg.sub.func')
+        base = py.test.ensuretemp('build_full_method_view')
+        snippet = build_full_method_view(base, self.linker, self.dsa,
+                                         'pkg.sub.func')
         html = snippet.unicode()
         print html
         parseString(html)
 
     def test_build_function_api_pages(self):
         base = py.test.ensuretemp('build_function_api_pages')
-        build_function_api_pages(self.project, self.linker, self.dsa, base,
-                               ['pkg.sub.func'])
+        data = prepare_function_api_pages(self.linker, self.dsa,
+                                          base, ['pkg.sub.func'])
+        build_function_api_pages(data, self.project, base)
         funcfile = base.join('api/pkg.sub.func.html')
         assert funcfile.check()
         html = funcfile.read()
@@ -78,15 +81,21 @@
             webcheck.check_html(html)
 
     def test_build_class_view(self):
-        snippet = build_class_view(self.linker, self.dsa, 'pkg.SomeClass')
+        base = py.test.ensuretemp('build_class_view')
+        prepare_source_pages(self.linker, self.fs_root, base)
+        snippet = build_class_view(base, self.linker, self.dsa,
+                                   'pkg.SomeClass')
         html = snippet.unicode()
         print html
         parseString(html)
 
     def test_build_class_api_pages(self):
         base = py.test.ensuretemp('build_class_api_pages')
-        build_class_api_pages(self.project, self.linker, self.dsa, base,
-                              ['pkg.SomeClass'])
+        data, methodsdata = prepare_class_api_pages(self.linker, self.dsa,
+                                                    base, ['pkg.SomeClass'])
+        prepare_source_pages(self.linker, self.fs_root, base)
+        build_class_api_pages(data, self.project, base)
+        build_method_api_pages(methodsdata, self.project, base)
         clsfile = base.join('api/pkg.SomeClass.html')
         assert clsfile.check()
         html = clsfile.read()
@@ -98,8 +107,11 @@
     def test_build_class_api_pages_nav_links(self):
         base = py.test.ensuretemp('build_class_api_pages_nav_links')
         self.linker.root = base.strpath
-        build_class_api_pages(self.project, self.linker, self.dsa, base,
-                              ['pkg.SomeSubClass', 'pkg.SomeClass'])
+        data, methodsdata = prepare_class_api_pages(self.linker, self.dsa,
+                                base, ['pkg.SomeSubClass', 'pkg.SomeClass'])
+        prepare_source_pages(self.linker, self.fs_root, base)
+        build_class_api_pages(data, self.project, base)
+        build_method_api_pages(methodsdata, self.project, base)
         clsfile = base.join('api/pkg.SomeClass.html')
         assert clsfile.check()
         html = clsfile.read()
@@ -107,14 +119,18 @@
         parseString(html)
         if option.webcheck:
             webcheck.check_html(html)
-        assert html.find('href="%s/api/pkg.SomeClass.__init__.html">__init__' % (
-                         base,)) > -1
+        assert html.find(
+            'href="%s/api/pkg.SomeClass.__init__.html">__init__' % (base,)
+        ) > -1
 
     def test_build_class_api_pages_base_link(self):
         base = py.test.ensuretemp('build_class_api_pages_base_link')
         self.linker.root = base.strpath
-        build_class_api_pages(self.project, self.linker, self.dsa, base,
-                              ['pkg.SomeSubClass', 'pkg.SomeClass'])
+        data, methodsdata = prepare_class_api_pages(self.linker, self.dsa,
+                                base, ['pkg.SomeSubClass', 'pkg.SomeClass'])
+        prepare_source_pages(self.linker, self.fs_root, base)
+        build_class_api_pages(data, self.project, base)
+        build_method_api_pages(methodsdata, self.project, base)
         clsfile = base.join('api/pkg.SomeSubClass.html')
         assert clsfile.check()
         html = clsfile.read()
@@ -122,3 +138,27 @@
         assert html.find('href="%s/api/pkg.SomeClass.html">pkg.SomeClass' % (
                          base,)) > -1
 
+    def test_build_source_pages(self):
+        base = py.test.ensuretemp('build_source_pages')
+        data = prepare_source_pages(self.linker, self.fs_root, base)
+        build_source_pages(data, self.project, base)
+        somesource = base.join('source/pkg/func.py.html').read()
+        parseString(somesource)
+        if option.webcheck:
+            webcheck.check_html(somesource)
+
+    def test_api_source_links(self):
+        base = py.test.ensuretemp('api_source_links')
+        self.linker.root = base.strpath
+        data, methodsdata = prepare_class_api_pages(self.linker, self.dsa,
+                                base, ['pkg.SomeSubClass', 'pkg.SomeClass'])
+        sourcedata = prepare_source_pages(self.linker, self.fs_root, base)
+        build_class_api_pages(data, self.project, base)
+        build_method_api_pages(methodsdata, self.project, base)
+        build_source_pages(sourcedata, self.project, base)
+        funchtml = base.join('api/pkg.SomeClass.html').read()
+        parseString(funchtml)
+        assert funchtml.find(
+            'href="%s/source/pkg/someclass.py.html"' % (base,)
+        ) > -1
+



More information about the pytest-commit mailing list