[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:
guido 2007-02-03 00:29:01 +01:00
parent 923c65f13e
commit 66cf52a6e2
4 changed files with 99 additions and 69 deletions

View File

@ -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)))

View File

@ -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):

View File

@ -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'))

View File

@ -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">&quot;bar&quot;</span>\n'
'</div>')