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