[svn r37383] Added call stacks, made that method pages aren't built at all anymore, made

that build_namespace_view isn't called for anything but namespaces anymore,
made that parts of documents are hidden at first (with a link to 'open' them).

--HG--
branch : trunk
This commit is contained in:
guido 2007-01-26 14:01:27 +01:00
parent c72120b8fc
commit b67ef229df
5 changed files with 112 additions and 41 deletions

View File

@ -1,7 +1,22 @@
function showhideel(el) { function showhideel(el) {
/* show or hide the element
sets the value of el.style.display to 'none' or 'block' depending
on the current value
*/
if (el.style.display == 'none') { if (el.style.display == 'none') {
el.style.display = 'block'; el.style.display = 'block';
} else { } else {
el.style.display = 'none'; el.style.display = 'none';
}; };
}; };
function getnextsibling(el) {
/* return next non-text sibling (or null) */
var node = el.nextSibling;
while (node && node.nodeType != 1) {
node = node.nextSibling;
};
return node;
};

View File

@ -37,7 +37,7 @@ def build(pkgdir, dsa):
ns_data = apb.prepare_namespace_pages(namespace_tree) ns_data = apb.prepare_namespace_pages(namespace_tree)
class_names = dsa.get_class_names() class_names = dsa.get_class_names()
class_data, method_data = apb.prepare_class_pages(namespace_tree, class_data = apb.prepare_class_pages(namespace_tree,
class_names) class_names)
function_names = dsa.get_function_names() function_names = dsa.get_function_names()
func_data = apb.prepare_function_pages(namespace_tree, function_names) func_data = apb.prepare_function_pages(namespace_tree, function_names)
@ -45,7 +45,7 @@ def build(pkgdir, dsa):
apb.build_namespace_pages(ns_data, proj) apb.build_namespace_pages(ns_data, proj)
apb.build_class_pages(class_data, proj) apb.build_class_pages(class_data, proj)
apb.build_method_pages(method_data, proj) #apb.build_method_pages(method_data, proj)
apb.build_function_pages(func_data, proj) apb.build_function_pages(func_data, proj)
spb.build_pages(source_data, proj, pkgdir) spb.build_pages(source_data, proj, pkgdir)

View File

