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