[svn r37837] A bit of cleanup of the HTML generation: some of the layout related stuff is
moved to the classes in the H namespace. This hopefully (when done, more can definitely be done later) seperates the HTML generation better from the presentation-related code. --HG-- branch : trunk
This commit is contained in:
		
							parent
							
								
									923c65f13e
								
							
						
					
					
						commit
						66cf52a6e2
					
				|  | @ -31,10 +31,22 @@ class H(html): | ||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
|     class FunctionDescription(Description): |     class FunctionDescription(Description): | ||||||
|         pass |         def __init__(self, localname, argdesc, docstring, valuedesc, csource, | ||||||
|  |                      callstack): | ||||||
|  |             fd = H.FunctionDef(localname, argdesc) | ||||||
|  |             ds = H.Docstring(docstring or '*no docstring available*') | ||||||
|  |             fi = H.FunctionInfo(valuedesc, csource, callstack) | ||||||
|  |             super(H.FunctionDescription, self).__init__(fd, ds, fi) | ||||||
| 
 | 
 | ||||||
|     class FunctionDef(html.h2): |     class FunctionDef(html.h2): | ||||||
|         pass |         def __init__(self, name, argdesc): | ||||||
|  |             super(H.FunctionDef, self).__init__('def %s%s:' % (name, argdesc)) | ||||||
|  | 
 | ||||||
|  |     class FunctionInfo(html.div): | ||||||
|  |         def __init__(self, valuedesc, csource, callstack): | ||||||
|  |             super(H.FunctionInfo, self).__init__( | ||||||
|  |                 H.Hideable('funcinfo', 'funcinfo', valuedesc, csource, | ||||||
|  |                            callstack)) | ||||||
| 
 | 
 | ||||||
|     class ParameterDescription(html.div): |     class ParameterDescription(html.div): | ||||||
|         pass |         pass | ||||||
|  | @ -49,11 +61,26 @@ class H(html): | ||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
|     class NavigationItem(html.div): |     class NavigationItem(html.div): | ||||||
|         pass |         def __init__(self, linker, linkid, name, indent, selected): | ||||||
|  |             href = linker.get_lazyhref(linkid) | ||||||
|  |             super(H.NavigationItem, self).__init__((indent * 2 * u'\xa0'), | ||||||
|  |                                                  H.a(name, href=href)) | ||||||
|  |             if selected: | ||||||
|  |                 self.attr.class_ = 'selected' | ||||||
| 
 | 
 | ||||||
|     class BaseDescription(html.a): |     class BaseDescription(html.a): | ||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
|  |     class SourceSnippet(html.div): | ||||||
|  |         def __init__(self, text, href, sourceels=None): | ||||||
|  |             if sourceels is None: | ||||||
|  |                 sourceels = [] | ||||||
|  |             link = text | ||||||
|  |             if href: | ||||||
|  |                 link = H.a(text, href=href) | ||||||
|  |             super(H.SourceSnippet, self).__init__( | ||||||
|  |                 link, H.div(class_='code', *sourceels)) | ||||||
|  |      | ||||||
|     class SourceDef(html.div): |     class SourceDef(html.div): | ||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
|  | @ -74,8 +101,24 @@ class H(html): | ||||||
|         pass |         pass | ||||||
| 
 | 
 | ||||||
|     class CallStackDescription(Description): |     class CallStackDescription(Description): | ||||||
|         pass |         def __init__(self, callstackdiv): | ||||||
|  |             super(H.CallStackDescription, self).__init__( | ||||||
|  |                 H.Hideable('callsites', 'callsites', csdiv)) | ||||||
| 
 | 
 | ||||||
|     class CallStackItem(html.div): |     class CallStackItem(html.div): | ||||||
|         class_ = 'callstackitem' |         def __init__(self, filename, lineno, traceback): | ||||||
|  |             super(H.CallStackItem, self).__init__( | ||||||
|  |                 H.Hideable("stack trace %s - line %s" % (filename, lineno), | ||||||
|  |                            'callstackitem', traceback)) | ||||||
|  | 
 | ||||||