@ -14,8 +14,11 @@ raw = py.xml.raw
# HTML related stuff # HTML related stuff
class H(html): class H(html):
class Description(html.div): class Content(html.div):
style = html.Style(margin_left='15em') style = html.Style(margin_left='15em')
class Description(html.div):
pass
class NamespaceDescription(Description): class NamespaceDescription(Description):
pass pass
@ -79,6 +82,12 @@ class H(html):
class ValueDescItem(html.li): class ValueDescItem(html.li):
pass pass
class CallStackDescription(Description):
pass
class CallStackItem(html.div):
class_ = 'callstackitem'
def get_param_htmldesc(linker, func): 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
@ -321,14 +330,23 @@ class ApiPageBuilder(AbstractPageBuilder):
else: else:
csource = H.SourceDef('could not get source file') csource = H.SourceDef('could not get source file')
csdiv = H.div(style='display: none')
for cs, _ in self.dsa.get_function_callpoints(dotted_name):
csdiv.append(self.build_callsite(dotted_name, cs))
callstack = H.CallStackDescription(
H.a('show/hide call sites',
href='#',
onclick='showhideel(getnextsibling(this)); return false;'),
csdiv,
)
snippet = H.FunctionDescription( snippet = H.FunctionDescription(
H.FunctionDef(localname, argdesc), H.FunctionDef(localname, argdesc),
H.Docstring(docstring or H.em('no docstring available')), H.Docstring(docstring or H.em('no docstring available')),
H.div(H.a('show/hide info', H.div(H.a('show/hide info',
href='#', href='#',
onclick=('showhideel(this.parentNode.lastChild);' onclick=('showhideel(getnextsibling(this));'
'return false;')), 'return false;')),
H.div(valuedesc, csource, style='display: none', H.div(valuedesc, csource, callstack, style='display: none',
class_='funcinfo')), class_='funcinfo')),
) )
@ -397,7 +415,7 @@ class ApiPageBuilder(AbstractPageBuilder):
H.NamespaceDef(namespace_dotted_name), H.NamespaceDef(namespace_dotted_name),
H.Docstring(docstring or H.em('no docstring available')) H.Docstring(docstring or H.em('no docstring available'))
) )
for dotted_name in item_dotted_names: for dotted_name in sorted(item_dotted_names):
itemname = dotted_name.split('.')[-1] itemname = dotted_name.split('.')[-1]
if is_private(itemname): if is_private(itemname):
continue continue
@ -412,26 +430,20 @@ class ApiPageBuilder(AbstractPageBuilder):
def prepare_class_pages(self, namespace_tree, classes_dotted_names): def prepare_class_pages(self, namespace_tree, classes_dotted_names):
passed = [] passed = []
methodsdata = [] for dotted_name in sorted(classes_dotted_names):
for dotted_name in classes_dotted_names:
parent_dotted_name, _ = split_of_last_part(dotted_name) parent_dotted_name, _ = split_of_last_part(dotted_name)
try: try:
sibling_dotted_names = namespace_tree[parent_dotted_name] sibling_dotted_names = namespace_tree[parent_dotted_name]
except KeyError: except KeyError:
# no siblings (built-in module or sth) # no siblings (built-in module or sth)
sibling_dotted_names = [] sibling_dotted_names = []
tag = self.build_class_view(dotted_name) tag = H.Content(self.build_class_view(dotted_name))
nav = self.build_navigation(parent_dotted_name, nav = self.build_navigation(parent_dotted_name,
sibling_dotted_names, dotted_name) sibling_dotted_names, dotted_name)
reltargetpath = "api/%s.html" % (dotted_name,) reltargetpath = "api/%s.html" % (dotted_name,)
self.linker.set_link(dotted_name, reltargetpath) self.linker.set_link(dotted_name, reltargetpath)
passed.append((dotted_name, tag, nav, reltargetpath)) passed.append((dotted_name, tag, nav, reltargetpath))
method_dotted_names = ['%s.%s' % (dotted_name, method_name) for return passed
method_name in
self.dsa.get_class_methods(dotted_name)]
methodsdata += self.prepare_method_pages(namespace_tree,
method_dotted_names)
return passed, methodsdata
def build_class_pages(self, data, project): def build_class_pages(self, data, project):
""" build the full api pages for a set of classes """ """ build the full api pages for a set of classes """
@ -443,7 +455,7 @@ class ApiPageBuilder(AbstractPageBuilder):
# XXX note that even though these pages are still built, there's no nav # XXX note that even though these pages are still built, there's no nav
# pointing to them anymore... # pointing to them anymore...
passed = [] passed = []
for dotted_name in method_dotted_names: for dotted_name in sorted(method_dotted_names):
parent_dotted_name, _ = split_of_last_part(dotted_name) parent_dotted_name, _ = split_of_last_part(dotted_name)
module_dotted_name, _ = split_of_last_part(parent_dotted_name) module_dotted_name, _ = split_of_last_part(parent_dotted_name)
sibling_dotted_names = namespace_tree[module_dotted_name] sibling_dotted_names = namespace_tree[module_dotted_name]
@ -462,11 +474,11 @@ class ApiPageBuilder(AbstractPageBuilder):
def prepare_function_pages(self, namespace_tree, method_dotted_names): def prepare_function_pages(self, namespace_tree, method_dotted_names):
passed = [] passed = []
for dotted_name in method_dotted_names: for dotted_name in sorted(method_dotted_names):
# XXX should we create a build_function_view instead? # XXX should we create a build_function_view instead?
parent_dotted_name, _ = split_of_last_part(dotted_name) parent_dotted_name, _ = split_of_last_part(dotted_name)
sibling_dotted_names = namespace_tree[parent_dotted_name] sibling_dotted_names = namespace_tree[parent_dotted_name]
tag = self.build_callable_view(dotted_name) tag = H.Content(self.build_callable_view(dotted_name))
nav = self.build_navigation(parent_dotted_name, nav = self.build_navigation(parent_dotted_name,
sibling_dotted_names, dotted_name) sibling_dotted_names, dotted_name)
reltargetpath = "api/%s.html" % (dotted_name,) reltargetpath = "api/%s.html" % (dotted_name,)
@ -485,9 +497,14 @@ class ApiPageBuilder(AbstractPageBuilder):
names = namespace_tree.keys() names = namespace_tree.keys()
names.sort() names.sort()
for dotted_name in names: function_names = self.dsa.get_function_names()
class_names = self.dsa.get_class_names()
for dotted_name in sorted(names):
if dotted_name in function_names or dotted_name in class_names:
continue
subitem_dotted_names = namespace_tree[dotted_name] subitem_dotted_names = namespace_tree[dotted_name]
tag = self.build_namespace_view(dotted_name, subitem_dotted_names) tag = H.Content(self.build_namespace_view(dotted_name,
subitem_dotted_names))
nav = self.build_navigation(dotted_name, subitem_dotted_names, nav = self.build_navigation(dotted_name, subitem_dotted_names,
dotted_name) dotted_name)
if dotted_name == '': if dotted_name == '':
@ -588,3 +605,42 @@ class ApiPageBuilder(AbstractPageBuilder):
def is_in_pkg(self, sourcefile): def is_in_pkg(self, sourcefile):
return py.path.local(sourcefile).relto(self.projpath) return py.path.local(sourcefile).relto(self.projpath)
def build_callsite(self, functionname, call_site):
tbtag = self.gen_traceback(functionname, call_site)
tag = H.CallStackItem(
H.a("%s - line %s" % (call_site[0].filename, call_site[0].lineno + 1),
href='#',
onclick="showhideel(getnextsibling(this)); return false;"),
H.div(tbtag, style='display: none')
)
return tag
def gen_traceback(self, funcname, call_site):
tbdiv = H.div()
for line in call_site:
lineno = line.lineno - line.firstlineno
source = line.source
sourcefile = line.filename
mangled = []
for i, sline in enumerate(str(source).split('\n')):
if i == lineno:
l = '-> %s' % (sline,)
else:
l = ' %s' % (sline,)
mangled.append(l)
if sourcefile:
linktext = '%s - line %s' % (sourcefile, line.lineno + 1)
# skip py.code.Source objects and source files outside of the
# package
if (not sourcefile.startswith('None') and
self.is_in_pkg(sourcefile)):
href = self.linker.get_lazyhref(sourcefile)
sourcelink = H.a(linktext, href=href)
else:
sourcelink = H.div(linktext)
else:
sourcelink = H.div('source unknown')
tbdiv.append(sourcelink)
tbdiv.append(H.pre('\n'.join(mangled)))
return tbdiv

