[svn r38005] Made that source snippets are now shown in two tables, to allow selecting
the source without the line numbers, decreased font size a bit, made that the Page class can be passed in from the outside (build() method) to more easily allow customization of the layout and pages. --HG-- branch : trunk
This commit is contained in:
parent
410e00320d
commit
3690e384a9
|
@ -12,6 +12,8 @@ from py.__.apigen import linker
|
||||||
from py.__.apigen import project
|
from py.__.apigen import project
|
||||||
from py.__.apigen.tracer.docstorage import pkg_to_dict
|
from py.__.apigen.tracer.docstorage import pkg_to_dict
|
||||||
|
|
||||||
|
from layout import LayoutPage
|
||||||
|
|
||||||
def get_documentable_items_pkgdir(pkgdir):
|
def get_documentable_items_pkgdir(pkgdir):
|
||||||
""" get all documentable items from an initpkg pkgdir
|
""" get all documentable items from an initpkg pkgdir
|
||||||
|
|
||||||
|
@ -31,20 +33,27 @@ def get_documentable_items(pkgdir):
|
||||||
return pkgname, pkgdict
|
return pkgname, pkgdict
|
||||||
|
|
||||||
def build(pkgdir, dsa, capture):
|
def build(pkgdir, dsa, capture):
|
||||||
|
# create a linker (link database) for cross-linking
|
||||||
l = linker.Linker()
|
l = linker.Linker()
|
||||||
|
|
||||||
|
# create a project.Project instance to contain the LayoutPage instances
|
||||||
proj = project.Project()
|
proj = project.Project()
|
||||||
|
|
||||||
|
# output dir
|
||||||
if 'APIGEN_TARGET' in os.environ:
|
if 'APIGEN_TARGET' in os.environ:
|
||||||
targetdir = py.path.local(os.environ['APIGEN_TARGET'])
|
targetdir = py.path.local(os.environ['APIGEN_TARGET'])
|
||||||
else:
|
else:
|
||||||
targetdir = pkgdir.dirpath().join('apigen')
|
targetdir = pkgdir.dirpath().join('apigen')
|
||||||
targetdir.ensure(dir=True)
|
targetdir.ensure(dir=True)
|
||||||
|
|
||||||
|
# find out what to build
|
||||||
all_names = dsa._get_names(filter=lambda x, y: True)
|
all_names = dsa._get_names(filter=lambda x, y: True)
|
||||||
namespace_tree = htmlgen.create_namespace_tree(all_names)
|
namespace_tree = htmlgen.create_namespace_tree(all_names)
|
||||||
|
|
||||||
|
# and build it
|
||||||
apb = htmlgen.ApiPageBuilder(targetdir, l, dsa, pkgdir, namespace_tree,
|
apb = htmlgen.ApiPageBuilder(targetdir, l, dsa, pkgdir, namespace_tree,
|
||||||
capture)
|
capture, LayoutPage)
|
||||||
spb = htmlgen.SourcePageBuilder(targetdir, l, pkgdir, capture)
|
spb = htmlgen.SourcePageBuilder(targetdir, l, pkgdir, capture, LayoutPage)
|
||||||
|
|
||||||
capture.err.writeorg('preparing namespace pages\n')
|
capture.err.writeorg('preparing namespace pages\n')
|
||||||
ns_data = apb.prepare_namespace_pages()
|
ns_data = apb.prepare_namespace_pages()
|
||||||
|
|
|
@ -4,7 +4,8 @@ from py.xml import html
|
||||||
# HTML related stuff
|
# HTML related stuff
|
||||||
class H(html):
|
class H(html):
|
||||||
class Content(html.div):
|
class Content(html.div):
|
||||||
pass # style = html.Style(margin_left='15em')
|
def __init__(self, *args):
|
||||||
|
super(H.Content, self).__init__(id='apigen-content', *args)
|
||||||
|
|
||||||
class Description(html.div):
|
class Description(html.div):
|
||||||
pass
|
pass
|
||||||
|
@ -88,12 +89,29 @@ class H(html):
|
||||||
if href:
|
if href:
|
||||||
link = H.a(text, href=href)
|
link = H.a(text, href=href)
|
||||||
super(H.SourceSnippet, self).__init__(
|
super(H.SourceSnippet, self).__init__(
|
||||||
link, H.div(class_='code', *sourceels))
|
link, H.div(*sourceels))
|
||||||
|
|
||||||
class SourceDef(html.div):
|
class SourceDef(html.div):
|
||||||
def __init__(self, *sourceels):
|
def __init__(self, *sourceels):
|
||||||
super(H.SourceDef, self).__init__(
|
super(H.SourceDef, self).__init__(
|
||||||
H.div(class_='code', *sourceels))
|
H.div(*sourceels))
|
||||||
|
|
||||||
|
class SourceCode(html.div):
|
||||||
|
style = html.Style(margin_top='1em', margin_bottom='1em')
|
||||||
|
def __init__(self):
|
||||||
|
self.linenotable = lntable = H.table(style='float: left')
|
||||||
|
self.linenotbody = lntbody = H.tbody()
|
||||||
|
lntable.append(lntbody)
|
||||||
|
|
||||||
|
self.linetable = ltable = H.table()
|
||||||
|
self.linetbody = ltbody = H.tbody()
|
||||||
|
ltable.append(ltbody)
|
||||||
|
|
||||||
|
super(H.SourceCode, self).__init__(lntable, ltable)
|
||||||
|
|
||||||
|
def add_line(self, lineno, els):
|
||||||
|
self.linenotbody.append(H.tr(H.td(lineno, class_='lineno')))
|
||||||
|
self.linetbody.append(H.tr(H.td(class_='code', *els)))
|
||||||
|
|
||||||
class NonPythonSource(html.pre):
|
class NonPythonSource(html.pre):
|
||||||
pass # style = html.Style(margin_left='15em')
|
pass # style = html.Style(margin_left='15em')
|
||||||
|
|
|
@ -115,32 +115,65 @@ def create_namespace_tree(dotted_names):
|
||||||
ret[ns].append(itempath)
|
ret[ns].append(itempath)
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def wrap_page(project, title, contentel, navel, relbase, basepath):
|
def wrap_page(project, title, contentel, navel, relbase, basepath,
|
||||||
page = LayoutPage(project, title, nav=navel, encoding='UTF-8',
|
pageclass):
|
||||||
|
page = pageclass(project, title, nav=navel, encoding='UTF-8',
|
||||||
relpath=relbase)
|
relpath=relbase)
|
||||||
page.set_content(contentel)
|
page.set_content(contentel)
|
||||||
page.setup_scripts_styles(basepath)
|
page.setup_scripts_styles(basepath)
|
||||||
return page
|
return page
|
||||||
|
|
||||||
|
def enumerate_and_color(codelines, firstlineno, enc):
|
||||||
|
snippet = H.SourceCode()
|
||||||
|
tokenizer = source_color.Tokenizer(source_color.PythonSchema)
|
||||||
|
for i, line in enumerate(codelines):
|
||||||
|
try:
|
||||||
|
snippet.add_line(i + firstlineno + 1,
|
||||||
|
source_html.prepare_line([line], tokenizer, enc))
|
||||||
|
except py.error.ENOENT:
|
||||||
|
# error reading source code, giving up
|
||||||
|
snippet = org
|
||||||
|
break
|
||||||
|
return snippet
|
||||||
|
|
||||||
|
def get_obj(pkg, dotted_name):
|
||||||
|
full_dotted_name = '%s.%s' % (pkg.__name__, dotted_name)
|
||||||
|
if dotted_name == '':
|
||||||
|
return pkg
|
||||||
|
path = dotted_name.split('.')
|
||||||
|
ret = pkg
|
||||||
|
for item in path:
|
||||||
|
marker = []
|
||||||
|
ret = getattr(ret, item, marker)
|
||||||
|
if ret is marker:
|
||||||
|
raise NameError('can not access %s in %s' % (item,
|
||||||
|
full_dotted_name))
|
||||||
|
return ret
|
||||||
|
|
||||||
# the PageBuilder classes take care of producing the docs (using the stuff
|
# the PageBuilder classes take care of producing the docs (using the stuff
|
||||||
# above)
|
# above)
|
||||||
class AbstractPageBuilder(object):
|
class AbstractPageBuilder(object):
|
||||||
|
pageclass = LayoutPage
|
||||||
|
|
||||||
def write_page(self, title, reltargetpath, project, tag, nav):
|
def write_page(self, title, reltargetpath, project, tag, nav):
|
||||||
targetpath = self.base.join(reltargetpath)
|
targetpath = self.base.join(reltargetpath)
|
||||||
relbase= relpath('%s%s' % (targetpath.dirpath(), targetpath.sep),
|
relbase= relpath('%s%s' % (targetpath.dirpath(), targetpath.sep),
|
||||||
self.base.strpath + '/')
|
self.base.strpath + '/')
|
||||||
page = wrap_page(project, title, tag, nav, relbase, self.base)
|
page = wrap_page(project, title, tag, nav, relbase, self.base,
|
||||||
|
self.pageclass)
|
||||||
content = self.linker.call_withbase(reltargetpath, page.unicode)
|
content = self.linker.call_withbase(reltargetpath, page.unicode)
|
||||||
targetpath.ensure()
|
targetpath.ensure()
|
||||||
targetpath.write(content.encode("utf8"))
|
targetpath.write(content.encode("utf8"))
|
||||||
|
|
||||||
class SourcePageBuilder(AbstractPageBuilder):
|
class SourcePageBuilder(AbstractPageBuilder):
|
||||||
""" builds the html for a source docs page """
|
""" builds the html for a source docs page """
|
||||||
def __init__(self, base, linker, projroot, capture=None):
|
def __init__(self, base, linker, projroot, capture=None,
|
||||||
|
pageclass=LayoutPage):
|
||||||
self.base = base
|
self.base = base
|
||||||
self.linker = linker
|
self.linker = linker
|
||||||
self.projroot = projroot
|
self.projroot = projroot
|
||||||
self.capture = capture
|
self.capture = capture
|
||||||
|
self.pageclass = pageclass
|
||||||
|
|
||||||
def build_navigation(self, fspath):
|
def build_navigation(self, fspath):
|
||||||
nav = H.Navigation(class_='sidebar')
|
nav = H.Navigation(class_='sidebar')
|
||||||
|
@ -191,7 +224,7 @@ class SourcePageBuilder(AbstractPageBuilder):
|
||||||
source = fspath.read()
|
source = fspath.read()
|
||||||
sep = get_linesep(source)
|
sep = get_linesep(source)
|
||||||
colored = enumerate_and_color(source.split(sep), 0, enc)
|
colored = enumerate_and_color(source.split(sep), 0, enc)
|
||||||
tag = H.SourceDef(*colored)
|
tag = H.SourceDef(colored)
|
||||||
nav = self.build_navigation(fspath)
|
nav = self.build_navigation(fspath)
|
||||||
return tag, nav
|
return tag, nav
|
||||||
|
|
||||||
|
@ -260,38 +293,10 @@ class SourcePageBuilder(AbstractPageBuilder):
|
||||||
'/')
|
'/')
|
||||||
self.write_page(title, reltargetpath, project, tag, nav)
|
self.write_page(title, reltargetpath, project, tag, nav)
|
||||||
|
|
||||||
def enumerate_and_color(codelines, firstlineno, enc):
|
|
||||||
tokenizer = source_color.Tokenizer(source_color.PythonSchema)
|
|
||||||
colored = []
|
|
||||||
for i, line in enumerate(codelines):
|
|
||||||
try:
|
|
||||||
colored.append(H.span('%04s: ' % (i + firstlineno + 1)))
|
|
||||||
colored.append(source_html.prepare_line([line], tokenizer, enc))
|
|
||||||
colored.append('\n')
|
|
||||||
except py.error.ENOENT:
|
|
||||||
# error reading source code, giving up
|
|
||||||
colored = org
|
|
||||||
break
|
|
||||||
return colored
|
|
||||||
|
|
||||||
def get_obj(pkg, dotted_name):
|
|
||||||
full_dotted_name = '%s.%s' % (pkg.__name__, dotted_name)
|
|
||||||
if dotted_name == '':
|
|
||||||
return pkg
|
|
||||||
path = dotted_name.split('.')
|
|
||||||
ret = pkg
|
|
||||||
for item in path:
|
|
||||||
marker = []
|
|
||||||
ret = getattr(ret, item, marker)
|
|
||||||
if ret is marker:
|
|
||||||
raise NameError('can not access %s in %s' % (item,
|
|
||||||
full_dotted_name))
|
|
||||||
return ret
|
|
||||||
|
|
||||||
class ApiPageBuilder(AbstractPageBuilder):
|
class ApiPageBuilder(AbstractPageBuilder):
|
||||||
""" builds the html for an api docs page """
|
""" builds the html for an api docs page """
|
||||||
def __init__(self, base, linker, dsa, projroot, namespace_tree,
|
def __init__(self, base, linker, dsa, projroot, namespace_tree,
|
||||||
capture=None):
|
capture=None, pageclass=LayoutPage):
|
||||||
self.base = base
|
self.base = base
|
||||||
self.linker = linker
|
self.linker = linker
|
||||||
self.dsa = dsa
|
self.dsa = dsa
|
||||||
|
@ -299,6 +304,7 @@ class ApiPageBuilder(AbstractPageBuilder):
|
||||||
self.projpath = py.path.local(projroot)
|
self.projpath = py.path.local(projroot)
|
||||||
self.namespace_tree = namespace_tree
|
self.namespace_tree = namespace_tree
|
||||||
self.capture = capture
|
self.capture = capture
|
||||||
|
self.pageclass = pageclass
|
||||||
|
|
||||||
pkgname = self.dsa.get_module_name().split('/')[-1]
|
pkgname = self.dsa.get_module_name().split('/')[-1]
|
||||||
self.pkg = __import__(pkgname)
|
self.pkg = __import__(pkgname)
|
||||||
|
@ -327,7 +333,7 @@ class ApiPageBuilder(AbstractPageBuilder):
|
||||||
firstlineno = func.func_code.co_firstlineno
|
firstlineno = func.func_code.co_firstlineno
|
||||||
sep = get_linesep(callable_source)
|
sep = get_linesep(callable_source)
|
||||||
org = callable_source.split(sep)
|
org = callable_source.split(sep)
|
||||||
colored = enumerate_and_color(org, firstlineno, enc)
|
colored = [enumerate_and_color(org, firstlineno, enc)]
|
||||||
text = 'source: %s' % (sourcefile,)
|
text = 'source: %s' % (sourcefile,)
|
||||||
if is_in_pkg:
|
if is_in_pkg:
|
||||||
href = self.linker.get_lazyhref(sourcefile)
|
href = self.linker.get_lazyhref(sourcefile)
|
||||||
|
@ -657,11 +663,12 @@ class ApiPageBuilder(AbstractPageBuilder):
|
||||||
else:
|
else:
|
||||||
enc = 'latin-1'
|
enc = 'latin-1'
|
||||||
sourcelink = H.div(linktext)
|
sourcelink = H.div(linktext)
|
||||||
colored = enumerate_and_color(mangled, frame.firstlineno, enc)
|
colored = [enumerate_and_color(mangled,
|
||||||
|
frame.firstlineno, enc)]
|
||||||
else:
|
else:
|
||||||
sourcelink = H.div('source unknown (%s)' % (sourcefile,))
|
sourcelink = H.div('source unknown (%s)' % (sourcefile,))
|
||||||
colored = mangled[:]
|
colored = mangled[:]
|
||||||
tbdiv.append(sourcelink)
|
tbdiv.append(sourcelink)
|
||||||
tbdiv.append(H.div(class_='code', *colored))
|
tbdiv.append(H.div(*colored))
|
||||||
return tbdiv
|
return tbdiv
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,10 @@
|
||||||
|
#apigen-content {
|
||||||
|
font-size: 0.8em;
|
||||||
|
}
|
||||||
|
|
||||||
div.sidebar {
|
div.sidebar {
|
||||||
font-family: Verdana, Helvetica, Arial, sans-serif;
|
font-family: Verdana, Helvetica, Arial, sans-serif;
|
||||||
|
font-size: 0.9em;
|
||||||
width: 155px;
|
width: 155px;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
margin-top: 0.5em;
|
margin-top: 0.5em;
|
||||||
|
|
|
@ -26,6 +26,14 @@ def setup_fs_project(name):
|
||||||
def get_somevar(self):
|
def get_somevar(self):
|
||||||
" get_somevar docstring "
|
" get_somevar docstring "
|
||||||
return self.somevar
|
return self.somevar
|
||||||
|
|
||||||
|
def get_some_source(self):
|
||||||
|
ret = py.code.Source('''\\
|
||||||
|
def foo():
|
||||||
|
return 'bar'
|
||||||
|
''')
|
||||||
|
return ret
|
||||||
|
|
||||||
"""))
|
"""))
|
||||||
temp.ensure('pak/sometestsubclass.py').write(py.code.Source("""\
|
temp.ensure('pak/sometestsubclass.py').write(py.code.Source("""\
|
||||||
from sometestclass import SomeTestClass
|
from sometestclass import SomeTestClass
|
||||||
|
|
|
@ -47,13 +47,54 @@ def test_enumerate_and_color():
|
||||||
colored = htmlgen.enumerate_and_color(['def foo():', ' print "bar"'], 0,
|
colored = htmlgen.enumerate_and_color(['def foo():', ' print "bar"'], 0,
|
||||||
'ascii')
|
'ascii')
|
||||||
div = py.xml.html.div(*colored).unicode(indent=0)
|
div = py.xml.html.div(*colored).unicode(indent=0)
|
||||||
assert div == ('<div>'
|
print repr(div)
|
||||||
'<span> 1: </span>'
|
assert div == (u'<div>'
|
||||||
'<span class="alt_keyword">def</span> foo():\n'
|
'<table style="float: left">'
|
||||||
'<span> 2: </span>'
|
'<tbody>'
|
||||||
' <span class="keyword">print</span>'
|
'<tr><td class="lineno">1</td></tr>'
|
||||||
' <span class="string">"bar"</span>\n'
|
'<tr><td class="lineno">2</td></tr>'
|
||||||
'</div>')
|
'</tbody>'
|
||||||
|
'</table>'
|
||||||
|
'<table>'
|
||||||
|
'<tbody>'
|
||||||
|
'<tr><td class="code">'
|
||||||
|
'<span class="alt_keyword">def</span> foo():'
|
||||||
|
'</td></tr>'
|
||||||
|
'<tr><td class="code">'
|
||||||
|
' <span class="keyword">print</span>'
|
||||||
|
' <span class="string">"bar"</span>'
|
||||||
|
'</td></tr>'
|
||||||
|
'</tbody>'
|
||||||
|
'</table>'
|
||||||
|
'</div>')
|
||||||
|
|
||||||
|
def test_enumerate_and_color_multiline():
|
||||||
|
colored = htmlgen.enumerate_and_color(['code = """\\', 'foo bar', '"""'],
|
||||||
|
0, 'ascii')
|
||||||
|
div = py.xml.html.div(*colored).unicode(indent=0)
|
||||||
|
print repr(div)
|
||||||
|
assert div == (u'<div>'
|
||||||
|
'<table style="float: left">'
|
||||||
|
'<tbody>'
|
||||||
|
'<tr><td class="lineno">1</td></tr>'
|
||||||
|
'<tr><td class="lineno">2</td></tr>'
|
||||||
|
'<tr><td class="lineno">3</td></tr>'
|
||||||
|
'</tbody>'
|
||||||
|
'</table>'
|
||||||
|
'<table>'
|
||||||
|
'<tbody>'
|
||||||
|
'<tr><td class="code">'
|
||||||
|
'code = <span class="string">"""\\</span>'
|
||||||
|
'</td></tr>'
|
||||||
|
'<tr><td class="code">'
|
||||||
|
'<span class="string">foo bar</span>'
|
||||||
|
'</td></tr>'
|
||||||
|
'<tr><td class="code">'
|
||||||
|
'<span class="string">"""</span>'
|
||||||
|
'</td></tr>'
|
||||||
|
'</tbody>'
|
||||||
|
'</table>'
|
||||||
|
'</div>')
|
||||||
|
|
||||||
def test_show_property():
|
def test_show_property():
|
||||||
assert htmlgen.show_property('foo')
|
assert htmlgen.show_property('foo')
|
||||||
|
|
Loading…
Reference in New Issue