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