~ubuntu-branches/debian/sid/pydoctor/sid

« back to all changes in this revision

Viewing changes to pydoctor/nevowhtml/pages/__init__.py

  • Committer: Package Import Robot
  • Author(s): Jelmer Vernooij
  • Date: 2013-09-15 13:58:49 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20130915135849-g206zbvqwvz0ptdg
Tags: 0.5b1+bzr603-1
* New upstream snapshot.
* Switch from cdbs to dh.
* Bump standards version to 3.9.4 (no changes).
* Update Vcs header.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
"""The classes that turn  L{Documentable} instances into objects Nevow can render."""
2
 
 
3
 
from nevow import loaders, page, tags
4
 
 
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
9
 
 
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)])."""
13
 
    args = argspec[0]
14
 
    defaults = argspec[-1]
15
 
    if not defaults:
16
 
        return (args, [])
17
 
    backargs = args[:]
18
 
    backargs.reverse()
19
 
    defaults = list(defaults)
20
 
    defaults.reverse()
21
 
    kws = zip(backargs, defaults)
22
 
    kws.reverse()
23
 
    allargs = args[:-len(kws)] + kws
24
 
    return (args[:-len(kws)], kws)
25
 
 
26
 
def _strtup(tup):
27
 
    # Ugh
28
 
    if not isinstance(tup, (tuple, list)):
29
 
        return str(tup)
30
 
    return '(' + ', '.join(map(_strtup, tup)) + ')'
31
 
 
32
 
def signature(argspec):
33
 
    """Return a nicely-formatted source-like signature, formatted from an
34
 
    argspec.