|  |     class Hideable(html.div): | ||||||
|  |         def __init__(self, name, class_, *content): | ||||||
|  |             super(H.Hideable, self).__init__( | ||||||
|  |                 H.div(H.a('show/hide %s' % (name,), | ||||||
|  |                           href='#', | ||||||
|  |                           onclick=('showhideel(getnextsibling(this));' | ||||||
|  |                                    'return false;')), | ||||||
|  |                       H.div(style='display: none', | ||||||
|  |                             class_=class_, | ||||||
|  |                             *content))) | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -50,14 +50,7 @@ def get_param_htmldesc(linker, func): | ||||||
|     """ get the html for the parameters of a function """ |     """ get the html for the parameters of a function """ | ||||||
|     import inspect |     import inspect | ||||||
|     # XXX copy and modify formatargspec to produce html |     # XXX copy and modify formatargspec to produce html | ||||||
|     return H.em(inspect.formatargspec(*inspect.getargspec(func))) |     return inspect.formatargspec(*inspect.getargspec(func)) | ||||||
| 
 |  | ||||||
| def build_navitem_html(linker, name, linkid, indent, selected): |  | ||||||
|     href = linker.get_lazyhref(linkid) |  | ||||||
|     navitem = H.NavigationItem((indent * 2 * u'\xa0'), H.a(name, href=href)) |  | ||||||
|     if selected: |  | ||||||
|         navitem.attr.class_ = 'selected' |  | ||||||
|     return navitem |  | ||||||
| 
 | 
 | ||||||
| # some helper functionality | # some helper functionality | ||||||
| def source_dirs_files(fspath): | def source_dirs_files(fspath): | ||||||
|  | @ -139,15 +132,15 @@ class SourcePageBuilder(AbstractPageBuilder): | ||||||
|                     text = self.projroot.basename |                     text = self.projroot.basename | ||||||
|                 else: |                 else: | ||||||
|                     text = path[i-1] |                     text = path[i-1] | ||||||
|                 nav.append(build_navitem_html(self.linker, text, abspath, |                 nav.append(H.NavigationItem(self.linker, abspath, text, | ||||||
|                                               indent, False)) |                                             indent, False)) | ||||||
|                 indent += 1 |                 indent += 1 | ||||||
|         # build siblings or children and self |         # build siblings or children and self | ||||||
|         if fspath.check(dir=True): |         if fspath.check(dir=True): | ||||||
|             # we're a dir, build ourselves and our children |             # we're a dir, build ourselves and our children | ||||||
|             dirpath = fspath |             dirpath = fspath | ||||||
|             nav.append(build_navitem_html(self.linker, dirpath.basename, |             nav.append(H.NavigationItem(self.linker, dirpath.strpath, | ||||||
|                                           dirpath.strpath, indent, True)) |                                         dirpath.basename, indent, True)) | ||||||
|             indent += 1 |             indent += 1 | ||||||
|         elif fspath.strpath == self.projroot.strpath: |         elif fspath.strpath == self.projroot.strpath: | ||||||
|             dirpath = fspath |             dirpath = fspath | ||||||
|  | @ -156,13 +149,13 @@ class SourcePageBuilder(AbstractPageBuilder): | ||||||
|             dirpath = fspath.dirpath() |             dirpath = fspath.dirpath() | ||||||
|         diritems, fileitems = source_dirs_files(dirpath) |         diritems, fileitems = source_dirs_files(dirpath) | ||||||
|         for dir in diritems: |         for dir in diritems: | ||||||
|             nav.append(build_navitem_html(self.linker, dir.basename, |             nav.append(H.NavigationItem(self.linker, dir.strpath, dir.basename, | ||||||
|                                           dir.strpath, indent, False)) |                                         indent, False)) | ||||||
|         for file in fileitems: |         for file in fileitems: | ||||||
|             selected = (fspath.check(file=True) and |             selected = (fspath.check(file=True) and | ||||||
|                         file.basename == fspath.basename) |                         file.basename == fspath.basename) | ||||||
|             nav.append(build_navitem_html(self.linker, file.basename, |             nav.append(H.NavigationItem(self.linker, file.strpath, | ||||||
|                                           file.strpath, indent, selected)) |                                         file.basename, indent, selected)) | ||||||
|         return nav |         return nav | ||||||
| 
 | 
 | ||||||
