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