View File

@ -163,9 +163,9 @@ class TestApiPageBuilder(AbstractBuilderTest):
_checkhtmlsnippet(html) _checkhtmlsnippet(html)
def test_build_class_pages(self): def test_build_class_pages(self):
data, methodsdata = self.apb.prepare_class_pages(self.namespace_tree, data = self.apb.prepare_class_pages(self.namespace_tree,
['main.SomeClass', ['main.SomeClass',
'main.SomeSubClass']) 'main.SomeSubClass'])
self.apb.build_class_pages(data, self.project) self.apb.build_class_pages(data, self.project)
clsfile = self.base.join('api/main.SomeClass.html') clsfile = self.base.join('api/main.SomeClass.html')
assert clsfile.check() assert clsfile.check()
@ -173,10 +173,10 @@ class TestApiPageBuilder(AbstractBuilderTest):
_checkhtml(html) _checkhtml(html)
def test_build_class_pages_instance(self): def test_build_class_pages_instance(self):
data, methodsdata = self.apb.prepare_class_pages(self.namespace_tree, data = self.apb.prepare_class_pages(self.namespace_tree,
['main.SomeClass', ['main.SomeClass',
'main.SomeSubClass', 'main.SomeSubClass',
'main.SomeInstance']) 'main.SomeInstance'])
self.apb.build_class_pages(data, self.project) self.apb.build_class_pages(data, self.project)
clsfile = self.base.join('api/main.SomeInstance.html') clsfile = self.base.join('api/main.SomeInstance.html')
assert clsfile.check() assert clsfile.check()
@ -187,9 +187,9 @@ class TestApiPageBuilder(AbstractBuilderTest):
]) ])
def test_build_class_pages_nav_links(self): def test_build_class_pages_nav_links(self):
data, methodsdata = self.apb.prepare_class_pages(self.namespace_tree, data = self.apb.prepare_class_pages(self.namespace_tree,
['main.SomeSubClass', ['main.SomeSubClass',
'main.SomeClass']) 'main.SomeClass'])
# fake some stuff that would be built from other methods # fake some stuff that would be built from other methods
self.linker.set_link('', 'api/index.html') self.linker.set_link('', 'api/index.html')
self.linker.set_link('main', 'api/main.html') self.linker.set_link('main', 'api/main.html')
@ -212,9 +212,9 @@ class TestApiPageBuilder(AbstractBuilderTest):
_checkhtml(html) _checkhtml(html)
def test_build_class_pages_base_link(self): def test_build_class_pages_base_link(self):
data, methodsdata = self.apb.prepare_class_pages(self.namespace_tree, data = self.apb.prepare_class_pages(self.namespace_tree,
['main.SomeSubClass', ['main.SomeSubClass',
'main.SomeClass']) 'main.SomeClass'])
self.apb.build_class_pages(data, self.project) self.apb.build_class_pages(data, self.project)
clsfile = self.base.join('api/main.SomeSubClass.html') clsfile = self.base.join('api/main.SomeSubClass.html')
assert clsfile.check() assert clsfile.check()
@ -227,9 +227,9 @@ class TestApiPageBuilder(AbstractBuilderTest):
_checkhtml(html) _checkhtml(html)
def test_source_links(self): def test_source_links(self):
data, methodsdata = self.apb.prepare_class_pages(self.namespace_tree, data = self.apb.prepare_class_pages(self.namespace_tree,
['main.SomeSubClass', ['main.SomeSubClass',
'main.SomeClass']) 'main.SomeClass'])
sourcedata = self.spb.prepare_pages(self.fs_root) sourcedata = self.spb.prepare_pages(self.fs_root)
self.apb.build_class_pages(data, self.project) self.apb.build_class_pages(data, self.project)
self.spb.build_pages(sourcedata, self.project, self.fs_root) self.spb.build_pages(sourcedata, self.project, self.fs_root)

View File

@ -113,9 +113,9 @@ def test_apigen_functional():
html = sometestclass_source.read() html = sometestclass_source.read()
assert '<div class="project_title">sources for sometestclass.py</div>' in html assert '<div class="project_title">sources for sometestclass.py</div>' in html
# XXX later... index = sourcedir.join('index.html')
#index = sourcedir.join('index.html') assert index.check(file=True)
#assert index.check(file=True) html = index.read()
#html = index.read() print html
#assert '<a href="main/index.html">main</a>' in html assert '<a href="test/index.html">test</a>' in html