|     re = py.std.re |     re = py.std.re | ||||||
|  | @ -232,6 +225,7 @@ class SourcePageBuilder(AbstractPageBuilder): | ||||||
|                 except (KeyboardInterrupt, SystemError): |                 except (KeyboardInterrupt, SystemError): | ||||||
|                     raise |                     raise | ||||||
|                 except: # XXX strange stuff going wrong at times... need to fix |                 except: # XXX strange stuff going wrong at times... need to fix | ||||||
|  |                     raise | ||||||
|                     exc, e, tb = py.std.sys.exc_info() |                     exc, e, tb = py.std.sys.exc_info() | ||||||
|                     print '%s - %s' % (exc, e) |                     print '%s - %s' % (exc, e) | ||||||
|                     print |                     print | ||||||
|  | @ -288,41 +282,26 @@ class ApiPageBuilder(AbstractPageBuilder): | ||||||
|         callable_source = self.dsa.get_function_source(dotted_name) |         callable_source = self.dsa.get_function_source(dotted_name) | ||||||
|         # i assume they're both either available or unavailable(XXX ?) |         # i assume they're both either available or unavailable(XXX ?) | ||||||
|         is_in_pkg = self.is_in_pkg(sourcefile) |         is_in_pkg = self.is_in_pkg(sourcefile) | ||||||
|  |         href = None | ||||||
|  |         text = 'could not get to source file' | ||||||
|  |         colored = [] | ||||||
|         if sourcefile and callable_source: |         if sourcefile and callable_source: | ||||||
|             enc = source_html.get_module_encoding(sourcefile) |             enc = source_html.get_module_encoding(sourcefile) | ||||||
|             tokenizer = source_color.Tokenizer(source_color.PythonSchema) |             tokenizer = source_color.Tokenizer(source_color.PythonSchema) | ||||||
|             firstlineno = func.func_code.co_firstlineno |             firstlineno = func.func_code.co_firstlineno | ||||||
|             org = callable_source.split('\n') |             org = callable_source.split('\n') | ||||||
|             colored = enumerate_and_color(org, firstlineno, enc) |             colored = enumerate_and_color(org, firstlineno, enc) | ||||||
|  |             text = 'source: %s' % (sourcefile,) | ||||||
|             if is_in_pkg: |             if is_in_pkg: | ||||||
|                 slink = H.a('source: %s' % (sourcefile,), |                 href = self.linker.get_lazyhref(sourcefile) | ||||||
|                             href=self.linker.get_lazyhref(sourcefile)) |  | ||||||
|             else: |  | ||||||
|                 slink = H.em('source: %s' % (sourcefile,)) |  | ||||||
|             csource = H.div(H.br(), slink, H.br(), |  | ||||||
|                             H.SourceDef(H.div(class_='code', *colored))) |  | ||||||
|         else: |  | ||||||
|             csource = H.SourceDef('could not get source file') |  | ||||||
| 
 | 
 | ||||||
