[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