1
"""The classes that turn L{Documentable} instances into objects Nevow can render."""
3
from nevow import loaders, page, tags
5
from pydoctor import epydoc2stan, model
6
from pydoctor.nevowhtml.pages.table import ChildTable
7
from pydoctor.nevowhtml.util import \
8
templatefile, fillSlots, srclink, taglink
10
def getBetterThanArgspec(argspec):
11
"""Ok, maybe argspec's format isn't the best after all: This takes an
12
argspec and returns (regularArguments, [(kwarg, kwval), (kwarg, kwval)])."""
14
defaults = argspec[-1]
19
defaults = list(defaults)
21
kws = zip(backargs, defaults)
23
allargs = args[:-len(kws)] + kws
24
return (args[:-len(kws)], kws)
28
if not isinstance(tup, (tuple, list)):
30
return '(' + ', '.join(map(_strtup, tup)) + ')'
32
def signature(argspec):
33
"""Return a nicely-formatted source-like signature, formatted from an
36
regargs, kwargs = getBetterThanArgspec(argspec)
37
varargname, varkwname = argspec[1:3]
39
for regarg in regargs:
40
if isinstance(regarg, list):
41
things.append(_strtup(regarg))
45
things.append('*%s' % varargname)
46
things += ['%s=%s' % (t[0], t[1]) for t in kwargs]
48
things.append('**%s' % varkwname)
49
return ', '.join(things)
51
class DocGetter(object):
52
def get(self, ob, summary=False):
53
return epydoc2stan.doc2html(ob, summary=summary)[0]
55
class CommonPage(page.Element):
56
docFactory = loaders.xmlfile(templatefile('common.html'))
58
def __init__(self, ob, docgetter=None):
61
docgetter = DocGetter()
62
self.docgetter = docgetter
63
self.usesorttable = ob.system.options.htmlusesorttable
64
self.usesplitlinks = ob.system.options.htmlusesplitlinks
65
self.shortenlists = ob.system.options.htmlshortenlists
68
return self.ob.fullName()
70
def mediumName(self, obj):
74
path, name = fn.rsplit('.', 1)
76
return obj.system.abbrevmapping.get(part, part[0])
77
return '.'.join([process(p) for p in path.split('.')]) + '.' + name
80
return tags.h1(class_=self.ob.css_class)[
81
self.mediumName(self.ob), " : ", self.ob.kind.lower(),
85
tag = tags.invisible()
87
parent = self.ob.parent
88
if isinstance(parent, model.Module) and parent.name == '__init__':
89
parent = parent.parent
92
parts.append(taglink(parent, parent.name))
94
parent = parent.parent
95
parts.append(taglink(parent, parent.name))
97
return tag['Part of ', parts]
102
if self.ob.system.options.projecturl:
103
return tags.a(href=self.ob.system.options.projecturl)[self.ob.system.options.projectname]
104
elif self.ob.system.options.projectname:
105
return self.ob.system.options.projectname
107
return self.ob.system.guessedprojectname
109
def source(self, tag):
110
sourceHref = srclink(self.ob)
113
return tag(href=sourceHref)
115
def inhierarchy(self, tag):
119
return tags.invisible()
122
return self.docgetter.get(self.ob)
126
[o for o in self.ob.orderedcontents if o.isVisible],
127
key=lambda o:-o.privacyClass)
129
def packageInitTable(self):
132
def baseTables(self, tag):
135
def bigTable(self, tag):
139
children = self.children()
141
return ChildTable(self.docgetter, self.ob, self.has_lineno_col(), children)
145
def has_lineno_col(self):
146
if not self.usesorttable:
148
return isinstance(self.ob, (model.Class, model.Module))
150
def ifusesorttable(self, tag):
151
if self.usesorttable:
157
return [o for o in self.ob.orderedcontents
158
if o.document_in_parent_page and o.isVisible]
161
from pydoctor.nevowhtml.pages.attributechild import AttributeChild
162
from pydoctor.nevowhtml.pages.functionchild import FunctionChild
164
for c in self.methods():
165
if isinstance(c, model.Function):
166
r.append(FunctionChild(self.docgetter, c, self.functionExtras(c)))
168
r.append(AttributeChild(self.docgetter, c))
171
def functionExtras(self, data):
174
def functionBody(self, data):
175
return self.docgetter.get(data)
177
def ifhasplitlinks(self, tag):
180
def pydoctorjs(self, tag):
181
if self.usesplitlinks or self.shortenlists:
187
def all(self, request, tag):
188
return fillSlots(tag,
190
ifusesorttable=self.ifusesorttable(tag.onePattern('ifusesorttable')),
191
pydoctorjs=self.pydoctorjs(tag.onePattern('pydoctorjs')),
192
heading=self.heading(),
194
source=self.source(tag.onePattern('source')),
195
inhierarchy=self.inhierarchy(tag.onePattern('inhierarchy')),
196
extras=self.extras(),
197
docstring=self.docstring(),
198
splittingLinks=self.ifhasplitlinks(tag.onePattern('splittingLinks')),
199
mainTable=self.mainTable(),
200
baseTables=self.baseTables(tag.patternGenerator('baseTable')),
201
bigTable=self.bigTable(tag.patternGenerator('bigTable')),
202
packageInitTable=self.packageInitTable(),
203
childlist=self.childlist(),
204
project=self.project(),
205
buildtime=self.ob.system.buildtime.strftime("%Y-%m-%d %H:%M:%S"),
209
class PackagePage(CommonPage):
211
return sorted([o for o in self.ob.orderedcontents
212
if o.name != '__init__' and o.isVisible],
213
key=lambda o2:(-o2.privacyClass, o2.fullName()))
215
def packageInitTable(self):
216
init = self.ob.contents['__init__']
218
[o for o in init.orderedcontents if o.isVisible],
219
key=lambda o2:(-o2.privacyClass, o2.fullName()))
221
return [tags.p["From the __init__.py module:"],
222
ChildTable(self.docgetter, init, self.usesorttable, children)]
227
return [o for o in self.ob.contents['__init__'].orderedcontents
228
if o.document_in_parent_page and o.isVisible]
230
class ModulePage(CommonPage):
233
def overriding_subclasses(c, name, firstcall=True):
234
if not firstcall and name in c.contents:
237
for sc in c.subclasses:
239
for sc2 in overriding_subclasses(sc, name, False):
244
for b2 in b.baseobjects:
247
for n in nested_bases(b2):
251
def unmasked_attrs(baselist):
252
maybe_masking = set()
253
for b in baselist[1:]:
254
maybe_masking.update(set([o.name for o in b.orderedcontents]))
255
return [o for o in baselist[0].orderedcontents if o.name not in maybe_masking]
258
def maybeShortenList(system, label, lst, idbase):
261
o = system.allobjects.get(name)
262
if o is None or o.isVisible:
268
if item in system.allobjects:
269
return taglink(system.allobjects[item])
280
if len(lst) <= 5 or not system.options.htmlshortenlists:
281
p.extend(commasep(lst))
283
p.extend(commasep(lst[:3]))
285
q.extend(commasep(lst[3:]))
286
q.append(tags.span(class_='showIfJS')[
289
onclick="showAndHide('%s');"%idbase,
291
['(hide last %d again)'%len(lst[3:])]])
292
p.append(tags.span(id=idbase, class_='hideIfJS')[q])
293
p.append(tags.span(id=idbase+'Link', class_='showIfJS')[
296
onclick="hideAndShow('%s');"%idbase,
298
['... and %d more'%len(lst[3:])]])
301
class ClassPage(CommonPage):
302
def __init__(self, ob, docgetter=None):
303
CommonPage.__init__(self, ob, docgetter)
305
self.usesplitlinks = ob.system.options.htmlusesplitlinks
306
for baselist in nested_bases(self.ob):
307
attrs = unmasked_attrs(baselist)
309
self.baselists.append((baselist, attrs))
310
self.overridenInCount = 0
313
r = super(ClassPage, self).extras()
314
scs = sorted(self.ob.subclasses, key=lambda o:o.fullName().lower())
317
p = maybeShortenList(self.ob.system, "Known subclasses: ",
318
[o.fullName() for o in scs], "moreSubclasses")
323
def ifhasplitlinks(self, tag):
324
if self.usesplitlinks and len(self.baselists) > 1:
329
def mediumName(self, ob):
330
r = [super(ClassPage, self).mediumName(ob)]
331
zipped = zip(self.ob.rawbases, self.ob.bases, self.ob.baseobjects)
334
for i, (n, m, o) in enumerate(zipped):
336
r.append(tags.span(title=m)[n])
338
r.append(taglink(o, n))
339
if i != len(zipped)-1:
344
def inhierarchy(self, tag):
345
return tag(href="classIndex.html#"+self.ob.fullName())
347
def baseTables(self, item):
348
baselists = self.baselists[:]
351
if baselists[0][0][0] == self.ob:
353
return [fillSlots(item,
354
baseName=self.baseName(b),
355
baseTable=ChildTable(self.docgetter, self.ob, self.has_lineno_col(),
356
sorted(attrs, key=lambda o:-o.privacyClass)))
357
for b, attrs in baselists]
359
def baseName(self, data):
360
tag = tags.invisible()
361
source_base = data[0]
362
tag[taglink(source_base, source_base.name)]
363
bases_to_mention = data[1:-1]
366
for b in reversed(bases_to_mention):
367
tail.append(taglink(b, b.name))
370
tag[' (via ', tail, ')']
373
def bigTable(self, tag):
374
if not self.usesplitlinks or len(self.baselists) == 1:
377
for b, attrs in self.baselists:
378
all_attrs.extend(attrs)
379
all_attrs.sort(key=lambda o:(-o.privacyClass, o.name.lower()))
380
return tag[ChildTable(self.docgetter, self.ob, self.has_lineno_col(), all_attrs)]
382
def functionExtras(self, data):
384
for b in self.ob.allbases():
385
if data.name not in b.contents:
387
overridden = b.contents[data.name]
388
r.append(tags.div(class_="interfaceinfo")['overrides ', taglink(overridden)])
390
ocs = sorted(overriding_subclasses(self.ob, data.name), key=lambda o:o.fullName().lower())
392
self.overridenInCount += 1
393
idbase = 'overridenIn' + str(self.overridenInCount)
394
l = maybeShortenList(self.ob.system, 'overridden in ',
395
[o.fullName() for o in ocs], idbase)
397
r.append(tags.div(class_="interfaceinfo")[l])
401
class ZopeInterfaceClassPage(ClassPage):
403
r = super(ZopeInterfaceClassPage, self).extras()
404
system = self.ob.system
406
if s in system.allobjects:
407
return taglink(system.allobjects[s])
410
if self.ob.isinterface:
411
namelist = sorted(self.ob.implementedby_directly, key=lambda x:x.lower())
412
label = 'Known implementations: '
414
namelist = sorted(self.ob.implements_directly, key=lambda x:x.lower())
415
label = 'Implements interfaces: '
417
l = maybeShortenList(self.ob.system, label, namelist, "moreInterface")
422
def interfaceMeth(self, methname):
423
system = self.ob.system
424
for interface in self.ob.allImplementedInterfaces:
425
if interface in system.allobjects:
426
io = system.allobjects[interface]
427
if methname in io.contents:
428
return io.contents[methname]
431
def functionExtras(self, data):
432
imeth = self.interfaceMeth(data.name)
435
r.append(tags.div(class_="interfaceinfo")['from ', taglink(imeth, imeth.parent.fullName())])
436
r.extend(super(ZopeInterfaceClassPage, self).functionExtras(data))
439
class FunctionPage(CommonPage):
440
def mediumName(self, ob):
442
super(FunctionPage, self).mediumName(ob), '(',
443
signature(self.ob.argspec), ')']