"""The old HTML generator. Deprecated, do not use."""
from pydoctor import model
from os.path import join as opj
import os, inspect, shutil
try:
from epydoc.markup import epytext
EPYTEXT = True
except:
print "no epytext found"
EPYTEXT = False
def link(o):
return o.fullName()+'.html'
def linkto(o, label=None):
if label is None:
label = o.fullName()
return '%s'%(link(o), label)
def summaryDoc(obj):
"""Generate a one-line summary of a docstring."""
if isinstance(obj, model.Package):
obj = obj.contents['__init__']
doc = obj.docstring
if not doc or not doc.strip():
return 'Undocumented'
# Return the first line of the docstring (that actually has stuff)
for doc in doc.splitlines():
if doc.strip():
return doc2html(obj, doc)
def boringDocstring(doc):
"""Generate an HTML representation of a docstring in a really boring
way."""
# inspect.getdoc requires an object with a __doc__ attribute, not
# just a string :-(
if doc is None or not doc.strip():
return '
' % inspect.getdoc(crappit)
errcount = 0
doc2html_cache = {}
def memoize(f):
_cache = {}
def g(*args):
if args in _cache:
return _cache[args]
else:
r = _cache[args] = f(*args)
return r
return g
@memoize
def doc2html(obj, doc):
"""Generate an HTML representation of a docstring"""
if doc is None or not doc.strip():
return '
Undocumented
'
if not EPYTEXT:
return boringDocstring(doc)
errs = []
pdoc = epytext.parse_docstring(doc, errs)
if errs:
errs = []
def crappit(): pass
crappit.__doc__ = doc
doc = inspect.getdoc(crappit)
pdoc = epytext.parse_docstring(doc, errs)
if errs:
if obj.system.options.verbosity > 0:
print obj
if obj.system.options.verbosity > 1:
for i, l in enumerate(doc.splitlines()):
print "%4s"%(i+1), l
for err in errs:
print err
global errcount
errcount += len(errs)
return boringDocstring(doc)
pdoc, fields = pdoc.split_fields()
crap = pdoc.to_html(_EpydocLinker(obj))
s = '
%s
' % (crap,)
for field in fields:
s += (('
%s '
'%s'
'%s
')
% (field.tag(), field.arg(),
field.body().to_html(_EpydocLinker(obj))))
return s
class _EpydocLinker(object):
def __init__(self, obj):
self.obj = obj
def translate_indexterm(self, something):
# X{foobar} is meant to put foobar in an index page (like, a
# proper end-of-the-book index). Should we support that? There
# are like 2 uses in Twisted.
return something.to_html(self)
def translate_identifier_xref(self, fullID, prettyID):
obj = self.obj.resolveDottedName(fullID)
if obj is None:
return prettyID
else:
return '%s'%(link(obj), prettyID)
def getBetterThanArgspec(argspec):
"""Ok, maybe argspec's format isn't the best after all: This takes an
argspec and returns (regularArguments, [(kwarg, kwval), (kwarg, kwval)])."""
args = argspec[0]
defaults = argspec[-1]
if not defaults:
return (args, [])
backargs = args[:]
backargs.reverse()
defaults = list(defaults)
defaults.reverse()
kws = zip(backargs, defaults)
kws.reverse()
allargs = args[:-len(kws)] + kws
return (args[:-len(kws)], kws)
def _strtup(tup):
# Ugh
if not isinstance(tup, (tuple, list)):
return str(tup)
return '(' + ', '.join(map(_strtup, tup)) + ')'
def signature(argspec):
"""Return a nicely-formatted source-like signature, formatted from an
argspec.
"""
regargs, kwargs = getBetterThanArgspec(argspec)
varargname, varkwname = argspec[1:3]
things = []
for regarg in regargs:
if isinstance(regarg, list):
things.append(_strtup(regarg))
else:
things.append(regarg)
if varargname:
things.append('*%s' % varargname)
things += ['%s=%s' % (t[0], t[1]) for t in kwargs]
if varkwname:
things.append('**%s' % varkwname)
return ', '.join(things)
def mediumName(obj):
fn = obj.fullName()
if '.' not in fn:
return fn
path, name = fn.rsplit('.', 1)
return '.'.join([p[0] for p in path.split('.')]) + '.' + name
class SystemWriter(object):
"""Construct me with a directory to write files to and call
writeIndividualFiles and/or writeModuleIndex."""
sourcebase = None
def __init__(self, base):
self.base = base
def prepOutputDirectory(self):
if not os.path.exists(self.base):
os.mkdir(self.base)
shutil.copyfile(sibpath(__file__, 'templates/apidocs.css'),
os.path.join(self.base, 'apidocs.css'))
def writeIndividualFiles(self, stuff, functionpages=False):
"""Writes HTML files for every documentable passed, recursively. This
looks up methods like 'genPage_DOCUMENTABLETYPE' on self to
get the HTML for particular kinds of documentables.
"""
for sub in stuff:
if isinstance(sub, model.Function) and not functionpages:
continue
html = self.getHTMLFor(sub)
f = open(opj(self.base, link(sub)), 'w')
f.write(html)
f.close()
self.writeIndividualFiles(sub.orderedcontents, functionpages)
def getHTMLFor(self, o):
for cls in o.__class__.__mro__:
fun = getattr(self, 'html_%s' % (cls.__name__,), None)
if fun is not None:
break
else:
raise TypeError("Don't know how to document a "+o.__class__.__name__)
d = fun(o)
d = '''
API docs for “%s”
%s
''' % (o.fullName(), d)
return d
def generateModuleIndex(self, pkg):
x = "
Package %s
" % pkg.fullName()
x += '
%s
' % self._allModules(pkg)
x += ''
return x
def writeModuleIndex(self, system):
"""Writes a module index to the file 'moduleindex.html' in the doc
directory."""
f = open(opj(self.base, 'moduleindex.html'), 'w')
f.write(self.generateModuleIndex(system.rootobjects[0]))
f.close()
## HTML Generators for Documentable types
def html_Package(self, pkg):
x = '
Package %s
' % (mediumName(pkg),)
x += self._parentLink(pkg)
z = doc2html(pkg, pkg.contents['__init__'].docstring)
x += '
%s
' % (z,)
x += self._genChildren([x for x in pkg.orderedcontents
if x.name != '__init__'])
return x
def html_Module(self, mod):
x = '
Module %s
' % (mediumName(mod),)
x += self._parentLink(mod)
z = doc2html(mod, mod.docstring)
x += '
%s
' % (z,)
def link_(obj):
if isinstance(obj, model.Function):
return '#' + obj.fullName()
else:
return link(obj)
x += self._genChildren(mod.orderedcontents, link=link_)
for func in mod.orderedcontents:
if not isinstance(func, model.Function):
continue
x += '''
''' % (
func.fullName(),
self._funsig(func), doc2html(func, func.docstring))
return x
def bases_html(self, cls):
r = []
for n, o in zip(cls.rawbases, cls.baseobjects):
if o is None:
r.append(n)
else:
r.append('%s'%(link(o), n))
if r:
return '(' + ', '.join(r) + ')'
else:
return ''
def html_Class(self, cls):
x = '
%s %s%s:
' % (cls.kind.lower(), cls.kind, mediumName(cls), self.bases_html(cls))
x += self._parentLink(cls)
if cls.subclasses:
x += '
known subclasses: %s
'%(', '.join(
map(linkto, cls.subclasses)))
z = doc2html(cls, cls.docstring)
x += '
%s
' % (z,)
link = lambda x: '#' + x.fullName()
x += self._genChildren(cls.orderedcontents, link=link)
for meth in cls.orderedcontents:
if not isinstance(meth, model.Function):
continue
x += '''
''' % (
meth.fullName(),
self._funsig(meth), doc2html(meth, meth.docstring))
return x
def html_TwistedClass(self, cls):
x = '
%s %s%s:
' % (cls.kind.lower(), cls.kind, mediumName(cls), self.bases_html(cls))
x += self._parentLink(cls)
if cls.subclasses:
x += '
known subclasses: %s
'%(', '.join(
map(linkto, cls.subclasses)))
if cls.isinterface and cls.allImplementations:
links = []
for implementation in cls.allImplementations:
if implementation in cls.implementedby_directly:
template = '%s'
else:
template = '%s'
if implementation in cls.system.allobjects:
l = linkto(cls.system.allobjects[implementation])
else:
l = implementation
links.append(template%(l,))
x += '
known implementations: %s
'%(', '.join(links),)
elif cls.allImplementedInterfaces:
links = []
for interface in cls.allImplementedInterfaces:
if interface in cls.implements_directly:
template = '%s'
else:
template = '%s'
if interface in cls.system.allobjects:
l = linkto(cls.system.allobjects[interface])
else:
l = interface
links.append(template%(l,))
x += '
implements interfaces: %s
'%(', '.join(links),)
z = doc2html(cls, cls.docstring)
x += '
%s
' % (z,)
link_ = lambda x: '#' + x.fullName()
x += self._genChildren(cls.orderedcontents, link=link_)
for meth in cls.orderedcontents:
if not isinstance(meth, model.Function):
continue
doc = meth.docstring
imeth = self.interfaceMeth(cls, meth)
if imeth:
if doc is None:
doc = imeth.docstring
interfaceInfo = '
''' % (
meth.fullName(),
self._funsig(meth),
interfaceInfo,
doc2html(meth, doc))
return x
def interfaceMeth(self, cls, meth):
for interface in cls.allImplementedInterfaces:
if interface in cls.system.allobjects:
io = cls.system.allobjects[interface]
if meth.name in io.contents:
return io.contents[meth.name]
return None
def html_Function(self, fun):
x = '
Function %s:
' % (self._funsig(fun))
x += self._parentLink(fun)
x += doc2html(fun, fun.docstring)
return x
## Utilities
def _funsig(self, fun):
return '%s(%s)' % (fun.name, signature(fun.argspec))
def _genChildren(self, children, link=link):
"""Render a table mapping children names to summary docstrings."""
x = '
'
return x
def _sourceLink(self, o):
if not self.sourcebase:
return ''
m = o
while not isinstance(m, (model.Module, model.Package)):
m = m.parent
if m is None:
return ''
sourceHref = '%s/%s'%(self.sourcebase, m.fullName().replace('.', '/'),)
if isinstance(m, model.Module):
sourceHref += '.py'
if isinstance(o, model.Module):
sourceHref += '#L1'
elif hasattr(o, 'linenumber'):
sourceHref += '#L'+str(o.linenumber)
return 'View Source'%(sourceHref,)
def _parentLink(self, o):
"""A link to the Documentable's parent and source."""
sourceLink = self._sourceLink(o)
if not o.parent:
parentLink = ''
else:
parentLink = 'Part of %s'%(linkto(o.parent),)
if sourceLink:
if parentLink:
t = ('
'
else:
return parentLink
def _allModules(self, pkg):
"""Generates an HTML representation of all modules (including
packages) in a nested list."""
x = ""
# orderedcontents isn't ordered for modules, for some reason.
pkg.orderedcontents.sort(key=lambda o: o.fullName())
for mod in pkg.orderedcontents:
if mod.name == '__init__':
# XXX Rehh??
continue
MOD = isinstance(mod, model.Module)
PKG = isinstance(mod, model.Package)
if MOD or PKG:
x += '