Home | History | Annotate | Download | only in Lib
      1 #!/usr/bin/env python

      2 # -*- coding: latin-1 -*-

      3 """Generate Python documentation in HTML or text for interactive use.
      4 
      5 In the Python interpreter, do "from pydoc import help" to provide online
      6 help.  Calling help(thing) on a Python object documents the object.
      7 
      8 Or, at the shell command line outside of Python:
      9 
     10 Run "pydoc <name>" to show documentation on something.  <name> may be
     11 the name of a function, module, package, or a dotted reference to a
     12 class or function within a module or module in a package.  If the
     13 argument contains a path segment delimiter (e.g. slash on Unix,
     14 backslash on Windows) it is treated as the path to a Python source file.
     15 
     16 Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
     17 of all available modules.
     18 
     19 Run "pydoc -p <port>" to start an HTTP server on a given port on the
     20 local machine to generate documentation web pages.
     21 
     22 For platforms without a command line, "pydoc -g" starts the HTTP server
     23 and also pops up a little window for controlling it.
     24 
     25 Run "pydoc -w <name>" to write out the HTML documentation for a module
     26 to a file named "<name>.html".
     27 
     28 Module docs for core modules are assumed to be in
     29 
     30     http://docs.python.org/library/
     31 
     32 This can be overridden by setting the PYTHONDOCS environment variable
     33 to a different URL or to a local directory containing the Library
     34 Reference Manual pages.
     35 """
     36 
     37 __author__ = "Ka-Ping Yee <ping (at] lfw.org>"
     38 __date__ = "26 February 2001"
     39 
     40 __version__ = "$Revision$"
     41 __credits__ = """Guido van Rossum, for an excellent programming language.
     42 Tommy Burnette, the original creator of manpy.
     43 Paul Prescod, for all his work on onlinehelp.
     44 Richard Chamberlain, for the first implementation of textdoc.
     45 """
     46 
     47 # Known bugs that can't be fixed here:

     48 #   - imp.load_module() cannot be prevented from clobbering existing

     49 #     loaded modules, so calling synopsis() on a binary module file

     50 #     changes the contents of any existing module with the same name.

     51 #   - If the __file__ attribute on a module is a relative path and

     52 #     the current directory is changed with os.chdir(), an incorrect

     53 #     path will be displayed.

     54 
     55 import sys, imp, os, re, types, inspect, __builtin__, pkgutil
     56 from repr import Repr
     57 from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
     58 from traceback import extract_tb
     59 try:
     60     from collections import deque
     61 except ImportError:
     62     # Python 2.3 compatibility

     63     class deque(list):
     64         def popleft(self):
     65             return self.pop(0)
     66 
     67 # --------------------------------------------------------- common routines

     68 
     69 def pathdirs():
     70     """Convert sys.path into a list of absolute, existing, unique paths."""
     71     dirs = []
     72     normdirs = []
     73     for dir in sys.path:
     74         dir = os.path.abspath(dir or '.')
     75         normdir = os.path.normcase(dir)
     76         if normdir not in normdirs and os.path.isdir(dir):
     77             dirs.append(dir)
     78             normdirs.append(normdir)
     79     return dirs
     80 
     81 def getdoc(object):
     82     """Get the doc string or comments for an object."""
     83     result = inspect.getdoc(object) or inspect.getcomments(object)
     84     return result and re.sub('^ *\n', '', rstrip(result)) or ''
     85 
     86 def splitdoc(doc):
     87     """Split a doc string into a synopsis line (if any) and the rest."""
     88     lines = split(strip(doc), '\n')
     89     if len(lines) == 1:
     90         return lines[0], ''
     91     elif len(lines) >= 2 and not rstrip(lines[1]):
     92         return lines[0], join(lines[2:], '\n')
     93     return '', join(lines, '\n')
     94 
     95 def classname(object, modname):
     96     """Get a class name and qualify it with a module name if necessary."""
     97     name = object.__name__
     98     if object.__module__ != modname:
     99         name = object.__module__ + '.' + name
    100     return name
    101 
    102 def isdata(object):
    103     """Check if an object is of a type that probably means it's data."""
    104     return not (inspect.ismodule(object) or inspect.isclass(object) or
    105                 inspect.isroutine(object) or inspect.isframe(object) or
    106                 inspect.istraceback(object) or inspect.iscode(object))
    107 
    108 def replace(text, *pairs):
    109     """Do a series of global replacements on a string."""
    110     while pairs:
    111         text = join(split(text, pairs[0]), pairs[1])
    112         pairs = pairs[2:]
    113     return text
    114 
    115 def cram(text, maxlen):
    116     """Omit part of a string if needed to make it fit in a maximum length."""
    117     if len(text) > maxlen:
    118         pre = max(0, (maxlen-3)//2)
    119         post = max(0, maxlen-3-pre)
    120         return text[:pre] + '...' + text[len(text)-post:]
    121     return text
    122 
    123 _re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
    124 def stripid(text):
    125     """Remove the hexadecimal id from a Python object representation."""
    126     # The behaviour of %p is implementation-dependent in terms of case.

    127     return _re_stripid.sub(r'\1', text)
    128 
    129 def _is_some_method(obj):
    130     return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
    131 
    132 def allmethods(cl):
    133     methods = {}
    134     for key, value in inspect.getmembers(cl, _is_some_method):
    135         methods[key] = 1
    136     for base in cl.__bases__:
    137         methods.update(allmethods(base)) # all your base are belong to us

    138     for key in methods.keys():
    139         methods[key] = getattr(cl, key)
    140     return methods
    141 
    142 def _split_list(s, predicate):
    143     """Split sequence s via predicate, and return pair ([true], [false]).
    144 
    145     The return value is a 2-tuple of lists,
    146         ([x for x in s if predicate(x)],
    147          [x for x in s if not predicate(x)])
    148     """
    149 
    150     yes = []
    151     no = []
    152     for x in s:
    153         if predicate(x):
    154             yes.append(x)
    155         else:
    156             no.append(x)
    157     return yes, no
    158 
    159 def visiblename(name, all=None, obj=None):
    160     """Decide whether to show documentation on a variable."""
    161     # Certain special names are redundant.

    162     _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__',
    163                      '__module__', '__name__', '__slots__', '__package__')
    164     if name in _hidden_names: return 0
    165     # Private names are hidden, but special names are displayed.

    166     if name.startswith('__') and name.endswith('__'): return 1
    167     # Namedtuples have public fields and methods with a single leading underscore

    168     if name.startswith('_') and hasattr(obj, '_fields'):
    169         return 1
    170     if all is not None:
    171         # only document that which the programmer exported in __all__

    172         return name in all
    173     else:
    174         return not name.startswith('_')
    175 
    176 def classify_class_attrs(object):
    177     """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
    178     def fixup(data):
    179         name, kind, cls, value = data
    180         if inspect.isdatadescriptor(value):
    181             kind = 'data descriptor'
    182         return name, kind, cls, value
    183     return map(fixup, inspect.classify_class_attrs(object))
    184 
    185 # ----------------------------------------------------- module manipulation

    186 
    187 def ispackage(path):
    188     """Guess whether a path refers to a package directory."""
    189     if os.path.isdir(path):
    190         for ext in ('.py', '.pyc', '.pyo'):
    191             if os.path.isfile(os.path.join(path, '__init__' + ext)):
    192                 return True
    193     return False
    194 
    195 def source_synopsis(file):
    196     line = file.readline()
    197     while line[:1] == '#' or not strip(line):
    198         line = file.readline()
    199         if not line: break
    200     line = strip(line)
    201     if line[:4] == 'r"""': line = line[1:]
    202     if line[:3] == '"""':
    203         line = line[3:]
    204         if line[-1:] == '\\': line = line[:-1]
    205         while not strip(line):
    206             line = file.readline()
    207             if not line: break
    208         result = strip(split(line, '"""')[0])
    209     else: result = None
    210     return result
    211 
    212 def synopsis(filename, cache={}):
    213     """Get the one-line summary out of a module file."""
    214     mtime = os.stat(filename).st_mtime
    215     lastupdate, result = cache.get(filename, (0, None))
    216     if lastupdate < mtime:
    217         info = inspect.getmoduleinfo(filename)
    218         try:
    219             file = open(filename)
    220         except IOError:
    221             # module can't be opened, so skip it
    222             return None
    223         if info and 'b' in info[2]: # binary modules have to be imported
    224             try: module = imp.load_module('__temp__', file, filename, info[1:])
    225             except: return None
    226             result = (module.__doc__ or '').splitlines()[0]
    227             del sys.modules['__temp__']
    228         else: # text modules can be directly examined
    229             result = source_synopsis(file)
    230             file.close()
    231         cache[filename] = (mtime, result)
    232     return result
    233 
    234 class ErrorDuringImport(Exception):
    235     """Errors that occurred while trying to import something to document it."""
    236     def __init__(self, filename, exc_info):
    237         exc, value, tb = exc_info
    238         self.filename = filename
    239         self.exc = exc
    240         self.value = value
    241         self.tb = tb
    242 
    243     def __str__(self):
    244         exc = self.exc
    245         if type(exc) is types.ClassType:
    246             exc = exc.__name__
    247         return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
    248 
    249 def importfile(path):
    250     """Import a Python source file or compiled file given its path."""
    251     magic = imp.get_magic()
    252     file = open(path, 'r')
    253     if file.read(len(magic)) == magic:
    254         kind = imp.PY_COMPILED
    255     else:
    256         kind = imp.PY_SOURCE
    257     file.close()
    258     filename = os.path.basename(path)
    259     name, ext = os.path.splitext(filename)
    260     file = open(path, 'r')
    261     try:
    262         module = imp.load_module(name, file, path, (ext, 'r', kind))
    263     except:
    264         raise ErrorDuringImport(path, sys.exc_info())
    265     file.close()
    266     return module
    267 
    268 def safeimport(path, forceload=0, cache={}):
    269     """Import a module; handle errors; return None if the module isn't found.
    270 
    271     If the module *is* found but an exception occurs, it's wrapped in an
    272     ErrorDuringImport exception and reraised.  Unlike __import__, if a
    273     package path is specified, the module at the end of the path is returned,
    274     not the package at the beginning.  If the optional 'forceload' argument
    275     is 1, we reload the module from disk (unless it's a dynamic extension)."""
    276     try:
    277         # If forceload is 1 and the module has been previously loaded from
    278         # disk, we always have to reload the module.  Checking the file's
    279         # mtime isn't good enough (e.g. the module could contain a class

    280         # that inherits from another module that has changed).

    281         if forceload and path in sys.modules:
    282             if path not in sys.builtin_module_names:
    283                 # Avoid simply calling reload() because it leaves names in

    284                 # the currently loaded module lying around if they're not

    285                 # defined in the new source file.  Instead, remove the

    286                 # module from sys.modules and re-import.  Also remove any

    287                 # submodules because they won't appear in the newly loaded

    288                 # module's namespace if they're already in sys.modules.

    289                 subs = [m for m in sys.modules if m.startswith(path + '.')]
    290                 for key in [path] + subs:
    291                     # Prevent garbage collection.

    292                     cache[key] = sys.modules[key]
    293                     del sys.modules[key]
    294         module = __import__(path)
    295     except:
    296         # Did the error occur before or after the module was found?

    297         (exc, value, tb) = info = sys.exc_info()
    298         if path in sys.modules:
    299             # An error occurred while executing the imported module.

    300             raise ErrorDuringImport(sys.modules[path].__file__, info)
    301         elif exc is SyntaxError:
    302             # A SyntaxError occurred before we could execute the module.

    303             raise ErrorDuringImport(value.filename, info)
    304         elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport':
    305             # The import error occurred directly in this function,

    306             # which means there is no such module in the path.

    307             return None
    308         else:
    309             # Some other error occurred during the importing process.

    310             raise ErrorDuringImport(path, sys.exc_info())
    311     for part in split(path, '.')[1:]:
    312         try: module = getattr(module, part)
    313         except AttributeError: return None
    314     return module
    315 
    316 # ---------------------------------------------------- formatter base class

    317 
    318 class Doc:
    319     def document(self, object, name=None, *args):
    320         """Generate documentation for an object."""
    321         args = (object, name) + args
    322         # 'try' clause is to attempt to handle the possibility that inspect

    323         # identifies something in a way that pydoc itself has issues handling;

    324         # think 'super' and how it is a descriptor (which raises the exception

    325         # by lacking a __name__ attribute) and an instance.

    326         if inspect.isgetsetdescriptor(object): return self.docdata(*args)
    327         if inspect.ismemberdescriptor(object): return self.docdata(*args)
    328         try:
    329             if inspect.ismodule(object): return self.docmodule(*args)
    330             if inspect.isclass(object): return self.docclass(*args)
    331             if inspect.isroutine(object): return self.docroutine(*args)
    332         except AttributeError:
    333             pass
    334         if isinstance(object, property): return self.docproperty(*args)
    335         return self.docother(*args)
    336 
    337     def fail(self, object, name=None, *args):
    338         """Raise an exception for unimplemented types."""
    339         message = "don't know how to document object%s of type %s" % (
    340             name and ' ' + repr(name), type(object).__name__)
    341         raise TypeError, message
    342 
    343     docmodule = docclass = docroutine = docother = docproperty = docdata = fail
    344 
    345     def getdocloc(self, object):
    346         """Return the location of module docs or None"""
    347 
    348         try:
    349             file = inspect.getabsfile(object)
    350         except TypeError:
    351             file = '(built-in)'
    352 
    353         docloc = os.environ.get("PYTHONDOCS",
    354                                 "http://docs.python.org/library")
    355         basedir = os.path.join(sys.exec_prefix, "lib",
    356                                "python"+sys.version[0:3])
    357         if (isinstance(object, type(os)) and
    358             (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
    359                                  'marshal', 'posix', 'signal', 'sys',
    360                                  'thread', 'zipimport') or
    361              (file.startswith(basedir) and
    362               not file.startswith(os.path.join(basedir, 'site-packages')))) and
    363             object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
    364             if docloc.startswith("http://"):
    365                 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__)
    366             else:
    367                 docloc = os.path.join(docloc, object.__name__ + ".html")
    368         else:
    369             docloc = None
    370         return docloc
    371 
    372 # -------------------------------------------- HTML documentation generator

    373 
    374 class HTMLRepr(Repr):
    375     """Class for safely making an HTML representation of a Python object."""
    376     def __init__(self):
    377         Repr.__init__(self)
    378         self.maxlist = self.maxtuple = 20
    379         self.maxdict = 10
    380         self.maxstring = self.maxother = 100
    381 
    382     def escape(self, text):
    383         return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
    384 
    385     def repr(self, object):
    386         return Repr.repr(self, object)
    387 
    388     def repr1(self, x, level):
    389         if hasattr(type(x), '__name__'):
    390             methodname = 'repr_' + join(split(type(x).__name__), '_')
    391             if hasattr(self, methodname):
    392                 return getattr(self, methodname)(x, level)
    393         return self.escape(cram(stripid(repr(x)), self.maxother))
    394 
    395     def repr_string(self, x, level):
    396         test = cram(x, self.maxstring)
    397         testrepr = repr(test)
    398         if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
    399             # Backslashes are only literal in the string and are never
    400             # needed to make any special characters, so show a raw string.
    401             return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
    402         return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
    403                       r'<font color="#c040c0">\1</font>',
    404                       self.escape(testrepr))
    405 
    406     repr_str = repr_string
    407 
    408     def repr_instance(self, x, level):
    409         try:
    410             return self.escape(cram(stripid(repr(x)), self.maxstring))
    411         except:
    412             return self.escape('<%s instance>' % x.__class__.__name__)
    413 
    414     repr_unicode = repr_string
    415 
    416 class HTMLDoc(Doc):
    417     """Formatter class for HTML documentation."""
    418 
    419     # ------------------------------------------- HTML formatting utilities

    420 
    421     _repr_instance = HTMLRepr()
    422     repr = _repr_instance.repr
    423     escape = _repr_instance.escape
    424 
    425     def page(self, title, contents):
    426         """Format an HTML page."""
    427         return '''
    428 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    429 <html><head><title>Python: %s</title>
    430 </head><body bgcolor="#f0f0f8">
    431 %s
    432 </body></html>''' % (title, contents)
    433 
    434     def heading(self, title, fgcol, bgcol, extras=''):
    435         """Format a page heading."""
    436         return '''
    437 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
    438 <tr bgcolor="%s">
    439 <td valign=bottom>&nbsp;<br>
    440 <font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
    441 ><td align=right valign=bottom
    442 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
    443     ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
    444 
    445     def section(self, title, fgcol, bgcol, contents, width=6,
    446                 prelude='', marginalia=None, gap='&nbsp;'):
    447         """Format a section with a heading."""
    448         if marginalia is None:
    449             marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
    450         result = '''<p>
    451 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
    452 <tr bgcolor="%s">
    453 <td colspan=3 valign=bottom>&nbsp;<br>
    454 <font color="%s" face="helvetica, arial">%s</font></td></tr>
    455     ''' % (bgcol, fgcol, title)
    456         if prelude:
    457             result = result + '''
    458 <tr bgcolor="%s"><td rowspan=2>%s</td>
    459 <td colspan=2>%s</td></tr>
    460 <tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
    461         else:
    462             result = result + '''
    463 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
    464 
    465         return result + '\n<td width="100%%">%s</td></tr></table>' % contents
    466 
    467     def bigsection(self, title, *args):
    468         """Format a section with a big heading."""
    469         title = '<big><strong>%s</strong></big>' % title
    470         return self.section(title, *args)
    471 
    472     def preformat(self, text):
    473         """Format literal preformatted text."""
    474         text = self.escape(expandtabs(text))
    475         return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
    476                              ' ', '&nbsp;', '\n', '<br>\n')
    477 
    478     def multicolumn(self, list, format, cols=4):
    479         """Format a list of items into a multi-column list."""
    480         result = ''
    481         rows = (len(list)+cols-1)//cols
    482         for col in range(cols):
    483             result = result + '<td width="%d%%" valign=top>' % (100//cols)
    484             for i in range(rows*col, rows*col+rows):
    485                 if i < len(list):
    486                     result = result + format(list[i]) + '<br>\n'
    487             result = result + '</td>'
    488         return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
    489 
    490     def grey(self, text): return '<font color="#909090">%s</font>' % text
    491 
    492     def namelink(self, name, *dicts):
    493         """Make a link for an identifier, given name-to-URL mappings."""
    494         for dict in dicts:
    495             if name in dict:
    496                 return '<a href="%s">%s</a>' % (dict[name], name)
    497         return name
    498 
    499     def classlink(self, object, modname):
    500         """Make a link for a class."""
    501         name, module = object.__name__, sys.modules.get(object.__module__)
    502         if hasattr(module, name) and getattr(module, name) is object:
    503             return '<a href="%s.html#%s">%s</a>' % (
    504                 module.__name__, name, classname(object, modname))
    505         return classname(object, modname)
    506 
    507     def modulelink(self, object):
    508         """Make a link for a module."""
    509         return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
    510 
    511     def modpkglink(self, data):
    512         """Make a link for a module or package to display in an index."""
    513         name, path, ispackage, shadowed = data
    514         if shadowed:
    515             return self.grey(name)
    516         if path:
    517             url = '%s.%s.html' % (path, name)
    518         else:
    519             url = '%s.html' % name
    520         if ispackage:
    521             text = '<strong>%s</strong>&nbsp;(package)' % name
    522         else:
    523             text = name
    524         return '<a href="%s">%s</a>' % (url, text)
    525 
    526     def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
    527         """Mark up some plain text, given a context of symbols to look for.
    528         Each context dictionary maps object names to anchor names."""
    529         escape = escape or self.escape
    530         results = []
    531         here = 0
    532         pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
    533                                 r'RFC[- ]?(\d+)|'
    534                                 r'PEP[- ]?(\d+)|'
    535                                 r'(self\.)?(\w+))')
    536         while True:
    537             match = pattern.search(text, here)
    538             if not match: break
    539             start, end = match.span()
    540             results.append(escape(text[here:start]))
    541 
    542             all, scheme, rfc, pep, selfdot, name = match.groups()
    543             if scheme:
    544                 url = escape(all).replace('"', '&quot;')
    545                 results.append('<a href="%s">%s</a>' % (url, url))
    546             elif rfc:
    547                 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
    548                 results.append('<a href="%s">%s</a>' % (url, escape(all)))
    549             elif pep:
    550                 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
    551                 results.append('<a href="%s">%s</a>' % (url, escape(all)))
    552             elif text[end:end+1] == '(':
    553                 results.append(self.namelink(name, methods, funcs, classes))
    554             elif selfdot:
    555                 results.append('self.<strong>%s</strong>' % name)
    556             else:
    557                 results.append(self.namelink(name, classes))
    558             here = end
    559         results.append(escape(text[here:]))
    560         return join(results, '')
    561 
    562     # ---------------------------------------------- type-specific routines

    563 
    564     def formattree(self, tree, modname, parent=None):
    565         """Produce HTML for a class tree as given by inspect.getclasstree()."""
    566         result = ''
    567         for entry in tree:
    568             if type(entry) is type(()):
    569                 c, bases = entry
    570                 result = result + '<dt><font face="helvetica, arial">'
    571                 result = result + self.classlink(c, modname)
    572                 if bases and bases != (parent,):
    573                     parents = []
    574                     for base in bases:
    575                         parents.append(self.classlink(base, modname))
    576                     result = result + '(' + join(parents, ', ') + ')'
    577                 result = result + '\n</font></dt>'
    578             elif type(entry) is type([]):
    579                 result = result + '<dd>\n%s</dd>\n' % self.formattree(
    580                     entry, modname, c)
    581         return '<dl>\n%s</dl>\n' % result
    582 
    583     def docmodule(self, object, name=None, mod=None, *ignored):
    584         """Produce HTML documentation for a module object."""
    585         name = object.__name__ # ignore the passed-in name

    586         try:
    587             all = object.__all__
    588         except AttributeError:
    589             all = None
    590         parts = split(name, '.')
    591         links = []
    592         for i in range(len(parts)-1):
    593             links.append(
    594                 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
    595                 (join(parts[:i+1], '.'), parts[i]))
    596         linkedname = join(links + parts[-1:], '.')
    597         head = '<big><big><strong>%s</strong></big></big>' % linkedname
    598         try:
    599             path = inspect.getabsfile(object)
    600             url = path
    601             if sys.platform == 'win32':
    602                 import nturl2path
    603                 url = nturl2path.pathname2url(path)
    604             filelink = '<a href="file:%s">%s</a>' % (url, path)
    605         except TypeError:
    606             filelink = '(built-in)'
    607         info = []
    608         if hasattr(object, '__version__'):
    609             version = str(object.__version__)
    610             if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
    611                 version = strip(version[11:-1])
    612             info.append('version %s' % self.escape(version))
    613         if hasattr(object, '__date__'):
    614             info.append(self.escape(str(object.__date__)))
    615         if info:
    616             head = head + ' (%s)' % join(info, ', ')
    617         docloc = self.getdocloc(object)
    618         if docloc is not None:
    619             docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
    620         else:
    621             docloc = ''
    622         result = self.heading(
    623             head, '#ffffff', '#7799ee',
    624             '<a href=".">index</a><br>' + filelink + docloc)
    625 
    626         modules = inspect.getmembers(object, inspect.ismodule)
    627 
    628         classes, cdict = [], {}
    629         for key, value in inspect.getmembers(object, inspect.isclass):
    630             # if __all__ exists, believe it.  Otherwise use old heuristic.

    631             if (all is not None or
    632                 (inspect.getmodule(value) or object) is object):
    633                 if visiblename(key, all, object):
    634                     classes.append((key, value))
    635                     cdict[key] = cdict[value] = '#' + key
    636         for key, value in classes:
    637             for base in value.__bases__:
    638                 key, modname = base.__name__, base.__module__
    639                 module = sys.modules.get(modname)
    640                 if modname != name and module and hasattr(module, key):
    641                     if getattr(module, key) is base:
    642                         if not key in cdict:
    643                             cdict[key] = cdict[base] = modname + '.html#' + key
    644         funcs, fdict = [], {}
    645         for key, value in inspect.getmembers(object, inspect.isroutine):
    646             # if __all__ exists, believe it.  Otherwise use old heuristic.

    647             if (all is not None or
    648                 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
    649                 if visiblename(key, all, object):
    650                     funcs.append((key, value))
    651                     fdict[key] = '#-' + key
    652                     if inspect.isfunction(value): fdict[value] = fdict[key]
    653         data = []
    654         for key, value in inspect.getmembers(object, isdata):
    655             if visiblename(key, all, object):
    656                 data.append((key, value))
    657 
    658         doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
    659         doc = doc and '<tt>%s</tt>' % doc
    660         result = result + '<p>%s</p>\n' % doc
    661 
    662         if hasattr(object, '__path__'):
    663             modpkgs = []
    664             for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
    665                 modpkgs.append((modname, name, ispkg, 0))
    666             modpkgs.sort()
    667             contents = self.multicolumn(modpkgs, self.modpkglink)
    668             result = result + self.bigsection(
    669                 'Package Contents', '#ffffff', '#aa55cc', contents)
    670         elif modules:
    671             contents = self.multicolumn(
    672                 modules, lambda key_value, s=self: s.modulelink(key_value[1]))
    673             result = result + self.bigsection(
    674                 'Modules', '#ffffff', '#aa55cc', contents)
    675 
    676         if classes:
    677             classlist = map(lambda key_value: key_value[1], classes)
    678             contents = [
    679                 self.formattree(inspect.getclasstree(classlist, 1), name)]
    680             for key, value in classes:
    681                 contents.append(self.document(value, key, name, fdict, cdict))
    682             result = result + self.bigsection(
    683                 'Classes', '#ffffff', '#ee77aa', join(contents))
    684         if funcs:
    685             contents = []
    686             for key, value in funcs:
    687                 contents.append(self.document(value, key, name, fdict, cdict))
    688             result = result + self.bigsection(
    689                 'Functions', '#ffffff', '#eeaa77', join(contents))
    690         if data:
    691             contents = []
    692             for key, value in data:
    693                 contents.append(self.document(value, key))
    694             result = result + self.bigsection(
    695                 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
    696         if hasattr(object, '__author__'):
    697             contents = self.markup(str(object.__author__), self.preformat)
    698             result = result + self.bigsection(
    699                 'Author', '#ffffff', '#7799ee', contents)
    700         if hasattr(object, '__credits__'):
    701             contents = self.markup(str(object.__credits__), self.preformat)
    702             result = result + self.bigsection(
    703                 'Credits', '#ffffff', '#7799ee', contents)
    704 
    705         return result
    706 
    707     def docclass(self, object, name=None, mod=None, funcs={}, classes={},
    708                  *ignored):
    709         """Produce HTML documentation for a class object."""
    710         realname = object.__name__
    711         name = name or realname
    712         bases = object.__bases__
    713 
    714         contents = []
    715         push = contents.append
    716 
    717         # Cute little class to pump out a horizontal rule between sections.

    718         class HorizontalRule:
    719             def __init__(self):
    720                 self.needone = 0
    721             def maybe(self):
    722                 if self.needone:
    723                     push('<hr>\n')
    724                 self.needone = 1
    725         hr = HorizontalRule()
    726 
    727         # List the mro, if non-trivial.

    728         mro = deque(inspect.getmro(object))
    729         if len(mro) > 2:
    730             hr.maybe()
    731             push('<dl><dt>Method resolution order:</dt>\n')
    732             for base in mro:
    733                 push('<dd>%s</dd>\n' % self.classlink(base,
    734                                                       object.__module__))
    735             push('</dl>\n')
    736 
    737         def spill(msg, attrs, predicate):
    738             ok, attrs = _split_list(attrs, predicate)
    739             if ok:
    740                 hr.maybe()
    741                 push(msg)
    742                 for name, kind, homecls, value in ok:
    743                     push(self.document(getattr(object, name), name, mod,
    744                                        funcs, classes, mdict, object))
    745                     push('\n')
    746             return attrs
    747 
    748         def spilldescriptors(msg, attrs, predicate):
    749             ok, attrs = _split_list(attrs, predicate)
    750             if ok:
    751                 hr.maybe()
    752                 push(msg)
    753                 for name, kind, homecls, value in ok:
    754                     push(self._docdescriptor(name, value, mod))
    755             return attrs
    756 
    757         def spilldata(msg, attrs, predicate):
    758             ok, attrs = _split_list(attrs, predicate)
    759             if ok:
    760                 hr.maybe()
    761                 push(msg)
    762                 for name, kind, homecls, value in ok:
    763                     base = self.docother(getattr(object, name), name, mod)
    764                     if (hasattr(value, '__call__') or
    765                             inspect.isdatadescriptor(value)):
    766                         doc = getattr(value, "__doc__", None)
    767                     else:
    768                         doc = None
    769                     if doc is None:
    770                         push('<dl><dt>%s</dl>\n' % base)
    771                     else:
    772                         doc = self.markup(getdoc(value), self.preformat,
    773                                           funcs, classes, mdict)
    774                         doc = '<dd><tt>%s</tt>' % doc
    775                         push('<dl><dt>%s%s</dl>\n' % (base, doc))
    776                     push('\n')
    777             return attrs
    778 
    779         attrs = filter(lambda data: visiblename(data[0], obj=object),
    780                        classify_class_attrs(object))
    781         mdict = {}
    782         for key, kind, homecls, value in attrs:
    783             mdict[key] = anchor = '#' + name + '-' + key
    784             value = getattr(object, key)
    785             try:
    786                 # The value may not be hashable (e.g., a data attr with

    787                 # a dict or list value).

    788                 mdict[value] = anchor
    789             except TypeError:
    790                 pass
    791 
    792         while attrs:
    793             if mro:
    794                 thisclass = mro.popleft()
    795             else:
    796                 thisclass = attrs[0][2]
    797             attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
    798 
    799             if thisclass is __builtin__.object:
    800                 attrs = inherited
    801                 continue
    802             elif thisclass is object:
    803                 tag = 'defined here'
    804             else:
    805                 tag = 'inherited from %s' % self.classlink(thisclass,
    806                                                            object.__module__)
    807             tag += ':<br>\n'
    808 
    809             # Sort attrs by name.

    810             try:
    811                 attrs.sort(key=lambda t: t[0])
    812             except TypeError:
    813                 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))    # 2.3 compat

    814 
    815             # Pump out the attrs, segregated by kind.

    816             attrs = spill('Methods %s' % tag, attrs,
    817                           lambda t: t[1] == 'method')
    818             attrs = spill('Class methods %s' % tag, attrs,
    819                           lambda t: t[1] == 'class method')
    820             attrs = spill('Static methods %s' % tag, attrs,
    821                           lambda t: t[1] == 'static method')
    822             attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
    823                                      lambda t: t[1] == 'data descriptor')
    824             attrs = spilldata('Data and other attributes %s' % tag, attrs,
    825                               lambda t: t[1] == 'data')
    826             assert attrs == []
    827             attrs = inherited
    828 
    829         contents = ''.join(contents)
    830 
    831         if name == realname:
    832             title = '<a name="%s">class <strong>%s</strong></a>' % (
    833                 name, realname)
    834         else:
    835             title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
    836                 name, name, realname)
    837         if bases:
    838             parents = []
    839             for base in bases:
    840                 parents.append(self.classlink(base, object.__module__))
    841             title = title + '(%s)' % join(parents, ', ')
    842         doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
    843         doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
    844 
    845         return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
    846 
    847     def formatvalue(self, object):
    848         """Format an argument default value as text."""
    849         return self.grey('=' + self.repr(object))
    850 
    851     def docroutine(self, object, name=None, mod=None,
    852                    funcs={}, classes={}, methods={}, cl=None):
    853         """Produce HTML documentation for a function or method object."""
    854         realname = object.__name__
    855         name = name or realname
    856         anchor = (cl and cl.__name__ or '') + '-' + name
    857         note = ''
    858         skipdocs = 0
    859         if inspect.ismethod(object):
    860             imclass = object.im_class
    861             if cl:
    862                 if imclass is not cl:
    863                     note = ' from ' + self.classlink(imclass, mod)
    864             else:
    865                 if object.im_self is not None:
    866                     note = ' method of %s instance' % self.classlink(
    867                         object.im_self.__class__, mod)
    868                 else:
    869                     note = ' unbound %s method' % self.classlink(imclass,mod)
    870             object = object.im_func
    871 
    872         if name == realname:
    873             title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
    874         else:
    875             if (cl and realname in cl.__dict__ and
    876                 cl.__dict__[realname] is object):
    877                 reallink = '<a href="#%s">%s</a>' % (
    878                     cl.__name__ + '-' + realname, realname)
    879                 skipdocs = 1
    880             else:
    881                 reallink = realname
    882             title = '<a name="%s"><strong>%s</strong></a> = %s' % (
    883                 anchor, name, reallink)
    884         if inspect.isfunction(object):
    885             args, varargs, varkw, defaults = inspect.getargspec(object)
    886             argspec = inspect.formatargspec(
    887                 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
    888             if realname == '<lambda>':
    889                 title = '<strong>%s</strong> <em>lambda</em> ' % name
    890                 argspec = argspec[1:-1] # remove parentheses

    891         else:
    892             argspec = '(...)'
    893 
    894         decl = title + argspec + (note and self.grey(
    895                '<font face="helvetica, arial">%s</font>' % note))
    896 
    897         if skipdocs:
    898             return '<dl><dt>%s</dt></dl>\n' % decl
    899         else:
    900             doc = self.markup(
    901                 getdoc(object), self.preformat, funcs, classes, methods)
    902             doc = doc and '<dd><tt>%s</tt></dd>' % doc
    903             return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
    904 
    905     def _docdescriptor(self, name, value, mod):
    906         results = []
    907         push = results.append
    908 
    909         if name:
    910             push('<dl><dt><strong>%s</strong></dt>\n' % name)
    911         if value.__doc__ is not None:
    912             doc = self.markup(getdoc(value), self.preformat)
    913             push('<dd><tt>%s</tt></dd>\n' % doc)
    914         push('</dl>\n')
    915 
    916         return ''.join(results)
    917 
    918     def docproperty(self, object, name=None, mod=None, cl=None):
    919         """Produce html documentation for a property."""
    920         return self._docdescriptor(name, object, mod)
    921 
    922     def docother(self, object, name=None, mod=None, *ignored):
    923         """Produce HTML documentation for a data object."""
    924         lhs = name and '<strong>%s</strong> = ' % name or ''
    925         return lhs + self.repr(object)
    926 
    927     def docdata(self, object, name=None, mod=None, cl=None):
    928         """Produce html documentation for a data descriptor."""
    929         return self._docdescriptor(name, object, mod)
    930 
    931     def index(self, dir, shadowed=None):
    932         """Generate an HTML index for a directory of modules."""
    933         modpkgs = []
    934         if shadowed is None: shadowed = {}
    935         for importer, name, ispkg in pkgutil.iter_modules([dir]):
    936             modpkgs.append((name, '', ispkg, name in shadowed))
    937             shadowed[name] = 1
    938 
    939         modpkgs.sort()
    940         contents = self.multicolumn(modpkgs, self.modpkglink)
    941         return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
    942 
    943 # -------------------------------------------- text documentation generator

    944 
    945 class TextRepr(Repr):
    946     """Class for safely making a text representation of a Python object."""
    947     def __init__(self):
    948         Repr.__init__(self)
    949         self.maxlist = self.maxtuple = 20
    950         self.maxdict = 10
    951         self.maxstring = self.maxother = 100
    952 
    953     def repr1(self, x, level):
    954         if hasattr(type(x), '__name__'):
    955             methodname = 'repr_' + join(split(type(x).__name__), '_')
    956             if hasattr(self, methodname):
    957                 return getattr(self, methodname)(x, level)
    958         return cram(stripid(repr(x)), self.maxother)
    959 
    960     def repr_string(self, x, level):
    961         test = cram(x, self.maxstring)
    962         testrepr = repr(test)
    963         if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
    964             # Backslashes are only literal in the string and are never
    965             # needed to make any special characters, so show a raw string.
    966             return 'r' + testrepr[0] + test + testrepr[0]
    967         return testrepr
    968 
    969     repr_str = repr_string
    970 
    971     def repr_instance(self, x, level):
    972         try:
    973             return cram(stripid(repr(x)), self.maxstring)
    974         except:
    975             return '<%s instance>' % x.__class__.__name__
    976 
    977 class TextDoc(Doc):
    978     """Formatter class for text documentation."""
    979 
    980     # ------------------------------------------- text formatting utilities
    981 
    982     _repr_instance = TextRepr()
    983     repr = _repr_instance.repr
    984 
    985     def bold(self, text):
    986         """Format a string in bold by overstriking."""
    987         return join(map(lambda ch: ch + '\b' + ch, text), '')
    988 
    989     def indent(self, text, prefix='    '):
    990         """Indent text by prepending a given prefix to each line."""
    991         if not text: return ''
    992         lines = split(text, '\n')
    993         lines = map(lambda line, prefix=prefix: prefix + line, lines)
    994         if lines: lines[-1] = rstrip(lines[-1])
    995         return join(lines, '\n')
    996 
    997     def section(self, title, contents):
    998         """Format a section with a given heading."""
    999         return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
   1000 
   1001     # ---------------------------------------------- type-specific routines
   1002 
   1003     def formattree(self, tree, modname, parent=None, prefix=''):
   1004         """Render in text a class tree as returned by inspect.getclasstree()."""
   1005         result = ''
   1006         for entry in tree:
   1007             if type(entry) is type(()):
   1008                 c, bases = entry
   1009                 result = result + prefix + classname(c, modname)
   1010                 if bases and bases != (parent,):
   1011                     parents = map(lambda c, m=modname: classname(c, m), bases)
   1012                     result = result + '(%s)' % join(parents, ', ')
   1013                 result = result + '\n'
   1014             elif type(entry) is type([]):
   1015                 result = result + self.formattree(
   1016                     entry, modname, c, prefix + '    ')
   1017         return result
   1018 
   1019     def docmodule(self, object, name=None, mod=None):
   1020         """Produce text documentation for a given module object."""
   1021         name = object.__name__ # ignore the passed-in name
   1022         synop, desc = splitdoc(getdoc(object))
   1023         result = self.section('NAME', name + (synop and ' - ' + synop))
   1024 
   1025         try:
   1026             all = object.__all__
   1027         except AttributeError:
   1028             all = None
   1029 
   1030         try:
   1031             file = inspect.getabsfile(object)
   1032         except TypeError:
   1033             file = '(built-in)'
   1034         result = result + self.section('FILE', file)
   1035 
   1036         docloc = self.getdocloc(object)
   1037         if docloc is not None:
   1038             result = result + self.section('MODULE DOCS', docloc)
   1039 
   1040         if desc:
   1041             result = result + self.section('DESCRIPTION', desc)
   1042 
   1043         classes = []
   1044         for key, value in inspect.getmembers(object, inspect.isclass):
   1045             # if __all__ exists, believe it.  Otherwise use old heuristic.
   1046             if (all is not None
   1047                 or (inspect.getmodule(value) or object) is object):
   1048                 if visiblename(key, all, object):
   1049                     classes.append((key, value))
   1050         funcs = []
   1051         for key, value in inspect.getmembers(object, inspect.isroutine):
   1052             # if __all__ exists, believe it.  Otherwise use old heuristic.
   1053             if (all is not None or
   1054                 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
   1055                 if visiblename(key, all, object):
   1056                     funcs.append((key, value))
   1057         data = []
   1058         for key, value in inspect.getmembers(object, isdata):
   1059             if visiblename(key, all, object):
   1060                 data.append((key, value))
   1061 
   1062         modpkgs = []
   1063         modpkgs_names = set()
   1064         if hasattr(object, '__path__'):
   1065             for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
   1066                 modpkgs_names.add(modname)
   1067                 if ispkg:
   1068                     modpkgs.append(modname + ' (package)')
   1069                 else:
   1070                     modpkgs.append(modname)
   1071 
   1072             modpkgs.sort()
   1073             result = result + self.section(
   1074                 'PACKAGE CONTENTS', join(modpkgs, '\n'))
   1075 
   1076         # Detect submodules as sometimes created by C extensions
   1077         submodules = []
   1078         for key, value in inspect.getmembers(object, inspect.ismodule):
   1079             if value.__name__.startswith(name + '.') and key not in modpkgs_names:
   1080                 submodules.append(key)
   1081         if submodules:
   1082             submodules.sort()
   1083             result = result + self.section(
   1084                 'SUBMODULES', join(submodules, '\n'))
   1085 
   1086         if classes:
   1087             classlist = map(lambda key_value: key_value[1], classes)
   1088             contents = [self.formattree(
   1089                 inspect.getclasstree(classlist, 1), name)]
   1090             for key, value in classes:
   1091                 contents.append(self.document(value, key, name))
   1092             result = result + self.section('CLASSES', join(contents, '\n'))
   1093 
   1094         if funcs:
   1095             contents = []
   1096             for key, value in funcs:
   1097                 contents.append(self.document(value, key, name))
   1098             result = result + self.section('FUNCTIONS', join(contents, '\n'))
   1099 
   1100         if data:
   1101             contents = []
   1102             for key, value in data:
   1103                 contents.append(self.docother(value, key, name, maxlen=70))
   1104             result = result + self.section('DATA', join(contents, '\n'))
   1105 
   1106         if hasattr(object, '__version__'):
   1107             version = str(object.__version__)
   1108             if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
   1109                 version = strip(version[11:-1])
   1110             result = result + self.section('VERSION', version)
   1111         if hasattr(object, '__date__'):
   1112             result = result + self.section('DATE', str(object.__date__))
   1113         if hasattr(object, '__author__'):
   1114             result = result + self.section('AUTHOR', str(object.__author__))
   1115         if hasattr(object, '__credits__'):
   1116             result = result + self.section('CREDITS', str(object.__credits__))
   1117         return result
   1118 
   1119     def docclass(self, object, name=None, mod=None, *ignored):
   1120         """Produce text documentation for a given class object."""
   1121         realname = object.__name__
   1122         name = name or realname
   1123         bases = object.__bases__
   1124 
   1125         def makename(c, m=object.__module__):
   1126             return classname(c, m)
   1127 
   1128         if name == realname:
   1129             title = 'class ' + self.bold(realname)
   1130         else:
   1131             title = self.bold(name) + ' = class ' + realname
   1132         if bases:
   1133             parents = map(makename, bases)
   1134             title = title + '(%s)' % join(parents, ', ')
   1135 
   1136         doc = getdoc(object)
   1137         contents = doc and [doc + '\n'] or []
   1138         push = contents.append
   1139 
   1140         # List the mro, if non-trivial.
   1141         mro = deque(inspect.getmro(object))
   1142         if len(mro) > 2:
   1143             push("Method resolution order:")
   1144             for base in mro:
   1145                 push('    ' + makename(base))
   1146             push('')
   1147 
   1148         # Cute little class to pump out a horizontal rule between sections.
   1149         class HorizontalRule:
   1150             def __init__(self):
   1151                 self.needone = 0
   1152             def maybe(self):
   1153                 if self.needone:
   1154                     push('-' * 70)
   1155                 self.needone = 1
   1156         hr = HorizontalRule()
   1157 
   1158         def spill(msg, attrs, predicate):
   1159             ok, attrs = _split_list(attrs, predicate)
   1160             if ok:
   1161                 hr.maybe()
   1162                 push(msg)
   1163                 for name, kind, homecls, value in ok:
   1164                     push(self.document(getattr(object, name),
   1165                                        name, mod, object))
   1166             return attrs
   1167 
   1168         def spilldescriptors(msg, attrs, predicate):
   1169             ok, attrs = _split_list(attrs, predicate)
   1170             if ok:
   1171                 hr.maybe()
   1172                 push(msg)
   1173                 for name, kind, homecls, value in ok:
   1174                     push(self._docdescriptor(name, value, mod))
   1175             return attrs
   1176 
   1177         def spilldata(msg, attrs, predicate):
   1178             ok, attrs = _split_list(attrs, predicate)
   1179             if ok:
   1180                 hr.maybe()
   1181                 push(msg)
   1182                 for name, kind, homecls, value in ok:
   1183                     if (hasattr(value, '__call__') or
   1184                             inspect.isdatadescriptor(value)):
   1185                         doc = getdoc(value)
   1186                     else:
   1187                         doc = None
   1188                     push(self.docother(getattr(object, name),
   1189                                        name, mod, maxlen=70, doc=doc) + '\n')
   1190             return attrs
   1191 
   1192         attrs = filter(lambda data: visiblename(data[0], obj=object),
   1193                        classify_class_attrs(object))
   1194         while attrs:
   1195             if mro:
   1196                 thisclass = mro.popleft()
   1197             else:
   1198                 thisclass = attrs[0][2]
   1199             attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
   1200 
   1201             if thisclass is __builtin__.object:
   1202                 attrs = inherited
   1203                 continue
   1204             elif thisclass is object:
   1205                 tag = "defined here"
   1206             else:
   1207                 tag = "inherited from %s" % classname(thisclass,
   1208                                                       object.__module__)
   1209 
   1210             # Sort attrs by name.
   1211             attrs.sort()
   1212 
   1213             # Pump out the attrs, segregated by kind.
   1214             attrs = spill("Methods %s:\n" % tag, attrs,
   1215                           lambda t: t[1] == 'method')
   1216             attrs = spill("Class methods %s:\n" % tag, attrs,
   1217                           lambda t: t[1] == 'class method')
   1218             attrs = spill("Static methods %s:\n" % tag, attrs,
   1219                           lambda t: t[1] == 'static method')
   1220             attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
   1221                                      lambda t: t[1] == 'data descriptor')
   1222             attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
   1223                               lambda t: t[1] == 'data')
   1224             assert attrs == []
   1225             attrs = inherited
   1226 
   1227         contents = '\n'.join(contents)
   1228         if not contents:
   1229             return title + '\n'
   1230         return title + '\n' + self.indent(rstrip(contents), ' |  ') + '\n'
   1231 
   1232     def formatvalue(self, object):
   1233         """Format an argument default value as text."""
   1234         return '=' + self.repr(object)
   1235 
   1236     def docroutine(self, object, name=None, mod=None, cl=None):
   1237         """Produce text documentation for a function or method object."""
   1238         realname = object.__name__
   1239         name = name or realname
   1240         note = ''
   1241         skipdocs = 0
   1242         if inspect.ismethod(object):
   1243             imclass = object.im_class
   1244             if cl:
   1245                 if imclass is not cl:
   1246                     note = ' from ' + classname(imclass, mod)
   1247             else:
   1248                 if object.im_self is not None:
   1249                     note = ' method of %s instance' % classname(
   1250                         object.im_self.__class__, mod)
   1251                 else:
   1252                     note = ' unbound %s method' % classname(imclass,mod)
   1253             object = object.im_func
   1254 
   1255         if name == realname:
   1256             title = self.bold(realname)
   1257         else:
   1258             if (cl and realname in cl.__dict__ and
   1259                 cl.__dict__[realname] is object):
   1260                 skipdocs = 1
   1261             title = self.bold(name) + ' = ' + realname
   1262         if inspect.isfunction(object):
   1263             args, varargs, varkw, defaults = inspect.getargspec(object)
   1264             argspec = inspect.formatargspec(
   1265                 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
   1266             if realname == '<lambda>':
   1267                 title = self.bold(name) + ' lambda '
   1268                 argspec = argspec[1:-1] # remove parentheses
   1269         else:
   1270             argspec = '(...)'
   1271         decl = title + argspec + note
   1272 
   1273         if skipdocs:
   1274             return decl + '\n'
   1275         else:
   1276             doc = getdoc(object) or ''
   1277             return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
   1278 
   1279     def _docdescriptor(self, name, value, mod):
   1280         results = []
   1281         push = results.append
   1282 
   1283         if name:
   1284             push(self.bold(name))
   1285             push('\n')
   1286         doc = getdoc(value) or ''
   1287         if doc:
   1288             push(self.indent(doc))
   1289             push('\n')
   1290         return ''.join(results)
   1291 
   1292     def docproperty(self, object, name=None, mod=None, cl=None):
   1293         """Produce text documentation for a property."""
   1294         return self._docdescriptor(name, object, mod)
   1295 
   1296     def docdata(self, object, name=None, mod=None, cl=None):
   1297         """Produce text documentation for a data descriptor."""
   1298         return self._docdescriptor(name, object, mod)
   1299 
   1300     def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
   1301         """Produce text documentation for a data object."""
   1302         repr = self.repr(object)
   1303         if maxlen:
   1304             line = (name and name + ' = ' or '') + repr
   1305             chop = maxlen - len(line)
   1306             if chop < 0: repr = repr[:chop] + '...'
   1307         line = (name and self.bold(name) + ' = ' or '') + repr
   1308         if doc is not None:
   1309             line += '\n' + self.indent(str(doc))
   1310         return line
   1311 
   1312 # --------------------------------------------------------- user interfaces
   1313 
   1314 def pager(text):
   1315     """The first time this is called, determine what kind of pager to use."""
   1316     global pager
   1317     pager = getpager()
   1318     pager(text)
   1319 
   1320 def getpager():
   1321     """Decide what method to use for paging through text."""
   1322     if type(sys.stdout) is not types.FileType:
   1323         return plainpager
   1324     if not sys.stdin.isatty() or not sys.stdout.isatty():
   1325         return plainpager
   1326     if 'PAGER' in os.environ:
   1327         if sys.platform == 'win32': # pipes completely broken in Windows
   1328             return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
   1329         elif sys.platform == 'uefi':
   1330             return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
   1331         elif os.environ.get('TERM') in ('dumb', 'emacs'):
   1332             return lambda text: pipepager(plain(text), os.environ['PAGER'])
   1333         else:
   1334             return lambda text: pipepager(text, os.environ['PAGER'])
   1335     if os.environ.get('TERM') in ('dumb', 'emacs'):
   1336         return plainpager
   1337     if sys.platform == 'uefi':
   1338         return plainpager
   1339     if sys.platform == 'win32' or sys.platform.startswith('os2'):
   1340         return lambda text: tempfilepager(plain(text), 'more <')
   1341     if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
   1342         return lambda text: pipepager(text, 'less')
   1343 
   1344     import tempfile
   1345     (fd, filename) = tempfile.mkstemp()
   1346     os.close(fd)
   1347     try:
   1348         if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
   1349             return lambda text: pipepager(text, 'more')
   1350         else:
   1351             return ttypager
   1352     finally:
   1353         os.unlink(filename)
   1354 
   1355 def plain(text):
   1356     """Remove boldface formatting from text."""
   1357     return re.sub('.\b', '', text)
   1358 
   1359 def pipepager(text, cmd):
   1360     """Page through text by feeding it to another program."""
   1361     pipe = os.popen(cmd, 'w')
   1362     try:
   1363         pipe.write(text)
   1364         pipe.close()
   1365     except IOError:
   1366         pass # Ignore broken pipes caused by quitting the pager program.
   1367 
   1368 def tempfilepager(text, cmd):
   1369     """Page through text by invoking a program on a temporary file."""
   1370     import tempfile
   1371     filename = tempfile.mktemp()
   1372     file = open(filename, 'w')
   1373     file.write(text)
   1374     file.close()
   1375     try:
   1376         os.system(cmd + ' "' + filename + '"')
   1377     finally:
   1378         os.unlink(filename)
   1379 
   1380 def ttypager(text):
   1381     """Page through text on a text terminal."""
   1382     lines = split(plain(text), '\n')
   1383     try:
   1384         import tty
   1385         fd = sys.stdin.fileno()
   1386         old = tty.tcgetattr(fd)
   1387         tty.setcbreak(fd)
   1388         getchar = lambda: sys.stdin.read(1)
   1389     except (ImportError, AttributeError):
   1390         tty = None
   1391         getchar = lambda: sys.stdin.readline()[:-1][:1]
   1392 
   1393     try:
   1394         r = inc = os.environ.get('LINES', 25) - 1
   1395         sys.stdout.write(join(lines[:inc], '\n') + '\n')
   1396         while lines[r:]:
   1397             sys.stdout.write('-- more --')
   1398             sys.stdout.flush()
   1399             c = getchar()
   1400 
   1401             if c in ('q', 'Q'):
   1402                 sys.stdout.write('\r          \r')
   1403                 break
   1404             elif c in ('\r', '\n'):
   1405                 sys.stdout.write('\r          \r' + lines[r] + '\n')
   1406                 r = r + 1
   1407                 continue
   1408             if c in ('b', 'B', '\x1b'):
   1409                 r = r - inc - inc
   1410                 if r < 0: r = 0
   1411             sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
   1412             r = r + inc
   1413 
   1414     finally:
   1415         if tty:
   1416             tty.tcsetattr(fd, tty.TCSAFLUSH, old)
   1417 
   1418 def plainpager(text):
   1419     """Simply print unformatted text.  This is the ultimate fallback."""
   1420     sys.stdout.write(plain(text))
   1421 
   1422 def describe(thing):
   1423     """Produce a short description of the given thing."""
   1424     if inspect.ismodule(thing):
   1425         if thing.__name__ in sys.builtin_module_names:
   1426             return 'built-in module ' + thing.__name__
   1427         if hasattr(thing, '__path__'):
   1428             return 'package ' + thing.__name__
   1429         else:
   1430             return 'module ' + thing.__name__
   1431     if inspect.isbuiltin(thing):
   1432         return 'built-in function ' + thing.__name__
   1433     if inspect.isgetsetdescriptor(thing):
   1434         return 'getset descriptor %s.%s.%s' % (
   1435             thing.__objclass__.__module__, thing.__objclass__.__name__,
   1436             thing.__name__)
   1437     if inspect.ismemberdescriptor(thing):
   1438         return 'member descriptor %s.%s.%s' % (
   1439             thing.__objclass__.__module__, thing.__objclass__.__name__,
   1440             thing.__name__)
   1441     if inspect.isclass(thing):
   1442         return 'class ' + thing.__name__
   1443     if inspect.isfunction(thing):
   1444         return 'function ' + thing.__name__
   1445     if inspect.ismethod(thing):
   1446         return 'method ' + thing.__name__
   1447     if type(thing) is types.InstanceType:
   1448         return 'instance of ' + thing.__class__.__name__
   1449     return type(thing).__name__
   1450 
   1451 def locate(path, forceload=0):
   1452     """Locate an object by name or dotted path, importing as necessary."""
   1453     parts = [part for part in split(path, '.') if part]
   1454     module, n = None, 0
   1455     while n < len(parts):
   1456         nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
   1457         if nextmodule: module, n = nextmodule, n + 1
   1458         else: break
   1459     if module:
   1460         object = module
   1461         for part in parts[n:]:
   1462             try: object = getattr(object, part)
   1463             except AttributeError: return None
   1464         return object
   1465     else:
   1466         if hasattr(__builtin__, path):
   1467             return getattr(__builtin__, path)
   1468 
   1469 # --------------------------------------- interactive interpreter interface
   1470 
   1471 text = TextDoc()
   1472 html = HTMLDoc()
   1473 
   1474 class _OldStyleClass: pass
   1475 _OLD_INSTANCE_TYPE = type(_OldStyleClass())
   1476 
   1477 def resolve(thing, forceload=0):
   1478     """Given an object or a path to an object, get the object and its name."""
   1479     if isinstance(thing, str):
   1480         object = locate(thing, forceload)
   1481         if not object:
   1482             raise ImportError, 'no Python documentation found for %r' % thing
   1483         return object, thing
   1484     else:
   1485         return thing, getattr(thing, '__name__', None)
   1486 
   1487 def render_doc(thing, title='Python Library Documentation: %s', forceload=0):
   1488     """Render text documentation, given an object or a path to an object."""
   1489     object, name = resolve(thing, forceload)
   1490     desc = describe(object)
   1491     module = inspect.getmodule(object)
   1492     if name and '.' in name:
   1493         desc += ' in ' + name[:name.rfind('.')]
   1494     elif module and module is not object:
   1495         desc += ' in module ' + module.__name__
   1496     if type(object) is _OLD_INSTANCE_TYPE:
   1497         # If the passed object is an instance of an old-style class,
   1498         # document its available methods instead of its value.
   1499         object = object.__class__
   1500     elif not (inspect.ismodule(object) or
   1501               inspect.isclass(object) or
   1502               inspect.isroutine(object) or
   1503               inspect.isgetsetdescriptor(object) or
   1504               inspect.ismemberdescriptor(object) or
   1505               isinstance(object, property)):
   1506         # If the passed object is a piece of data or an instance,
   1507         # document its available methods instead of its value.
   1508         object = type(object)
   1509         desc += ' object'
   1510     return title % desc + '\n\n' + text.document(object, name)
   1511 
   1512 def doc(thing, title='Python Library Documentation: %s', forceload=0):
   1513     """Display text documentation, given an object or a path to an object."""
   1514     try:
   1515         pager(render_doc(thing, title, forceload))
   1516     except (ImportError, ErrorDuringImport), value:
   1517         print value
   1518 
   1519 def writedoc(thing, forceload=0):
   1520     """Write HTML documentation to a file in the current directory."""
   1521     try:
   1522         object, name = resolve(thing, forceload)
   1523         page = html.page(describe(object), html.document(object, name))
   1524         file = open(name + '.html', 'w')
   1525         file.write(page)
   1526         file.close()
   1527         print 'wrote', name + '.html'
   1528     except (ImportError, ErrorDuringImport), value:
   1529         print value
   1530 
   1531 def writedocs(dir, pkgpath='', done=None):
   1532     """Write out HTML documentation for all modules in a directory tree."""
   1533     if done is None: done = {}
   1534     for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
   1535         writedoc(modname)
   1536     return
   1537 
   1538 class Helper:
   1539 
   1540     # These dictionaries map a topic name to either an alias, or a tuple
   1541     # (label, seealso-items).  The "label" is the label of the corresponding
   1542     # section in the .rst file under Doc/ and an index into the dictionary
   1543     # in pydoc_data/topics.py.
   1544     #
   1545     # CAUTION: if you change one of these dictionaries, be sure to adapt the
   1546     #          list of needed labels in Doc/tools/sphinxext/pyspecific.py and
   1547     #          regenerate the pydoc_data/topics.py file by running
   1548     #              make pydoc-topics
   1549     #          in Doc/ and copying the output file into the Lib/ directory.
   1550 
   1551     keywords = {
   1552         'and': 'BOOLEAN',
   1553         'as': 'with',
   1554         'assert': ('assert', ''),
   1555         'break': ('break', 'while for'),
   1556         'class': ('class', 'CLASSES SPECIALMETHODS'),
   1557         'continue': ('continue', 'while for'),
   1558         'def': ('function', ''),
   1559         'del': ('del', 'BASICMETHODS'),
   1560         'elif': 'if',
   1561         'else': ('else', 'while for'),
   1562         'except': 'try',
   1563         'exec': ('exec', ''),
   1564         'finally': 'try',
   1565         'for': ('for', 'break continue while'),
   1566         'from': 'import',
   1567         'global': ('global', 'NAMESPACES'),
   1568         'if': ('if', 'TRUTHVALUE'),
   1569         'import': ('import', 'MODULES'),
   1570         'in': ('in', 'SEQUENCEMETHODS2'),
   1571         'is': 'COMPARISON',
   1572         'lambda': ('lambda', 'FUNCTIONS'),
   1573         'not': 'BOOLEAN',
   1574         'or': 'BOOLEAN',
   1575         'pass': ('pass', ''),
   1576         'print': ('print', ''),
   1577         'raise': ('raise', 'EXCEPTIONS'),
   1578         'return': ('return', 'FUNCTIONS'),
   1579         'try': ('try', 'EXCEPTIONS'),
   1580         'while': ('while', 'break continue if TRUTHVALUE'),
   1581         'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
   1582         'yield': ('yield', ''),
   1583     }
   1584     # Either add symbols to this dictionary or to the symbols dictionary
   1585     # directly: Whichever is easier. They are merged later.
   1586     _symbols_inverse = {
   1587         'STRINGS' : ("'", "'''", "r'", "u'", '"""', '"', 'r"', 'u"'),
   1588         'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
   1589                        '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
   1590         'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
   1591         'UNARY' : ('-', '~'),
   1592         'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
   1593                                 '^=', '<<=', '>>=', '**=', '//='),
   1594         'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
   1595         'COMPLEX' : ('j', 'J')
   1596     }
   1597     symbols = {
   1598         '%': 'OPERATORS FORMATTING',
   1599         '**': 'POWER',
   1600         ',': 'TUPLES LISTS FUNCTIONS',
   1601         '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
   1602         '...': 'ELLIPSIS',
   1603         ':': 'SLICINGS DICTIONARYLITERALS',
   1604         '@': 'def class',
   1605         '\\': 'STRINGS',
   1606         '_': 'PRIVATENAMES',
   1607         '__': 'PRIVATENAMES SPECIALMETHODS',
   1608         '`': 'BACKQUOTES',
   1609         '(': 'TUPLES FUNCTIONS CALLS',
   1610         ')': 'TUPLES FUNCTIONS CALLS',
   1611         '[': 'LISTS SUBSCRIPTS SLICINGS',
   1612         ']': 'LISTS SUBSCRIPTS SLICINGS'
   1613     }
   1614     for topic, symbols_ in _symbols_inverse.iteritems():
   1615         for symbol in symbols_:
   1616             topics = symbols.get(symbol, topic)
   1617             if topic not in topics:
   1618                 topics = topics + ' ' + topic
   1619             symbols[symbol] = topics
   1620 
   1621     topics = {
   1622         'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
   1623                   'FUNCTIONS CLASSES MODULES FILES inspect'),
   1624         'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING '
   1625                     'TYPES'),
   1626         'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
   1627         'FORMATTING': ('formatstrings', 'OPERATORS'),
   1628         'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
   1629                     'FORMATTING TYPES'),
   1630         'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
   1631         'INTEGER': ('integers', 'int range'),
   1632         'FLOAT': ('floating', 'float math'),
   1633         'COMPLEX': ('imaginary', 'complex cmath'),
   1634         'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
   1635         'MAPPINGS': 'DICTIONARIES',
   1636         'FUNCTIONS': ('typesfunctions', 'def TYPES'),
   1637         'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
   1638         'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
   1639         'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
   1640         'FRAMEOBJECTS': 'TYPES',
   1641         'TRACEBACKS': 'TYPES',
   1642         'NONE': ('bltin-null-object', ''),
   1643         'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
   1644         'FILES': ('bltin-file-objects', ''),
   1645         'SPECIALATTRIBUTES': ('specialattrs', ''),
   1646         'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
   1647         'MODULES': ('typesmodules', 'import'),
   1648         'PACKAGES': 'import',
   1649         'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
   1650                         'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
   1651                         'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
   1652                         'LISTS DICTIONARIES BACKQUOTES'),
   1653         'OPERATORS': 'EXPRESSIONS',
   1654         'PRECEDENCE': 'EXPRESSIONS',
   1655         'OBJECTS': ('objects', 'TYPES'),
   1656         'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
   1657                            'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS '
   1658                            'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
   1659         'BASICMETHODS': ('customization', 'cmp hash repr str SPECIALMETHODS'),
   1660         'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
   1661         'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
   1662         'SEQUENCEMETHODS1': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 '
   1663                              'SPECIALMETHODS'),
   1664         'SEQUENCEMETHODS2': ('sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 '
   1665                              'SPECIALMETHODS'),
   1666         'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
   1667         'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
   1668                           'SPECIALMETHODS'),
   1669         'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
   1670         'NAMESPACES': ('naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
   1671         'DYNAMICFEATURES': ('dynamic-features', ''),
   1672         'SCOPING': 'NAMESPACES',
   1673         'FRAMES': 'NAMESPACES',
   1674         'EXCEPTIONS': ('exceptions', 'try except finally raise'),
   1675         'COERCIONS': ('coercion-rules','CONVERSIONS'),
   1676         'CONVERSIONS': ('conversions', 'COERCIONS'),
   1677         'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
   1678         'SPECIALIDENTIFIERS': ('id-classes', ''),
   1679         'PRIVATENAMES': ('atom-identifiers', ''),
   1680         'LITERALS': ('atom-literals', 'STRINGS BACKQUOTES NUMBERS '
   1681                      'TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
   1682         'TUPLES': 'SEQUENCES',
   1683         'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
   1684         'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
   1685         'LISTLITERALS': ('lists', 'LISTS LITERALS'),
   1686         'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
   1687         'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
   1688         'BACKQUOTES': ('string-conversions', 'repr str STRINGS LITERALS'),
   1689         'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr '
   1690                        'ATTRIBUTEMETHODS'),
   1691         'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS1'),
   1692         'SLICINGS': ('slicings', 'SEQUENCEMETHODS2'),
   1693         'CALLS': ('calls', 'EXPRESSIONS'),
   1694         'POWER': ('power', 'EXPRESSIONS'),
   1695         'UNARY': ('unary', 'EXPRESSIONS'),
   1696         'BINARY': ('binary', 'EXPRESSIONS'),
   1697         'SHIFTING': ('shifting', 'EXPRESSIONS'),
   1698         'BITWISE': ('bitwise', 'EXPRESSIONS'),
   1699         'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
   1700         'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
   1701         'ASSERTION': 'assert',
   1702         'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
   1703         'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
   1704         'DELETION': 'del',
   1705         'PRINTING': 'print',
   1706         'RETURNING': 'return',
   1707         'IMPORTING': 'import',
   1708         'CONDITIONAL': 'if',
   1709         'LOOPING': ('compound', 'for while break continue'),
   1710         'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
   1711         'DEBUGGING': ('debugger', 'pdb'),
   1712         'CONTEXTMANAGERS': ('context-managers', 'with'),
   1713     }
   1714 
   1715     def __init__(self, input=None, output=None):
   1716         self._input = input
   1717         self._output = output
   1718 
   1719     input  = property(lambda self: self._input or sys.stdin)
   1720     output = property(lambda self: self._output or sys.stdout)
   1721 
   1722     def __repr__(self):
   1723         if inspect.stack()[1][3] == '?':
   1724             self()
   1725             return ''
   1726         return '<pydoc.Helper instance>'
   1727 
   1728     _GoInteractive = object()
   1729     def __call__(self, request=_GoInteractive):
   1730         if request is not self._GoInteractive:
   1731             self.help(request)
   1732         else:
   1733             self.intro()
   1734             self.interact()
   1735             self.output.write('''
   1736 You are now leaving help and returning to the Python interpreter.
   1737 If you want to ask for help on a particular object directly from the
   1738 interpreter, you can type "help(object)".  Executing "help('string')"
   1739 has the same effect as typing a particular string at the help> prompt.
   1740 ''')
   1741 
   1742     def interact(self):
   1743         self.output.write('\n')
   1744         while True:
   1745             try:
   1746                 request = self.getline('help> ')
   1747                 if not request: break
   1748             except (KeyboardInterrupt, EOFError):
   1749                 break
   1750             request = strip(replace(request, '"', '', "'", ''))
   1751             if lower(request) in ('q', 'quit'): break
   1752             self.help(request)
   1753 
   1754     def getline(self, prompt):
   1755         """Read one line, using raw_input when available."""
   1756         if self.input is sys.stdin:
   1757             return raw_input(prompt)
   1758         else:
   1759             self.output.write(prompt)
   1760             self.output.flush()
   1761             return self.input.readline()
   1762 
   1763     def help(self, request):
   1764         if type(request) is type(''):
   1765             request = request.strip()
   1766             if request == 'help': self.intro()
   1767             elif request == 'keywords': self.listkeywords()
   1768             elif request == 'symbols': self.listsymbols()
   1769             elif request == 'topics': self.listtopics()
   1770             elif request == 'modules': self.listmodules()
   1771             elif request[:8] == 'modules ':
   1772                 self.listmodules(split(request)[1])
   1773             elif request in self.symbols: self.showsymbol(request)
   1774             elif request in self.keywords: self.showtopic(request)
   1775             elif request in self.topics: self.showtopic(request)
   1776             elif request: doc(request, 'Help on %s:')
   1777         elif isinstance(request, Helper): self()
   1778         else: doc(request, 'Help on %s:')
   1779         self.output.write('\n')
   1780 
   1781     def intro(self):
   1782         self.output.write('''
   1783 Welcome to Python %s!  This is the online help utility.
   1784 
   1785 If this is your first time using Python, you should definitely check out
   1786 the tutorial on the Internet at http://docs.python.org/tutorial/.
   1787 
   1788 Enter the name of any module, keyword, or topic to get help on writing
   1789 Python programs and using Python modules.  To quit this help utility and
   1790 return to the interpreter, just type "quit".
   1791 
   1792 To get a list of available modules, keywords, or topics, type "modules",
   1793 "keywords", or "topics".  Each module also comes with a one-line summary
   1794 of what it does; to list the modules whose summaries contain a given word
   1795 such as "spam", type "modules spam".
   1796 ''' % sys.version[:3])
   1797 
   1798     def list(self, items, columns=4, width=80):
   1799         items = items[:]
   1800         items.sort()
   1801         colw = width / columns
   1802         rows = (len(items) + columns - 1) / columns
   1803         for row in range(rows):
   1804             for col in range(columns):
   1805                 i = col * rows + row
   1806                 if i < len(items):
   1807                     self.output.write(items[i])
   1808                     if col < columns - 1:
   1809                         self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
   1810             self.output.write('\n')
   1811 
   1812     def listkeywords(self):
   1813         self.output.write('''
   1814 Here is a list of the Python keywords.  Enter any keyword to get more help.
   1815 
   1816 ''')
   1817         self.list(self.keywords.keys())
   1818 
   1819     def listsymbols(self):
   1820         self.output.write('''
   1821 Here is a list of the punctuation symbols which Python assigns special meaning
   1822 to. Enter any symbol to get more help.
   1823 
   1824 ''')
   1825         self.list(self.symbols.keys())
   1826 
   1827     def listtopics(self):
   1828         self.output.write('''
   1829 Here is a list of available topics.  Enter any topic name to get more help.
   1830 
   1831 ''')
   1832         self.list(self.topics.keys())
   1833 
   1834     def showtopic(self, topic, more_xrefs=''):
   1835         try:
   1836             import pydoc_data.topics
   1837         except ImportError:
   1838             self.output.write('''
   1839 Sorry, topic and keyword documentation is not available because the
   1840 module "pydoc_data.topics" could not be found.
   1841 ''')
   1842             return
   1843         target = self.topics.get(topic, self.keywords.get(topic))
   1844         if not target:
   1845             self.output.write('no documentation found for %s\n' % repr(topic))
   1846             return
   1847         if type(target) is type(''):
   1848             return self.showtopic(target, more_xrefs)
   1849 
   1850         label, xrefs = target
   1851         try:
   1852             doc = pydoc_data.topics.topics[label]
   1853         except KeyError:
   1854             self.output.write('no documentation found for %s\n' % repr(topic))
   1855             return
   1856         pager(strip(doc) + '\n')
   1857         if more_xrefs:
   1858             xrefs = (xrefs or '') + ' ' + more_xrefs
   1859         if xrefs:
   1860             import StringIO, formatter
   1861             buffer = StringIO.StringIO()
   1862             formatter.DumbWriter(buffer).send_flowing_data(
   1863                 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
   1864             self.output.write('\n%s\n' % buffer.getvalue())
   1865 
   1866     def showsymbol(self, symbol):
   1867         target = self.symbols[symbol]
   1868         topic, _, xrefs = target.partition(' ')
   1869         self.showtopic(topic, xrefs)
   1870 
   1871     def listmodules(self, key=''):
   1872         if key:
   1873             self.output.write('''
   1874 Here is a list of matching modules.  Enter any module name to get more help.
   1875 
   1876 ''')
   1877             apropos(key)
   1878         else:
   1879             self.output.write('''
   1880 Please wait a moment while I gather a list of all available modules...
   1881 
   1882 ''')
   1883             modules = {}
   1884             def callback(path, modname, desc, modules=modules):
   1885                 if modname and modname[-9:] == '.__init__':
   1886                     modname = modname[:-9] + ' (package)'
   1887                 if find(modname, '.') < 0:
   1888                     modules[modname] = 1
   1889             def onerror(modname):
   1890                 callback(None, modname, None)
   1891             ModuleScanner().run(callback, onerror=onerror)
   1892             self.list(modules.keys())
   1893             self.output.write('''
   1894 Enter any module name to get more help.  Or, type "modules spam" to search
   1895 for modules whose descriptions contain the word "spam".
   1896 ''')
   1897 
   1898 help = Helper()
   1899 
   1900 class Scanner:
   1901     """A generic tree iterator."""
   1902     def __init__(self, roots, children, descendp):
   1903         self.roots = roots[:]
   1904         self.state = []
   1905         self.children = children
   1906         self.descendp = descendp
   1907 
   1908     def next(self):
   1909         if not self.state:
   1910             if not self.roots:
   1911                 return None
   1912             root = self.roots.pop(0)
   1913             self.state = [(root, self.children(root))]
   1914         node, children = self.state[-1]
   1915         if not children:
   1916             self.state.pop()
   1917             return self.next()
   1918         child = children.pop(0)
   1919         if self.descendp(child):
   1920             self.state.append((child, self.children(child)))
   1921         return child
   1922 
   1923 
   1924 class ModuleScanner:
   1925     """An interruptible scanner that searches module synopses."""
   1926 
   1927     def run(self, callback, key=None, completer=None, onerror=None):
   1928         if key: key = lower(key)
   1929         self.quit = False
   1930         seen = {}
   1931 
   1932         for modname in sys.builtin_module_names:
   1933             if modname != '__main__':
   1934                 seen[modname] = 1
   1935                 if key is None:
   1936                     callback(None, modname, '')
   1937                 else:
   1938                     desc = split(__import__(modname).__doc__ or '', '\n')[0]
   1939                     if find(lower(modname + ' - ' + desc), key) >= 0:
   1940                         callback(None, modname, desc)
   1941 
   1942         for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
   1943             if self.quit:
   1944                 break
   1945             if key is None:
   1946                 callback(None, modname, '')
   1947             else:
   1948                 loader = importer.find_module(modname)
   1949                 if hasattr(loader,'get_source'):
   1950                     import StringIO
   1951                     desc = source_synopsis(
   1952                         StringIO.StringIO(loader.get_source(modname))
   1953                     ) or ''
   1954                     if hasattr(loader,'get_filename'):
   1955                         path = loader.get_filename(modname)
   1956                     else:
   1957                         path = None
   1958                 else:
   1959                     module = loader.load_module(modname)
   1960                     desc = (module.__doc__ or '').splitlines()[0]
   1961                     path = getattr(module,'__file__',None)
   1962                 if find(lower(modname + ' - ' + desc), key) >= 0:
   1963                     callback(path, modname, desc)
   1964 
   1965         if completer:
   1966             completer()
   1967 
   1968 def apropos(key):
   1969     """Print all the one-line module summaries that contain a substring."""
   1970     def callback(path, modname, desc):
   1971         if modname[-9:] == '.__init__':
   1972             modname = modname[:-9] + ' (package)'
   1973         print modname, desc and '- ' + desc
   1974     try: import warnings
   1975     except ImportError: pass
   1976     else: warnings.filterwarnings('ignore') # ignore problems during import
   1977     ModuleScanner().run(callback, key)
   1978 
   1979 # --------------------------------------------------- web browser interface
   1980 
   1981 def serve(port, callback=None, completer=None):
   1982     import BaseHTTPServer, mimetools, select
   1983 
   1984     # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
   1985     class Message(mimetools.Message):
   1986         def __init__(self, fp, seekable=1):
   1987             Message = self.__class__
   1988             Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
   1989             self.encodingheader = self.getheader('content-transfer-encoding')
   1990             self.typeheader = self.getheader('content-type')
   1991             self.parsetype()
   1992             self.parseplist()
   1993 
   1994     class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
   1995         def send_document(self, title, contents):
   1996             try:
   1997                 self.send_response(200)
   1998                 self.send_header('Content-Type', 'text/html')
   1999                 self.end_headers()
   2000                 self.wfile.write(html.page(title, contents))
   2001             except IOError: pass
   2002 
   2003         def do_GET(self):
   2004             path = self.path
   2005             if path[-5:] == '.html': path = path[:-5]
   2006             if path[:1] == '/': path = path[1:]
   2007             if path and path != '.':
   2008                 try:
   2009                     obj = locate(path, forceload=1)
   2010                 except ErrorDuringImport, value:
   2011                     self.send_document(path, html.escape(str(value)))
   2012                     return
   2013                 if obj:
   2014                     self.send_document(describe(obj), html.document(obj, path))
   2015                 else:
   2016                     self.send_document(path,
   2017 'no Python documentation found for %s' % repr(path))
   2018             else:
   2019                 heading = html.heading(
   2020 '<big><big><strong>Python: Index of Modules</strong></big></big>',
   2021 '#ffffff', '#7799ee')
   2022                 def bltinlink(name):
   2023                     return '<a href="%s.html">%s</a>' % (name, name)
   2024                 names = filter(lambda x: x != '__main__',
   2025                                sys.builtin_module_names)
   2026                 contents = html.multicolumn(names, bltinlink)
   2027                 indices = ['<p>' + html.bigsection(
   2028                     'Built-in Modules', '#ffffff', '#ee77aa', contents)]
   2029 
   2030                 seen = {}
   2031                 for dir in sys.path:
   2032                     indices.append(html.index(dir, seen))
   2033                 contents = heading + join(indices) + '''<p align=right>
   2034 <font color="#909090" face="helvetica, arial"><strong>
   2035 pydoc</strong> by Ka-Ping Yee &lt;ping (at] lfw.org&gt;</font>'''
   2036                 self.send_document('Index of Modules', contents)
   2037 
   2038         def log_message(self, *args): pass
   2039 
   2040     class DocServer(BaseHTTPServer.HTTPServer):
   2041         def __init__(self, port, callback):
   2042             host = 'localhost'
   2043             self.address = (host, port)
   2044             self.url = 'http://%s:%d/' % (host, port)
   2045             self.callback = callback
   2046             self.base.__init__(self, self.address, self.handler)
   2047 
   2048         def serve_until_quit(self):
   2049             import select
   2050             self.quit = False
   2051             while not self.quit:
   2052                 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
   2053                 if rd: self.handle_request()
   2054 
   2055         def server_activate(self):
   2056             self.base.server_activate(self)
   2057             if self.callback: self.callback(self)
   2058 
   2059     DocServer.base = BaseHTTPServer.HTTPServer
   2060     DocServer.handler = DocHandler
   2061     DocHandler.MessageClass = Message
   2062     try:
   2063         try:
   2064             DocServer(port, callback).serve_until_quit()
   2065         except (KeyboardInterrupt, select.error):
   2066             pass
   2067     finally:
   2068         if completer: completer()
   2069 
   2070 # ----------------------------------------------------- graphical interface

   2071 
   2072 def gui():
   2073     """Graphical interface (starts web server and pops up a control window)."""
   2074     class GUI:
   2075         def __init__(self, window, port=7464):
   2076             self.window = window
   2077             self.server = None
   2078             self.scanner = None
   2079 
   2080             import Tkinter
   2081             self.server_frm = Tkinter.Frame(window)
   2082             self.title_lbl = Tkinter.Label(self.server_frm,
   2083                 text='Starting server...\n ')
   2084             self.open_btn = Tkinter.Button(self.server_frm,
   2085                 text='open browser', command=self.open, state='disabled')
   2086             self.quit_btn = Tkinter.Button(self.server_frm,
   2087                 text='quit serving', command=self.quit, state='disabled')
   2088 
   2089             self.search_frm = Tkinter.Frame(window)
   2090             self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
   2091             self.search_ent = Tkinter.Entry(self.search_frm)
   2092             self.search_ent.bind('<Return>', self.search)
   2093             self.stop_btn = Tkinter.Button(self.search_frm,
   2094                 text='stop', pady=0, command=self.stop, state='disabled')
   2095             if sys.platform == 'win32':
   2096                 # Trying to hide and show this button crashes under Windows.

   2097                 self.stop_btn.pack(side='right')
   2098 
   2099             self.window.title('pydoc')
   2100             self.window.protocol('WM_DELETE_WINDOW', self.quit)
   2101             self.title_lbl.pack(side='top', fill='x')
   2102             self.open_btn.pack(side='left', fill='x', expand=1)
   2103             self.quit_btn.pack(side='right', fill='x', expand=1)
   2104             self.server_frm.pack(side='top', fill='x')
   2105 
   2106             self.search_lbl.pack(side='left')
   2107             self.search_ent.pack(side='right', fill='x', expand=1)
   2108             self.search_frm.pack(side='top', fill='x')
   2109             self.search_ent.focus_set()
   2110 
   2111             font = ('helvetica', sys.platform == 'win32' and 8 or 10)
   2112             self.result_lst = Tkinter.Listbox(window, font=font, height=6)
   2113             self.result_lst.bind('<Button-1>', self.select)
   2114             self.result_lst.bind('<Double-Button-1>', self.goto)
   2115             self.result_scr = Tkinter.Scrollbar(window,
   2116                 orient='vertical', command=self.result_lst.yview)
   2117             self.result_lst.config(yscrollcommand=self.result_scr.set)
   2118 
   2119             self.result_frm = Tkinter.Frame(window)
   2120             self.goto_btn = Tkinter.Button(self.result_frm,
   2121                 text='go to selected', command=self.goto)
   2122             self.hide_btn = Tkinter.Button(self.result_frm,
   2123                 text='hide results', command=self.hide)
   2124             self.goto_btn.pack(side='left', fill='x', expand=1)
   2125             self.hide_btn.pack(side='right', fill='x', expand=1)
   2126 
   2127             self.window.update()
   2128             self.minwidth = self.window.winfo_width()
   2129             self.minheight = self.window.winfo_height()
   2130             self.bigminheight = (self.server_frm.winfo_reqheight() +
   2131                                  self.search_frm.winfo_reqheight() +
   2132                                  self.result_lst.winfo_reqheight() +
   2133                                  self.result_frm.winfo_reqheight())
   2134             self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
   2135             self.expanded = 0
   2136             self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
   2137             self.window.wm_minsize(self.minwidth, self.minheight)
   2138             self.window.tk.willdispatch()
   2139 
   2140             import threading
   2141             threading.Thread(
   2142                 target=serve, args=(port, self.ready, self.quit)).start()
   2143 
   2144         def ready(self, server):
   2145             self.server = server
   2146             self.title_lbl.config(
   2147                 text='Python documentation server at\n' + server.url)
   2148             self.open_btn.config(state='normal')
   2149             self.quit_btn.config(state='normal')
   2150 
   2151         def open(self, event=None, url=None):
   2152             url = url or self.server.url
   2153             try:
   2154                 import webbrowser
   2155                 webbrowser.open(url)
   2156             except ImportError: # pre-webbrowser.py compatibility

   2157                 if sys.platform == 'win32':
   2158                     os.system('start "%s"' % url)
   2159                 else:
   2160                     rc = os.system('netscape -remote "openURL(%s)" &' % url)
   2161                     if rc: os.system('netscape "%s" &' % url)
   2162 
   2163         def quit(self, event=None):
   2164             if self.server:
   2165                 self.server.quit = 1
   2166             self.window.quit()
   2167 
   2168         def search(self, event=None):
   2169             key = self.search_ent.get()
   2170             self.stop_btn.pack(side='right')
   2171             self.stop_btn.config(state='normal')
   2172             self.search_lbl.config(text='Searching for "%s"...' % key)
   2173             self.search_ent.forget()
   2174             self.search_lbl.pack(side='left')
   2175             self.result_lst.delete(0, 'end')
   2176             self.goto_btn.config(state='disabled')
   2177             self.expand()
   2178 
   2179             import threading
   2180             if self.scanner:
   2181                 self.scanner.quit = 1
   2182             self.scanner = ModuleScanner()
   2183             threading.Thread(target=self.scanner.run,
   2184                              args=(self.update, key, self.done)).start()
   2185 
   2186         def update(self, path, modname, desc):
   2187             if modname[-9:] == '.__init__':
   2188                 modname = modname[:-9] + ' (package)'
   2189             self.result_lst.insert('end',
   2190                 modname + ' - ' + (desc or '(no description)'))
   2191 
   2192         def stop(self, event=None):
   2193             if self.scanner:
   2194                 self.scanner.quit = 1
   2195                 self.scanner = None
   2196 
   2197         def done(self):
   2198             self.scanner = None
   2199             self.search_lbl.config(text='Search for')
   2200             self.search_lbl.pack(side='left')
   2201             self.search_ent.pack(side='right', fill='x', expand=1)
   2202             if sys.platform != 'win32': self.stop_btn.forget()
   2203             self.stop_btn.config(state='disabled')
   2204 
   2205         def select(self, event=None):
   2206             self.goto_btn.config(state='normal')
   2207 
   2208         def goto(self, event=None):
   2209             selection = self.result_lst.curselection()
   2210             if selection:
   2211                 modname = split(self.result_lst.get(selection[0]))[0]
   2212                 self.open(url=self.server.url + modname + '.html')
   2213 
   2214         def collapse(self):
   2215             if not self.expanded: return
   2216             self.result_frm.forget()
   2217             self.result_scr.forget()
   2218             self.result_lst.forget()
   2219             self.bigwidth = self.window.winfo_width()
   2220             self.bigheight = self.window.winfo_height()
   2221             self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
   2222             self.window.wm_minsize(self.minwidth, self.minheight)
   2223             self.expanded = 0
   2224 
   2225         def expand(self):
   2226             if self.expanded: return
   2227             self.result_frm.pack(side='bottom', fill='x')
   2228             self.result_scr.pack(side='right', fill='y')
   2229             self.result_lst.pack(side='top', fill='both', expand=1)
   2230             self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
   2231             self.window.wm_minsize(self.minwidth, self.bigminheight)
   2232             self.expanded = 1
   2233 
   2234         def hide(self, event=None):
   2235             self.stop()
   2236             self.collapse()
   2237 
   2238     import Tkinter
   2239     try:
   2240         root = Tkinter.Tk()
   2241         # Tk will crash if pythonw.exe has an XP .manifest

   2242         # file and the root has is not destroyed explicitly.

   2243         # If the problem is ever fixed in Tk, the explicit

   2244         # destroy can go.

   2245         try:
   2246             gui = GUI(root)
   2247             root.mainloop()
   2248         finally:
   2249             root.destroy()
   2250     except KeyboardInterrupt:
   2251         pass
   2252 
   2253 # -------------------------------------------------- command-line interface

   2254 
   2255 def ispath(x):
   2256     return isinstance(x, str) and find(x, os.sep) >= 0
   2257 
   2258 def cli():
   2259     """Command-line interface (looks at sys.argv to decide what to do)."""
   2260     import getopt
   2261     class BadUsage: pass
   2262 
   2263     # Scripts don't get the current directory in their path by default

   2264     # unless they are run with the '-m' switch

   2265     if '' not in sys.path:
   2266         scriptdir = os.path.dirname(sys.argv[0])
   2267         if scriptdir in sys.path:
   2268             sys.path.remove(scriptdir)
   2269         sys.path.insert(0, '.')
   2270 
   2271     try:
   2272         opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
   2273         writing = 0
   2274 
   2275         for opt, val in opts:
   2276             if opt == '-g':
   2277                 gui()
   2278                 return
   2279             if opt == '-k':
   2280                 apropos(val)
   2281                 return
   2282             if opt == '-p':
   2283                 try:
   2284                     port = int(val)
   2285                 except ValueError:
   2286                     raise BadUsage
   2287                 def ready(server):
   2288                     print 'pydoc server ready at %s' % server.url
   2289                 def stopped():
   2290                     print 'pydoc server stopped'
   2291                 serve(port, ready, stopped)
   2292                 return
   2293             if opt == '-w':
   2294                 writing = 1
   2295 
   2296         if not args: raise BadUsage
   2297         for arg in args:
   2298             if ispath(arg) and not os.path.exists(arg):
   2299                 print 'file %r does not exist' % arg
   2300                 break
   2301             try:
   2302                 if ispath(arg) and os.path.isfile(arg):
   2303                     arg = importfile(arg)
   2304                 if writing:
   2305                     if ispath(arg) and os.path.isdir(arg):
   2306                         writedocs(arg)
   2307                     else:
   2308                         writedoc(arg)
   2309                 else:
   2310                     help.help(arg)
   2311             except ErrorDuringImport, value:
   2312                 print value
   2313 
   2314     except (getopt.error, BadUsage):
   2315         cmd = os.path.basename(sys.argv[0])
   2316         print """pydoc - the Python documentation tool
   2317 
   2318 %s <name> ...
   2319     Show text documentation on something.  <name> may be the name of a
   2320     Python keyword, topic, function, module, or package, or a dotted
   2321     reference to a class or function within a module or module in a
   2322     package.  If <name> contains a '%s', it is used as the path to a
   2323     Python source file to document. If name is 'keywords', 'topics',
   2324     or 'modules', a listing of these things is displayed.
   2325 
   2326 %s -k <keyword>
   2327     Search for a keyword in the synopsis lines of all available modules.
   2328 
   2329 %s -p <port>
   2330     Start an HTTP server on the given port on the local machine.
   2331 
   2332 %s -g
   2333     Pop up a graphical interface for finding and serving documentation.
   2334 
   2335 %s -w <name> ...
   2336     Write out the HTML documentation for a module to a file in the current
   2337     directory.  If <name> contains a '%s', it is treated as a filename; if
   2338     it names a directory, documentation is written for all the contents.
   2339 """ % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
   2340 
   2341 if __name__ == '__main__': cli()
   2342