[svn r37545] Moved get_star_import_tree out of the DocStorage class, created 'pkg_to_dict'
function in docstorage.py and using that from apigen.py (to later simplify py.test integration, and to improve testability). Simplified 'deindent()' a bit, made the wrap_page use the filenames from the stylesheeturl and the scripturls instead of having them hard-coded, some minor HTML/CSS changes. --HG-- branch : trunk
This commit is contained in:
parent
06cbe63616
commit
fe3a71994a
|
@ -10,11 +10,12 @@ import sys
|
|||
from py.__.apigen import htmlgen
|
||||
from py.__.apigen import linker
|
||||
from py.__.apigen import project
|
||||
from py.__.apigen.tracer.docstorage import pkg_to_dict
|
||||
|
||||
def get_documentable_items(pkgdir):
|
||||
sys.path.insert(0, str(pkgdir.dirpath()))
|
||||
rootmod = __import__(pkgdir.basename)
|
||||
return rootmod
|
||||
return pkg_to_dict(rootmod)
|
||||
|
||||
def build(pkgdir, dsa):
|
||||
l = linker.Linker()
|
||||
|
|
|
@ -19,26 +19,23 @@ def deindent(str, linesep=os.linesep):
|
|||
line to the side always, and determines the indentation of the rest
|
||||
of the text by taking that of the least indented (filled) line
|
||||
"""
|
||||
lines = str.split(linesep)
|
||||
lines = str.strip().split(linesep)
|
||||
normalized = []
|
||||
deindent = None
|
||||
normalized.append(lines[0].strip())
|
||||
# replace tabs with spaces, empty lines that contain spaces only, and
|
||||
# find out what the smallest indentation is
|
||||
for line in lines[1:]:
|
||||
if not line.strip():
|
||||
line = line.replace('\t', ' ')
|
||||
stripped = line.strip()
|
||||
if not stripped:
|
||||
normalized.append('')
|
||||
else:
|
||||
line = line.rstrip()
|
||||
line = line.replace('\t', ' ')
|
||||
indent = 0
|
||||
for c in line:
|
||||
if c != ' ':
|
||||
break
|
||||
indent += 1
|
||||
rstripped = line.rstrip()
|
||||
indent = len(rstripped) - len(stripped)
|
||||
if deindent is None or indent < deindent:
|
||||
deindent = indent
|
||||
normalized.append(line)
|
||||
while normalized[-1] == '':
|
||||
normalized.pop()
|
||||
ret = [normalized[0]]
|
||||
for line in normalized[1:]:
|
||||
if not line:
|
||||
|
@ -182,10 +179,12 @@ def wrap_page(project, title, contentel, navel, outputpath, stylesheeturl,
|
|||
stylesheeturl=stylesheeturl, scripturls=scripturls)
|
||||
page.set_content(contentel)
|
||||
here = py.magic.autopath().dirpath()
|
||||
style = here.join('style.css').read()
|
||||
outputpath.join('style.css').write(style)
|
||||
apijs = here.join('api.js').read()
|
||||
outputpath.join('api.js').write(apijs)
|
||||
style = here.join(stylesheeturl.split('/')[-1]).read()
|
||||
outputpath.join(stylesheeturl.split('/')[-1]).write(style)
|
||||
for spath in scripturls:
|
||||
sname = spath.split('/')[-1]
|
||||
sdata = here.join(sname).read()
|
||||
outputpath.join(sname).write(sdata)
|
||||
return page
|
||||
|
||||
# the PageBuilder classes take care of producing the docs (using the stuff
|
||||
|
@ -281,6 +280,7 @@ class SourcePageBuilder(AbstractPageBuilder):
|
|||
try:
|
||||
tag = H.NonPythonSource(unicode(fspath.read(), 'utf-8'))
|
||||
except UnicodeError:
|
||||
# XXX we should fix non-ascii support here!!
|
||||
tag = H.NonPythonSource('no source available (binary file?)')
|
||||
nav = self.build_navigation(fspath)
|
||||
return tag, nav
|
||||
|
@ -380,7 +380,7 @@ class ApiPageBuilder(AbstractPageBuilder):
|
|||
csdiv,
|
||||
)
|
||||
snippet = H.FunctionDescription(
|
||||
H.FunctionDef(localname, argdesc),
|
||||
H.FunctionDef('def %s' % (localname,), argdesc),
|
||||
H.Docstring(docstring or '*no docstring available*'),
|
||||
H.div(H.a('show/hide info',
|
||||
href='#',
|
||||
|
@ -684,7 +684,7 @@ class ApiPageBuilder(AbstractPageBuilder):
|
|||
call_site[0].filename, call_site[0].lineno + 1),
|
||||
href='#',
|
||||
onclick="showhideel(getnextsibling(this)); return false;"),
|
||||
H.div(tbtag, style='display: none')
|
||||
H.div(tbtag, style='display: none', class_='callstackitem'),
|
||||
)
|
||||
return tag
|
||||
|
||||
|
|
|
@ -42,12 +42,15 @@
|
|||
font-weight: bold;
|
||||
}
|
||||
|
||||
body, div, p, h1, h2, h3, h4 {
|
||||
font-family: Trebuchet MS, Verdana, Arial;
|
||||
body {
|
||||
background-color: #FFE;
|
||||
color: black;
|
||||
}
|
||||
|
||||
body, div, p, h1, h2, h3, h4 {
|
||||
font-family: Trebuchet MS, Verdana, Arial;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #006;
|
||||
text-decoration: none;
|
||||
|
@ -107,5 +110,11 @@ a:hover {
|
|||
border: 1px solid black;
|
||||
color: black;
|
||||
padding: 1em;
|
||||
background-color: white;
|
||||
}
|
||||
|
||||
.callstackitem {
|
||||
border: 1px solid black;
|
||||
margin-bottom: 1em;
|
||||
}
|
||||
|
||||
|
|
|
@ -47,6 +47,7 @@ def setup_fs_project(name):
|
|||
'main.SomeTestClass': ('./sometestclass.py', 'SomeTestClass'),
|
||||
'main.SomeTestSubClass': ('./sometestsubclass.py',
|
||||
'SomeTestSubClass'),
|
||||
'somenamespace': ('./somenamespace.py', '*'),
|
||||
})
|
||||
"""))
|
||||
temp.ensure('pak/test/test_pak.py').write(py.code.Source("""\
|
||||
|
@ -82,9 +83,9 @@ def setup_fs_project(name):
|
|||
def test_get_documentable_items():
|
||||
fs_root, package_name = setup_fs_project('test_get_documentable_items')
|
||||
documentable = apigen.get_documentable_items(fs_root.join(package_name))
|
||||
assert sorted(documentable.__package__.exportdefs.keys()) == [
|
||||
assert sorted(documentable.keys()) == [
|
||||
'main.SomeTestClass', 'main.SomeTestSubClass', 'main.func',
|
||||
'main.sub.func']
|
||||
'main.sub.func', 'somenamespace.baz', 'somenamespace.foo']
|
||||
|
||||
def test_apigen_functional():
|
||||
fs_root, package_name = setup_fs_project('test_apigen_functional')
|
||||
|
|
|
@ -15,6 +15,44 @@ from py.__.apigen.tracer import model
|
|||
|
||||
sorted = py.builtin.sorted
|
||||
|
||||
def pkg_to_dict(module):
|
||||
defs = module.__package__.exportdefs
|
||||
d = {}
|
||||
for key, value in defs.iteritems():
|
||||
chain = key.split('.')
|
||||
base = module
|
||||
for elem in chain:
|
||||
base = getattr(base, elem)
|
||||
if value[1] == '*':
|
||||
d.update(get_star_import_tree(base, key))
|
||||
else:
|
||||
d[key] = base
|
||||
return d
|
||||
|
||||
def get_star_import_tree(module, modname):
|
||||
""" deal with '*' entries in an initpkg situation """
|
||||
ret = {}
|
||||
modpath = py.path.local(inspect.getsourcefile(module))
|
||||
pkgpath = module.__package__.getpath()
|
||||
for objname in dir(module):
|
||||
if objname.startswith('_'):
|
||||
continue # also skip __*__ attributes
|
||||
obj = getattr(module, objname)
|
||||
if (isinstance(obj, types.ClassType) or
|
||||
isinstance(obj, types.ObjectType)):
|
||||
try:
|
||||
sourcefile_object = py.path.local(
|
||||
inspect.getsourcefile(obj))
|
||||
except TypeError:
|
||||
continue
|
||||
else:
|
||||
if sourcefile_object.strpath != modpath.strpath:
|
||||
# not in this package
|
||||
continue
|
||||
dotted_name = '%s.%s' % (modname, objname)
|
||||
ret[dotted_name] = obj
|
||||
return ret
|
||||
|
||||
class DocStorage(object):
|
||||
""" Class storing info about API
|
||||
"""
|
||||
|
@ -117,45 +155,10 @@ class DocStorage(object):
|
|||
|
||||
def from_pkg(self, module, keep_frames=False):
|
||||
self.module = module
|
||||
defs = module.__package__.exportdefs
|
||||
d = {}
|
||||
for key, value in defs.iteritems():
|
||||
chain = key.split('.')
|
||||
base = module
|
||||
for elem in chain:
|
||||
base = getattr(base, elem)
|
||||
if value[1] == '*':
|
||||
d.update(self.get_star_import_tree(base, key))
|
||||
else:
|
||||
d[key] = base
|
||||
self.from_dict(d, keep_frames)
|
||||
self.from_dict(pkg_to_dict(module), keep_frames)
|
||||
# XXX
|
||||
return self
|
||||
|
||||
def get_star_import_tree(self, module, modname):
|
||||
""" deal with '*' entries in an initpkg situation """
|
||||
ret = {}
|
||||
modpath = py.path.local(inspect.getsourcefile(module))
|
||||
pkgpath = module.__package__.getpath()
|
||||
for objname in dir(module):
|
||||
if objname.startswith('_'):
|
||||
continue # also skip __*__ attributes
|
||||
obj = getattr(module, objname)
|
||||
if (isinstance(obj, types.ClassType) or
|
||||
isinstance(obj, types.ObjectType)):
|
||||
try:
|
||||
sourcefile_object = py.path.local(
|
||||
inspect.getsourcefile(obj))
|
||||
except TypeError:
|
||||
continue
|
||||
else:
|
||||
if sourcefile_object.strpath != modpath.strpath:
|
||||
# not in this package
|
||||
continue
|
||||
dotted_name = '%s.%s' % (modname, objname)
|
||||
ret[dotted_name] = obj
|
||||
return ret
|
||||
|
||||
def from_module(self, func):
|
||||
raise NotImplementedError("From module")
|
||||
|
||||
|
|
|
@ -6,8 +6,9 @@ import py
|
|||
import sys
|
||||
|
||||
#try:
|
||||
from py.__.apigen.tracer.tracer import DocStorage, Tracer
|
||||
from py.__.apigen.tracer.docstorage import DocStorageAccessor
|
||||
from py.__.apigen.tracer.tracer import Tracer
|
||||
from py.__.apigen.tracer.docstorage import DocStorageAccessor, DocStorage, \
|
||||
get_star_import_tree, pkg_to_dict
|
||||
from py.__.apigen.tracer.testing.runtest import cut_pyc
|
||||
from py.__.apigen.tracer.description import FunctionDesc
|
||||
from py.__.apigen.tracer import model
|
||||
|
@ -426,7 +427,7 @@ def setup_pkg_docstorage():
|
|||
|
||||
def test_get_initpkg_star_items():
|
||||
pkg, ds = setup_pkg_docstorage()
|
||||
sit = ds.get_star_import_tree(pkg.other, 'pkg.other')
|
||||
sit = get_star_import_tree(pkg.other, 'pkg.other')
|
||||
assert sorted(sit.keys()) == ['pkg.other.baz', 'pkg.other.foo']
|
||||
t = Tracer(ds)
|
||||
t.start_tracing()
|
||||
|
@ -446,3 +447,11 @@ def test_get_initpkg_star_items():
|
|||
assert isinstance(cell, model.SomeInstance)
|
||||
assert cell.classdef.cls is desc.pyobj
|
||||
|
||||
def test_pkg_to_dict():
|
||||
pkg, ds = setup_pkg_docstorage()
|
||||
assert sorted(pkg_to_dict(pkg).keys()) == ['main.SomeClass',
|
||||
'main.SomeSubClass',
|
||||
'main.sub.func',
|
||||
'other.baz',
|
||||
'other.foo']
|
||||
|
||||
|
|
Loading…
Reference in New Issue