|         csdiv = H.div(style='display: none') |         csource = H.SourceSnippet(text, href, colored) | ||||||
|         for cs, _ in self.dsa.get_function_callpoints(dotted_name): |         callstack = self.dsa.get_function_callpoints(dotted_name) | ||||||
|             csdiv.append(self.build_callsite(dotted_name, cs)) |         csitems = [] | ||||||
|         callstack = H.CallStackDescription( |         for cs, _ in callstack: | ||||||
|             H.a('show/hide call sites', |             csitems.append(self.build_callsite(dotted_name, cs)) | ||||||
|                 href='#', |         snippet = H.FunctionDescription(localname, argdesc, docstring, | ||||||
|                 onclick='showhideel(getnextsibling(this)); return false;'), |                                         valuedesc, csource, csitems) | ||||||
|             csdiv, |  | ||||||
|         ) |  | ||||||
|         snippet = H.FunctionDescription( |  | ||||||
|             H.FunctionDef('def %s' % (localname,), argdesc), |  | ||||||
|             H.Docstring(docstring or '*no docstring available*'), |  | ||||||
|             H.div(H.a('show/hide info', |  | ||||||
|                       href='#', |  | ||||||
|                       onclick=('showhideel(getnextsibling(this));' |  | ||||||
|                                'return false;')), |  | ||||||
|                   H.div(valuedesc, csource, callstack, style='display: none', |  | ||||||
|                         class_='funcinfo')), |  | ||||||
|         ) |  | ||||||
|          |          | ||||||
|         return snippet |         return snippet | ||||||
| 
 | 
 | ||||||
|  | @ -501,8 +480,8 @@ class ApiPageBuilder(AbstractPageBuilder): | ||||||
| 
 | 
 | ||||||
|         # top namespace, index.html |         # top namespace, index.html | ||||||
|         module_name = self.dsa.get_module_name().split('/')[-1] |         module_name = self.dsa.get_module_name().split('/')[-1] | ||||||
|         navitems.append(build_navitem_html(self.linker, module_name, '', 0, |         navitems.append(H.NavigationItem(self.linker, '', module_name, 0, | ||||||
|                                            True)) |                                          True)) | ||||||
|         def build_nav_level(dotted_name, depth=1): |         def build_nav_level(dotted_name, depth=1): | ||||||
|             navitems = [] |             navitems = [] | ||||||
|             path = dotted_name.split('.')[:depth] |             path = dotted_name.split('.')[:depth] | ||||||
|  | @ -513,8 +492,8 @@ class ApiPageBuilder(AbstractPageBuilder): | ||||||
|                 sibname = sibpath[-1] |                 sibname = sibpath[-1] | ||||||
|                 if is_private(sibname): |                 if is_private(sibname): | ||||||
|                     continue |                     continue | ||||||
|                 navitems.append(build_navitem_html(self.linker, sibname, |                 navitems.append(H.NavigationItem(self.linker, dn, sibname, | ||||||
|                                                    dn, depth, selected)) |                                                  depth, selected)) | ||||||
|                 if selected: |                 if selected: | ||||||
|                     lastlevel = dn.count('.') == dotted_name.count('.') |                     lastlevel = dn.count('.') == dotted_name.count('.') | ||||||
|                     if not lastlevel: |                     if not lastlevel: | ||||||
|  | @ -581,15 +560,10 @@ class ApiPageBuilder(AbstractPageBuilder): | ||||||
|         return py.path.local(sourcefile).relto(self.projpath) |         return py.path.local(sourcefile).relto(self.projpath) | ||||||
| 
 | 
 | ||||||
|     def build_callsite(self, functionname, call_site): |     def build_callsite(self, functionname, call_site): | ||||||
|  |         print 'building callsite for', functionname | ||||||
|         tbtag = self.gen_traceback(functionname, reversed(call_site)) |         tbtag = self.gen_traceback(functionname, reversed(call_site)) | ||||||
|         tag = H.CallStackItem( |         return H.CallStackItem(call_site[0].filename, call_site[0].lineno + 1, | ||||||
|             H.a("show/hide stack trace %s - line %s" % ( |                                tbtag) | ||||||
|                     call_site[0].filename, call_site[0].lineno + 1), |  | ||||||
|                 href='#', |  | ||||||
|                 onclick="showhideel(getnextsibling(this)); return false;"), |  | ||||||
|             H.div(tbtag, style='display: none', class_='callstackitem'), |  | ||||||
|         ) |  | ||||||
|         return tag |  | ||||||
|      |      | ||||||
|     _reg_source = py.std.re.compile(r'([^>]*)<(.*)>') |     _reg_source = py.std.re.compile(r'([^>]*)<(.*)>') | ||||||
|     def gen_traceback(self, funcname, call_site): |     def gen_traceback(self, funcname, call_site): | ||||||
|  |  | ||||||
|  | @ -364,6 +364,16 @@ class TestSourcePageBuilder(AbstractBuilderTest): | ||||||
|             '<h2>files</h2>']) |             '<h2>files</h2>']) | ||||||
|         _checkhtml(html) |         _checkhtml(html) | ||||||
| 
 | 
 | ||||||
