import py |
import os |
import inspect |
from py.__.apigen.layout import LayoutPage |
from py.__.apigen.source import browser as source_browser |
from py.__.apigen.source import html as source_html |
from py.__.apigen.source import color as source_color |
from py.__.apigen.tracer.description import is_private |
from py.__.apigen.rest.genrest import split_of_last_part |
from py.__.apigen.linker import relpath |
from py.__.apigen.html import H |
|
|
reversed = py.builtin.reversed |
|
|
sorted = py.builtin.sorted |
html = py.xml.html |
raw = py.xml.raw |
|
|
REDUCE_CALLSITES = True |
|
|
def is_navigateable(name): |
return (not is_private(name) and name != '__doc__') |
|
|
def show_property(name): |
if not name.startswith('_'): |
return True |
if name.startswith('__') and name.endswith('__'): |
|
if (name not in dir(object) and |
name not in ['__doc__', '__dict__', '__name__', '__module__', |
'__weakref__', '__apigen_hide_from_nav__']): |
return True |
return False |
|
|
def deindent(str, linesep='\n'): |
""" de-indent string |
|
can be used to de-indent Python docstrings, it de-indents the first |
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.strip().split(linesep) |
normalized = [] |
deindent = None |
normalized.append(lines[0].strip()) |
|
|
for line in lines[1:]: |
line = line.replace('\t', ' ' * 4) |
stripped = line.strip() |
if not stripped: |
normalized.append('') |
else: |
rstripped = line.rstrip() |
indent = len(rstripped) - len(stripped) |
if deindent is None or indent < deindent: |
deindent = indent |
normalized.append(line) |
ret = [normalized[0]] |
for line in normalized[1:]: |
if not line: |
ret.append(line) |
else: |
ret.append(line[deindent:]) |
return '%s\n' % (linesep.join(ret),) |
|
|
def get_linesep(s, default='\n'): |
""" return the line seperator of a string |
|
returns 'default' if no seperator can be found |
""" |
for sep in ('\r\n', '\r', '\n'): |
if sep in s: |
return sep |
return default |
|
|
def get_param_htmldesc(linker, func): |
""" get the html for the parameters of a function """ |
import inspect |
|
return inspect.formatargspec(*inspect.getargspec(func)) |
|
|
|
|
def source_dirs_files(fspath): |
""" returns a tuple (dirs, files) for fspath |
|
dirs are all the subdirs, files are the files which are interesting |
in building source documentation for a Python code tree (basically all |
normal files excluding .pyc and .pyo ones) |
|
all files and dirs that have a name starting with . are considered |
hidden |
""" |
dirs = [] |
files = [] |
for child in fspath.listdir(): |
if child.basename.startswith('.'): |
continue |
if child.check(dir=True): |
dirs.append(child) |
elif child.check(file=True): |
if child.ext in ['.pyc', '.pyo']: |
continue |
files.append(child) |
return sorted(dirs), sorted(files) |
|
|
def create_namespace_tree(dotted_names): |
""" creates a tree (in dict form) from a set of dotted names |
""" |
ret = {} |
for dn in dotted_names: |
path = dn.split('.') |
for i in xrange(len(path)): |
ns = '.'.join(path[:i]) |
itempath = '.'.join(path[:i + 1]) |
if ns not in ret: |
ret[ns] = [] |
if itempath not in ret[ns]: |
ret[ns].append(itempath) |
return ret |
|
|
def wrap_page(project, title, targetpath, contentel, navel, basepath, |
pageclass): |
page = pageclass(project, title, targetpath, nav=navel, encoding='UTF-8') |
page.set_content(contentel) |
page.setup_scripts_styles(basepath) |
return page |
|
|
def enumerate_and_color(codelines, firstlineno, enc): |
snippet = H.SourceBlock() |
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: |
|
snippet = org |
break |
return snippet |
|
|
_get_obj_cache = {} |
def get_obj(dsa, pkg, dotted_name): |
full_dotted_name = '%s.%s' % (pkg.__name__, dotted_name) |
if dotted_name == '': |
return pkg |
try: |
return _get_obj_cache[dotted_name] |
except KeyError: |
pass |
path = dotted_name.split('.') |
ret = pkg |
for item in path: |
marker = [] |
ret = getattr(ret, item, marker) |
if ret is marker: |
try: |
ret = dsa.get_obj(dotted_name) |
except KeyError: |
raise NameError('can not access %s in %s' % (item, |
full_dotted_name)) |
else: |
break |
_get_obj_cache[dotted_name] = ret |
return ret |
|
|
def get_rel_sourcepath(projpath, filename, default=None): |
relpath = py.path.local(filename).relto(projpath) |
if not relpath: |
return default |
return relpath |
|
|
def get_package_revision(packageroot, _revcache={}): |
try: |
rev = _revcache[packageroot] |
except KeyError: |
wc = py.path.svnwc(packageroot) |
rev = None |
if wc.check(versioned=True): |
rev = py.path.svnwc(packageroot).info().rev |
_revcache[packageroot] = rev |
if packageroot.basename == "py": |
assert rev is not None |
return rev |
|
|
|
|
|
|
class AbstractPageBuilder(object): |
pageclass = LayoutPage |
|
def write_page(self, title, reltargetpath, tag, nav): |
targetpath = self.base.join(reltargetpath) |
relbase= relpath('%s%s' % (targetpath.dirpath(), targetpath.sep), |
self.base.strpath + '/') |
page = wrap_page(self.project, title, targetpath, tag, nav, self.base, |
self.pageclass) |
|
|
content = page.unicode() |
targetpath.ensure() |
targetpath.write(content.encode("utf8")) |
|
|
class SourcePageBuilder(AbstractPageBuilder): |
""" builds the html for a source docs page """ |
def __init__(self, base, linker, projroot, project, capture=None, |
pageclass=LayoutPage): |
self.base = base |
self.linker = linker |
self.projroot = projroot |
self.project = project |
self.capture = capture |
self.pageclass = pageclass |
|
def build_navigation(self, fspath): |
nav = H.Navigation(class_='sidebar') |
relpath = fspath.relto(self.projroot) |
path = relpath.split(os.path.sep) |
indent = 0 |
|
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(H.NavigationItem(self.linker, abspath, text, |
indent, False)) |
indent += 1 |
|
if fspath.check(dir=True): |
|
dirpath = fspath |
nav.append(H.NavigationItem(self.linker, dirpath.strpath, |
dirpath.basename, indent, True)) |
indent += 1 |
elif fspath.strpath == self.projroot.strpath: |
dirpath = fspath |
else: |
|
dirpath = fspath.dirpath() |
diritems, fileitems = source_dirs_files(dirpath) |
for dir in diritems: |
nav.append(H.NavigationItem(self.linker, dir.strpath, dir.basename, |
indent, False)) |
for file in fileitems: |
selected = (fspath.check(file=True) and |
file.basename == fspath.basename) |
nav.append(H.NavigationItem(self.linker, file.strpath, |
file.basename, indent, selected)) |
return nav |
|
|
re = py.std.re |
_reg_body = re.compile(r'<body[^>]*>(.*)</body>', re.S) |
def build_python_page(self, fspath): |
|
|
enc = source_html.get_module_encoding(fspath.strpath) |
source = fspath.read() |
sep = get_linesep(source) |
colored = [enumerate_and_color(source.split(sep), 0, enc)] |
tag = H.PythonSource(colored) |
nav = self.build_navigation(fspath) |
return tag, nav |
|
|
def build_dir_page(self, fspath): |
dirs, files = source_dirs_files(fspath) |
dirs = [(p.basename, self.linker.get_lazyhref(str(p))) for p in dirs] |
files = [(p.basename, self.linker.get_lazyhref(str(p))) for p in files] |
tag = H.DirList(dirs, files) |
nav = self.build_navigation(fspath) |
return tag, nav |
|
|
def build_nonpython_page(self, fspath): |
try: |
tag = H.NonPythonSource(unicode(fspath.read(), 'utf-8')) |
except UnicodeError: |
tag = H.NonPythonSource('no source available (binary file?)') |
nav = self.build_navigation(fspath) |
return tag, nav |
|
|
def build_pages(self, base): |
for fspath in [base] + list(base.visit()): |
if fspath.ext in ['.pyc', '.pyo']: |
continue |
if self.capture: |
self.capture.err.writeorg('.') |
relfspath = fspath.relto(base) |
if relfspath.find('%s.' % (os.path.sep,)) > -1: |
|
continue |
elif fspath.check(dir=True): |
if relfspath != '': |
relfspath += os.path.sep |
reloutputpath = 'source%s%sindex.html' % (os.path.sep, |
relfspath) |
else: |
reloutputpath = "source%s%s.html" % (os.path.sep, relfspath) |
reloutputpath = reloutputpath.replace(os.path.sep, '/') |
outputpath = self.base.join(reloutputpath) |
self.linker.set_link(str(fspath), reloutputpath) |
self.build_page(fspath, outputpath, base) |
|
|
def build_page(self, fspath, outputpath, base): |
""" build syntax-colored source views """ |
if fspath.check(ext='.py'): |
try: |
tag, nav = self.build_python_page(fspath) |
except (KeyboardInterrupt, SystemError): |
raise |
except: |
raise |
exc, e, tb = py.std.sys.exc_info() |
print '%s - %s' % (exc, e) |
print |
print ''.join(py.std.traceback.format_tb(tb)) |
print '-' * 79 |
del tb |
tag, nav = self.build_nonpython_page(fspath) |
elif fspath.check(dir=True): |
|
|