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

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

      3 
      4 # Module 'pydoc' -- Generate Python documentation in HTML or text for interactive use.

      5 #

      6 # Copyright (c) 2015, Daryl McDaniel. All rights reserved.<BR>

      7 # Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>

      8 # This program and the accompanying materials are licensed and made available under

      9 # the terms and conditions of the BSD License that accompanies this distribution.

     10 # The full text of the license may be found at

     11 # http://opensource.org/licenses/bsd-license.

     12 #

     13 # THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,

     14 # WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.

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

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

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

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

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

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

     67 #     path will be displayed.

     68 
     69 import sys, imp, os, re, types, inspect, __builtin__, pkgutil, warnings
     70 from repr import Repr
     71 from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
     72 from traceback import extract_tb
     73 try:
     74     from collections import deque
     75 except ImportError:
     76     # Python 2.3 compatibility

     77     class deque(list):
     78         def popleft(self):
     79             return self.pop(0)
     80 
     81 # --------------------------------------------------------- common routines

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

    142     return _re_stripid.sub(r'\1', text)
    143 
    144 def _is_some_method(obj):
    145     return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
    146 
    147 def allmethods(cl):
    148     methods = {}
    149     for key, value in inspect.getmembers(cl, _is_some_method):
    150         methods[key] = 1
    151     for base in cl.__bases__:
    152         methods.update(allmethods(base)) # all your base are belong to us

    153     for key in methods.keys():
    154         methods[key] = getattr(cl, key)
    155     return methods
    156 
    157 def _split_list(s, predicate):
    158     """Split sequence s via predicate, and return pair ([true], [false]).
    159 
    160     The return value is a 2-tuple of lists,
    161         ([x for x in s if predicate(x)],
    162          [x for x in s if not predicate(x)])
    163     """
    164 
    165     yes = []
    166     no = []
    167     for x in s:
    168         if predicate(x):
    169             yes.append(x)
    170         else:
    171             no.append(x)
    172     return yes, no
    173 
    174 def visiblename(name, all=None, obj=None):
    175     """Decide whether to show documentation on a variable."""
    176     # Certain special names are redundant.

    177     _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__',
    178                      '__module__', '__name__', '__slots__', '__package__')
    179     if name in _hidden_names: return 0
    180     # Private names are hidden, but special names are displayed.

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

    183     if name.startswith('_') and hasattr(obj, '_fields'):
    184         return 1
    185     if all is not None:
    186         # only document that which the programmer exported in __all__

    187         return name in all
    188     else:
    189         return not name.startswith('_')
    190 
    191 def classify_class_attrs(object):
    192     """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
    193     def fixup(data):
    194         name, kind, cls, value = data
    195         if inspect.isdatadescriptor(value):
    196             kind = 'data descriptor'
    197         return name, kind, cls, value
    198     return map(fixup, inspect.classify_class_attrs(object))
    199 
    200 # ----------------------------------------------------- Unicode support helpers

    201 
    202 try:
    203     _unicode = unicode
    204 except NameError:
    205     # If Python is built without Unicode support, the unicode type

    206     # will not exist. Fake one that nothing will match, and make

    207     # the _encode function that do nothing.

    208     class _unicode(object):
    209         pass
    210     _encoding = 'ascii'
    211     def _encode(text, encoding='ascii'):
    212         return text
    213 else:
    214     import locale
    215     _encoding = locale.getpreferredencoding()
    216 
    217     def _encode(text, encoding=None):
    218         if isinstance(text, unicode):
    219             return text.encode(encoding or _encoding, 'xmlcharrefreplace')
    220         else:
    221             return text
    222 
    223 def _binstr(obj):
    224     # Ensure that we have an encoded (binary) string representation of obj,

    225     # even if it is a unicode string.

    226     if isinstance(obj, _unicode):
    227         return obj.encode(_encoding, 'xmlcharrefreplace')
    228     return str(obj)
    229 
    230 # ----------------------------------------------------- module manipulation

    231 
    232 def ispackage(path):
    233     """Guess whether a path refers to a package directory."""
    234     if os.path.isdir(path):
    235         for ext in ('.py', '.pyc', '.pyo'):
    236             if os.path.isfile(os.path.join(path, '__init__' + ext)):
    237                 return True
    238     return False
    239 
    240 def source_synopsis(file):
    241     line = file.readline()
    242     while line[:1] == '#' or not strip(line):
    243         line = file.readline()
    244         if not line: break
    245     line = strip(line)
    246     if line[:4] == 'r"""': line = line[1:]
    247     if line[:3] == '"""':
    248         line = line[3:]
    249         if line[-1:] == '\\': line = line[:-1]
    250         while not strip(line):
    251             line = file.readline()
    252             if not line: break
    253         result = strip(split(line, '"""')[0])
    254     else: result = None
    255     return result
    256 
    257 def synopsis(filename, cache={}):
    258     """Get the one-line summary out of a module file."""
    259     mtime = os.stat(filename).st_mtime
    260     lastupdate, result = cache.get(filename, (None, None))
    261     if lastupdate is None or lastupdate < mtime:
    262         info = inspect.getmoduleinfo(filename)
    263         try:
    264             file = open(filename)
    265         except IOError:
    266             # module can't be opened, so skip it
    267             return None
    268         if info and 'b' in info[2]: # binary modules have to be imported
    269             try: module = imp.load_module('__temp__', file, filename, info[1:])
    270             except: return None
    271             result = module.__doc__.splitlines()[0] if module.__doc__ else None
    272             del sys.modules['__temp__']
    273         else: # text modules can be directly examined
    274             result = source_synopsis(file)
    275             file.close()
    276         cache[filename] = (mtime, result)
    277     return result
    278 
    279 class ErrorDuringImport(Exception):
    280     """Errors that occurred while trying to import something to document it."""
    281     def __init__(self, filename, exc_info):
    282         exc, value, tb = exc_info
    283         self.filename = filename
    284         self.exc = exc
    285         self.value = value
    286         self.tb = tb
    287 
    288     def __str__(self):
    289         exc = self.exc
    290         if type(exc) is types.ClassType:
    291             exc = exc.__name__
    292         return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
    293 
    294 def importfile(path):
    295     """Import a Python source file or compiled file given its path."""
    296     magic = imp.get_magic()
    297     file = open(path, 'r')
    298     if file.read(len(magic)) == magic:
    299         kind = imp.PY_COMPILED
    300     else:
    301         kind = imp.PY_SOURCE
    302     file.close()
    303     filename = os.path.basename(path)
    304     name, ext = os.path.splitext(filename)
    305     file = open(path, 'r')
    306     try:
    307         module = imp.load_module(name, file, path, (ext, 'r', kind))
    308     except:
    309         raise ErrorDuringImport(path, sys.exc_info())
    310     file.close()
    311     return module
    312 
    313 def safeimport(path, forceload=0, cache={}):
    314     """Import a module; handle errors; return None if the module isn't found.
    315 
    316     If the module *is* found but an exception occurs, it's wrapped in an
    317     ErrorDuringImport exception and reraised.  Unlike __import__, if a
    318     package path is specified, the module at the end of the path is returned,
    319     not the package at the beginning.  If the optional 'forceload' argument
    320     is 1, we reload the module from disk (unless it's a dynamic extension)."""
    321     try:
    322         # If forceload is 1 and the module has been previously loaded from
    323         # disk, we always have to reload the module.  Checking the file's
    324         # mtime isn't good enough (e.g. the module could contain a class

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

    326         if forceload and path in sys.modules:
    327             if path not in sys.builtin_module_names:
    328                 # Avoid simply calling reload() because it leaves names in

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

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

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

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

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

    334                 subs = [m for m in sys.modules if m.startswith(path + '.')]
    335                 for key in [path] + subs:
    336                     # Prevent garbage collection.

    337                     cache[key] = sys.modules[key]
    338                     del sys.modules[key]
    339         module = __import__(path)
    340     except:
    341         # Did the error occur before or after the module was found?

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

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

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

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

    352             return None
    353         else:
    354             # Some other error occurred during the importing process.

    355             raise ErrorDuringImport(path, sys.exc_info())
    356     for part in split(path, '.')[1:]:
    357         try: module = getattr(module, part)
    358         except AttributeError: return None
    359     return module
    360 
    361 # ---------------------------------------------------- formatter base class

    362 
    363 class Doc:
    364     def document(self, object, name=None, *args):
    365         """Generate documentation for an object."""
    366         args = (object, name) + args
    367         # 'try' clause is to attempt to handle the possibility that inspect

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

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

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

    371         if inspect.isgetsetdescriptor(object): return self.docdata(*args)
    372         if inspect.ismemberdescriptor(object): return self.docdata(*args)
    373         try:
    374             if inspect.ismodule(object): return self.docmodule(*args)
    375             if inspect.isclass(object): return self.docclass(*args)
    376             if inspect.isroutine(object): return self.docroutine(*args)
    377         except AttributeError:
    378             pass
    379         if isinstance(object, property): return self.docproperty(*args)
    380         return self.docother(*args)
    381 
    382     def fail(self, object, name=None, *args):
    383         """Raise an exception for unimplemented types."""
    384         message = "don't know how to document object%s of type %s" % (
    385             name and ' ' + repr(name), type(object).__name__)
    386         raise TypeError, message
    387 
    388     docmodule = docclass = docroutine = docother = docproperty = docdata = fail
    389 
    390     def getdocloc(self, object):
    391         """Return the location of module docs or None"""
    392 
    393         try:
    394             file = inspect.getabsfile(object)
    395         except TypeError:
    396             file = '(built-in)'
    397 
    398         docloc = os.environ.get("PYTHONDOCS",
    399                                 "http://docs.python.org/library")
    400         basedir = os.path.join(sys.exec_prefix, "lib",
    401                                "python"+sys.version[0:3])
    402         if (isinstance(object, type(os)) and
    403             (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
    404                                  'marshal', 'posix', 'signal', 'sys',
    405                                  'thread', 'zipimport') or
    406              (file.startswith(basedir) and
    407               not file.startswith(os.path.join(basedir, 'site-packages')))) and
    408             object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
    409             if docloc.startswith("http://"):
    410                 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__)
    411             else:
    412                 docloc = os.path.join(docloc, object.__name__ + ".html")
    413         else:
    414             docloc = None
    415         return docloc
    416 
    417 # -------------------------------------------- HTML documentation generator

    418 
    419 class HTMLRepr(Repr):
    420     """Class for safely making an HTML representation of a Python object."""
    421     def __init__(self):
    422         Repr.__init__(self)
    423         self.maxlist = self.maxtuple = 20
    424         self.maxdict = 10
    425         self.maxstring = self.maxother = 100
    426 
    427     def escape(self, text):
    428         return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
    429 
    430     def repr(self, object):
    431         return Repr.repr(self, object)
    432 
    433     def repr1(self, x, level):
    434         if hasattr(type(x), '__name__'):
    435             methodname = 'repr_' + join(split(type(x).__name__), '_')
    436             if hasattr(self, methodname):
    437                 return getattr(self, methodname)(x, level)
    438         return self.escape(cram(stripid(repr(x)), self.maxother))
    439 
    440     def repr_string(self, x, level):
    441         test = cram(x, self.maxstring)
    442         testrepr = repr(test)
    443         if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
    444             # Backslashes are only literal in the string and are never
    445             # needed to make any special characters, so show a raw string.
    446             return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
    447         return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
    448                       r'<font color="#c040c0">\1</font>',
    449                       self.escape(testrepr))
    450 
    451     repr_str = repr_string
    452 
    453     def repr_instance(self, x, level):
    454         try:
    455             return self.escape(cram(stripid(repr(x)), self.maxstring))
    456         except:
    457             return self.escape('<%s instance>' % x.__class__.__name__)
    458 
    459     repr_unicode = repr_string
    460 
    461 class HTMLDoc(Doc):
    462     """Formatter class for HTML documentation."""
    463 
    464     # ------------------------------------------- HTML formatting utilities

    465 
    466     _repr_instance = HTMLRepr()
    467     repr = _repr_instance.repr
    468     escape = _repr_instance.escape
    469 
    470     def page(self, title, contents):
    471         """Format an HTML page."""
    472         return _encode('''
    473 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
    474 <html><head><title>Python: %s</title>
    475 <meta charset="utf-8">
    476 </head><body bgcolor="#f0f0f8">
    477 %s
    478 </body></html>''' % (title, contents), 'ascii')
    479 
    480     def heading(self, title, fgcol, bgcol, extras=''):
    481         """Format a page heading."""
    482         return '''
    483 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
    484 <tr bgcolor="%s">
    485 <td valign=bottom>&nbsp;<br>
    486 <font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
    487 ><td align=right valign=bottom
    488 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
    489     ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
    490 
    491     def section(self, title, fgcol, bgcol, contents, width=6,
    492                 prelude='', marginalia=None, gap='&nbsp;'):
    493         """Format a section with a heading."""
    494         if marginalia is None:
    495             marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
    496         result = '''<p>
    497 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
    498 <tr bgcolor="%s">
    499 <td colspan=3 valign=bottom>&nbsp;<br>
    500 <font color="%s" face="helvetica, arial">%s</font></td></tr>
    501     ''' % (bgcol, fgcol, title)
    502         if prelude:
    503             result = result + '''
    504 <tr bgcolor="%s"><td rowspan=2>%s</td>
    505 <td colspan=2>%s</td></tr>
    506 <tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
    507         else:
    508             result = result + '''
    509 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
    510 
    511         return result + '\n<td width="100%%">%s</td></tr></table>' % contents
    512 
    513     def bigsection(self, title, *args):
    514         """Format a section with a big heading."""
    515         title = '<big><strong>%s</strong></big>' % title
    516         return self.section(title, *args)
    517 
    518     def preformat(self, text):
    519         """Format literal preformatted text."""
    520         text = self.escape(expandtabs(text))
    521         return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
    522                              ' ', '&nbsp;', '\n', '<br>\n')
    523 
    524     def multicolumn(self, list, format, cols=4):
    525         """Format a list of items into a multi-column list."""
    526         result = ''
    527         rows = (len(list)+cols-1)//cols
    528         for col in range(cols):
    529             result = result + '<td width="%d%%" valign=top>' % (100//cols)
    530             for i in range(rows*col, rows*col+rows):
    531                 if i < len(list):
    532                     result = result + format(list[i]) + '<br>\n'
    533             result = result + '</td>'
    534         return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
    535 
    536     def grey(self, text): return '<font color="#909090">%s</font>' % text
    537 
    538     def namelink(self, name, *dicts):
    539         """Make a link for an identifier, given name-to-URL mappings."""
    540         for dict in dicts:
    541             if name in dict:
    542                 return '<a href="%s">%s</a>' % (dict[name], name)
    543         return name
    544 
    545     def classlink(self, object, modname):
    546         """Make a link for a class."""
    547         name, module = object.__name__, sys.modules.get(object.__module__)
    548         if hasattr(module, name) and getattr(module, name) is object:
    549             return '<a href="%s.html#%s">%s</a>' % (
    550                 module.__name__, name, classname(object, modname))
    551         return classname(object, modname)
    552 
    553     def modulelink(self, object):
    554         """Make a link for a module."""
    555         return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
    556 
    557     def modpkglink(self, data):
    558         """Make a link for a module or package to display in an index."""
    559         name, path, ispackage, shadowed = data
    560         if shadowed:
    561             return self.grey(name)
    562         if path:
    563             url = '%s.%s.html' % (path, name)
    564         else:
    565             url = '%s.html' % name
    566         if ispackage:
    567             text = '<strong>%s</strong>&nbsp;(package)' % name
    568         else:
    569             text = name
    570         return '<a href="%s">%s</a>' % (url, text)
    571 
    572     def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
    573         """Mark up some plain text, given a context of symbols to look for.
    574         Each context dictionary maps object names to anchor names."""
    575         escape = escape or self.escape
    576         results = []
    577         here = 0
    578         pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
    579                                 r'RFC[- ]?(\d+)|'
    580                                 r'PEP[- ]?(\d+)|'
    581                                 r'(self\.)?(\w+))')
    582         while True:
    583             match = pattern.search(text, here)
    584             if not match: break
    585             start, end = match.span()
    586             results.append(escape(text[here:start]))
    587 
    588             all, scheme, rfc, pep, selfdot, name = match.groups()
    589             if scheme:
    590                 url = escape(all).replace('"', '&quot;')
    591                 results.append('<a href="%s">%s</a>' % (url, url))
    592             elif rfc:
    593                 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
    594                 results.append('<a href="%s">%s</a>' % (url, escape(all)))
    595             elif pep:
    596                 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
    597                 results.append('<a href="%s">%s</a>' % (url, escape(all)))
    598             elif selfdot:
    599                 # Create a link for methods like 'self.method(...)'

    600                 # and use <strong> for attributes like 'self.attr'

    601                 if text[end:end+1] == '(':
    602                     results.append('self.' + self.namelink(name, methods))
    603                 else:
    604                     results.append('self.<strong>%s</strong>' % name)
    605             elif text[end:end+1] == '(':
    606                 results.append(self.namelink(name, methods, funcs, classes))
    607             else:
    608                 results.append(self.namelink(name, classes))
    609             here = end
    610         results.append(escape(text[here:]))
    611         return join(results, '')
    612 
    613     # ---------------------------------------------- type-specific routines

    614 
    615     def formattree(self, tree, modname, parent=None):
    616         """Produce HTML for a class tree as given by inspect.getclasstree()."""
    617         result = ''
    618         for entry in tree:
    619             if type(entry) is type(()):
    620                 c, bases = entry
    621                 result = result + '<dt><font face="helvetica, arial">'
    622                 result = result + self.classlink(c, modname)
    623                 if bases and bases != (parent,):
    624                     parents = []
    625                     for base in bases:
    626                         parents.append(self.classlink(base, modname))
    627                     result = result + '(' + join(parents, ', ') + ')'
    628                 result = result + '\n</font></dt>'
    629             elif type(entry) is type([]):
    630                 result = result + '<dd>\n%s</dd>\n' % self.formattree(
    631                     entry, modname, c)
    632         return '<dl>\n%s</dl>\n' % result
    633 
    634     def docmodule(self, object, name=None, mod=None, *ignored):
    635         """Produce HTML documentation for a module object."""
    636         name = object.__name__ # ignore the passed-in name

    637         try:
    638             all = object.__all__
    639         except AttributeError:
    640             all = None
    641         parts = split(name, '.')
    642         links = []
    643         for i in range(len(parts)-1):
    644             links.append(
    645                 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
    646                 (join(parts[:i+1], '.'), parts[i]))
    647         linkedname = join(links + parts[-1:], '.')
    648         head = '<big><big><strong>%s</strong></big></big>' % linkedname
    649         try:
    650             path = inspect.getabsfile(object)
    651             url = path
    652             if sys.platform == 'win32':
    653                 import nturl2path
    654                 url = nturl2path.pathname2url(path)
    655             filelink = '<a href="file:%s">%s</a>' % (url, path)
    656         except TypeError:
    657             filelink = '(built-in)'
    658         info = []
    659         if hasattr(object, '__version__'):
    660             version = _binstr(object.__version__)
    661             if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
    662                 version = strip(version[11:-1])
    663             info.append('version %s' % self.escape(version))
    664         if hasattr(object, '__date__'):
    665             info.append(self.escape(_binstr(object.__date__)))
    666         if info:
    667             head = head + ' (%s)' % join(info, ', ')
    668         docloc = self.getdocloc(object)
    669         if docloc is not None:
    670             docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
    671         else:
    672             docloc = ''
    673         result = self.heading(
    674             head, '#ffffff', '#7799ee',
    675             '<a href=".">index</a><br>' + filelink + docloc)
    676 
    677         modules = inspect.getmembers(object, inspect.ismodule)
    678 
    679         classes, cdict = [], {}
    680         for key, value in inspect.getmembers(object, inspect.isclass):
    681             # if __all__ exists, believe it.  Otherwise use old heuristic.

    682             if (all is not None or
    683                 (inspect.getmodule(value) or object) is object):
    684                 if visiblename(key, all, object):
    685                     classes.append((key, value))
    686                     cdict[key] = cdict[value] = '#' + key
    687         for key, value in classes:
    688             for base in value.__bases__:
    689                 key, modname = base.__name__, base.__module__
    690                 module = sys.modules.get(modname)
    691                 if modname != name and module and hasattr(module, key):
    692                     if getattr(module, key) is base:
    693                         if not key in cdict:
    694                             cdict[key] = cdict[base] = modname + '.html#' + key
    695         funcs, fdict = [], {}
    696         for key, value in inspect.getmembers(object, inspect.isroutine):
    697             # if __all__ exists, believe it.  Otherwise use old heuristic.

    698             if (all is not None or
    699                 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
    700                 if visiblename(key, all, object):
    701                     funcs.append((key, value))
    702                     fdict[key] = '#-' + key
    703                     if inspect.isfunction(value): fdict[value] = fdict[key]
    704         data = []
    705         for key, value in inspect.getmembers(object, isdata):
    706             if visiblename(key, all, object):
    707                 data.append((key, value))
    708 
    709         doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
    710         doc = doc and '<tt>%s</tt>' % doc
    711         result = result + '<p>%s</p>\n' % doc
    712 
    713         if hasattr(object, '__path__'):
    714             modpkgs = []
    715             for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
    716                 modpkgs.append((modname, name, ispkg, 0))
    717             modpkgs.sort()
    718             contents = self.multicolumn(modpkgs, self.modpkglink)
    719             result = result + self.bigsection(
    720                 'Package Contents', '#ffffff', '#aa55cc', contents)
    721         elif modules:
    722             contents = self.multicolumn(
    723                 modules, lambda key_value, s=self: s.modulelink(key_value[1]))
    724             result = result + self.bigsection(
    725                 'Modules', '#ffffff', '#aa55cc', contents)
    726 
    727         if classes:
    728             classlist = map(lambda key_value: key_value[1], classes)
    729             contents = [
    730                 self.formattree(inspect.getclasstree(classlist, 1), name)]
    731             for key, value in classes:
    732                 contents.append(self.document(value, key, name, fdict, cdict))
    733             result = result + self.bigsection(
    734                 'Classes', '#ffffff', '#ee77aa', join(contents))
    735         if funcs:
    736             contents = []
    737             for key, value in funcs:
    738                 contents.append(self.document(value, key, name, fdict, cdict))
    739             result = result + self.bigsection(
    740                 'Functions', '#ffffff', '#eeaa77', join(contents))
    741         if data:
    742             contents = []
    743             for key, value in data:
    744                 contents.append(self.document(value, key))
    745             result = result + self.bigsection(
    746                 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
    747         if hasattr(object, '__author__'):
    748             contents = self.markup(_binstr(object.__author__), self.preformat)
    749             result = result + self.bigsection(
    750                 'Author', '#ffffff', '#7799ee', contents)
    751         if hasattr(object, '__credits__'):
    752             contents = self.markup(_binstr(object.__credits__), self.preformat)
    753             result = result + self.bigsection(
    754                 'Credits', '#ffffff', '#7799ee', contents)
    755 
    756         return result
    757 
    758     def docclass(self, object, name=None, mod=None, funcs={}, classes={},
    759                  *ignored):
    760         """Produce HTML documentation for a class object."""
    761         realname = object.__name__
    762         name = name or realname
    763         bases = object.__bases__
    764 
    765         contents = []
    766         push = contents.append
    767 
    768         # Cute little class to pump out a horizontal rule between sections.

    769         class HorizontalRule:
    770             def __init__(self):
    771                 self.needone = 0
    772             def maybe(self):
    773                 if self.needone:
    774                     push('<hr>\n')
    775                 self.needone = 1
    776         hr = HorizontalRule()
    777 
    778         # List the mro, if non-trivial.

    779         mro = deque(inspect.getmro(object))
    780         if len(mro) > 2:
    781             hr.maybe()
    782             push('<dl><dt>Method resolution order:</dt>\n')
    783             for base in mro:
    784                 push('<dd>%s</dd>\n' % self.classlink(base,
    785                                                       object.__module__))
    786             push('</dl>\n')
    787 
    788         def spill(msg, attrs, predicate):
    789             ok, attrs = _split_list(attrs, predicate)
    790             if ok:
    791                 hr.maybe()
    792                 push(msg)
    793                 for name, kind, homecls, value in ok:
    794                     try:
    795                         value = getattr(object, name)
    796                     except Exception:
    797                         # Some descriptors may meet a failure in their __get__.

    798                         # (bug #1785)

    799                         push(self._docdescriptor(name, value, mod))
    800                     else:
    801                         push(self.document(value, name, mod,
    802                                         funcs, classes, mdict, object))
    803                     push('\n')
    804             return attrs
    805 
    806         def spilldescriptors(msg, attrs, predicate):
    807             ok, attrs = _split_list(attrs, predicate)
    808             if ok:
    809                 hr.maybe()
    810                 push(msg)
    811                 for name, kind, homecls, value in ok:
    812                     push(self._docdescriptor(name, value, mod))
    813             return attrs
    814 
    815         def spilldata(msg, attrs, predicate):
    816             ok, attrs = _split_list(attrs, predicate)
    817             if ok:
    818                 hr.maybe()
    819                 push(msg)
    820                 for name, kind, homecls, value in ok:
    821                     base = self.docother(getattr(object, name), name, mod)
    822                     if (hasattr(value, '__call__') or
    823                             inspect.isdatadescriptor(value)):
    824                         doc = getattr(value, "__doc__", None)
    825                     else:
    826                         doc = None
    827                     if doc is None:
    828                         push('<dl><dt>%s</dl>\n' % base)
    829                     else:
    830                         doc = self.markup(getdoc(value), self.preformat,
    831                                           funcs, classes, mdict)
    832                         doc = '<dd><tt>%s</tt>' % doc
    833                         push('<dl><dt>%s%s</dl>\n' % (base, doc))
    834                     push('\n')
    835             return attrs
    836 
    837         attrs = filter(lambda data: visiblename(data[0], obj=object),
    838                        classify_class_attrs(object))
    839         mdict = {}
    840         for key, kind, homecls, value in attrs:
    841             mdict[key] = anchor = '#' + name + '-' + key
    842             try:
    843                 value = getattr(object, name)
    844             except Exception:
    845                 # Some descriptors may meet a failure in their __get__.

    846                 # (bug #1785)

    847                 pass
    848             try:
    849                 # The value may not be hashable (e.g., a data attr with

    850                 # a dict or list value).

    851                 mdict[value] = anchor
    852             except TypeError:
    853                 pass
    854 
    855         while attrs:
    856             if mro:
    857                 thisclass = mro.popleft()
    858             else:
    859                 thisclass = attrs[0][2]
    860             attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
    861 
    862             if thisclass is __builtin__.object:
    863                 attrs = inherited
    864                 continue
    865             elif thisclass is object:
    866                 tag = 'defined here'
    867             else:
    868                 tag = 'inherited from %s' % self.classlink(thisclass,
    869                                                            object.__module__)
    870             tag += ':<br>\n'
    871 
    872             # Sort attrs by name.

    873             try:
    874                 attrs.sort(key=lambda t: t[0])
    875             except TypeError:
    876                 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))    # 2.3 compat

    877 
    878             # Pump out the attrs, segregated by kind.

    879             attrs = spill('Methods %s' % tag, attrs,
    880                           lambda t: t[1] == 'method')
    881             attrs = spill('Class methods %s' % tag, attrs,
    882                           lambda t: t[1] == 'class method')
    883             attrs = spill('Static methods %s' % tag, attrs,
    884                           lambda t: t[1] == 'static method')
    885             attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
    886                                      lambda t: t[1] == 'data descriptor')
    887             attrs = spilldata('Data and other attributes %s' % tag, attrs,
    888                               lambda t: t[1] == 'data')
    889             assert attrs == []
    890             attrs = inherited
    891 
    892         contents = ''.join(contents)
    893 
    894         if name == realname:
    895             title = '<a name="%s">class <strong>%s</strong></a>' % (
    896                 name, realname)
    897         else:
    898             title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
    899                 name, name, realname)
    900         if bases:
    901             parents = []
    902             for base in bases:
    903                 parents.append(self.classlink(base, object.__module__))
    904             title = title + '(%s)' % join(parents, ', ')
    905         doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
    906         doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
    907 
    908         return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
    909 
    910     def formatvalue(self, object):
    911         """Format an argument default value as text."""
    912         return self.grey('=' + self.repr(object))
    913 
    914     def docroutine(self, object, name=None, mod=None,
    915                    funcs={}, classes={}, methods={}, cl=None):
    916         """Produce HTML documentation for a function or method object."""
    917         realname = object.__name__
    918         name = name or realname
    919         anchor = (cl and cl.__name__ or '') + '-' + name
    920         note = ''
    921         skipdocs = 0
    922         if inspect.ismethod(object):
    923             imclass = object.im_class
    924             if cl:
    925                 if imclass is not cl:
    926                     note = ' from ' + self.classlink(imclass, mod)
    927             else:
    928                 if object.im_self is not None:
    929                     note = ' method of %s instance' % self.classlink(
    930                         object.im_self.__class__, mod)
    931                 else:
    932                     note = ' unbound %s method' % self.classlink(imclass,mod)
    933             object = object.im_func
    934 
    935         if name == realname:
    936             title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
    937         else:
    938             if (cl and realname in cl.__dict__ and
    939                 cl.__dict__[realname] is object):
    940                 reallink = '<a href="#%s">%s</a>' % (
    941                     cl.__name__ + '-' + realname, realname)
    942                 skipdocs = 1
    943             else:
    944                 reallink = realname
    945             title = '<a name="%s"><strong>%s</strong></a> = %s' % (
    946                 anchor, name, reallink)
    947         if inspect.isfunction(object):
    948             args, varargs, varkw, defaults = inspect.getargspec(object)
    949             argspec = inspect.formatargspec(
    950                 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
    951             if realname == '<lambda>':
    952                 title = '<strong>%s</strong> <em>lambda</em> ' % name
    953                 argspec = argspec[1:-1] # remove parentheses

    954         else:
    955             argspec = '(...)'
    956 
    957         decl = title + argspec + (note and self.grey(
    958                '<font face="helvetica, arial">%s</font>' % note))
    959 
    960         if skipdocs:
    961             return '<dl><dt>%s</dt></dl>\n' % decl
    962         else:
    963             doc = self.markup(
    964                 getdoc(object), self.preformat, funcs, classes, methods)
    965             doc = doc and '<dd><tt>%s</tt></dd>' % doc
    966             return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
    967 
    968     def _docdescriptor(self, name, value, mod):
    969         results = []
    970         push = results.append
    971 
    972         if name:
    973             push('<dl><dt><strong>%s</strong></dt>\n' % name)
    974         if value.__doc__ is not None:
    975             doc = self.markup(getdoc(value), self.preformat)
    976             push('<dd><tt>%s</tt></dd>\n' % doc)
    977         push('</dl>\n')
    978 
    979         return ''.join(results)
    980 
    981     def docproperty(self, object, name=None, mod=None, cl=None):
    982         """Produce html documentation for a property."""
    983         return self._docdescriptor(name, object, mod)
    984 
    985     def docother(self, object, name=None, mod=None, *ignored):
    986         """Produce HTML documentation for a data object."""
    987         lhs = name and '<strong>%s</strong> = ' % name or ''
    988         return lhs + self.repr(object)
    989 
    990     def docdata(self, object, name=None, mod=None, cl=None):
    991         """Produce html documentation for a data descriptor."""
    992         return self._docdescriptor(name, object, mod)
    993 
    994     def index(self, dir, shadowed=None):
    995         """Generate an HTML index for a directory of modules."""
    996         modpkgs = []
    997         if shadowed is None: shadowed = {}
    998         for importer, name, ispkg in pkgutil.iter_modules([dir]):
    999             modpkgs.append((name, '', ispkg, name in shadowed))
   1000             shadowed[name] = 1
   1001 
   1002         modpkgs.sort()
   1003         contents = self.multicolumn(modpkgs, self.modpkglink)
   1004         return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
   1005 
   1006 # -------------------------------------------- text documentation generator

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

   2152 
   2153 def gui():
   2154     """Graphical interface (starts web server and pops up a control window)."""
   2155     class GUI:
   2156         def __init__(self, window, port=7464):
   2157             self.window = window
   2158             self.server = None
   2159             self.scanner = None
   2160 
   2161             import Tkinter
   2162             self.server_frm = Tkinter.Frame(window)
   2163             self.title_lbl = Tkinter.Label(self.server_frm,
   2164                 text='Starting server...\n ')
   2165             self.open_btn = Tkinter.Button(self.server_frm,
   2166                 text='open browser', command=self.open, state='disabled')
   2167             self.quit_btn = Tkinter.Button(self.server_frm,
   2168                 text='quit serving', command=self.quit, state='disabled')
   2169 
   2170             self.search_frm = Tkinter.Frame(window)
   2171             self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
   2172             self.search_ent = Tkinter.Entry(self.search_frm)
   2173             self.search_ent.bind('<Return>', self.search)
   2174             self.stop_btn = Tkinter.Button(self.search_frm,
   2175                 text='stop', pady=0, command=self.stop, state='disabled')
   2176             if sys.platform == 'win32':
   2177                 # Trying to hide and show this button crashes under Windows.

   2178                 self.stop_btn.pack(side='right')
   2179 
   2180             self.window.title('pydoc')
   2181             self.window.protocol('WM_DELETE_WINDOW', self.quit)
   2182             self.title_lbl.pack(side='top', fill='x')
   2183             self.open_btn.pack(side='left', fill='x', expand=1)
   2184             self.quit_btn.pack(side='right', fill='x', expand=1)
   2185             self.server_frm.pack(side='top', fill='x')
   2186 
   2187             self.search_lbl.pack(side='left')
   2188             self.search_ent.pack(side='right', fill='x', expand=1)
   2189             self.search_frm.pack(side='top', fill='x')
   2190             self.search_ent.focus_set()
   2191 
   2192             font = ('helvetica', sys.platform == 'win32' and 8 or 10)
   2193             self.result_lst = Tkinter.Listbox(window, font=font, height=6)
   2194             self.result_lst.bind('<Button-1>', self.select)
   2195             self.result_lst.bind('<Double-Button-1>', self.goto)
   2196             self.result_scr = Tkinter.Scrollbar(window,
   2197                 orient='vertical', command=self.result_lst.yview)
   2198             self.result_lst.config(yscrollcommand=self.result_scr.set)
   2199 
   2200             self.result_frm = Tkinter.Frame(window)
   2201             self.goto_btn = Tkinter.Button(self.result_frm,
   2202                 text='go to selected', command=self.goto)
   2203             self.hide_btn = Tkinter.Button(self.result_frm,
   2204                 text='hide results', command=self.hide)
   2205             self.goto_btn.pack(side='left', fill='x', expand=1)
   2206             self.hide_btn.pack(side='right', fill='x', expand=1)
   2207 
   2208             self.window.update()
   2209             self.minwidth = self.window.winfo_width()
   2210             self.minheight = self.window.winfo_height()
   2211             self.bigminheight = (self.server_frm.winfo_reqheight() +
   2212                                  self.search_frm.winfo_reqheight() +
   2213                                  self.result_lst.winfo_reqheight() +
   2214                                  self.result_frm.winfo_reqheight())
   2215             self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
   2216             self.expanded = 0
   2217             self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
   2218             self.window.wm_minsize(self.minwidth, self.minheight)
   2219             self.window.tk.willdispatch()
   2220 
   2221             import threading
   2222             threading.Thread(
   2223                 target=serve, args=(port, self.ready, self.quit)).start()
   2224 
   2225         def ready(self, server):
   2226             self.server = server
   2227             self.title_lbl.config(
   2228                 text='Python documentation server at\n' + server.url)
   2229             self.open_btn.config(state='normal')
   2230             self.quit_btn.config(state='normal')
   2231 
   2232         def open(self, event=None, url=None):
   2233             url = url or self.server.url
   2234             try:
   2235                 import webbrowser
   2236                 webbrowser.open(url)
   2237             except ImportError: # pre-webbrowser.py compatibility

   2238                 if sys.platform == 'win32':
   2239                     os.system('start "%s"' % url)
   2240                 else:
   2241                     rc = os.system('netscape -remote "openURL(%s)" &' % url)
   2242                     if rc: os.system('netscape "%s" &' % url)
   2243 
   2244         def quit(self, event=None):
   2245             if self.server:
   2246                 self.server.quit = 1
   2247             self.window.quit()
   2248 
   2249         def search(self, event=None):
   2250             key = self.search_ent.get()
   2251             self.stop_btn.pack(side='right')
   2252             self.stop_btn.config(state='normal')
   2253             self.search_lbl.config(text='Searching for "%s"...' % key)
   2254             self.search_ent.forget()
   2255             self.search_lbl.pack(side='left')
   2256             self.result_lst.delete(0, 'end')
   2257             self.goto_btn.config(state='disabled')
   2258             self.expand()
   2259 
   2260             import threading
   2261             if self.scanner:
   2262                 self.scanner.quit = 1
   2263             self.scanner = ModuleScanner()
   2264             threading.Thread(target=self.scanner.run,
   2265                              args=(self.update, key, self.done)).start()
   2266 
   2267         def update(self, path, modname, desc):
   2268             if modname[-9:] == '.__init__':
   2269                 modname = modname[:-9] + ' (package)'
   2270             self.result_lst.insert('end',
   2271                 modname + ' - ' + (desc or '(no description)'))
   2272 
   2273         def stop(self, event=None):
   2274             if self.scanner:
   2275                 self.scanner.quit = 1
   2276                 self.scanner = None
   2277 
   2278         def done(self):
   2279             self.scanner = None
   2280             self.search_lbl.config(text='Search for')
   2281             self.search_lbl.pack(side='left')
   2282             self.search_ent.pack(side='right', fill='x', expand=1)
   2283             if sys.platform != 'win32': self.stop_btn.forget()
   2284             self.stop_btn.config(state='disabled')
   2285 
   2286         def select(self, event=None):
   2287             self.goto_btn.config(state='normal')
   2288 
   2289         def goto(self, event=None):
   2290             selection = self.result_lst.curselection()
   2291             if selection:
   2292                 modname = split(self.result_lst.get(selection[0]))[0]
   2293                 self.open(url=self.server.url + modname + '.html')
   2294 
   2295         def collapse(self):
   2296             if not self.expanded: return
   2297             self.result_frm.forget()
   2298             self.result_scr.forget()
   2299             self.result_lst.forget()
   2300             self.bigwidth = self.window.winfo_width()
   2301             self.bigheight = self.window.winfo_height()
   2302             self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
   2303             self.window.wm_minsize(self.minwidth, self.minheight)
   2304             self.expanded = 0
   2305 
   2306         def expand(self):
   2307             if self.expanded: return
   2308             self.result_frm.pack(side='bottom', fill='x')
   2309             self.result_scr.pack(side='right', fill='y')
   2310             self.result_lst.pack(side='top', fill='both', expand=1)
   2311             self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
   2312             self.window.wm_minsize(self.minwidth, self.bigminheight)
   2313             self.expanded = 1
   2314 
   2315         def hide(self, event=None):
   2316             self.stop()
   2317             self.collapse()
   2318 
   2319     import Tkinter
   2320     try:
   2321         root = Tkinter.Tk()
   2322         # Tk will crash if pythonw.exe has an XP .manifest

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

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

   2325         # destroy can go.

   2326         try:
   2327             gui = GUI(root)
   2328             root.mainloop()
   2329         finally:
   2330             root.destroy()
   2331     except KeyboardInterrupt:
   2332         pass
   2333 
   2334 # -------------------------------------------------- command-line interface

   2335 
   2336 def ispath(x):
   2337     return isinstance(x, str) and find(x, os.sep) >= 0
   2338 
   2339 def cli():
   2340     """Command-line interface (looks at sys.argv to decide what to do)."""
   2341     import getopt
   2342     class BadUsage: pass
   2343 
   2344     # Scripts don't get the current directory in their path by default

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

   2346     if '' not in sys.path:
   2347         scriptdir = os.path.dirname(sys.argv[0])
   2348         if scriptdir in sys.path:
   2349             sys.path.remove(scriptdir)
   2350         sys.path.insert(0, '.')
   2351 
   2352     try:
   2353         opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
   2354         writing = 0
   2355 
   2356         for opt, val in opts:
   2357             if opt == '-g':
   2358                 gui()
   2359                 return
   2360             if opt == '-k':
   2361                 apropos(val)
   2362                 return
   2363             if opt == '-p':
   2364                 try:
   2365                     port = int(val)
   2366                 except ValueError:
   2367                     raise BadUsage
   2368                 def ready(server):
   2369                     print 'pydoc server ready at %s' % server.url
   2370                 def stopped():
   2371                     print 'pydoc server stopped'
   2372                 serve(port, ready, stopped)
   2373                 return
   2374             if opt == '-w':
   2375                 writing = 1
   2376 
   2377         if not args: raise BadUsage
   2378         for arg in args:
   2379             if ispath(arg) and not os.path.exists(arg):
   2380                 print 'file %r does not exist' % arg
   2381                 break
   2382             try:
   2383                 if ispath(arg) and os.path.isfile(arg):
   2384                     arg = importfile(arg)
   2385                 if writing:
   2386                     if ispath(arg) and os.path.isdir(arg):
   2387                         writedocs(arg)
   2388                     else:
   2389                         writedoc(arg)
   2390                 else:
   2391                     help.help(arg)
   2392             except ErrorDuringImport, value:
   2393                 print value
   2394 
   2395     except (getopt.error, BadUsage):
   2396         cmd = os.path.basename(sys.argv[0])
   2397         print """pydoc - the Python documentation tool
   2398 
   2399 %s <name> ...
   2400     Show text documentation on something.  <name> may be the name of a
   2401     Python keyword, topic, function, module, or package, or a dotted
   2402     reference to a class or function within a module or module in a
   2403     package.  If <name> contains a '%s', it is used as the path to a
   2404     Python source file to document. If name is 'keywords', 'topics',
   2405     or 'modules', a listing of these things is displayed.
   2406 
   2407 %s -k <keyword>
   2408     Search for a keyword in the synopsis lines of all available modules.
   2409 
   2410 %s -p <port>
   2411     Start an HTTP server on the given port on the local machine.  Port
   2412     number 0 can be used to get an arbitrary unused port.
   2413 
   2414 %s -g
   2415     Pop up a graphical interface for finding and serving documentation.
   2416 
   2417 %s -w <name> ...
   2418     Write out the HTML documentation for a module to a file in the current
   2419     directory.  If <name> contains a '%s', it is treated as a filename; if
   2420     it names a directory, documentation is written for all the contents.
   2421 """ % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
   2422 
   2423 if __name__ == '__main__': cli()
   2424