diff --git a/py/apigen/apigen.py b/py/apigen/apigen.py index e2688f93c..539c69c52 100644 --- a/py/apigen/apigen.py +++ b/py/apigen/apigen.py @@ -14,11 +14,7 @@ from py.__.apigen import project def get_documentable_items(pkgdir): sys.path.insert(0, str(pkgdir.dirpath())) rootmod = __import__(pkgdir.basename) - #rootmod = import_pkgdir(pkgdir) - if hasattr(rootmod, '__package__'): - return rootmod - # XXX fix non-initpkg situations(?) - return {} + return rootmod def build(pkgdir, dsa): l = linker.Linker() @@ -32,15 +28,14 @@ def build(pkgdir, dsa): all_names = dsa._get_names(filter=lambda x, y: True) namespace_tree = htmlgen.create_namespace_tree(all_names) - apb = htmlgen.ApiPageBuilder(targetdir, l, dsa, pkgdir) + apb = htmlgen.ApiPageBuilder(targetdir, l, dsa, pkgdir, namespace_tree) spb = htmlgen.SourcePageBuilder(targetdir, l, pkgdir) - ns_data = apb.prepare_namespace_pages(namespace_tree) + ns_data = apb.prepare_namespace_pages() class_names = dsa.get_class_names() - class_data = apb.prepare_class_pages(namespace_tree, - class_names) + class_data = apb.prepare_class_pages(class_names) function_names = dsa.get_function_names() - func_data = apb.prepare_function_pages(namespace_tree, function_names) + func_data = apb.prepare_function_pages(function_names) source_data = spb.prepare_pages(pkgdir) apb.build_namespace_pages(ns_data, proj) diff --git a/py/apigen/htmlgen.py b/py/apigen/htmlgen.py index ceabb4e55..5a252199d 100644 --- a/py/apigen/htmlgen.py +++ b/py/apigen/htmlgen.py @@ -180,16 +180,17 @@ class SourcePageBuilder(AbstractPageBuilder): path = relpath.split(os.path.sep) indent = 0 # build links to parents - for i in xrange(len(path)): - dirpath = os.path.sep.join(path[:i]) - abspath = self.projroot.join(dirpath).strpath - if i == 0: - text = 'root' - else: - text = path[i-1] - nav.append(build_navitem_html(self.linker, text, abspath, - indent, False)) - indent += 1 + if relpath != '': + for i in xrange(len(path)): + dirpath = os.path.sep.join(path[:i]) + abspath = self.projroot.join(dirpath).strpath + if i == 0: + text = self.projroot.basename + else: + text = path[i-1] + nav.append(build_navitem_html(self.linker, text, abspath, + indent, False)) + indent += 1 # build siblings or children and self if fspath.check(dir=True): # we're a dir, build ourselves and our children @@ -296,12 +297,13 @@ class SourcePageBuilder(AbstractPageBuilder): class ApiPageBuilder(AbstractPageBuilder): """ builds the html for an api docs page """ - def __init__(self, base, linker, dsa, projroot): + def __init__(self, base, linker, dsa, projroot, namespace_tree): self.base = base self.linker = linker self.dsa = dsa self.projroot = projroot self.projpath = py.path.local(projroot) + self.namespace_tree = namespace_tree def build_callable_view(self, dotted_name): """ build the html for a class method """ @@ -428,18 +430,17 @@ class ApiPageBuilder(AbstractPageBuilder): ) return snippet - def prepare_class_pages(self, namespace_tree, classes_dotted_names): + def prepare_class_pages(self, classes_dotted_names): passed = [] for dotted_name in sorted(classes_dotted_names): parent_dotted_name, _ = split_of_last_part(dotted_name) try: - sibling_dotted_names = namespace_tree[parent_dotted_name] + sibling_dotted_names = self.namespace_tree[parent_dotted_name] except KeyError: # no siblings (built-in module or sth) sibling_dotted_names = [] tag = H.Content(self.build_class_view(dotted_name)) - nav = self.build_navigation(parent_dotted_name, - sibling_dotted_names, dotted_name) + nav = self.build_navigation(dotted_name, False) reltargetpath = "api/%s.html" % (dotted_name,) self.linker.set_link(dotted_name, reltargetpath) passed.append((dotted_name, tag, nav, reltargetpath)) @@ -451,17 +452,16 @@ class ApiPageBuilder(AbstractPageBuilder): title = 'api documentation for %s' % (dotted_name,) self.write_page(title, reltargetpath, project, tag, nav) - def prepare_method_pages(self, namespace_tree, method_dotted_names): + def prepare_method_pages(self, method_dotted_names): # XXX note that even though these pages are still built, there's no nav # pointing to them anymore... passed = [] for dotted_name in sorted(method_dotted_names): parent_dotted_name, _ = split_of_last_part(dotted_name) module_dotted_name, _ = split_of_last_part(parent_dotted_name) - sibling_dotted_names = namespace_tree[module_dotted_name] + sibling_dotted_names = self.namespace_tree[module_dotted_name] tag = self.build_callable_view(dotted_name) - nav = self.build_navigation(parent_dotted_name, - sibling_dotted_names, dotted_name) + nav = self.build_navigation(dotted_name, False) reltargetpath = "api/%s.html" % (dotted_name,) self.linker.set_link(dotted_name, reltargetpath) passed.append((dotted_name, tag, nav, reltargetpath)) @@ -472,15 +472,14 @@ class ApiPageBuilder(AbstractPageBuilder): title = 'api documentation for %s' % (dotted_name,) self.write_page(title, reltargetpath, project, tag, nav) - def prepare_function_pages(self, namespace_tree, method_dotted_names): + def prepare_function_pages(self, method_dotted_names): passed = [] for dotted_name in sorted(method_dotted_names): # XXX should we create a build_function_view instead? parent_dotted_name, _ = split_of_last_part(dotted_name) - sibling_dotted_names = namespace_tree[parent_dotted_name] + sibling_dotted_names = self.namespace_tree[parent_dotted_name] tag = H.Content(self.build_callable_view(dotted_name)) - nav = self.build_navigation(parent_dotted_name, - sibling_dotted_names, dotted_name) + nav = self.build_navigation(dotted_name, False) reltargetpath = "api/%s.html" % (dotted_name,) self.linker.set_link(dotted_name, reltargetpath) passed.append((dotted_name, tag, nav, reltargetpath)) @@ -491,22 +490,21 @@ class ApiPageBuilder(AbstractPageBuilder): title = 'api documentation for %s' % (dotted_name,) self.write_page(title, reltargetpath, project, tag, nav) - def prepare_namespace_pages(self, namespace_tree): + def prepare_namespace_pages(self): passed = [] module_name = self.dsa.get_module_name().split('/')[-1] - names = namespace_tree.keys() + names = self.namespace_tree.keys() names.sort() 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 = self.namespace_tree[dotted_name] tag = H.Content(self.build_namespace_view(dotted_name, subitem_dotted_names)) - nav = self.build_navigation(dotted_name, subitem_dotted_names, - dotted_name) + nav = self.build_navigation(dotted_name, True) if dotted_name == '': reltargetpath = 'api/index.html' else: @@ -522,7 +520,39 @@ class ApiPageBuilder(AbstractPageBuilder): title = 'index of %s namespace' % (dotted_name,) self.write_page(title, reltargetpath, project, tag, nav) - def build_navigation(self, dotted_name, item_dotted_names, selection): + def build_navigation(self, dotted_name, build_children=True): + navitems = [] + + # top namespace, index.html + module_name = self.dsa.get_module_name().split('/')[-1] + navitems.append(build_navitem_html(self.linker, module_name, '', 0, + True)) + def build_nav_level(dotted_name, depth=1): + navitems = [] + path = dotted_name.split('.')[:depth] + siblings = self.namespace_tree.get('.'.join(path[:-1])) + for dn in sorted(siblings): + selected = dn == '.'.join(path) + sibpath = dn.split('.') + navitems.append(build_navitem_html(self.linker, sibpath[-1], + dn, depth, + selected)) + if selected: + lastlevel = dn.count('.') == dotted_name.count('.') + if not lastlevel: + navitems += build_nav_level(dotted_name, depth+1) + elif lastlevel and build_children: + # XXX hack + navitems += build_nav_level('%s.' % (dotted_name,), + depth+2) + + return navitems + + navitems += build_nav_level(dotted_name) + return H.Navigation(*navitems) + + + navitems = [] # top namespace, index.html diff --git a/py/apigen/testing/test_apigen_example.py b/py/apigen/testing/test_apigen_example.py index d22474050..f0b8f5004 100644 --- a/py/apigen/testing/test_apigen_example.py +++ b/py/apigen/testing/test_apigen_example.py @@ -104,15 +104,19 @@ class AbstractBuilderTest(object): self.base = base = py.test.ensuretemp('%s_%s' % ( self.__class__.__name__, meth.im_func.func_name)) self.linker = linker = LinkerForTests() - self.apb = ApiPageBuilder(base, linker, self.dsa, self.fs_root) - self.spb = SourcePageBuilder(base, linker, self.fs_root) - self.namespace_tree = create_namespace_tree(['main.sub', - 'main.sub.func', - 'main.SomeClass', - 'main.SomeSubClass', - 'main.SomeInstance', - 'other.foo', - 'other.bar']) + namespace_tree = create_namespace_tree(['main.sub', + 'main.sub.func', + 'main.SomeClass', + 'main.SomeSubClass', + 'main.SomeInstance', + 'other.foo', + 'other.bar']) + self.namespace_tree = namespace_tree + self.apb = ApiPageBuilder(base, linker, self.dsa, + self.fs_root.join(self.pkg_name), + namespace_tree) + self.spb = SourcePageBuilder(base, linker, + self.fs_root.join(self.pkg_name)) class TestApiPageBuilder(AbstractBuilderTest): def test_build_callable_view(self): @@ -123,7 +127,8 @@ class TestApiPageBuilder(AbstractBuilderTest): pkg.main.sub.func(10) pkg.main.sub.func(pkg.main.SomeClass(10)) t.end_tracing() - apb = ApiPageBuilder(self.base, self.linker, dsa, self.fs_root) + apb = ApiPageBuilder(self.base, self.linker, dsa, self.fs_root, + self.namespace_tree) snippet = apb.build_callable_view('main.sub.func') html = snippet.unicode() print html @@ -149,8 +154,7 @@ class TestApiPageBuilder(AbstractBuilderTest): _checkhtmlsnippet(html) def test_build_function_pages(self): - data = self.apb.prepare_function_pages(self.namespace_tree, - ['main.sub.func']) + data = self.apb.prepare_function_pages(['main.sub.func']) self.apb.build_function_pages(data, self.project) funcfile = self.base.join('api/main.sub.func.html') assert funcfile.check() @@ -163,8 +167,7 @@ class TestApiPageBuilder(AbstractBuilderTest): _checkhtmlsnippet(html) def test_build_class_pages(self): - data = self.apb.prepare_class_pages(self.namespace_tree, - ['main.SomeClass', + data = self.apb.prepare_class_pages(['main.SomeClass', 'main.SomeSubClass']) self.apb.build_class_pages(data, self.project) clsfile = self.base.join('api/main.SomeClass.html') @@ -173,8 +176,7 @@ class TestApiPageBuilder(AbstractBuilderTest): _checkhtml(html) def test_build_class_pages_instance(self): - data = self.apb.prepare_class_pages(self.namespace_tree, - ['main.SomeClass', + data = self.apb.prepare_class_pages(['main.SomeClass', 'main.SomeSubClass', 'main.SomeInstance']) self.apb.build_class_pages(data, self.project) @@ -187,8 +189,7 @@ class TestApiPageBuilder(AbstractBuilderTest): ]) def test_build_class_pages_nav_links(self): - data = self.apb.prepare_class_pages(self.namespace_tree, - ['main.SomeSubClass', + data = self.apb.prepare_class_pages(['main.SomeSubClass', 'main.SomeClass']) # fake some stuff that would be built from other methods self.linker.set_link('', 'api/index.html') @@ -212,8 +213,7 @@ class TestApiPageBuilder(AbstractBuilderTest): _checkhtml(html) def test_build_class_pages_base_link(self): - data = self.apb.prepare_class_pages(self.namespace_tree, - ['main.SomeSubClass', + data = self.apb.prepare_class_pages(['main.SomeSubClass', 'main.SomeClass']) self.apb.build_class_pages(data, self.project) clsfile = self.base.join('api/main.SomeSubClass.html') @@ -227,8 +227,7 @@ class TestApiPageBuilder(AbstractBuilderTest): _checkhtml(html) def test_source_links(self): - data = self.apb.prepare_class_pages(self.namespace_tree, - ['main.SomeSubClass', + data = self.apb.prepare_class_pages(['main.SomeSubClass', 'main.SomeClass']) sourcedata = self.spb.prepare_pages(self.fs_root) self.apb.build_class_pages(data, self.project) @@ -238,7 +237,7 @@ class TestApiPageBuilder(AbstractBuilderTest): _checkhtml(funchtml) def test_build_namespace_pages(self): - data = self.apb.prepare_namespace_pages(self.namespace_tree) + data = self.apb.prepare_namespace_pages() self.apb.build_namespace_pages(data, self.project) mainfile = self.base.join('api/main.html') assert mainfile.check() @@ -258,7 +257,7 @@ class TestApiPageBuilder(AbstractBuilderTest): _checkhtml(otherhtml) def test_build_namespace_pages_index(self): - data = self.apb.prepare_namespace_pages(self.namespace_tree) + data = self.apb.prepare_namespace_pages() self.apb.build_namespace_pages(data, self.project) pkgfile = self.base.join('api/index.html') assert pkgfile.check() @@ -267,7 +266,7 @@ class TestApiPageBuilder(AbstractBuilderTest): _checkhtml(html) def test_build_namespace_pages_subnamespace(self): - data = self.apb.prepare_namespace_pages(self.namespace_tree) + data = self.apb.prepare_namespace_pages() self.apb.build_namespace_pages(data, self.project) subfile = self.base.join('api/main.sub.html') assert subfile.check() @@ -275,8 +274,7 @@ class TestApiPageBuilder(AbstractBuilderTest): _checkhtml(html) def test_build_function_api_pages_nav(self): - data = self.apb.prepare_function_pages(self.namespace_tree, - ['main.sub.func']) + data = self.apb.prepare_function_pages(['main.sub.func']) self.linker.set_link('', 'api/index.html') self.linker.set_link('main', 'api/main.html') self.linker.set_link('main.sub', 'api/main.sub.html') @@ -293,22 +291,30 @@ class TestApiPageBuilder(AbstractBuilderTest): _checkhtml(html) def test_build_function_navigation(self): - self.apb.prepare_namespace_pages(self.namespace_tree) - self.apb.prepare_function_pages(self.namespace_tree, ['main.sub.func']) - nav = self.apb.build_navigation('main.sub', ['main.sub.func'], - 'main.sub.func') + self.apb.prepare_namespace_pages() + self.apb.prepare_function_pages(['main.sub.func']) + self.apb.prepare_class_pages(['main.SomeClass', + 'main.SomeSubClass', + 'main.SomeInstance']) + nav = self.apb.build_navigation('main.sub.func', False) html = nav.unicode(indent=0) print html.encode('UTF-8') - assert (u'
pkg
' - u'
\xa0\xa0main
' - u'
\xa0\xa0\xa0\xa0' + assert (u'
pkg
' + u'
\xa0\xa0main
' + u'
\xa0\xa0\xa0\xa0' + u'SomeClass
' + u'
\xa0\xa0\xa0\xa0' + u'SomeInstance
' + u'
\xa0\xa0\xa0\xa0' + u'SomeSubClass
' + u'
\xa0\xa0\xa0\xa0' u'sub
' u'
\xa0\xa0\xa0\xa0\xa0\xa0' u'func
' ) in html def test_build_root_namespace_view(self): - data = self.apb.prepare_namespace_pages(self.namespace_tree) + data = self.apb.prepare_namespace_pages() self.apb.build_namespace_pages(data, self.project) rootfile = self.base.join('api/index.html') assert rootfile.check() @@ -332,7 +338,6 @@ class TestSourcePageBuilder(AbstractBuilderTest): print html run_string_sequence_test(html, [ 'href="../../style.css"', - 'root', 'pkg', 'someclass.py', 'somesubclass.py', @@ -347,7 +352,6 @@ class TestSourcePageBuilder(AbstractBuilderTest): print html run_string_sequence_test(html, [ 'href="../../style.css"', - 'root', 'pkg', 'func.py', 'someclass.py', @@ -362,7 +366,6 @@ class TestSourcePageBuilder(AbstractBuilderTest): html = nav.unicode(indent=0) print html.encode('UTF-8') run_string_sequence_test(html, [ - 'href="source/index.html">root', 'href="source/pkg/index.html">pkg', 'href="source/pkg/func.py.html">func.py', 'href="source/pkg/someclass.py.html">someclass.py', diff --git a/py/apigen/testing/test_apigen_functional.py b/py/apigen/testing/test_apigen_functional.py index 7658b203f..e425dfe1b 100644 --- a/py/apigen/testing/test_apigen_functional.py +++ b/py/apigen/testing/test_apigen_functional.py @@ -4,6 +4,7 @@ """ import py +from py.__.apigen import apigen def setup_fs_project(): temp = py.test.ensuretemp('apigen_functional') @@ -70,6 +71,13 @@ def setup_fs_project(): """)) return temp, 'pkg' +def test_get_documentable_items(): + fs_root, package_name = setup_fs_project() + documentable = apigen.get_documentable_items(fs_root.join(package_name)) + assert documentable.__package__.exportdefs.keys() == [ + 'main.sub.func', 'main.func', 'main.SomeTestSubClass', + 'main.SomeTestClass'] + def test_apigen_functional(): fs_root, package_name = setup_fs_project() tempdir = py.test.ensuretemp('test_apigen_functional_results')