source: titan/mediathek/localhoster/lib/python2.7/pydoc.py @ 40114

Last change on this file since 40114 was 40094, checked in by obi, 5 years ago

tithek add yoztube-dl support

File size: 93.3 KB
Line 
1#!/usr/bin/env python
2# -*- coding: latin-1 -*-
3"""Generate Python documentation in HTML or text for interactive use.
4
5In the Python interpreter, do "from pydoc import help" to provide online
6help.  Calling help(thing) on a Python object documents the object.
7
8Or, at the shell command line outside of Python:
9
10Run "pydoc <name>" to show documentation on something.  <name> may be
11the name of a function, module, package, or a dotted reference to a
12class or function within a module or module in a package.  If the
13argument contains a path segment delimiter (e.g. slash on Unix,
14backslash on Windows) it is treated as the path to a Python source file.
15
16Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17of all available modules.
18
19Run "pydoc -p <port>" to start an HTTP server on a given port on the
20local machine to generate documentation web pages.  Port number 0 can be
21used to get an arbitrary unused port.
22
23For platforms without a command line, "pydoc -g" starts the HTTP server
24and also pops up a little window for controlling it.
25
26Run "pydoc -w <name>" to write out the HTML documentation for a module
27to a file named "<name>.html".
28
29Module docs for core modules are assumed to be in
30
31    http://docs.python.org/library/
32
33This can be overridden by setting the PYTHONDOCS environment variable
34to a different URL or to a local directory containing the Library
35Reference Manual pages.
36"""
37
38__author__ = "Ka-Ping Yee <ping@lfw.org>"
39__date__ = "26 February 2001"
40
41__version__ = "$Revision: 88564 $"
42__credits__ = """Guido van Rossum, for an excellent programming language.
43Tommy Burnette, the original creator of manpy.
44Paul Prescod, for all his work on onlinehelp.
45Richard Chamberlain, for the first implementation of textdoc.
46"""
47
48# Known bugs that can't be fixed here:
49#   - imp.load_module() cannot be prevented from clobbering existing
50#     loaded modules, so calling synopsis() on a binary module file
51#     changes the contents of any existing module with the same name.
52#   - If the __file__ attribute on a module is a relative path and
53#     the current directory is changed with os.chdir(), an incorrect
54#     path will be displayed.
55
56import sys, imp, os, re, types, inspect, __builtin__, pkgutil, warnings
57from repr import Repr
58from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
59from traceback import extract_tb
60try:
61    from collections import deque
62except ImportError:
63    # Python 2.3 compatibility
64    class deque(list):
65        def popleft(self):
66            return self.pop(0)
67
68# --------------------------------------------------------- common routines
69
70def pathdirs():
71    """Convert sys.path into a list of absolute, existing, unique paths."""
72    dirs = []
73    normdirs = []
74    for dir in sys.path:
75        dir = os.path.abspath(dir or '.')
76        normdir = os.path.normcase(dir)
77        if normdir not in normdirs and os.path.isdir(dir):
78            dirs.append(dir)
79            normdirs.append(normdir)
80    return dirs
81
82def getdoc(object):
83    """Get the doc string or comments for an object."""
84    result = inspect.getdoc(object) or inspect.getcomments(object)
85    result = _encode(result)
86    return result and re.sub('^ *\n', '', rstrip(result)) or ''
87
88def splitdoc(doc):
89    """Split a doc string into a synopsis line (if any) and the rest."""
90    lines = split(strip(doc), '\n')
91    if len(lines) == 1:
92        return lines[0], ''
93    elif len(lines) >= 2 and not rstrip(lines[1]):
94        return lines[0], join(lines[2:], '\n')
95    return '', join(lines, '\n')
96
97def classname(object, modname):
98    """Get a class name and qualify it with a module name if necessary."""
99    name = object.__name__
100    if object.__module__ != modname:
101        name = object.__module__ + '.' + name
102    return name
103
104def isdata(object):
105    """Check if an object is of a type that probably means it's data."""
106    return not (inspect.ismodule(object) or inspect.isclass(object) or
107                inspect.isroutine(object) or inspect.isframe(object) or
108                inspect.istraceback(object) or inspect.iscode(object))
109
110def replace(text, *pairs):
111    """Do a series of global replacements on a string."""
112    while pairs:
113        text = join(split(text, pairs[0]), pairs[1])
114        pairs = pairs[2:]
115    return text
116
117def cram(text, maxlen):
118    """Omit part of a string if needed to make it fit in a maximum length."""
119    if len(text) > maxlen:
120        pre = max(0, (maxlen-3)//2)
121        post = max(0, maxlen-3-pre)
122        return text[:pre] + '...' + text[len(text)-post:]
123    return text
124
125_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
126def stripid(text):
127    """Remove the hexadecimal id from a Python object representation."""
128    # The behaviour of %p is implementation-dependent in terms of case.
129    return _re_stripid.sub(r'\1', text)
130
131def _is_some_method(obj):
132    return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
133
134def allmethods(cl):
135    methods = {}
136    for key, value in inspect.getmembers(cl, _is_some_method):
137        methods[key] = 1
138    for base in cl.__bases__:
139        methods.update(allmethods(base)) # all your base are belong to us
140    for key in methods.keys():
141        methods[key] = getattr(cl, key)
142    return methods
143
144def _split_list(s, predicate):
145    """Split sequence s via predicate, and return pair ([true], [false]).
146
147    The return value is a 2-tuple of lists,
148        ([x for x in s if predicate(x)],
149         [x for x in s if not predicate(x)])
150    """
151
152    yes = []
153    no = []
154    for x in s:
155        if predicate(x):
156            yes.append(x)
157        else:
158            no.append(x)
159    return yes, no
160
161def visiblename(name, all=None, obj=None):
162    """Decide whether to show documentation on a variable."""
163    # Certain special names are redundant.
164    _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__',
165                     '__module__', '__name__', '__slots__', '__package__')
166    if name in _hidden_names: return 0
167    # Private names are hidden, but special names are displayed.
168    if name.startswith('__') and name.endswith('__'): return 1
169    # Namedtuples have public fields and methods with a single leading underscore
170    if name.startswith('_') and hasattr(obj, '_fields'):
171        return 1
172    if all is not None:
173        # only document that which the programmer exported in __all__
174        return name in all
175    else:
176        return not name.startswith('_')
177
178def classify_class_attrs(object):
179    """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
180    def fixup(data):
181        name, kind, cls, value = data
182        if inspect.isdatadescriptor(value):
183            kind = 'data descriptor'
184        return name, kind, cls, value
185    return map(fixup, inspect.classify_class_attrs(object))
186
187# ----------------------------------------------------- Unicode support helpers
188
189try:
190    _unicode = unicode
191except NameError:
192    # If Python is built without Unicode support, the unicode type
193    # will not exist. Fake one that nothing will match, and make
194    # the _encode function that do nothing.
195    class _unicode(object):
196        pass
197    _encoding = 'ascii'
198    def _encode(text, encoding='ascii'):
199        return text
200else:
201    import locale
202    _encoding = locale.getpreferredencoding()
203
204    def _encode(text, encoding=None):
205        if isinstance(text, unicode):
206            return text.encode(encoding or _encoding, 'xmlcharrefreplace')
207        else:
208            return text
209
210def _binstr(obj):
211    # Ensure that we have an encoded (binary) string representation of obj,
212    # even if it is a unicode string.
213    if isinstance(obj, _unicode):
214        return obj.encode(_encoding, 'xmlcharrefreplace')
215    return str(obj)
216
217# ----------------------------------------------------- module manipulation
218
219def ispackage(path):
220    """Guess whether a path refers to a package directory."""
221    if os.path.isdir(path):
222        for ext in ('.py', '.pyc', '.pyo'):
223            if os.path.isfile(os.path.join(path, '__init__' + ext)):
224                return True
225    return False
226
227def source_synopsis(file):
228    line = file.readline()
229    while line[:1] == '#' or not strip(line):
230        line = file.readline()
231        if not line: break
232    line = strip(line)
233    if line[:4] == 'r"""': line = line[1:]
234    if line[:3] == '"""':
235        line = line[3:]
236        if line[-1:] == '\\': line = line[:-1]
237        while not strip(line):
238            line = file.readline()
239            if not line: break
240        result = strip(split(line, '"""')[0])
241    else: result = None
242    return result
243
244def synopsis(filename, cache={}):
245    """Get the one-line summary out of a module file."""
246    mtime = os.stat(filename).st_mtime
247    lastupdate, result = cache.get(filename, (None, None))
248    if lastupdate is None or lastupdate < mtime:
249        info = inspect.getmoduleinfo(filename)
250        try:
251            file = open(filename)
252        except IOError:
253            # module can't be opened, so skip it
254            return None
255        if info and 'b' in info[2]: # binary modules have to be imported
256            try: module = imp.load_module('__temp__', file, filename, info[1:])
257            except: return None
258            result = module.__doc__.splitlines()[0] if module.__doc__ else None
259            del sys.modules['__temp__']
260        else: # text modules can be directly examined
261            result = source_synopsis(file)
262            file.close()
263        cache[filename] = (mtime, result)
264    return result
265
266class ErrorDuringImport(Exception):
267    """Errors that occurred while trying to import something to document it."""
268    def __init__(self, filename, exc_info):
269        exc, value, tb = exc_info
270        self.filename = filename
271        self.exc = exc
272        self.value = value
273        self.tb = tb
274
275    def __str__(self):
276        exc = self.exc
277        if type(exc) is types.ClassType:
278            exc = exc.__name__
279        return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
280
281def importfile(path):
282    """Import a Python source file or compiled file given its path."""
283    magic = imp.get_magic()
284    file = open(path, 'r')
285    if file.read(len(magic)) == magic:
286        kind = imp.PY_COMPILED
287    else:
288        kind = imp.PY_SOURCE
289    file.close()
290    filename = os.path.basename(path)
291    name, ext = os.path.splitext(filename)
292    file = open(path, 'r')
293    try:
294        module = imp.load_module(name, file, path, (ext, 'r', kind))
295    except:
296        raise ErrorDuringImport(path, sys.exc_info())
297    file.close()
298    return module
299
300def safeimport(path, forceload=0, cache={}):
301    """Import a module; handle errors; return None if the module isn't found.
302
303    If the module *is* found but an exception occurs, it's wrapped in an
304    ErrorDuringImport exception and reraised.  Unlike __import__, if a
305    package path is specified, the module at the end of the path is returned,
306    not the package at the beginning.  If the optional 'forceload' argument
307    is 1, we reload the module from disk (unless it's a dynamic extension)."""
308    try:
309        # If forceload is 1 and the module has been previously loaded from
310        # disk, we always have to reload the module.  Checking the file's
311        # mtime isn't good enough (e.g. the module could contain a class
312        # that inherits from another module that has changed).
313        if forceload and path in sys.modules:
314            if path not in sys.builtin_module_names:
315                # Avoid simply calling reload() because it leaves names in
316                # the currently loaded module lying around if they're not
317                # defined in the new source file.  Instead, remove the
318                # module from sys.modules and re-import.  Also remove any
319                # submodules because they won't appear in the newly loaded
320                # module's namespace if they're already in sys.modules.
321                subs = [m for m in sys.modules if m.startswith(path + '.')]
322                for key in [path] + subs:
323                    # Prevent garbage collection.
324                    cache[key] = sys.modules[key]
325                    del sys.modules[key]
326        module = __import__(path)
327    except:
328        # Did the error occur before or after the module was found?
329        (exc, value, tb) = info = sys.exc_info()
330        if path in sys.modules:
331            # An error occurred while executing the imported module.
332            raise ErrorDuringImport(sys.modules[path].__file__, info)
333        elif exc is SyntaxError:
334            # A SyntaxError occurred before we could execute the module.
335            raise ErrorDuringImport(value.filename, info)
336        elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport':
337            # The import error occurred directly in this function,
338            # which means there is no such module in the path.
339            return None
340        else:
341            # Some other error occurred during the importing process.
342            raise ErrorDuringImport(path, sys.exc_info())
343    for part in split(path, '.')[1:]:
344        try: module = getattr(module, part)
345        except AttributeError: return None
346    return module
347
348# ---------------------------------------------------- formatter base class
349
350class Doc:
351    def document(self, object, name=None, *args):
352        """Generate documentation for an object."""
353        args = (object, name) + args
354        # 'try' clause is to attempt to handle the possibility that inspect
355        # identifies something in a way that pydoc itself has issues handling;
356        # think 'super' and how it is a descriptor (which raises the exception
357        # by lacking a __name__ attribute) and an instance.
358        if inspect.isgetsetdescriptor(object): return self.docdata(*args)
359        if inspect.ismemberdescriptor(object): return self.docdata(*args)
360        try:
361            if inspect.ismodule(object): return self.docmodule(*args)
362            if inspect.isclass(object): return self.docclass(*args)
363            if inspect.isroutine(object): return self.docroutine(*args)
364        except AttributeError:
365            pass
366        if isinstance(object, property): return self.docproperty(*args)
367        return self.docother(*args)
368
369    def fail(self, object, name=None, *args):
370        """Raise an exception for unimplemented types."""
371        message = "don't know how to document object%s of type %s" % (
372            name and ' ' + repr(name), type(object).__name__)
373        raise TypeError, message
374
375    docmodule = docclass = docroutine = docother = docproperty = docdata = fail
376
377    def getdocloc(self, object):
378        """Return the location of module docs or None"""
379
380        try:
381            file = inspect.getabsfile(object)
382        except TypeError:
383            file = '(built-in)'
384
385        docloc = os.environ.get("PYTHONDOCS",
386                                "http://docs.python.org/library")
387        basedir = os.path.join(sys.exec_prefix, sys.lib,
388                               "python"+sys.version[0:3])
389        if (isinstance(object, type(os)) and
390            (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
391                                 'marshal', 'posix', 'signal', 'sys',
392                                 'thread', 'zipimport') or
393             (file.startswith(basedir) and
394              not file.startswith(os.path.join(basedir, 'site-packages')))) and
395            object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
396            if docloc.startswith("http://"):
397                docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__)
398            else:
399                docloc = os.path.join(docloc, object.__name__ + ".html")
400        else:
401            docloc = None
402        return docloc
403
404# -------------------------------------------- HTML documentation generator
405
406class HTMLRepr(Repr):
407    """Class for safely making an HTML representation of a Python object."""
408    def __init__(self):
409        Repr.__init__(self)
410        self.maxlist = self.maxtuple = 20
411        self.maxdict = 10
412        self.maxstring = self.maxother = 100
413
414    def escape(self, text):
415        return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
416
417    def repr(self, object):
418        return Repr.repr(self, object)
419
420    def repr1(self, x, level):
421        if hasattr(type(x), '__name__'):
422            methodname = 'repr_' + join(split(type(x).__name__), '_')
423            if hasattr(self, methodname):
424                return getattr(self, methodname)(x, level)
425        return self.escape(cram(stripid(repr(x)), self.maxother))
426
427    def repr_string(self, x, level):
428        test = cram(x, self.maxstring)
429        testrepr = repr(test)
430        if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
431            # Backslashes are only literal in the string and are never
432            # needed to make any special characters, so show a raw string.
433            return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
434        return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
435                      r'<font color="#c040c0">\1</font>',
436                      self.escape(testrepr))
437
438    repr_str = repr_string
439
440    def repr_instance(self, x, level):
441        try:
442            return self.escape(cram(stripid(repr(x)), self.maxstring))
443        except:
444            return self.escape('<%s instance>' % x.__class__.__name__)
445
446    repr_unicode = repr_string
447
448class HTMLDoc(Doc):
449    """Formatter class for HTML documentation."""
450
451    # ------------------------------------------- HTML formatting utilities
452
453    _repr_instance = HTMLRepr()
454    repr = _repr_instance.repr
455    escape = _repr_instance.escape
456
457    def page(self, title, contents):
458        """Format an HTML page."""
459        return _encode('''
460<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
461<html><head><title>Python: %s</title>
462<meta charset="utf-8">
463</head><body bgcolor="#f0f0f8">
464%s
465</body></html>''' % (title, contents), 'ascii')
466
467    def heading(self, title, fgcol, bgcol, extras=''):
468        """Format a page heading."""
469        return '''
470<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
471<tr bgcolor="%s">
472<td valign=bottom>&nbsp;<br>
473<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
474><td align=right valign=bottom
475><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
476    ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
477
478    def section(self, title, fgcol, bgcol, contents, width=6,
479                prelude='', marginalia=None, gap='&nbsp;'):
480        """Format a section with a heading."""
481        if marginalia is None:
482            marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
483        result = '''<p>
484<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
485<tr bgcolor="%s">
486<td colspan=3 valign=bottom>&nbsp;<br>
487<font color="%s" face="helvetica, arial">%s</font></td></tr>
488    ''' % (bgcol, fgcol, title)
489        if prelude:
490            result = result + '''
491<tr bgcolor="%s"><td rowspan=2>%s</td>
492<td colspan=2>%s</td></tr>
493<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
494        else:
495            result = result + '''
496<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
497
498        return result + '\n<td width="100%%">%s</td></tr></table>' % contents
499
500    def bigsection(self, title, *args):
501        """Format a section with a big heading."""
502        title = '<big><strong>%s</strong></big>' % title
503        return self.section(title, *args)
504
505    def preformat(self, text):
506        """Format literal preformatted text."""
507        text = self.escape(expandtabs(text))
508        return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
509                             ' ', '&nbsp;', '\n', '<br>\n')
510
511    def multicolumn(self, list, format, cols=4):
512        """Format a list of items into a multi-column list."""
513        result = ''
514        rows = (len(list)+cols-1)//cols
515        for col in range(cols):
516            result = result + '<td width="%d%%" valign=top>' % (100//cols)
517            for i in range(rows*col, rows*col+rows):
518                if i < len(list):
519                    result = result + format(list[i]) + '<br>\n'
520            result = result + '</td>'
521        return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
522
523    def grey(self, text): return '<font color="#909090">%s</font>' % text
524
525    def namelink(self, name, *dicts):
526        """Make a link for an identifier, given name-to-URL mappings."""
527        for dict in dicts:
528            if name in dict:
529                return '<a href="%s">%s</a>' % (dict[name], name)
530        return name
531
532    def classlink(self, object, modname):
533        """Make a link for a class."""
534        name, module = object.__name__, sys.modules.get(object.__module__)
535        if hasattr(module, name) and getattr(module, name) is object:
536            return '<a href="%s.html#%s">%s</a>' % (
537                module.__name__, name, classname(object, modname))
538        return classname(object, modname)
539
540    def modulelink(self, object):
541        """Make a link for a module."""
542        return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
543
544    def modpkglink(self, data):
545        """Make a link for a module or package to display in an index."""
546        name, path, ispackage, shadowed = data
547        if shadowed:
548            return self.grey(name)
549        if path:
550            url = '%s.%s.html' % (path, name)
551        else:
552            url = '%s.html' % name
553        if ispackage:
554            text = '<strong>%s</strong>&nbsp;(package)' % name
555        else:
556            text = name
557        return '<a href="%s">%s</a>' % (url, text)
558
559    def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
560        """Mark up some plain text, given a context of symbols to look for.
561        Each context dictionary maps object names to anchor names."""
562        escape = escape or self.escape
563        results = []
564        here = 0
565        pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
566                                r'RFC[- ]?(\d+)|'
567                                r'PEP[- ]?(\d+)|'
568                                r'(self\.)?(\w+))')
569        while True:
570            match = pattern.search(text, here)
571            if not match: break
572            start, end = match.span()
573            results.append(escape(text[here:start]))
574
575            all, scheme, rfc, pep, selfdot, name = match.groups()
576            if scheme:
577                url = escape(all).replace('"', '&quot;')
578                results.append('<a href="%s">%s</a>' % (url, url))
579            elif rfc:
580                url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
581                results.append('<a href="%s">%s</a>' % (url, escape(all)))
582            elif pep:
583                url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
584                results.append('<a href="%s">%s</a>' % (url, escape(all)))
585            elif selfdot:
586                # Create a link for methods like 'self.method(...)'
587                # and use <strong> for attributes like 'self.attr'
588                if text[end:end+1] == '(':
589                    results.append('self.' + self.namelink(name, methods))
590                else:
591                    results.append('self.<strong>%s</strong>' % name)
592            elif text[end:end+1] == '(':
593                results.append(self.namelink(name, methods, funcs, classes))
594            else:
595                results.append(self.namelink(name, classes))
596            here = end
597        results.append(escape(text[here:]))
598        return join(results, '')
599
600    # ---------------------------------------------- type-specific routines
601
602    def formattree(self, tree, modname, parent=None):
603        """Produce HTML for a class tree as given by inspect.getclasstree()."""
604        result = ''
605        for entry in tree:
606            if type(entry) is type(()):
607                c, bases = entry
608                result = result + '<dt><font face="helvetica, arial">'
609                result = result + self.classlink(c, modname)
610                if bases and bases != (parent,):
611                    parents = []
612                    for base in bases:
613                        parents.append(self.classlink(base, modname))
614                    result = result + '(' + join(parents, ', ') + ')'
615                result = result + '\n</font></dt>'
616            elif type(entry) is type([]):
617                result = result + '<dd>\n%s</dd>\n' % self.formattree(
618                    entry, modname, c)
619        return '<dl>\n%s</dl>\n' % result
620
621    def docmodule(self, object, name=None, mod=None, *ignored):
622        """Produce HTML documentation for a module object."""
623        name = object.__name__ # ignore the passed-in name
624        try:
625            all = object.__all__
626        except AttributeError:
627            all = None
628        parts = split(name, '.')
629        links = []
630        for i in range(len(parts)-1):
631            links.append(
632                '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
633                (join(parts[:i+1], '.'), parts[i]))
634        linkedname = join(links + parts[-1:], '.')
635        head = '<big><big><strong>%s</strong></big></big>' % linkedname
636        try:
637            path = inspect.getabsfile(object)
638            url = path
639            if sys.platform == 'win32':
640                import nturl2path
641                url = nturl2path.pathname2url(path)
642            filelink = '<a href="file:%s">%s</a>' % (url, path)
643        except TypeError:
644            filelink = '(built-in)'
645        info = []
646        if hasattr(object, '__version__'):
647            version = _binstr(object.__version__)
648            if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
649                version = strip(version[11:-1])
650            info.append('version %s' % self.escape(version))
651        if hasattr(object, '__date__'):
652            info.append(self.escape(_binstr(object.__date__)))
653        if info:
654            head = head + ' (%s)' % join(info, ', ')
655        docloc = self.getdocloc(object)
656        if docloc is not None:
657            docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
658        else:
659            docloc = ''
660        result = self.heading(
661            head, '#ffffff', '#7799ee',
662            '<a href=".">index</a><br>' + filelink + docloc)
663
664        modules = inspect.getmembers(object, inspect.ismodule)
665
666        classes, cdict = [], {}
667        for key, value in inspect.getmembers(object, inspect.isclass):
668            # if __all__ exists, believe it.  Otherwise use old heuristic.
669            if (all is not None or
670                (inspect.getmodule(value) or object) is object):
671                if visiblename(key, all, object):
672                    classes.append((key, value))
673                    cdict[key] = cdict[value] = '#' + key
674        for key, value in classes:
675            for base in value.__bases__:
676                key, modname = base.__name__, base.__module__
677                module = sys.modules.get(modname)
678                if modname != name and module and hasattr(module, key):
679                    if getattr(module, key) is base:
680                        if not key in cdict:
681                            cdict[key] = cdict[base] = modname + '.html#' + key
682        funcs, fdict = [], {}
683        for key, value in inspect.getmembers(object, inspect.isroutine):
684            # if __all__ exists, believe it.  Otherwise use old heuristic.
685            if (all is not None or
686                inspect.isbuiltin(value) or inspect.getmodule(value) is object):
687                if visiblename(key, all, object):
688                    funcs.append((key, value))
689                    fdict[key] = '#-' + key
690                    if inspect.isfunction(value): fdict[value] = fdict[key]
691        data = []
692        for key, value in inspect.getmembers(object, isdata):
693            if visiblename(key, all, object):
694                data.append((key, value))
695
696        doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
697        doc = doc and '<tt>%s</tt>' % doc
698        result = result + '<p>%s</p>\n' % doc
699
700        if hasattr(object, '__path__'):
701            modpkgs = []
702            for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
703                modpkgs.append((modname, name, ispkg, 0))
704            modpkgs.sort()
705            contents = self.multicolumn(modpkgs, self.modpkglink)
706            result = result + self.bigsection(
707                'Package Contents', '#ffffff', '#aa55cc', contents)
708        elif modules:
709            contents = self.multicolumn(
710                modules, lambda key_value, s=self: s.modulelink(key_value[1]))
711            result = result + self.bigsection(
712                'Modules', '#ffffff', '#aa55cc', contents)
713
714        if classes:
715            classlist = map(lambda key_value: key_value[1], classes)
716            contents = [
717                self.formattree(inspect.getclasstree(classlist, 1), name)]
718            for key, value in classes:
719                contents.append(self.document(value, key, name, fdict, cdict))
720            result = result + self.bigsection(
721                'Classes', '#ffffff', '#ee77aa', join(contents))
722        if funcs:
723            contents = []
724            for key, value in funcs:
725                contents.append(self.document(value, key, name, fdict, cdict))
726            result = result + self.bigsection(
727                'Functions', '#ffffff', '#eeaa77', join(contents))
728        if data:
729            contents = []
730            for key, value in data:
731                contents.append(self.document(value, key))
732            result = result + self.bigsection(
733                'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
734        if hasattr(object, '__author__'):
735            contents = self.markup(_binstr(object.__author__), self.preformat)
736            result = result + self.bigsection(
737                'Author', '#ffffff', '#7799ee', contents)
738        if hasattr(object, '__credits__'):
739            contents = self.markup(_binstr(object.__credits__), self.preformat)
740            result = result + self.bigsection(
741                'Credits', '#ffffff', '#7799ee', contents)
742
743        return result
744
745    def docclass(self, object, name=None, mod=None, funcs={}, classes={},
746                 *ignored):
747        """Produce HTML documentation for a class object."""
748        realname = object.__name__
749        name = name or realname
750        bases = object.__bases__
751
752        contents = []
753        push = contents.append
754
755        # Cute little class to pump out a horizontal rule between sections.
756        class HorizontalRule:
757            def __init__(self):
758                self.needone = 0
759            def maybe(self):
760                if self.needone:
761                    push('<hr>\n')
762                self.needone = 1
763        hr = HorizontalRule()
764
765        # List the mro, if non-trivial.
766        mro = deque(inspect.getmro(object))
767        if len(mro) > 2:
768            hr.maybe()
769            push('<dl><dt>Method resolution order:</dt>\n')
770            for base in mro:
771                push('<dd>%s</dd>\n' % self.classlink(base,
772                                                      object.__module__))
773            push('</dl>\n')
774
775        def spill(msg, attrs, predicate):
776            ok, attrs = _split_list(attrs, predicate)
777            if ok:
778                hr.maybe()
779                push(msg)
780                for name, kind, homecls, value in ok:
781                    try:
782                        value = getattr(object, name)
783                    except Exception:
784                        # Some descriptors may meet a failure in their __get__.
785                        # (bug #1785)
786                        push(self._docdescriptor(name, value, mod))
787                    else:
788                        push(self.document(value, name, mod,
789                                        funcs, classes, mdict, object))
790                    push('\n')
791            return attrs
792
793        def spilldescriptors(msg, attrs, predicate):
794            ok, attrs = _split_list(attrs, predicate)
795            if ok:
796                hr.maybe()
797                push(msg)
798                for name, kind, homecls, value in ok:
799                    push(self._docdescriptor(name, value, mod))
800            return attrs
801
802        def spilldata(msg, attrs, predicate):
803            ok, attrs = _split_list(attrs, predicate)
804            if ok:
805                hr.maybe()
806                push(msg)
807                for name, kind, homecls, value in ok:
808                    base = self.docother(getattr(object, name), name, mod)
809                    if (hasattr(value, '__call__') or
810                            inspect.isdatadescriptor(value)):
811                        doc = getattr(value, "__doc__", None)
812                    else:
813                        doc = None
814                    if doc is None:
815                        push('<dl><dt>%s</dl>\n' % base)
816                    else:
817                        doc = self.markup(getdoc(value), self.preformat,
818                                          funcs, classes, mdict)
819                        doc = '<dd><tt>%s</tt>' % doc
820                        push('<dl><dt>%s%s</dl>\n' % (base, doc))
821                    push('\n')
822            return attrs
823
824        attrs = filter(lambda data: visiblename(data[0], obj=object),
825                       classify_class_attrs(object))
826        mdict = {}
827        for key, kind, homecls, value in attrs:
828            mdict[key] = anchor = '#' + name + '-' + key
829            try:
830                value = getattr(object, name)
831            except Exception:
832                # Some descriptors may meet a failure in their __get__.
833                # (bug #1785)
834                pass
835            try:
836                # The value may not be hashable (e.g., a data attr with
837                # a dict or list value).
838                mdict[value] = anchor
839            except TypeError:
840                pass
841
842        while attrs:
843            if mro:
844                thisclass = mro.popleft()
845            else:
846                thisclass = attrs[0][2]
847            attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
848
849            if thisclass is __builtin__.object:
850                attrs = inherited
851                continue
852            elif thisclass is object:
853                tag = 'defined here'
854            else:
855                tag = 'inherited from %s' % self.classlink(thisclass,
856                                                           object.__module__)
857            tag += ':<br>\n'
858
859            # Sort attrs by name.
860            try:
861                attrs.sort(key=lambda t: t[0])
862            except TypeError:
863                attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))    # 2.3 compat
864
865            # Pump out the attrs, segregated by kind.
866            attrs = spill('Methods %s' % tag, attrs,
867                          lambda t: t[1] == 'method')
868            attrs = spill('Class methods %s' % tag, attrs,
869                          lambda t: t[1] == 'class method')
870            attrs = spill('Static methods %s' % tag, attrs,
871                          lambda t: t[1] == 'static method')
872            attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
873                                     lambda t: t[1] == 'data descriptor')
874            attrs = spilldata('Data and other attributes %s' % tag, attrs,
875                              lambda t: t[1] == 'data')
876            assert attrs == []
877            attrs = inherited
878
879        contents = ''.join(contents)
880
881        if name == realname:
882            title = '<a name="%s">class <strong>%s</strong></a>' % (
883                name, realname)
884        else:
885            title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
886                name, name, realname)
887        if bases:
888            parents = []
889            for base in bases:
890                parents.append(self.classlink(base, object.__module__))
891            title = title + '(%s)' % join(parents, ', ')
892        doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
893        doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
894
895        return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
896
897    def formatvalue(self, object):
898        """Format an argument default value as text."""
899        return self.grey('=' + self.repr(object))
900
901    def docroutine(self, object, name=None, mod=None,
902                   funcs={}, classes={}, methods={}, cl=None):
903        """Produce HTML documentation for a function or method object."""
904        realname = object.__name__
905        name = name or realname
906        anchor = (cl and cl.__name__ or '') + '-' + name
907        note = ''
908        skipdocs = 0
909        if inspect.ismethod(object):
910            imclass = object.im_class
911            if cl:
912                if imclass is not cl:
913                    note = ' from ' + self.classlink(imclass, mod)
914            else:
915                if object.im_self is not None:
916                    note = ' method of %s instance' % self.classlink(
917                        object.im_self.__class__, mod)
918                else:
919                    note = ' unbound %s method' % self.classlink(imclass,mod)
920            object = object.im_func
921
922        if name == realname:
923            title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
924        else:
925            if (cl and realname in cl.__dict__ and
926                cl.__dict__[realname] is object):
927                reallink = '<a href="#%s">%s</a>' % (
928                    cl.__name__ + '-' + realname, realname)
929                skipdocs = 1
930            else:
931                reallink = realname
932            title = '<a name="%s"><strong>%s</strong></a> = %s' % (
933                anchor, name, reallink)
934        if inspect.isfunction(object):
935            args, varargs, varkw, defaults = inspect.getargspec(object)
936            argspec = inspect.formatargspec(
937                args, varargs, varkw, defaults, formatvalue=self.formatvalue)
938            if realname == '<lambda>':
939                title = '<strong>%s</strong> <em>lambda</em> ' % name
940                argspec = argspec[1:-1] # remove parentheses
941        else:
942            argspec = '(...)'
943
944        decl = title + argspec + (note and self.grey(
945               '<font face="helvetica, arial">%s</font>' % note))
946
947        if skipdocs:
948            return '<dl><dt>%s</dt></dl>\n' % decl
949        else:
950            doc = self.markup(
951                getdoc(object), self.preformat, funcs, classes, methods)
952            doc = doc and '<dd><tt>%s</tt></dd>' % doc
953            return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
954
955    def _docdescriptor(self, name, value, mod):
956        results = []
957        push = results.append
958
959        if name:
960            push('<dl><dt><strong>%s</strong></dt>\n' % name)
961        if value.__doc__ is not None:
962            doc = self.markup(getdoc(value), self.preformat)
963            push('<dd><tt>%s</tt></dd>\n' % doc)
964        push('</dl>\n')
965
966        return ''.join(results)
967
968    def docproperty(self, object, name=None, mod=None, cl=None):
969        """Produce html documentation for a property."""
970        return self._docdescriptor(name, object, mod)
971
972    def docother(self, object, name=None, mod=None, *ignored):
973        """Produce HTML documentation for a data object."""
974        lhs = name and '<strong>%s</strong> = ' % name or ''
975        return lhs + self.repr(object)
976
977    def docdata(self, object, name=None, mod=None, cl=None):
978        """Produce html documentation for a data descriptor."""
979        return self._docdescriptor(name, object, mod)
980
981    def index(self, dir, shadowed=None):
982        """Generate an HTML index for a directory of modules."""
983        modpkgs = []
984        if shadowed is None: shadowed = {}
985        for importer, name, ispkg in pkgutil.iter_modules([dir]):
986            modpkgs.append((name, '', ispkg, name in shadowed))
987            shadowed[name] = 1
988
989        modpkgs.sort()
990        contents = self.multicolumn(modpkgs, self.modpkglink)
991        return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
992
993# -------------------------------------------- text documentation generator
994
995class TextRepr(Repr):
996    """Class for safely making a text representation of a Python object."""
997    def __init__(self):
998        Repr.__init__(self)
999        self.maxlist = self.maxtuple = 20
1000        self.maxdict = 10
1001        self.maxstring = self.maxother = 100
1002
1003    def repr1(self, x, level):
1004        if hasattr(type(x), '__name__'):
1005            methodname = 'repr_' + join(split(type(x).__name__), '_')
1006            if hasattr(self, methodname):
1007                return getattr(self, methodname)(x, level)
1008        return cram(stripid(repr(x)), self.maxother)
1009
1010    def repr_string(self, x, level):
1011        test = cram(x, self.maxstring)
1012        testrepr = repr(test)
1013        if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
1014            # Backslashes are only literal in the string and are never
1015            # needed to make any special characters, so show a raw string.
1016            return 'r' + testrepr[0] + test + testrepr[0]
1017        return testrepr
1018
1019    repr_str = repr_string
1020
1021    def repr_instance(self, x, level):
1022        try:
1023            return cram(stripid(repr(x)), self.maxstring)
1024        except:
1025            return '<%s instance>' % x.__class__.__name__
1026
1027class TextDoc(Doc):
1028    """Formatter class for text documentation."""
1029
1030    # ------------------------------------------- text formatting utilities
1031
1032    _repr_instance = TextRepr()
1033    repr = _repr_instance.repr
1034
1035    def bold(self, text):
1036        """Format a string in bold by overstriking."""
1037        return join(map(lambda ch: ch + '\b' + ch, text), '')
1038
1039    def indent(self, text, prefix='    '):
1040        """Indent text by prepending a given prefix to each line."""
1041        if not text: return ''
1042        lines = split(text, '\n')
1043        lines = map(lambda line, prefix=prefix: prefix + line, lines)
1044        if lines: lines[-1] = rstrip(lines[-1])
1045        return join(lines, '\n')
1046
1047    def section(self, title, contents):
1048        """Format a section with a given heading."""
1049        return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
1050
1051    # ---------------------------------------------- type-specific routines
1052
1053    def formattree(self, tree, modname, parent=None, prefix=''):
1054        """Render in text a class tree as returned by inspect.getclasstree()."""
1055        result = ''
1056        for entry in tree:
1057            if type(entry) is type(()):
1058                c, bases = entry
1059                result = result + prefix + classname(c, modname)
1060                if bases and bases != (parent,):
1061                    parents = map(lambda c, m=modname: classname(c, m), bases)
1062                    result = result + '(%s)' % join(parents, ', ')
1063                result = result + '\n'
1064            elif type(entry) is type([]):
1065                result = result + self.formattree(
1066                    entry, modname, c, prefix + '    ')
1067        return result
1068
1069    def docmodule(self, object, name=None, mod=None):
1070        """Produce text documentation for a given module object."""
1071        name = object.__name__ # ignore the passed-in name
1072        synop, desc = splitdoc(getdoc(object))
1073        result = self.section('NAME', name + (synop and ' - ' + synop))
1074
1075        try:
1076            all = object.__all__
1077        except AttributeError:
1078            all = None
1079
1080        try:
1081            file = inspect.getabsfile(object)
1082        except TypeError:
1083            file = '(built-in)'
1084        result = result + self.section('FILE', file)
1085
1086        docloc = self.getdocloc(object)
1087        if docloc is not None:
1088            result = result + self.section('MODULE DOCS', docloc)
1089
1090        if desc:
1091            result = result + self.section('DESCRIPTION', desc)
1092
1093        classes = []
1094        for key, value in inspect.getmembers(object, inspect.isclass):
1095            # if __all__ exists, believe it.  Otherwise use old heuristic.
1096            if (all is not None
1097                or (inspect.getmodule(value) or object) is object):
1098                if visiblename(key, all, object):
1099                    classes.append((key, value))
1100        funcs = []
1101        for key, value in inspect.getmembers(object, inspect.isroutine):
1102            # if __all__ exists, believe it.  Otherwise use old heuristic.
1103            if (all is not None or
1104                inspect.isbuiltin(value) or inspect.getmodule(value) is object):
1105                if visiblename(key, all, object):
1106                    funcs.append((key, value))
1107        data = []
1108        for key, value in inspect.getmembers(object, isdata):
1109            if visiblename(key, all, object):
1110                data.append((key, value))
1111
1112        modpkgs = []
1113        modpkgs_names = set()
1114        if hasattr(object, '__path__'):
1115            for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
1116                modpkgs_names.add(modname)
1117                if ispkg:
1118                    modpkgs.append(modname + ' (package)')
1119                else:
1120                    modpkgs.append(modname)
1121
1122            modpkgs.sort()
1123            result = result + self.section(
1124                'PACKAGE CONTENTS', join(modpkgs, '\n'))
1125
1126        # Detect submodules as sometimes created by C extensions
1127        submodules = []
1128        for key, value in inspect.getmembers(object, inspect.ismodule):
1129            if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1130                submodules.append(key)
1131        if submodules:
1132            submodules.sort()
1133            result = result + self.section(
1134                'SUBMODULES', join(submodules, '\n'))
1135
1136        if classes:
1137            classlist = map(lambda key_value: key_value[1], classes)
1138            contents = [self.formattree(
1139                inspect.getclasstree(classlist, 1), name)]
1140            for key, value in classes:
1141                contents.append(self.document(value, key, name))
1142            result = result + self.section('CLASSES', join(contents, '\n'))
1143
1144        if funcs:
1145            contents = []
1146            for key, value in funcs:
1147                contents.append(self.document(value, key, name))
1148            result = result + self.section('FUNCTIONS', join(contents, '\n'))
1149
1150        if data:
1151            contents = []
1152            for key, value in data:
1153                contents.append(self.docother(value, key, name, maxlen=70))
1154            result = result + self.section('DATA', join(contents, '\n'))
1155
1156        if hasattr(object, '__version__'):
1157            version = _binstr(object.__version__)
1158            if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1159                version = strip(version[11:-1])
1160            result = result + self.section('VERSION', version)
1161        if hasattr(object, '__date__'):
1162            result = result + self.section('DATE', _binstr(object.__date__))
1163        if hasattr(object, '__author__'):
1164            result = result + self.section('AUTHOR', _binstr(object.__author__))
1165        if hasattr(object, '__credits__'):
1166            result = result + self.section('CREDITS', _binstr(object.__credits__))
1167        return result
1168
1169    def docclass(self, object, name=None, mod=None, *ignored):
1170        """Produce text documentation for a given class object."""
1171        realname = object.__name__
1172        name = name or realname
1173        bases = object.__bases__
1174
1175        def makename(c, m=object.__module__):
1176            return classname(c, m)
1177
1178        if name == realname:
1179            title = 'class ' + self.bold(realname)
1180        else:
1181            title = self.bold(name) + ' = class ' + realname
1182        if bases:
1183            parents = map(makename, bases)
1184            title = title + '(%s)' % join(parents, ', ')
1185
1186        doc = getdoc(object)
1187        contents = doc and [doc + '\n'] or []
1188        push = contents.append
1189
1190        # List the mro, if non-trivial.
1191        mro = deque(inspect.getmro(object))
1192        if len(mro) > 2:
1193            push("Method resolution order:")
1194            for base in mro:
1195                push('    ' + makename(base))
1196            push('')
1197
1198        # Cute little class to pump out a horizontal rule between sections.
1199        class HorizontalRule:
1200            def __init__(self):
1201                self.needone = 0
1202            def maybe(self):
1203                if self.needone:
1204                    push('-' * 70)
1205                self.needone = 1
1206        hr = HorizontalRule()
1207
1208        def spill(msg, attrs, predicate):
1209            ok, attrs = _split_list(attrs, predicate)
1210            if ok:
1211                hr.maybe()
1212                push(msg)
1213                for name, kind, homecls, value in ok:
1214                    try:
1215                        value = getattr(object, name)
1216                    except Exception:
1217                        # Some descriptors may meet a failure in their __get__.
1218                        # (bug #1785)
1219                        push(self._docdescriptor(name, value, mod))
1220                    else:
1221                        push(self.document(value,
1222                                        name, mod, object))
1223            return attrs
1224
1225        def spilldescriptors(msg, attrs, predicate):
1226            ok, attrs = _split_list(attrs, predicate)
1227            if ok:
1228                hr.maybe()
1229                push(msg)
1230                for name, kind, homecls, value in ok:
1231                    push(self._docdescriptor(name, value, mod))
1232            return attrs
1233
1234        def spilldata(msg, attrs, predicate):
1235            ok, attrs = _split_list(attrs, predicate)
1236            if ok:
1237                hr.maybe()
1238                push(msg)
1239                for name, kind, homecls, value in ok:
1240                    if (hasattr(value, '__call__') or
1241                            inspect.isdatadescriptor(value)):
1242                        doc = getdoc(value)
1243                    else:
1244                        doc = None
1245                    push(self.docother(getattr(object, name),
1246                                       name, mod, maxlen=70, doc=doc) + '\n')
1247            return attrs
1248
1249        attrs = filter(lambda data: visiblename(data[0], obj=object),
1250                       classify_class_attrs(object))
1251        while attrs:
1252            if mro:
1253                thisclass = mro.popleft()
1254            else:
1255                thisclass = attrs[0][2]
1256            attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1257
1258            if thisclass is __builtin__.object:
1259                attrs = inherited
1260                continue
1261            elif thisclass is object:
1262                tag = "defined here"
1263            else:
1264                tag = "inherited from %s" % classname(thisclass,
1265                                                      object.__module__)
1266
1267            # Sort attrs by name.
1268            attrs.sort()
1269
1270            # Pump out the attrs, segregated by kind.
1271            attrs = spill("Methods %s:\n" % tag, attrs,
1272                          lambda t: t[1] == 'method')
1273            attrs = spill("Class methods %s:\n" % tag, attrs,
1274                          lambda t: t[1] == 'class method')
1275            attrs = spill("Static methods %s:\n" % tag, attrs,
1276                          lambda t: t[1] == 'static method')
1277            attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1278                                     lambda t: t[1] == 'data descriptor')
1279            attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1280                              lambda t: t[1] == 'data')
1281            assert attrs == []
1282            attrs = inherited
1283
1284        contents = '\n'.join(contents)
1285        if not contents:
1286            return title + '\n'
1287        return title + '\n' + self.indent(rstrip(contents), ' |  ') + '\n'
1288
1289    def formatvalue(self, object):
1290        """Format an argument default value as text."""
1291        return '=' + self.repr(object)
1292
1293    def docroutine(self, object, name=None, mod=None, cl=None):
1294        """Produce text documentation for a function or method object."""
1295        realname = object.__name__
1296        name = name or realname
1297        note = ''
1298        skipdocs = 0
1299        if inspect.ismethod(object):
1300            imclass = object.im_class
1301            if cl:
1302                if imclass is not cl:
1303                    note = ' from ' + classname(imclass, mod)
1304            else:
1305                if object.im_self is not None:
1306                    note = ' method of %s instance' % classname(
1307                        object.im_self.__class__, mod)
1308                else:
1309                    note = ' unbound %s method' % classname(imclass,mod)
1310            object = object.im_func
1311
1312        if name == realname:
1313            title = self.bold(realname)
1314        else:
1315            if (cl and realname in cl.__dict__ and
1316                cl.__dict__[realname] is object):
1317                skipdocs = 1
1318            title = self.bold(name) + ' = ' + realname
1319        if inspect.isfunction(object):
1320            args, varargs, varkw, defaults = inspect.getargspec(object)
1321            argspec = inspect.formatargspec(
1322                args, varargs, varkw, defaults, formatvalue=self.formatvalue)
1323            if realname == '<lambda>':
1324                title = self.bold(name) + ' lambda '
1325                argspec = argspec[1:-1] # remove parentheses
1326        else:
1327            argspec = '(...)'
1328        decl = title + argspec + note
1329
1330        if skipdocs:
1331            return decl + '\n'
1332        else:
1333            doc = getdoc(object) or ''
1334            return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
1335
1336    def _docdescriptor(self, name, value, mod):
1337        results = []
1338        push = results.append
1339
1340        if name:
1341            push(self.bold(name))
1342            push('\n')
1343        doc = getdoc(value) or ''
1344        if doc:
1345            push(self.indent(doc))
1346            push('\n')
1347        return ''.join(results)
1348
1349    def docproperty(self, object, name=None, mod=None, cl=None):
1350        """Produce text documentation for a property."""
1351        return self._docdescriptor(name, object, mod)
1352
1353    def docdata(self, object, name=None, mod=None, cl=None):
1354        """Produce text documentation for a data descriptor."""
1355        return self._docdescriptor(name, object, mod)
1356
1357    def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
1358        """Produce text documentation for a data object."""
1359        repr = self.repr(object)
1360        if maxlen:
1361            line = (name and name + ' = ' or '') + repr
1362            chop = maxlen - len(line)
1363            if chop < 0: repr = repr[:chop] + '...'
1364        line = (name and self.bold(name) + ' = ' or '') + repr
1365        if doc is not None:
1366            line += '\n' + self.indent(str(doc))
1367        return line
1368
1369# --------------------------------------------------------- user interfaces
1370
1371def pager(text):
1372    """The first time this is called, determine what kind of pager to use."""
1373    global pager
1374    pager = getpager()
1375    pager(text)
1376
1377def getpager():
1378    """Decide what method to use for paging through text."""
1379    if type(sys.stdout) is not types.FileType:
1380        return plainpager
1381    if not hasattr(sys.stdin, "isatty"):
1382        return plainpager
1383    if not sys.stdin.isatty() or not sys.stdout.isatty():
1384        return plainpager
1385    if 'PAGER' in os.environ:
1386        if sys.platform == 'win32': # pipes completely broken in Windows
1387            return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1388        elif os.environ.get('TERM') in ('dumb', 'emacs'):
1389            return lambda text: pipepager(plain(text), os.environ['PAGER'])
1390        else:
1391            return lambda text: pipepager(text, os.environ['PAGER'])
1392    if os.environ.get('TERM') in ('dumb', 'emacs'):
1393        return plainpager
1394    if sys.platform == 'win32' or sys.platform.startswith('os2'):
1395        return lambda text: tempfilepager(plain(text), 'more <')
1396    if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
1397        return lambda text: pipepager(text, 'less')
1398
1399    import tempfile
1400    (fd, filename) = tempfile.mkstemp()
1401    os.close(fd)
1402    try:
1403        if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
1404            return lambda text: pipepager(text, 'more')
1405        else:
1406            return ttypager
1407    finally:
1408        os.unlink(filename)
1409
1410def plain(text):
1411    """Remove boldface formatting from text."""
1412    return re.sub('.\b', '', text)
1413
1414def pipepager(text, cmd):
1415    """Page through text by feeding it to another program."""
1416    pipe = os.popen(cmd, 'w')
1417    try:
1418        pipe.write(_encode(text))
1419        pipe.close()
1420    except IOError:
1421        pass # Ignore broken pipes caused by quitting the pager program.
1422
1423def tempfilepager(text, cmd):
1424    """Page through text by invoking a program on a temporary file."""
1425    import tempfile
1426    filename = tempfile.mktemp()
1427    file = open(filename, 'w')
1428    file.write(_encode(text))
1429    file.close()
1430    try:
1431        os.system(cmd + ' "' + filename + '"')
1432    finally:
1433        os.unlink(filename)
1434
1435def ttypager(text):
1436    """Page through text on a text terminal."""
1437    lines = plain(_encode(plain(text), getattr(sys.stdout, 'encoding', _encoding))).split('\n')
1438    try:
1439        import tty
1440        fd = sys.stdin.fileno()
1441        old = tty.tcgetattr(fd)
1442        tty.setcbreak(fd)
1443        getchar = lambda: sys.stdin.read(1)
1444    except (ImportError, AttributeError):
1445        tty = None
1446        getchar = lambda: sys.stdin.readline()[:-1][:1]
1447
1448    try:
1449        try:
1450            h = int(os.environ.get('LINES', 0))
1451        except ValueError:
1452            h = 0
1453        if h <= 1:
1454            h = 25
1455        r = inc = h - 1
1456        sys.stdout.write(join(lines[:inc], '\n') + '\n')
1457        while lines[r:]:
1458            sys.stdout.write('-- more --')
1459            sys.stdout.flush()
1460            c = getchar()
1461
1462            if c in ('q', 'Q'):
1463                sys.stdout.write('\r          \r')
1464                break
1465            elif c in ('\r', '\n'):
1466                sys.stdout.write('\r          \r' + lines[r] + '\n')
1467                r = r + 1
1468                continue
1469            if c in ('b', 'B', '\x1b'):
1470                r = r - inc - inc
1471                if r < 0: r = 0
1472            sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1473            r = r + inc
1474
1475    finally:
1476        if tty:
1477            tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1478
1479def plainpager(text):
1480    """Simply print unformatted text.  This is the ultimate fallback."""
1481    sys.stdout.write(_encode(plain(text), getattr(sys.stdout, 'encoding', _encoding)))
1482
1483def describe(thing):
1484    """Produce a short description of the given thing."""
1485    if inspect.ismodule(thing):
1486        if thing.__name__ in sys.builtin_module_names:
1487            return 'built-in module ' + thing.__name__
1488        if hasattr(thing, '__path__'):
1489            return 'package ' + thing.__name__
1490        else:
1491            return 'module ' + thing.__name__
1492    if inspect.isbuiltin(thing):
1493        return 'built-in function ' + thing.__name__
1494    if inspect.isgetsetdescriptor(thing):
1495        return 'getset descriptor %s.%s.%s' % (
1496            thing.__objclass__.__module__, thing.__objclass__.__name__,
1497            thing.__name__)
1498    if inspect.ismemberdescriptor(thing):
1499        return 'member descriptor %s.%s.%s' % (
1500            thing.__objclass__.__module__, thing.__objclass__.__name__,
1501            thing.__name__)
1502    if inspect.isclass(thing):
1503        return 'class ' + thing.__name__
1504    if inspect.isfunction(thing):
1505        return 'function ' + thing.__name__
1506    if inspect.ismethod(thing):
1507        return 'method ' + thing.__name__
1508    if type(thing) is types.InstanceType:
1509        return 'instance of ' + thing.__class__.__name__
1510    return type(thing).__name__
1511
1512def locate(path, forceload=0):
1513    """Locate an object by name or dotted path, importing as necessary."""
1514    parts = [part for part in split(path, '.') if part]
1515    module, n = None, 0
1516    while n < len(parts):
1517        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
1518        if nextmodule: module, n = nextmodule, n + 1
1519        else: break
1520    if module:
1521        object = module
1522    else:
1523        object = __builtin__
1524    for part in parts[n:]:
1525        try:
1526            object = getattr(object, part)
1527        except AttributeError:
1528            return None
1529    return object
1530
1531# --------------------------------------- interactive interpreter interface
1532
1533text = TextDoc()
1534html = HTMLDoc()
1535
1536class _OldStyleClass: pass
1537_OLD_INSTANCE_TYPE = type(_OldStyleClass())
1538
1539def resolve(thing, forceload=0):
1540    """Given an object or a path to an object, get the object and its name."""
1541    if isinstance(thing, str):
1542        object = locate(thing, forceload)
1543        if object is None:
1544            raise ImportError, 'no Python documentation found for %r' % thing
1545        return object, thing
1546    else:
1547        name = getattr(thing, '__name__', None)
1548        return thing, name if isinstance(name, str) else None
1549
1550def render_doc(thing, title='Python Library Documentation: %s', forceload=0):
1551    """Render text documentation, given an object or a path to an object."""
1552    object, name = resolve(thing, forceload)
1553    desc = describe(object)
1554    module = inspect.getmodule(object)
1555    if name and '.' in name:
1556        desc += ' in ' + name[:name.rfind('.')]
1557    elif module and module is not object:
1558        desc += ' in module ' + module.__name__
1559    if type(object) is _OLD_INSTANCE_TYPE:
1560        # If the passed object is an instance of an old-style class,
1561        # document its available methods instead of its value.
1562        object = object.__class__
1563    elif not (inspect.ismodule(object) or
1564              inspect.isclass(object) or
1565              inspect.isroutine(object) or
1566              inspect.isgetsetdescriptor(object) or
1567              inspect.ismemberdescriptor(object) or
1568              isinstance(object, property)):
1569        # If the passed object is a piece of data or an instance,
1570        # document its available methods instead of its value.
1571        object = type(object)
1572        desc += ' object'
1573    return title % desc + '\n\n' + text.document(object, name)
1574
1575def doc(thing, title='Python Library Documentation: %s', forceload=0):
1576    """Display text documentation, given an object or a path to an object."""
1577    try:
1578        pager(render_doc(thing, title, forceload))
1579    except (ImportError, ErrorDuringImport), value:
1580        print value
1581
1582def writedoc(thing, forceload=0):
1583    """Write HTML documentation to a file in the current directory."""
1584    try:
1585        object, name = resolve(thing, forceload)
1586        page = html.page(describe(object), html.document(object, name))
1587        file = open(name + '.html', 'w')
1588        file.write(page)
1589        file.close()
1590        print 'wrote', name + '.html'
1591    except (ImportError, ErrorDuringImport), value:
1592        print value
1593
1594def writedocs(dir, pkgpath='', done=None):
1595    """Write out HTML documentation for all modules in a directory tree."""
1596    if done is None: done = {}
1597    for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1598        writedoc(modname)
1599    return
1600
1601class Helper:
1602
1603    # These dictionaries map a topic name to either an alias, or a tuple
1604    # (label, seealso-items).  The "label" is the label of the corresponding
1605    # section in the .rst file under Doc/ and an index into the dictionary
1606    # in pydoc_data/topics.py.
1607    #
1608    # CAUTION: if you change one of these dictionaries, be sure to adapt the
1609    #          list of needed labels in Doc/tools/pyspecific.py and
1610    #          regenerate the pydoc_data/topics.py file by running
1611    #              make pydoc-topics
1612    #          in Doc/ and copying the output file into the Lib/ directory.
1613
1614    keywords = {
1615        'and': 'BOOLEAN',
1616        'as': 'with',
1617        'assert': ('assert', ''),
1618        'break': ('break', 'while for'),
1619        'class': ('class', 'CLASSES SPECIALMETHODS'),
1620        'continue': ('continue', 'while for'),
1621        'def': ('function', ''),
1622        'del': ('del', 'BASICMETHODS'),
1623        'elif': 'if',
1624        'else': ('else', 'while for'),
1625        'except': 'try',
1626        'exec': ('exec', ''),
1627        'finally': 'try',
1628        'for': ('for', 'break continue while'),
1629        'from': 'import',
1630        'global': ('global', 'NAMESPACES'),
1631        'if': ('if', 'TRUTHVALUE'),
1632        'import': ('import', 'MODULES'),
1633        'in': ('in', 'SEQUENCEMETHODS2'),
1634        'is': 'COMPARISON',
1635        'lambda': ('lambda', 'FUNCTIONS'),
1636        'not': 'BOOLEAN',
1637        'or': 'BOOLEAN',
1638        'pass': ('pass', ''),
1639        'print': ('print', ''),
1640        'raise': ('raise', 'EXCEPTIONS'),
1641        'return': ('return', 'FUNCTIONS'),
1642        'try': ('try', 'EXCEPTIONS'),
1643        'while': ('while', 'break continue if TRUTHVALUE'),
1644        'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1645        'yield': ('yield', ''),
1646    }
1647    # Either add symbols to this dictionary or to the symbols dictionary
1648    # directly: Whichever is easier. They are merged later.
1649    _symbols_inverse = {
1650        'STRINGS' : ("'", "'''", "r'", "u'", '"""', '"', 'r"', 'u"'),
1651        'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1652                       '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1653        'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1654        'UNARY' : ('-', '~'),
1655        'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1656                                '^=', '<<=', '>>=', '**=', '//='),
1657        'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1658        'COMPLEX' : ('j', 'J')
1659    }
1660    symbols = {
1661        '%': 'OPERATORS FORMATTING',
1662        '**': 'POWER',
1663        ',': 'TUPLES LISTS FUNCTIONS',
1664        '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1665        '...': 'ELLIPSIS',
1666        ':': 'SLICINGS DICTIONARYLITERALS',
1667        '@': 'def class',
1668        '\\': 'STRINGS',
1669        '_': 'PRIVATENAMES',
1670        '__': 'PRIVATENAMES SPECIALMETHODS',
1671        '`': 'BACKQUOTES',
1672        '(': 'TUPLES FUNCTIONS CALLS',
1673        ')': 'TUPLES FUNCTIONS CALLS',
1674        '[': 'LISTS SUBSCRIPTS SLICINGS',
1675        ']': 'LISTS SUBSCRIPTS SLICINGS'
1676    }
1677    for topic, symbols_ in _symbols_inverse.iteritems():
1678        for symbol in symbols_:
1679            topics = symbols.get(symbol, topic)
1680            if topic not in topics:
1681                topics = topics + ' ' + topic
1682            symbols[symbol] = topics
1683
1684    topics = {
1685        'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1686                  'FUNCTIONS CLASSES MODULES FILES inspect'),
1687        'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING '
1688                    'TYPES'),
1689        'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1690        'FORMATTING': ('formatstrings', 'OPERATORS'),
1691        'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1692                    'FORMATTING TYPES'),
1693        'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1694        'INTEGER': ('integers', 'int range'),
1695        'FLOAT': ('floating', 'float math'),
1696        'COMPLEX': ('imaginary', 'complex cmath'),
1697        'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1698        'MAPPINGS': 'DICTIONARIES',
1699        'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1700        'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1701        'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1702        'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
1703        'FRAMEOBJECTS': 'TYPES',
1704        'TRACEBACKS': 'TYPES',
1705        'NONE': ('bltin-null-object', ''),
1706        'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
1707        'FILES': ('bltin-file-objects', ''),
1708        'SPECIALATTRIBUTES': ('specialattrs', ''),
1709        'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1710        'MODULES': ('typesmodules', 'import'),
1711        'PACKAGES': 'import',
1712        'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1713                        'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1714                        'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1715                        'LISTS DICTIONARIES BACKQUOTES'),
1716        'OPERATORS': 'EXPRESSIONS',
1717        'PRECEDENCE': 'EXPRESSIONS',
1718        'OBJECTS': ('objects', 'TYPES'),
1719        'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
1720                           'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS '
1721                           'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1722        'BASICMETHODS': ('customization', 'cmp hash repr str SPECIALMETHODS'),
1723        'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1724        'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
1725        'SEQUENCEMETHODS1': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 '
1726                             'SPECIALMETHODS'),
1727        'SEQUENCEMETHODS2': ('sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 '
1728                             'SPECIALMETHODS'),
1729        'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1730        'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1731                          'SPECIALMETHODS'),
1732        'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1733        'NAMESPACES': ('naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1734        'DYNAMICFEATURES': ('dynamic-features', ''),
1735        'SCOPING': 'NAMESPACES',
1736        'FRAMES': 'NAMESPACES',
1737        'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1738        'COERCIONS': ('coercion-rules','CONVERSIONS'),
1739        'CONVERSIONS': ('conversions', 'COERCIONS'),
1740        'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1741        'SPECIALIDENTIFIERS': ('id-classes', ''),
1742        'PRIVATENAMES': ('atom-identifiers', ''),
1743        'LITERALS': ('atom-literals', 'STRINGS BACKQUOTES NUMBERS '
1744                     'TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1745        'TUPLES': 'SEQUENCES',
1746        'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1747        'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1748        'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1749        'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1750        'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1751        'BACKQUOTES': ('string-conversions', 'repr str STRINGS LITERALS'),
1752        'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr '
1753                       'ATTRIBUTEMETHODS'),
1754        'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS1'),
1755        'SLICINGS': ('slicings', 'SEQUENCEMETHODS2'),
1756        'CALLS': ('calls', 'EXPRESSIONS'),
1757        'POWER': ('power', 'EXPRESSIONS'),
1758        'UNARY': ('unary', 'EXPRESSIONS'),
1759        'BINARY': ('binary', 'EXPRESSIONS'),
1760        'SHIFTING': ('shifting', 'EXPRESSIONS'),
1761        'BITWISE': ('bitwise', 'EXPRESSIONS'),
1762        'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1763        'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
1764        'ASSERTION': 'assert',
1765        'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1766        'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
1767        'DELETION': 'del',
1768        'PRINTING': 'print',
1769        'RETURNING': 'return',
1770        'IMPORTING': 'import',
1771        'CONDITIONAL': 'if',
1772        'LOOPING': ('compound', 'for while break continue'),
1773        'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1774        'DEBUGGING': ('debugger', 'pdb'),
1775        'CONTEXTMANAGERS': ('context-managers', 'with'),
1776    }
1777
1778    def __init__(self, input=None, output=None):
1779        self._input = input
1780        self._output = output
1781
1782    input  = property(lambda self: self._input or sys.stdin)
1783    output = property(lambda self: self._output or sys.stdout)
1784
1785    def __repr__(self):
1786        if inspect.stack()[1][3] == '?':
1787            self()
1788            return ''
1789        return '<pydoc.Helper instance>'
1790
1791    _GoInteractive = object()
1792    def __call__(self, request=_GoInteractive):
1793        if request is not self._GoInteractive:
1794            self.help(request)
1795        else:
1796            self.intro()
1797            self.interact()
1798            self.output.write('''
1799You are now leaving help and returning to the Python interpreter.
1800If you want to ask for help on a particular object directly from the
1801interpreter, you can type "help(object)".  Executing "help('string')"
1802has the same effect as typing a particular string at the help> prompt.
1803''')
1804
1805    def interact(self):
1806        self.output.write('\n')
1807        while True:
1808            try:
1809                request = self.getline('help> ')
1810                if not request: break
1811            except (KeyboardInterrupt, EOFError):
1812                break
1813            request = strip(replace(request, '"', '', "'", ''))
1814            if lower(request) in ('q', 'quit'): break
1815            self.help(request)
1816
1817    def getline(self, prompt):
1818        """Read one line, using raw_input when available."""
1819        if self.input is sys.stdin:
1820            return raw_input(prompt)
1821        else:
1822            self.output.write(prompt)
1823            self.output.flush()
1824            return self.input.readline()
1825
1826    def help(self, request):
1827        if type(request) is type(''):
1828            request = request.strip()
1829            if request == 'help': self.intro()
1830            elif request == 'keywords': self.listkeywords()
1831            elif request == 'symbols': self.listsymbols()
1832            elif request == 'topics': self.listtopics()
1833            elif request == 'modules': self.listmodules()
1834            elif request[:8] == 'modules ':
1835                self.listmodules(split(request)[1])
1836            elif request in self.symbols: self.showsymbol(request)
1837            elif request in self.keywords: self.showtopic(request)
1838            elif request in self.topics: self.showtopic(request)
1839            elif request: doc(request, 'Help on %s:')
1840        elif isinstance(request, Helper): self()
1841        else: doc(request, 'Help on %s:')
1842        self.output.write('\n')
1843
1844    def intro(self):
1845        self.output.write('''
1846Welcome to Python %s!  This is the online help utility.
1847
1848If this is your first time using Python, you should definitely check out
1849the tutorial on the Internet at http://docs.python.org/%s/tutorial/.
1850
1851Enter the name of any module, keyword, or topic to get help on writing
1852Python programs and using Python modules.  To quit this help utility and
1853return to the interpreter, just type "quit".
1854
1855To get a list of available modules, keywords, or topics, type "modules",
1856"keywords", or "topics".  Each module also comes with a one-line summary
1857of what it does; to list the modules whose summaries contain a given word
1858such as "spam", type "modules spam".
1859''' % tuple([sys.version[:3]]*2))
1860
1861    def list(self, items, columns=4, width=80):
1862        items = items[:]
1863        items.sort()
1864        colw = width / columns
1865        rows = (len(items) + columns - 1) / columns
1866        for row in range(rows):
1867            for col in range(columns):
1868                i = col * rows + row
1869                if i < len(items):
1870                    self.output.write(items[i])
1871                    if col < columns - 1:
1872                        self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1873            self.output.write('\n')
1874
1875    def listkeywords(self):
1876        self.output.write('''
1877Here is a list of the Python keywords.  Enter any keyword to get more help.
1878
1879''')
1880        self.list(self.keywords.keys())
1881
1882    def listsymbols(self):
1883        self.output.write('''
1884Here is a list of the punctuation symbols which Python assigns special meaning
1885to. Enter any symbol to get more help.
1886
1887''')
1888        self.list(self.symbols.keys())
1889
1890    def listtopics(self):
1891        self.output.write('''
1892Here is a list of available topics.  Enter any topic name to get more help.
1893
1894''')
1895        self.list(self.topics.keys())
1896
1897    def showtopic(self, topic, more_xrefs=''):
1898        try:
1899            import pydoc_data.topics
1900        except ImportError:
1901            self.output.write('''
1902Sorry, topic and keyword documentation is not available because the
1903module "pydoc_data.topics" could not be found.
1904''')
1905            return
1906        target = self.topics.get(topic, self.keywords.get(topic))
1907        if not target:
1908            self.output.write('no documentation found for %s\n' % repr(topic))
1909            return
1910        if type(target) is type(''):
1911            return self.showtopic(target, more_xrefs)
1912
1913        label, xrefs = target
1914        try:
1915            doc = pydoc_data.topics.topics[label]
1916        except KeyError:
1917            self.output.write('no documentation found for %s\n' % repr(topic))
1918            return
1919        pager(strip(doc) + '\n')
1920        if more_xrefs:
1921            xrefs = (xrefs or '') + ' ' + more_xrefs
1922        if xrefs:
1923            import StringIO, formatter
1924            buffer = StringIO.StringIO()
1925            formatter.DumbWriter(buffer).send_flowing_data(
1926                'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1927            self.output.write('\n%s\n' % buffer.getvalue())
1928
1929    def showsymbol(self, symbol):
1930        target = self.symbols[symbol]
1931        topic, _, xrefs = target.partition(' ')
1932        self.showtopic(topic, xrefs)
1933
1934    def listmodules(self, key=''):
1935        if key:
1936            self.output.write('''
1937Here is a list of matching modules.  Enter any module name to get more help.
1938
1939''')
1940            apropos(key)
1941        else:
1942            self.output.write('''
1943Please wait a moment while I gather a list of all available modules...
1944
1945''')
1946            modules = {}
1947            def callback(path, modname, desc, modules=modules):
1948                if modname and modname[-9:] == '.__init__':
1949                    modname = modname[:-9] + ' (package)'
1950                if find(modname, '.') < 0:
1951                    modules[modname] = 1
1952            def onerror(modname):
1953                callback(None, modname, None)
1954            ModuleScanner().run(callback, onerror=onerror)
1955            self.list(modules.keys())
1956            self.output.write('''
1957Enter any module name to get more help.  Or, type "modules spam" to search
1958for modules whose descriptions contain the word "spam".
1959''')
1960
1961help = Helper()
1962
1963class Scanner:
1964    """A generic tree iterator."""
1965    def __init__(self, roots, children, descendp):
1966        self.roots = roots[:]
1967        self.state = []
1968        self.children = children
1969        self.descendp = descendp
1970
1971    def next(self):
1972        if not self.state:
1973            if not self.roots:
1974                return None
1975            root = self.roots.pop(0)
1976            self.state = [(root, self.children(root))]
1977        node, children = self.state[-1]
1978        if not children:
1979            self.state.pop()
1980            return self.next()
1981        child = children.pop(0)
1982        if self.descendp(child):
1983            self.state.append((child, self.children(child)))
1984        return child
1985
1986
1987class ModuleScanner:
1988    """An interruptible scanner that searches module synopses."""
1989
1990    def run(self, callback, key=None, completer=None, onerror=None):
1991        if key: key = lower(key)
1992        self.quit = False
1993        seen = {}
1994
1995        for modname in sys.builtin_module_names:
1996            if modname != '__main__':
1997                seen[modname] = 1
1998                if key is None:
1999                    callback(None, modname, '')
2000                else:
2001                    desc = split(__import__(modname).__doc__ or '', '\n')[0]
2002                    if find(lower(modname + ' - ' + desc), key) >= 0:
2003                        callback(None, modname, desc)
2004
2005        for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
2006            if self.quit:
2007                break
2008            if key is None:
2009                callback(None, modname, '')
2010            else:
2011                loader = importer.find_module(modname)
2012                if hasattr(loader,'get_source'):
2013                    import StringIO
2014                    desc = source_synopsis(
2015                        StringIO.StringIO(loader.get_source(modname))
2016                    ) or ''
2017                    if hasattr(loader,'get_filename'):
2018                        path = loader.get_filename(modname)
2019                    else:
2020                        path = None
2021                else:
2022                    module = loader.load_module(modname)
2023                    desc = module.__doc__.splitlines()[0] if module.__doc__ else ''
2024                    path = getattr(module,'__file__',None)
2025                if find(lower(modname + ' - ' + desc), key) >= 0:
2026                    callback(path, modname, desc)
2027
2028        if completer:
2029            completer()
2030
2031def apropos(key):
2032    """Print all the one-line module summaries that contain a substring."""
2033    def callback(path, modname, desc):
2034        if modname[-9:] == '.__init__':
2035            modname = modname[:-9] + ' (package)'
2036        print modname, desc and '- ' + desc
2037    def onerror(modname):
2038        pass
2039    with warnings.catch_warnings():
2040        warnings.filterwarnings('ignore') # ignore problems during import
2041        ModuleScanner().run(callback, key, onerror=onerror)
2042
2043# --------------------------------------------------- web browser interface
2044
2045def serve(port, callback=None, completer=None):
2046    import BaseHTTPServer, mimetools, select
2047
2048    # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
2049    class Message(mimetools.Message):
2050        def __init__(self, fp, seekable=1):
2051            Message = self.__class__
2052            Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
2053            self.encodingheader = self.getheader('content-transfer-encoding')
2054            self.typeheader = self.getheader('content-type')
2055            self.parsetype()
2056            self.parseplist()
2057
2058    class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
2059        def send_document(self, title, contents):
2060            try:
2061                self.send_response(200)
2062                self.send_header('Content-Type', 'text/html')
2063                self.end_headers()
2064                self.wfile.write(html.page(title, contents))
2065            except IOError: pass
2066
2067        def do_GET(self):
2068            path = self.path
2069            if path[-5:] == '.html': path = path[:-5]
2070            if path[:1] == '/': path = path[1:]
2071            if path and path != '.':
2072                try:
2073                    obj = locate(path, forceload=1)
2074                except ErrorDuringImport, value:
2075                    self.send_document(path, html.escape(str(value)))
2076                    return
2077                if obj:
2078                    self.send_document(describe(obj), html.document(obj, path))
2079                else:
2080                    self.send_document(path,
2081'no Python documentation found for %s' % repr(path))
2082            else:
2083                heading = html.heading(
2084'<big><big><strong>Python: Index of Modules</strong></big></big>',
2085'#ffffff', '#7799ee')
2086                def bltinlink(name):
2087                    return '<a href="%s.html">%s</a>' % (name, name)
2088                names = filter(lambda x: x != '__main__',
2089                               sys.builtin_module_names)
2090                contents = html.multicolumn(names, bltinlink)
2091                indices = ['<p>' + html.bigsection(
2092                    'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2093
2094                seen = {}
2095                for dir in sys.path:
2096                    indices.append(html.index(dir, seen))
2097                contents = heading + join(indices) + '''<p align=right>
2098<font color="#909090" face="helvetica, arial"><strong>
2099pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
2100                self.send_document('Index of Modules', contents)
2101
2102        def log_message(self, *args): pass
2103
2104    class DocServer(BaseHTTPServer.HTTPServer):
2105        def __init__(self, port, callback):
2106            host = 'localhost'
2107            self.address = (host, port)
2108            self.callback = callback
2109            self.base.__init__(self, self.address, self.handler)
2110
2111        def serve_until_quit(self):
2112            import select
2113            self.quit = False
2114            while not self.quit:
2115                rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2116                if rd: self.handle_request()
2117
2118        def server_activate(self):
2119            self.base.server_activate(self)
2120            self.url = 'http://%s:%d/' % (self.address[0], self.server_port)
2121            if self.callback: self.callback(self)
2122
2123    DocServer.base = BaseHTTPServer.HTTPServer
2124    DocServer.handler = DocHandler
2125    DocHandler.MessageClass = Message
2126    try:
2127        try:
2128            DocServer(port, callback).serve_until_quit()
2129        except (KeyboardInterrupt, select.error):
2130            pass
2131    finally:
2132        if completer: completer()
2133
2134# ----------------------------------------------------- graphical interface
2135
2136def gui():
2137    """Graphical interface (starts web server and pops up a control window)."""
2138    class GUI:
2139        def __init__(self, window, port=7464):
2140            self.window = window
2141            self.server = None
2142            self.scanner = None
2143
2144            import Tkinter
2145            self.server_frm = Tkinter.Frame(window)
2146            self.title_lbl = Tkinter.Label(self.server_frm,
2147                text='Starting server...\n ')
2148            self.open_btn = Tkinter.Button(self.server_frm,
2149                text='open browser', command=self.open, state='disabled')
2150            self.quit_btn = Tkinter.Button(self.server_frm,
2151                text='quit serving', command=self.quit, state='disabled')
2152
2153            self.search_frm = Tkinter.Frame(window)
2154            self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
2155            self.search_ent = Tkinter.Entry(self.search_frm)
2156            self.search_ent.bind('<Return>', self.search)
2157            self.stop_btn = Tkinter.Button(self.search_frm,
2158                text='stop', pady=0, command=self.stop, state='disabled')
2159            if sys.platform == 'win32':
2160                # Trying to hide and show this button crashes under Windows.
2161                self.stop_btn.pack(side='right')
2162
2163            self.window.title('pydoc')
2164            self.window.protocol('WM_DELETE_WINDOW', self.quit)
2165            self.title_lbl.pack(side='top', fill='x')
2166            self.open_btn.pack(side='left', fill='x', expand=1)
2167            self.quit_btn.pack(side='right', fill='x', expand=1)
2168            self.server_frm.pack(side='top', fill='x')
2169
2170            self.search_lbl.pack(side='left')
2171            self.search_ent.pack(side='right', fill='x', expand=1)
2172            self.search_frm.pack(side='top', fill='x')
2173            self.search_ent.focus_set()
2174
2175            font = ('helvetica', sys.platform == 'win32' and 8 or 10)
2176            self.result_lst = Tkinter.Listbox(window, font=font, height=6)
2177            self.result_lst.bind('<Button-1>', self.select)
2178            self.result_lst.bind('<Double-Button-1>', self.goto)
2179            self.result_scr = Tkinter.Scrollbar(window,
2180                orient='vertical', command=self.result_lst.yview)
2181            self.result_lst.config(yscrollcommand=self.result_scr.set)
2182
2183            self.result_frm = Tkinter.Frame(window)
2184            self.goto_btn = Tkinter.Button(self.result_frm,
2185                text='go to selected', command=self.goto)
2186            self.hide_btn = Tkinter.Button(self.result_frm,
2187                text='hide results', command=self.hide)
2188            self.goto_btn.pack(side='left', fill='x', expand=1)
2189            self.hide_btn.pack(side='right', fill='x', expand=1)
2190
2191            self.window.update()
2192            self.minwidth = self.window.winfo_width()
2193            self.minheight = self.window.winfo_height()
2194            self.bigminheight = (self.server_frm.winfo_reqheight() +
2195                                 self.search_frm.winfo_reqheight() +
2196                                 self.result_lst.winfo_reqheight() +
2197                                 self.result_frm.winfo_reqheight())
2198            self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2199            self.expanded = 0
2200            self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2201            self.window.wm_minsize(self.minwidth, self.minheight)
2202            self.window.tk.willdispatch()
2203
2204            import threading
2205            threading.Thread(
2206                target=serve, args=(port, self.ready, self.quit)).start()
2207
2208        def ready(self, server):
2209            self.server = server
2210            self.title_lbl.config(
2211                text='Python documentation server at\n' + server.url)
2212            self.open_btn.config(state='normal')
2213            self.quit_btn.config(state='normal')
2214
2215        def open(self, event=None, url=None):
2216            url = url or self.server.url
2217            try:
2218                import webbrowser
2219                webbrowser.open(url)
2220            except ImportError: # pre-webbrowser.py compatibility
2221                if sys.platform == 'win32':
2222                    os.system('start "%s"' % url)
2223                else:
2224                    rc = os.system('netscape -remote "openURL(%s)" &' % url)
2225                    if rc: os.system('netscape "%s" &' % url)
2226
2227        def quit(self, event=None):
2228            if self.server:
2229                self.server.quit = 1
2230            self.window.quit()
2231
2232        def search(self, event=None):
2233            key = self.search_ent.get()
2234            self.stop_btn.pack(side='right')
2235            self.stop_btn.config(state='normal')
2236            self.search_lbl.config(text='Searching for "%s"...' % key)
2237            self.search_ent.forget()
2238            self.search_lbl.pack(side='left')
2239            self.result_lst.delete(0, 'end')
2240            self.goto_btn.config(state='disabled')
2241            self.expand()
2242
2243            import threading
2244            if self.scanner:
2245                self.scanner.quit = 1
2246            self.scanner = ModuleScanner()
2247            def onerror(modname):
2248                pass
2249            threading.Thread(target=self.scanner.run,
2250                             args=(self.update, key, self.done),
2251                             kwargs=dict(onerror=onerror)).start()
2252
2253        def update(self, path, modname, desc):
2254            if modname[-9:] == '.__init__':
2255                modname = modname[:-9] + ' (package)'
2256            self.result_lst.insert('end',
2257                modname + ' - ' + (desc or '(no description)'))
2258
2259        def stop(self, event=None):
2260            if self.scanner:
2261                self.scanner.quit = 1
2262                self.scanner = None
2263
2264        def done(self):
2265            self.scanner = None
2266            self.search_lbl.config(text='Search for')
2267            self.search_lbl.pack(side='left')
2268            self.search_ent.pack(side='right', fill='x', expand=1)
2269            if sys.platform != 'win32': self.stop_btn.forget()
2270            self.stop_btn.config(state='disabled')
2271
2272        def select(self, event=None):
2273            self.goto_btn.config(state='normal')
2274
2275        def goto(self, event=None):
2276            selection = self.result_lst.curselection()
2277            if selection:
2278                modname = split(self.result_lst.get(selection[0]))[0]
2279                self.open(url=self.server.url + modname + '.html')
2280
2281        def collapse(self):
2282            if not self.expanded: return
2283            self.result_frm.forget()
2284            self.result_scr.forget()
2285            self.result_lst.forget()
2286            self.bigwidth = self.window.winfo_width()
2287            self.bigheight = self.window.winfo_height()
2288            self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2289            self.window.wm_minsize(self.minwidth, self.minheight)
2290            self.expanded = 0
2291
2292        def expand(self):
2293            if self.expanded: return
2294            self.result_frm.pack(side='bottom', fill='x')
2295            self.result_scr.pack(side='right', fill='y')
2296            self.result_lst.pack(side='top', fill='both', expand=1)
2297            self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2298            self.window.wm_minsize(self.minwidth, self.bigminheight)
2299            self.expanded = 1
2300
2301        def hide(self, event=None):
2302            self.stop()
2303            self.collapse()
2304
2305    import Tkinter
2306    try:
2307        root = Tkinter.Tk()
2308        # Tk will crash if pythonw.exe has an XP .manifest
2309        # file and the root has is not destroyed explicitly.
2310        # If the problem is ever fixed in Tk, the explicit
2311        # destroy can go.
2312        try:
2313            gui = GUI(root)
2314            root.mainloop()
2315        finally:
2316            root.destroy()
2317    except KeyboardInterrupt:
2318        pass
2319
2320# -------------------------------------------------- command-line interface
2321
2322def ispath(x):
2323    return isinstance(x, str) and find(x, os.sep) >= 0
2324
2325def cli():
2326    """Command-line interface (looks at sys.argv to decide what to do)."""
2327    import getopt
2328    class BadUsage: pass
2329
2330    # Scripts don't get the current directory in their path by default
2331    # unless they are run with the '-m' switch
2332    if '' not in sys.path:
2333        scriptdir = os.path.dirname(sys.argv[0])
2334        if scriptdir in sys.path:
2335            sys.path.remove(scriptdir)
2336        sys.path.insert(0, '.')
2337
2338    try:
2339        opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
2340        writing = 0
2341
2342        for opt, val in opts:
2343            if opt == '-g':
2344                gui()
2345                return
2346            if opt == '-k':
2347                apropos(val)
2348                return
2349            if opt == '-p':
2350                try:
2351                    port = int(val)
2352                except ValueError:
2353                    raise BadUsage
2354                def ready(server):
2355                    print 'pydoc server ready at %s' % server.url
2356                def stopped():
2357                    print 'pydoc server stopped'
2358                serve(port, ready, stopped)
2359                return
2360            if opt == '-w':
2361                writing = 1
2362
2363        if not args: raise BadUsage
2364        for arg in args:
2365            if ispath(arg) and not os.path.exists(arg):
2366                print 'file %r does not exist' % arg
2367                break
2368            try:
2369                if ispath(arg) and os.path.isfile(arg):
2370                    arg = importfile(arg)
2371                if writing:
2372                    if ispath(arg) and os.path.isdir(arg):
2373                        writedocs(arg)
2374                    else:
2375                        writedoc(arg)
2376                else:
2377                    help.help(arg)
2378            except ErrorDuringImport, value:
2379                print value
2380
2381    except (getopt.error, BadUsage):
2382        cmd = os.path.basename(sys.argv[0])
2383        print """pydoc - the Python documentation tool
2384
2385%s <name> ...
2386    Show text documentation on something.  <name> may be the name of a
2387    Python keyword, topic, function, module, or package, or a dotted
2388    reference to a class or function within a module or module in a
2389    package.  If <name> contains a '%s', it is used as the path to a
2390    Python source file to document. If name is 'keywords', 'topics',
2391    or 'modules', a listing of these things is displayed.
2392
2393%s -k <keyword>
2394    Search for a keyword in the synopsis lines of all available modules.
2395
2396%s -p <port>
2397    Start an HTTP server on the given port on the local machine.  Port
2398    number 0 can be used to get an arbitrary unused port.
2399
2400%s -g
2401    Pop up a graphical interface for finding and serving documentation.
2402
2403%s -w <name> ...
2404    Write out the HTML documentation for a module to a file in the current
2405    directory.  If <name> contains a '%s', it is treated as a filename; if
2406    it names a directory, documentation is written for all the contents.
2407""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
2408
2409if __name__ == '__main__': cli()
Note: See TracBrowser for help on using the repository browser.