35
 
    """
36
 
    regargs, kwargs = getBetterThanArgspec(argspec)
37
 
    varargname, varkwname = argspec[1:3]
38
 
    things = []
39
 
    for regarg in regargs:
40
 
        if isinstance(regarg, list):
41
 
            things.append(_strtup(regarg))
42
 
        else:
43
 
            things.append(regarg)
44
 
    if varargname:
45
 
        things.append('*%s' % varargname)
46
 
    things += ['%s=%s' % (t[0], t[1]) for t in kwargs]
47
 
    if varkwname:
48
 
        things.append('**%s' % varkwname)
49
 
    return ', '.join(things)
50
 
 
51
 
class DocGetter(object):
52
 
    def get(self, ob, summary=False):
53
 
        return epydoc2stan.doc2html(ob, summary=summary)[0]
54
 
 
55
 
class CommonPage(page.Element):
56
 
    docFactory = loaders.xmlfile(templatefile('common.html'))
57
 
 
58
 
    def __init__(self, ob, docgetter=None):
59
 
        self.ob = ob
60
 
        if docgetter is 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
66
 
 
67
 
    def title(self):
68
 
        return self.ob.fullName()
69
 
 
70
 
    def mediumName(self, obj):
71
 
        fn = obj.fullName()
72
 
        if '.' not in fn:
73
 
            return fn
74
 
        path, name = fn.rsplit('.', 1)
75
 
        def process(part):
76
 
            return obj.system.abbrevmapping.get(part, part[0])
77
 
        return '.'.join([process(p) for p in path.split('.')]) + '.' + name
78
 
 
79
 
    def heading(self):
80
 
        return tags.h1(class_=self.ob.css_class)[
81
 
            self.mediumName(self.ob), " : ", self.ob.kind.lower(),
82
 
            " documentation"]
83
 
 
84
 
    def part(self):
85
 
        tag = tags.invisible()
86
 
        if self.ob.parent:
87
 
            parent = self.ob.parent
88
 
            if isinstance(parent, model.Module) and parent.name == '__init__':
89
 
                parent = parent.parent
90
 
            parts = []
91
 
            while parent.parent:
92
 
                parts.append(taglink(parent, parent.name))
93
 
                parts.append('.')
94
 
                parent = parent.parent
95
 
            parts.append(taglink(parent, parent.name))
96
 
            parts.reverse()
97
 
            return tag['Part of ', parts]
98
 
        else:
99
 
            return tag
100
 
 
101
 
    def project(self):
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
106
 
        else:
107
 
            return self.ob.system.guessedprojectname
108
 
 
109
 
    def source(self, tag):
110
 
        sourceHref = srclink(self.ob)
111
 
        if not sourceHref:
112
 
            return ()
113
 
        return tag(href=sourceHref)
114
 
 
115
 
    def inhierarchy(self, tag):
116
 
        return ()
117
 
 
118
 
    def extras(self):
119
 
        return tags.invisible()
120
 
 
121
 
    def docstring(self):
122
 
        return self.docgetter.get(self.ob)
123
 
 
124
 
    def children(self):
125
 
        return sorted(
126
 
            [o for o in self.ob.orderedcontents if o.isVisible],
127
 
            key=lambda o:-o.privacyClass)
128
 
 
129
 
    def packageInitTable(self):
130
 
        return ()
131
 
 
132
 
    def baseTables(self, tag):
133
 
        return ()
134
 
 
135
 
    def bigTable(self, tag):
136
 
        return ()
137
 
 
138
 
    def mainTable(self):
139
 
        children = self.children()
140
 
        if children:
141
 
            return ChildTable(self.docgetter, self.ob, self.has_lineno_col(), children)
142
 
        else:
143
 
            return ()
144
 
 
145
 
    def has_lineno_col(self):
146
 
        if not self.usesorttable:
147
 
            return False
148
 
        return isinstance(self.ob, (model.Class, model.Module))
149
 
 
150
 
    def ifusesorttable(self, tag):
151
 
        if self.usesorttable:
152
 
            return tag
153
 
        else:
154
 
            return ()
155
 
 
156
 
    def methods(self):
157
 
        return [o for o in self.ob.orderedcontents
158
 
                if o.document_in_parent_page and o.isVisible]
159
 
 
160
 
    def childlist(self):
161
 
        from pydoctor.nevowhtml.pages.attributechild import AttributeChild
162
 
        from pydoctor.nevowhtml.pages.functionchild import FunctionChild
163
 
        r = []
164
 
        for c in self.methods():
165
 
            if isinstance(c, model.Function):
166
 
                r.append(FunctionChild(self.docgetter, c, self.functionExtras(c)))
167
 
            else:
168
 
                r.append(AttributeChild(self.docgetter, c))
169
 
        return r
170
 
 
171
 
    def functionExtras(self, data):
172
 
        return []
173
 
 
174
 
    def functionBody(self, data):
175
 
        return self.docgetter.get(data)
176
 
 
177
 
    def ifhasplitlinks(self, tag):
178
 
        return ()
179
 
 
180
 
    def pydoctorjs(self, tag):
181
 
        if self.usesplitlinks or self.shortenlists:
182
 
            return tag
183
 
        else:
184
 
            return ()
185
 
 
186
 
    @page.renderer
187
 
    def all(self, request, tag):
188
 
        return fillSlots(tag,
189
 
                         title=self.title(),
190
 
                         ifusesorttable=self.ifusesorttable(tag.onePattern('ifusesorttable')),
191
 
                         pydoctorjs=self.pydoctorjs(tag.onePattern('pydoctorjs')),
192
 
                         heading=self.heading(),
193
 
                         part=self.part(),
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"),
206
 
                         )
207
 
 
208
 
 
209
 
class PackagePage(CommonPage):
210
 
    def children(self):
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()))
214
 
 
215
 
    def packageInitTable(self):
216
 
        init = self.ob.contents['__init__']
217
 
        children = sorted(
218
 
            [o for o in init.orderedcontents if o.isVisible],
219
 
            key=lambda o2:(-o2.privacyClass, o2.fullName()))
220
 
        if children:
221
 
            return [tags.p["From the __init__.py module:"],
222
 
                    ChildTable(self.docgetter, init, self.usesorttable, children)]
223
 
        else:
224
 
            return ()
225
 
 
226
 
    def methods(self):
227
 
        return [o for o in self.ob.contents['__init__'].orderedcontents
228
 
                if o.document_in_parent_page and o.isVisible]
229
 
 
230
 
class ModulePage(CommonPage):
231
 
    pass
232
 
 
233
 
def overriding_subclasses(c, name, firstcall=True):
234
 
    if not firstcall and name in c.contents:
235
 
        yield c
236
 
    else:
237
 
        for sc in c.subclasses:
238
 
            if sc.isVisible:
239
 
                for sc2 in overriding_subclasses(sc, name, False):
240
 
                    yield sc2
241
 
 
242
 
def nested_bases(b):
243
 
    r = [(b,)]
244
 
    for b2 in b.baseobjects:
245
 
        if b2 is None:
246
 
            continue
247
 
        for n in nested_bases(b2):
248
 
            r.append(n + (b,))
249
 
    return r
250
 
 
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]
256
 
 
257
 
 
258
 
def maybeShortenList(system, label, lst, idbase):
259
 
    lst2 = []
260
 
    for name in lst:
261
 
        o = system.allobjects.get(name)
262
 
        if o is None or o.isVisible:
263
 
            lst2.append(name)
264
 
    lst = lst2
265
 
    if not lst:
266
 
        return None
267
 
    def one(item):
268
 
        if item in system.allobjects:
269
 
            return taglink(system.allobjects[item])
270
 
        else:
271
 
            return item
272
 
    def commasep(items):
273
 
        r = []
274
 
        for item in items:
275
 
            r.append(one(item))
276
 
            r.append(', ')
277
 
        del r[-1]
278
 
        return r
279
 
    p = [label]
280
 
    if len(lst) <= 5 or not system.options.htmlshortenlists:
281
 
        p.extend(commasep(lst))
282
 
    else:
283
 
        p.extend(commasep(lst[:3]))
284
 
        q = [', ']
285
 
        q.extend(commasep(lst[3:]))
286
 
        q.append(tags.span(class_='showIfJS')[
287
 
            ' ',
288
 
            tags.a(href="#",
289
 
                   onclick="showAndHide('%s');"%idbase,
290
 
                   class_="jslink")
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')[
294
 
            ' ',
295
 
            tags.a(href="#",
296
 
                   onclick="hideAndShow('%s');"%idbase,
297
 
                   class_="jslink")
298
 
            ['... and %d more'%len(lst[3:])]])
299
 
    return p
300
 
 
301
 
class ClassPage(CommonPage):
302
 
    def __init__(self, ob, docgetter=None):
303
 
        CommonPage.__init__(self, ob, docgetter)
304
 
        self.baselists = []
305
 
        self.usesplitlinks = ob.system.options.htmlusesplitlinks
306
 
        for baselist in nested_bases(self.ob):
307
 
            attrs = unmasked_attrs(baselist)
308
 
            if attrs:
309
 
                self.baselists.append((baselist, attrs))
310
 
        self.overridenInCount = 0
311
 
 
312
 
    def extras(self):
313
 
        r = super(ClassPage, self).extras()
314
 
        scs = sorted(self.ob.subclasses, key=lambda o:o.fullName().lower())
315
 
        if not scs:
316
 
            return r
317
 
        p = maybeShortenList(self.ob.system, "Known subclasses: ",
318
 
                             [o.fullName() for o in scs], "moreSubclasses")
319
 
        if p is not None:
320
 
            r[tags.p[p]]
321
 
        return r
322
 
 
323
 
    def ifhasplitlinks(self, tag):
324
 
        if self.usesplitlinks and len(self.baselists) > 1:
325
 
            return tag
326
 
        else:
327
 
            return ()
328
 
 
329
 
    def mediumName(self, ob):
330
 
        r = [super(ClassPage, self).mediumName(ob)]
331
 
        zipped = zip(self.ob.rawbases, self.ob.bases, self.ob.baseobjects)
332
 
        if zipped:
333
 
            r.append('(')
334
 
            for i, (n, m, o) in enumerate(zipped):
335
 
                if o is None:
336
 
                    r.append(tags.span(title=m)[n])
337
 
                else:
338
 
                    r.append(taglink(o, n))
339
 
                if i != len(zipped)-1:
340
 
                    r.append(', ')
341
 
            r.append(')')
342
 
        return r
343
 
 
344
 
    def inhierarchy(self, tag):
345
 
        return tag(href="classIndex.html#"+self.ob.fullName())
346
 
 
347
 
    def baseTables(self, item):
348
 
        baselists = self.baselists[:]
349
 
        if not baselists:
350
 
            return []
351
 
        if baselists[0][0][0] == self.ob:
352
 
            del baselists[0]
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]
358
 
 
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]
364
 
        if bases_to_mention:
365
 
            tail = []
366
 
            for b in reversed(bases_to_mention):
367
 
                tail.append(taglink(b, b.name))
368
 
                tail.append(', ')
369
 
            del tail[-1]
370
 
            tag[' (via ', tail, ')']
371
 
        return tag
372
 
 
373
 
    def bigTable(self, tag):
374
 
        if not self.usesplitlinks or len(self.baselists) == 1:
375
 
            return ()
376
 
        all_attrs = []
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)]
381
 
 
382
 
    def functionExtras(self, data):
383
 
        r = []
384
 
        for b in self.ob.allbases():
385
 
            if data.name not in b.contents:
386
 
                continue
387
 
            overridden = b.contents[data.name]
388
 
            r.append(tags.div(class_="interfaceinfo")['overrides ', taglink(overridden)])
389
 
            break
390
 
        ocs = sorted(overriding_subclasses(self.ob, data.name), key=lambda o:o.fullName().lower())
391
 
        if ocs:
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)
396
 
            if l is not None:
397
 
                r.append(tags.div(class_="interfaceinfo")[l])
398
 
        return r
399
 
 
400
 
 
401
 
class ZopeInterfaceClassPage(ClassPage):
402
 
    def extras(self):
403
 
        r = super(ZopeInterfaceClassPage, self).extras()
404
 
        system = self.ob.system
405
 
        def tl(s):
406
 
            if s in system.allobjects:
407
 
                return taglink(system.allobjects[s])
408
 
            else:
409
 
                return s
410
 
        if self.ob.isinterface:
411
 
            namelist = sorted(self.ob.implementedby_directly, key=lambda x:x.lower())
412
 
            label = 'Known implementations: '
413
 
        else:
414
 
            namelist = sorted(self.ob.implements_directly, key=lambda x:x.lower())
415
 
            label = 'Implements interfaces: '
416
 
        if namelist:
417
 
            l = maybeShortenList(self.ob.system, label, namelist, "moreInterface")
418
 
            if l is not None:
419
 
                r[tags.p[l]]
420
 
        return r
421
 
 
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]
429
 
        return None
430
 
 
431
 
    def functionExtras(self, data):
432
 
        imeth = self.interfaceMeth(data.name)
433
 
        r = []
434
 
        if imeth:
435
 
            r.append(tags.div(class_="interfaceinfo")['from ', taglink(imeth, imeth.parent.fullName())])
436
 
        r.extend(super(ZopeInterfaceClassPage, self).functionExtras(data))
437
 
        return r
438
 
 
439
 
class FunctionPage(CommonPage):
440
 
    def mediumName(self, ob):
441
 
        return [
442
 
            super(FunctionPage, self).mediumName(ob), '(',
443
 
            signature(self.ob.argspec), ')']