|  |     def test_build_source_page(self): | ||||||
|  |         data = self.spb.prepare_pages(self.fs_root) | ||||||
|  |         self.spb.build_pages(data, self.project, self.fs_root) | ||||||
|  |         funcsource = self.base.join('source/pkg/func.py.html') | ||||||
|  |         assert funcsource.check(file=True) | ||||||
|  |         html = funcsource.read() | ||||||
|  |         print html | ||||||
|  |         assert ('<span class="alt_keyword">def</span> ' | ||||||
|  |                 '<a href="#func" name="func">func</a>(arg1):') in html | ||||||
|  | 
 | ||||||
|     def test_build_navigation_root(self): |     def test_build_navigation_root(self): | ||||||
|         self.spb.prepare_pages(self.fs_root) |         self.spb.prepare_pages(self.fs_root) | ||||||
|         nav = self.spb.build_navigation(self.fs_root.join('pkg')) |         nav = self.spb.build_navigation(self.fs_root.join('pkg')) | ||||||
|  |  | ||||||
|  | @ -19,15 +19,6 @@ def test_create_namespace_tree(): | ||||||
|                     'pkg': ['pkg.sub', 'pkg.SomeClass', |                     'pkg': ['pkg.sub', 'pkg.SomeClass', | ||||||
|                             'pkg.SomeSubClass']} |                             'pkg.SomeSubClass']} | ||||||
| 
 | 
 | ||||||
| def test_build_navitem_html(): |  | ||||||
|     l = Linker() |  | ||||||
|     l.set_link('spam.eggs.foo', 'foo.html') |  | ||||||
|     h = htmlgen.build_navitem_html(l, 'foo', 'spam.eggs.foo', 0, False) |  | ||||||
|     assert unicode(h) == u'<div><a href="foo.html">foo</a></div>' |  | ||||||
|     h = htmlgen.build_navitem_html(l, 'bar', 'spam.eggs.foo', 1, True) |  | ||||||
|     assert unicode(h) == (u'<div class="selected">\xa0\xa0' |  | ||||||
|                           u'<a href="foo.html">bar</a></div>') |  | ||||||
| 
 |  | ||||||
| def test_source_dirs_files(): | def test_source_dirs_files(): | ||||||
|     temp = py.test.ensuretemp('test_source_dirs_files') |     temp = py.test.ensuretemp('test_source_dirs_files') | ||||||
|     temp.join('dir').ensure(dir=True) |     temp.join('dir').ensure(dir=True) | ||||||
|  | @ -52,3 +43,15 @@ def test_deindent(): | ||||||
|     assert htmlgen.deindent('foo\n\n      bar\n    baz\n') == ( |     assert htmlgen.deindent('foo\n\n      bar\n    baz\n') == ( | ||||||
|         'foo\n\n  bar\nbaz\n') |         'foo\n\n  bar\nbaz\n') | ||||||
| 
 | 
 | ||||||
|  | def test_enumerate_and_color(): | ||||||
|  |     colored = htmlgen.enumerate_and_color(['def foo():', '  print "bar"'], 0, | ||||||
|  |                                           'ascii') | ||||||
|  |     div = py.xml.html.div(*colored).unicode(indent=0) | ||||||
|  |     assert div == ('<div>' | ||||||
|  |                    '<span>   1: </span>' | ||||||
|  |                    '<span class="alt_keyword">def</span> foo():\n' | ||||||
|  |                    '<span>   2: </span>' | ||||||
|  |                    '  <span class="keyword">print</span>' | ||||||
|  |                    ' <span class="string">"bar"</span>\n' | ||||||
|  |                    '</div>') | ||||||
|  | 
 | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue