13ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel#!/usr/bin/env python
23ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# -*- coding: latin-1 -*-
3d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel
4d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel# Module 'pydoc' -- Generate Python documentation in HTML or text for interactive use.
5d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel#
6d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel# Copyright (c) 2015, Daryl McDaniel. All rights reserved.<BR>
7d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel# Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>
8d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel# This program and the accompanying materials are licensed and made available under
9d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel# the terms and conditions of the BSD License that accompanies this distribution.
10d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel# The full text of the license may be found at
11d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel# http://opensource.org/licenses/bsd-license.
12d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel#
13d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
14d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel
163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel"""Generate Python documentation in HTML or text for interactive use.
173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielIn the Python interpreter, do "from pydoc import help" to provide online
193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielhelp.  Calling help(thing) on a Python object documents the object.
203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielOr, at the shell command line outside of Python:
223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielRun "pydoc <name>" to show documentation on something.  <name> may be
243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielthe name of a function, module, package, or a dotted reference to a
253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielclass or function within a module or module in a package.  If the
263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielargument contains a path segment delimiter (e.g. slash on Unix,
273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielbackslash on Windows) it is treated as the path to a Python source file.
283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielRun "pydoc -k <keyword>" to search for a keyword in the synopsis lines
303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielof all available modules.
313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielRun "pydoc -p <port>" to start an HTTP server on a given port on the
333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniellocal machine to generate documentation web pages.  Port number 0 can be
343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielused to get an arbitrary unused port.
353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielFor platforms without a command line, "pydoc -g" starts the HTTP server
373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieland also pops up a little window for controlling it.
383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielRun "pydoc -w <name>" to write out the HTML documentation for a module
403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielto a file named "<name>.html".
413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielModule docs for core modules are assumed to be in
433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    http://docs.python.org/library/
453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielThis can be overridden by setting the PYTHONDOCS environment variable
473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielto a different URL or to a local directory containing the Library
483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielReference Manual pages.
493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel"""
503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel__author__ = "Ka-Ping Yee <ping@lfw.org>"
523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel__date__ = "26 February 2001"
533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel__version__ = "$Revision: 88564 $"
553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel__credits__ = """Guido van Rossum, for an excellent programming language.
563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielTommy Burnette, the original creator of manpy.
573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielPaul Prescod, for all his work on onlinehelp.
583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielRichard Chamberlain, for the first implementation of textdoc.
593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel"""
603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# Known bugs that can't be fixed here:
623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel#   - imp.load_module() cannot be prevented from clobbering existing
633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel#     loaded modules, so calling synopsis() on a binary module file
643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel#     changes the contents of any existing module with the same name.
653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel#   - If the __file__ attribute on a module is a relative path and
663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel#     the current directory is changed with os.chdir(), an incorrect
673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel#     path will be displayed.
683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielimport sys, imp, os, re, types, inspect, __builtin__, pkgutil, warnings
703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielfrom repr import Repr
713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielfrom string import expandtabs, find, join, lower, split, strip, rfind, rstrip
723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielfrom traceback import extract_tb
733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieltry:
743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    from collections import deque
753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielexcept ImportError:
763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # Python 2.3 compatibility
773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    class deque(list):
783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def popleft(self):
793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return self.pop(0)
803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# --------------------------------------------------------- common routines
823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef pathdirs():
843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Convert sys.path into a list of absolute, existing, unique paths."""
853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    dirs = []
863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    normdirs = []
873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    for dir in sys.path:
883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        dir = os.path.abspath(dir or '.')
893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        normdir = os.path.normcase(dir)
903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if normdir not in normdirs and os.path.isdir(dir):
913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            dirs.append(dir)
923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            normdirs.append(normdir)
933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return dirs
943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef getdoc(object):
963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Get the doc string or comments for an object."""
973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    result = inspect.getdoc(object) or inspect.getcomments(object)
983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    result = _encode(result)
993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return result and re.sub('^ *\n', '', rstrip(result)) or ''
1003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef splitdoc(doc):
1023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Split a doc string into a synopsis line (if any) and the rest."""
1033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    lines = split(strip(doc), '\n')
1043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if len(lines) == 1:
1053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return lines[0], ''
1063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    elif len(lines) >= 2 and not rstrip(lines[1]):
1073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return lines[0], join(lines[2:], '\n')
1083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return '', join(lines, '\n')
1093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef classname(object, modname):
1113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Get a class name and qualify it with a module name if necessary."""
1123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    name = object.__name__
1133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if object.__module__ != modname:
1143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        name = object.__module__ + '.' + name
1153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return name
1163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef isdata(object):
1183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Check if an object is of a type that probably means it's data."""
1193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return not (inspect.ismodule(object) or inspect.isclass(object) or
1203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                inspect.isroutine(object) or inspect.isframe(object) or
1213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                inspect.istraceback(object) or inspect.iscode(object))
1223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef replace(text, *pairs):
1243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Do a series of global replacements on a string."""
1253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    while pairs:
1263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        text = join(split(text, pairs[0]), pairs[1])
1273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        pairs = pairs[2:]
1283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return text
1293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef cram(text, maxlen):
1313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Omit part of a string if needed to make it fit in a maximum length."""
1323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if len(text) > maxlen:
1333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        pre = max(0, (maxlen-3)//2)
1343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        post = max(0, maxlen-3-pre)
1353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return text[:pre] + '...' + text[len(text)-post:]
1363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return text
1373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
1393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef stripid(text):
1403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Remove the hexadecimal id from a Python object representation."""
1413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # The behaviour of %p is implementation-dependent in terms of case.
1423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return _re_stripid.sub(r'\1', text)
1433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef _is_some_method(obj):
1453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
1463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef allmethods(cl):
1483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    methods = {}
1493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    for key, value in inspect.getmembers(cl, _is_some_method):
1503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        methods[key] = 1
1513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    for base in cl.__bases__:
1523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        methods.update(allmethods(base)) # all your base are belong to us
1533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    for key in methods.keys():
1543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        methods[key] = getattr(cl, key)
1553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return methods
1563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef _split_list(s, predicate):
1583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Split sequence s via predicate, and return pair ([true], [false]).
1593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    The return value is a 2-tuple of lists,
1613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        ([x for x in s if predicate(x)],
1623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel         [x for x in s if not predicate(x)])
1633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """
1643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    yes = []
1663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    no = []
1673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    for x in s:
1683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if predicate(x):
1693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            yes.append(x)
1703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
1713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            no.append(x)
1723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return yes, no
1733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef visiblename(name, all=None, obj=None):
1753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Decide whether to show documentation on a variable."""
1763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # Certain special names are redundant.
1773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__',
1783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                     '__module__', '__name__', '__slots__', '__package__')
1793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if name in _hidden_names: return 0
1803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # Private names are hidden, but special names are displayed.
1813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if name.startswith('__') and name.endswith('__'): return 1
1823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # Namedtuples have public fields and methods with a single leading underscore
1833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if name.startswith('_') and hasattr(obj, '_fields'):
1843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return 1
1853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if all is not None:
1863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # only document that which the programmer exported in __all__
1873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return name in all
1883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    else:
1893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return not name.startswith('_')
1903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
1913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef classify_class_attrs(object):
1923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
1933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def fixup(data):
1943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        name, kind, cls, value = data
1953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if inspect.isdatadescriptor(value):
1963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            kind = 'data descriptor'
1973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return name, kind, cls, value
1983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return map(fixup, inspect.classify_class_attrs(object))
1993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
2003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# ----------------------------------------------------- Unicode support helpers
2013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
2023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieltry:
2033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    _unicode = unicode
2043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielexcept NameError:
2053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # If Python is built without Unicode support, the unicode type
2063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # will not exist. Fake one that nothing will match, and make
2073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # the _encode function that do nothing.
2083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    class _unicode(object):
2093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        pass
2103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    _encoding = 'ascii'
2113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def _encode(text, encoding='ascii'):
2123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return text
2133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielelse:
2143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    import locale
2153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    _encoding = locale.getpreferredencoding()
2163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
2173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def _encode(text, encoding=None):
2183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if isinstance(text, unicode):
2193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return text.encode(encoding or _encoding, 'xmlcharrefreplace')
2203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
2213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return text
2223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
2233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef _binstr(obj):
2243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # Ensure that we have an encoded (binary) string representation of obj,
2253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # even if it is a unicode string.
2263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if isinstance(obj, _unicode):
2273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return obj.encode(_encoding, 'xmlcharrefreplace')
2283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return str(obj)
2293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
2303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# ----------------------------------------------------- module manipulation
2313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
2323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef ispackage(path):
2333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Guess whether a path refers to a package directory."""
2343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if os.path.isdir(path):
2353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for ext in ('.py', '.pyc', '.pyo'):
2363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if os.path.isfile(os.path.join(path, '__init__' + ext)):
2373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                return True
2383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return False
2393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
2403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef source_synopsis(file):
2413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    line = file.readline()
2423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    while line[:1] == '#' or not strip(line):
2433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        line = file.readline()
2443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if not line: break
2453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    line = strip(line)
2463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if line[:4] == 'r"""': line = line[1:]
2473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if line[:3] == '"""':
2483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        line = line[3:]
2493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if line[-1:] == '\\': line = line[:-1]
2503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        while not strip(line):
2513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            line = file.readline()
2523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if not line: break
2533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        result = strip(split(line, '"""')[0])
2543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    else: result = None
2553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return result
2563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
2573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef synopsis(filename, cache={}):
2583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Get the one-line summary out of a module file."""
2593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    mtime = os.stat(filename).st_mtime
2603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    lastupdate, result = cache.get(filename, (None, None))
2613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if lastupdate is None or lastupdate < mtime:
2623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        info = inspect.getmoduleinfo(filename)
2633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
2643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            file = open(filename)
2653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except IOError:
2663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # module can't be opened, so skip it
2673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return None
2683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if info and 'b' in info[2]: # binary modules have to be imported
2693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            try: module = imp.load_module('__temp__', file, filename, info[1:])
2703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            except: return None
2713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = module.__doc__.splitlines()[0] if module.__doc__ else None
2723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            del sys.modules['__temp__']
2733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else: # text modules can be directly examined
2743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = source_synopsis(file)
2753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            file.close()
2763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        cache[filename] = (mtime, result)
2773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return result
2783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
2793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielclass ErrorDuringImport(Exception):
2803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Errors that occurred while trying to import something to document it."""
2813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def __init__(self, filename, exc_info):
2823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        exc, value, tb = exc_info
2833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.filename = filename
2843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.exc = exc
2853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.value = value
2863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.tb = tb
2873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
2883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def __str__(self):
2893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        exc = self.exc
2903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if type(exc) is types.ClassType:
2913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            exc = exc.__name__
2923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
2933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
2943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef importfile(path):
2953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Import a Python source file or compiled file given its path."""
2963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    magic = imp.get_magic()
2973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    file = open(path, 'r')
2983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if file.read(len(magic)) == magic:
2993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        kind = imp.PY_COMPILED
3003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    else:
3013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        kind = imp.PY_SOURCE
3023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    file.close()
3033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    filename = os.path.basename(path)
3043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    name, ext = os.path.splitext(filename)
3053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    file = open(path, 'r')
3063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
3073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        module = imp.load_module(name, file, path, (ext, 'r', kind))
3083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    except:
3093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        raise ErrorDuringImport(path, sys.exc_info())
3103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    file.close()
3113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return module
3123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
3133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef safeimport(path, forceload=0, cache={}):
3143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Import a module; handle errors; return None if the module isn't found.
3153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
3163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    If the module *is* found but an exception occurs, it's wrapped in an
3173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    ErrorDuringImport exception and reraised.  Unlike __import__, if a
3183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    package path is specified, the module at the end of the path is returned,
3193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    not the package at the beginning.  If the optional 'forceload' argument
3203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    is 1, we reload the module from disk (unless it's a dynamic extension)."""
3213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
3223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # If forceload is 1 and the module has been previously loaded from
3233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # disk, we always have to reload the module.  Checking the file's
3243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # mtime isn't good enough (e.g. the module could contain a class
3253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # that inherits from another module that has changed).
3263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if forceload and path in sys.modules:
3273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if path not in sys.builtin_module_names:
3283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # Avoid simply calling reload() because it leaves names in
3293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # the currently loaded module lying around if they're not
3303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # defined in the new source file.  Instead, remove the
3313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # module from sys.modules and re-import.  Also remove any
3323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # submodules because they won't appear in the newly loaded
3333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # module's namespace if they're already in sys.modules.
3343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                subs = [m for m in sys.modules if m.startswith(path + '.')]
3353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                for key in [path] + subs:
3363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    # Prevent garbage collection.
3373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    cache[key] = sys.modules[key]
3383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    del sys.modules[key]
3393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        module = __import__(path)
3403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    except:
3413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # Did the error occur before or after the module was found?
3423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        (exc, value, tb) = info = sys.exc_info()
3433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if path in sys.modules:
3443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # An error occurred while executing the imported module.
3453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            raise ErrorDuringImport(sys.modules[path].__file__, info)
3463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        elif exc is SyntaxError:
3473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # A SyntaxError occurred before we could execute the module.
3483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            raise ErrorDuringImport(value.filename, info)
3493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport':
3503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # The import error occurred directly in this function,
3513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # which means there is no such module in the path.
3523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return None
3533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
3543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # Some other error occurred during the importing process.
3553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            raise ErrorDuringImport(path, sys.exc_info())
3563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    for part in split(path, '.')[1:]:
3573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try: module = getattr(module, part)
3583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except AttributeError: return None
3593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return module
3603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
3613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# ---------------------------------------------------- formatter base class
3623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
3633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielclass Doc:
3643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def document(self, object, name=None, *args):
3653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Generate documentation for an object."""
3663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        args = (object, name) + args
3673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # 'try' clause is to attempt to handle the possibility that inspect
3683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # identifies something in a way that pydoc itself has issues handling;
3693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # think 'super' and how it is a descriptor (which raises the exception
3703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # by lacking a __name__ attribute) and an instance.
3713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if inspect.isgetsetdescriptor(object): return self.docdata(*args)
3723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if inspect.ismemberdescriptor(object): return self.docdata(*args)
3733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
3743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if inspect.ismodule(object): return self.docmodule(*args)
3753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if inspect.isclass(object): return self.docclass(*args)
3763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if inspect.isroutine(object): return self.docroutine(*args)
3773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except AttributeError:
3783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            pass
3793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if isinstance(object, property): return self.docproperty(*args)
3803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return self.docother(*args)
3813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
3823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def fail(self, object, name=None, *args):
3833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Raise an exception for unimplemented types."""
3843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        message = "don't know how to document object%s of type %s" % (
3853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            name and ' ' + repr(name), type(object).__name__)
3863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        raise TypeError, message
3873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
3883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    docmodule = docclass = docroutine = docother = docproperty = docdata = fail
3893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
3903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def getdocloc(self, object):
3913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Return the location of module docs or None"""
3923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
3933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
3943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            file = inspect.getabsfile(object)
3953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except TypeError:
3963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            file = '(built-in)'
3973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
3983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        docloc = os.environ.get("PYTHONDOCS",
3993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                "http://docs.python.org/library")
4003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        basedir = os.path.join(sys.exec_prefix, "lib",
4013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                               "python"+sys.version[0:3])
4023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if (isinstance(object, type(os)) and
4033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
4043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                 'marshal', 'posix', 'signal', 'sys',
4053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                 'thread', 'zipimport') or
4063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel             (file.startswith(basedir) and
4073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel              not file.startswith(os.path.join(basedir, 'site-packages')))) and
4083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
4093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if docloc.startswith("http://"):
4103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__)
4113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            else:
4123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                docloc = os.path.join(docloc, object.__name__ + ".html")
4133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
4143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            docloc = None
4153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return docloc
4163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# -------------------------------------------- HTML documentation generator
4183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielclass HTMLRepr(Repr):
4203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Class for safely making an HTML representation of a Python object."""
4213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def __init__(self):
4223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        Repr.__init__(self)
4233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.maxlist = self.maxtuple = 20
4243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.maxdict = 10
4253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.maxstring = self.maxother = 100
4263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def escape(self, text):
4283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
4293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def repr(self, object):
4313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return Repr.repr(self, object)
4323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def repr1(self, x, level):
4343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(type(x), '__name__'):
4353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            methodname = 'repr_' + join(split(type(x).__name__), '_')
4363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if hasattr(self, methodname):
4373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                return getattr(self, methodname)(x, level)
4383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return self.escape(cram(stripid(repr(x)), self.maxother))
4393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def repr_string(self, x, level):
4413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        test = cram(x, self.maxstring)
4423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        testrepr = repr(test)
4433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
4443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # Backslashes are only literal in the string and are never
4453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # needed to make any special characters, so show a raw string.
4463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
4473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
4483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                      r'<font color="#c040c0">\1</font>',
4493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                      self.escape(testrepr))
4503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    repr_str = repr_string
4523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def repr_instance(self, x, level):
4543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
4553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return self.escape(cram(stripid(repr(x)), self.maxstring))
4563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except:
4573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return self.escape('<%s instance>' % x.__class__.__name__)
4583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    repr_unicode = repr_string
4603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielclass HTMLDoc(Doc):
4623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Formatter class for HTML documentation."""
4633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # ------------------------------------------- HTML formatting utilities
4653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    _repr_instance = HTMLRepr()
4673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    repr = _repr_instance.repr
4683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    escape = _repr_instance.escape
4693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def page(self, title, contents):
4713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Format an HTML page."""
4723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return _encode('''
4733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
4743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<html><head><title>Python: %s</title>
4753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<meta charset="utf-8">
4763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel</head><body bgcolor="#f0f0f8">
4773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel%s
4783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel</body></html>''' % (title, contents), 'ascii')
4793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def heading(self, title, fgcol, bgcol, extras=''):
4813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Format a page heading."""
4823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return '''
4833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
4843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<tr bgcolor="%s">
4853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<td valign=bottom>&nbsp;<br>
4863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
4873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel><td align=right valign=bottom
4883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
4893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
4903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
4913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def section(self, title, fgcol, bgcol, contents, width=6,
4923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                prelude='', marginalia=None, gap='&nbsp;'):
4933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Format a section with a heading."""
4943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if marginalia is None:
4953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
4963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        result = '''<p>
4973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
4983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<tr bgcolor="%s">
4993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<td colspan=3 valign=bottom>&nbsp;<br>
5003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<font color="%s" face="helvetica, arial">%s</font></td></tr>
5013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    ''' % (bgcol, fgcol, title)
5023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if prelude:
5033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + '''
5043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<tr bgcolor="%s"><td rowspan=2>%s</td>
5053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<td colspan=2>%s</td></tr>
5063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
5073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
5083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + '''
5093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
5103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
5113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return result + '\n<td width="100%%">%s</td></tr></table>' % contents
5123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
5133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def bigsection(self, title, *args):
5143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Format a section with a big heading."""
5153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        title = '<big><strong>%s</strong></big>' % title
5163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return self.section(title, *args)
5173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
5183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def preformat(self, text):
5193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Format literal preformatted text."""
5203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        text = self.escape(expandtabs(text))
5213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
5223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                             ' ', '&nbsp;', '\n', '<br>\n')
5233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
5243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def multicolumn(self, list, format, cols=4):
5253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Format a list of items into a multi-column list."""
5263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        result = ''
5273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        rows = (len(list)+cols-1)//cols
5283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for col in range(cols):
5293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + '<td width="%d%%" valign=top>' % (100//cols)
5303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for i in range(rows*col, rows*col+rows):
5313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if i < len(list):
5323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    result = result + format(list[i]) + '<br>\n'
5333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + '</td>'
5343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
5353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
5363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def grey(self, text): return '<font color="#909090">%s</font>' % text
5373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
5383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def namelink(self, name, *dicts):
5393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Make a link for an identifier, given name-to-URL mappings."""
5403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for dict in dicts:
5413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if name in dict:
5423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                return '<a href="%s">%s</a>' % (dict[name], name)
5433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return name
5443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
5453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def classlink(self, object, modname):
5463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Make a link for a class."""
5473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        name, module = object.__name__, sys.modules.get(object.__module__)
5483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(module, name) and getattr(module, name) is object:
5493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return '<a href="%s.html#%s">%s</a>' % (
5503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                module.__name__, name, classname(object, modname))
5513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return classname(object, modname)
5523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
5533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def modulelink(self, object):
5543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Make a link for a module."""
5553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
5563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
5573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def modpkglink(self, data):
5583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Make a link for a module or package to display in an index."""
5593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        name, path, ispackage, shadowed = data
5603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if shadowed:
5613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return self.grey(name)
5623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if path:
5633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            url = '%s.%s.html' % (path, name)
5643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
5653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            url = '%s.html' % name
5663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if ispackage:
5673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            text = '<strong>%s</strong>&nbsp;(package)' % name
5683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
5693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            text = name
5703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return '<a href="%s">%s</a>' % (url, text)
5713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
5723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
5733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Mark up some plain text, given a context of symbols to look for.
5743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        Each context dictionary maps object names to anchor names."""
5753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        escape = escape or self.escape
5763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        results = []
5773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        here = 0
5783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
5793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                r'RFC[- ]?(\d+)|'
5803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                r'PEP[- ]?(\d+)|'
5813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                r'(self\.)?(\w+))')
5823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        while True:
5833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            match = pattern.search(text, here)
5843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if not match: break
5853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            start, end = match.span()
5863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            results.append(escape(text[here:start]))
5873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
5883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            all, scheme, rfc, pep, selfdot, name = match.groups()
5893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if scheme:
5903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                url = escape(all).replace('"', '&quot;')
5913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                results.append('<a href="%s">%s</a>' % (url, url))
5923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif rfc:
5933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
5943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                results.append('<a href="%s">%s</a>' % (url, escape(all)))
5953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif pep:
5963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
5973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                results.append('<a href="%s">%s</a>' % (url, escape(all)))
5983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif selfdot:
5993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # Create a link for methods like 'self.method(...)'
6003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # and use <strong> for attributes like 'self.attr'
6013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if text[end:end+1] == '(':
6023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    results.append('self.' + self.namelink(name, methods))
6033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                else:
6043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    results.append('self.<strong>%s</strong>' % name)
6053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif text[end:end+1] == '(':
6063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                results.append(self.namelink(name, methods, funcs, classes))
6073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            else:
6083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                results.append(self.namelink(name, classes))
6093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            here = end
6103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        results.append(escape(text[here:]))
6113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return join(results, '')
6123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
6133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # ---------------------------------------------- type-specific routines
6143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
6153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def formattree(self, tree, modname, parent=None):
6163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce HTML for a class tree as given by inspect.getclasstree()."""
6173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        result = ''
6183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for entry in tree:
6193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if type(entry) is type(()):
6203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                c, bases = entry
6213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                result = result + '<dt><font face="helvetica, arial">'
6223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                result = result + self.classlink(c, modname)
6233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if bases and bases != (parent,):
6243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    parents = []
6253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    for base in bases:
6263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        parents.append(self.classlink(base, modname))
6273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    result = result + '(' + join(parents, ', ') + ')'
6283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                result = result + '\n</font></dt>'
6293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif type(entry) is type([]):
6303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                result = result + '<dd>\n%s</dd>\n' % self.formattree(
6313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    entry, modname, c)
6323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return '<dl>\n%s</dl>\n' % result
6333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
6343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docmodule(self, object, name=None, mod=None, *ignored):
6353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce HTML documentation for a module object."""
6363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        name = object.__name__ # ignore the passed-in name
6373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
6383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            all = object.__all__
6393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except AttributeError:
6403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            all = None
6413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        parts = split(name, '.')
6423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        links = []
6433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for i in range(len(parts)-1):
6443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            links.append(
6453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
6463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                (join(parts[:i+1], '.'), parts[i]))
6473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        linkedname = join(links + parts[-1:], '.')
6483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        head = '<big><big><strong>%s</strong></big></big>' % linkedname
6493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
6503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            path = inspect.getabsfile(object)
6513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            url = path
6523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if sys.platform == 'win32':
6533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                import nturl2path
6543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                url = nturl2path.pathname2url(path)
6553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            filelink = '<a href="file:%s">%s</a>' % (url, path)
6563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except TypeError:
6573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            filelink = '(built-in)'
6583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        info = []
6593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(object, '__version__'):
6603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            version = _binstr(object.__version__)
6613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
6623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                version = strip(version[11:-1])
6633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            info.append('version %s' % self.escape(version))
6643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(object, '__date__'):
6653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            info.append(self.escape(_binstr(object.__date__)))
6663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if info:
6673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            head = head + ' (%s)' % join(info, ', ')
6683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        docloc = self.getdocloc(object)
6693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if docloc is not None:
6703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
6713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
6723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            docloc = ''
6733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        result = self.heading(
6743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            head, '#ffffff', '#7799ee',
6753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            '<a href=".">index</a><br>' + filelink + docloc)
6763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
6773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        modules = inspect.getmembers(object, inspect.ismodule)
6783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
6793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        classes, cdict = [], {}
6803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for key, value in inspect.getmembers(object, inspect.isclass):
6813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # if __all__ exists, believe it.  Otherwise use old heuristic.
6823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if (all is not None or
6833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                (inspect.getmodule(value) or object) is object):
6843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if visiblename(key, all, object):
6853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    classes.append((key, value))
6863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    cdict[key] = cdict[value] = '#' + key
6873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for key, value in classes:
6883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for base in value.__bases__:
6893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                key, modname = base.__name__, base.__module__
6903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                module = sys.modules.get(modname)
6913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if modname != name and module and hasattr(module, key):
6923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    if getattr(module, key) is base:
6933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        if not key in cdict:
6943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                            cdict[key] = cdict[base] = modname + '.html#' + key
6953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        funcs, fdict = [], {}
6963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for key, value in inspect.getmembers(object, inspect.isroutine):
6973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # if __all__ exists, believe it.  Otherwise use old heuristic.
6983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if (all is not None or
6993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                inspect.isbuiltin(value) or inspect.getmodule(value) is object):
7003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if visiblename(key, all, object):
7013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    funcs.append((key, value))
7023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    fdict[key] = '#-' + key
7033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    if inspect.isfunction(value): fdict[value] = fdict[key]
7043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        data = []
7053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for key, value in inspect.getmembers(object, isdata):
7063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if visiblename(key, all, object):
7073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                data.append((key, value))
7083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
7093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
7103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        doc = doc and '<tt>%s</tt>' % doc
7113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        result = result + '<p>%s</p>\n' % doc
7123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
7133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(object, '__path__'):
7143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            modpkgs = []
7153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
7163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                modpkgs.append((modname, name, ispkg, 0))
7173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            modpkgs.sort()
7183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            contents = self.multicolumn(modpkgs, self.modpkglink)
7193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.bigsection(
7203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                'Package Contents', '#ffffff', '#aa55cc', contents)
7213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        elif modules:
7223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            contents = self.multicolumn(
7233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                modules, lambda key_value, s=self: s.modulelink(key_value[1]))
7243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.bigsection(
7253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                'Modules', '#ffffff', '#aa55cc', contents)
7263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
7273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if classes:
7283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            classlist = map(lambda key_value: key_value[1], classes)
7293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            contents = [
7303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.formattree(inspect.getclasstree(classlist, 1), name)]
7313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for key, value in classes:
7323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                contents.append(self.document(value, key, name, fdict, cdict))
7333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.bigsection(
7343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                'Classes', '#ffffff', '#ee77aa', join(contents))
7353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if funcs:
7363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            contents = []
7373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for key, value in funcs:
7383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                contents.append(self.document(value, key, name, fdict, cdict))
7393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.bigsection(
7403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                'Functions', '#ffffff', '#eeaa77', join(contents))
7413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if data:
7423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            contents = []
7433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for key, value in data:
7443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                contents.append(self.document(value, key))
7453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.bigsection(
7463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
7473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(object, '__author__'):
7483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            contents = self.markup(_binstr(object.__author__), self.preformat)
7493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.bigsection(
7503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                'Author', '#ffffff', '#7799ee', contents)
7513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(object, '__credits__'):
7523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            contents = self.markup(_binstr(object.__credits__), self.preformat)
7533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.bigsection(
7543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                'Credits', '#ffffff', '#7799ee', contents)
7553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
7563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return result
7573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
7583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docclass(self, object, name=None, mod=None, funcs={}, classes={},
7593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                 *ignored):
7603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce HTML documentation for a class object."""
7613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        realname = object.__name__
7623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        name = name or realname
7633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        bases = object.__bases__
7643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
7653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        contents = []
7663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        push = contents.append
7673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
7683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # Cute little class to pump out a horizontal rule between sections.
7693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        class HorizontalRule:
7703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            def __init__(self):
7713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.needone = 0
7723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            def maybe(self):
7733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if self.needone:
7743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    push('<hr>\n')
7753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.needone = 1
7763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        hr = HorizontalRule()
7773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
7783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # List the mro, if non-trivial.
7793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        mro = deque(inspect.getmro(object))
7803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if len(mro) > 2:
7813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            hr.maybe()
7823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            push('<dl><dt>Method resolution order:</dt>\n')
7833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for base in mro:
7843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                push('<dd>%s</dd>\n' % self.classlink(base,
7853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                                      object.__module__))
7863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            push('</dl>\n')
7873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
7883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def spill(msg, attrs, predicate):
7893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            ok, attrs = _split_list(attrs, predicate)
7903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if ok:
7913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                hr.maybe()
7923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                push(msg)
7933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                for name, kind, homecls, value in ok:
7943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    try:
7953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        value = getattr(object, name)
7963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    except Exception:
7973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        # Some descriptors may meet a failure in their __get__.
7983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        # (bug #1785)
7993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        push(self._docdescriptor(name, value, mod))
8003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    else:
8013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        push(self.document(value, name, mod,
8023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                        funcs, classes, mdict, object))
8033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    push('\n')
8043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return attrs
8053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
8063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def spilldescriptors(msg, attrs, predicate):
8073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            ok, attrs = _split_list(attrs, predicate)
8083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if ok:
8093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                hr.maybe()
8103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                push(msg)
8113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                for name, kind, homecls, value in ok:
8123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    push(self._docdescriptor(name, value, mod))
8133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return attrs
8143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
8153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def spilldata(msg, attrs, predicate):
8163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            ok, attrs = _split_list(attrs, predicate)
8173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if ok:
8183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                hr.maybe()
8193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                push(msg)
8203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                for name, kind, homecls, value in ok:
8213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    base = self.docother(getattr(object, name), name, mod)
8223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    if (hasattr(value, '__call__') or
8233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                            inspect.isdatadescriptor(value)):
8243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        doc = getattr(value, "__doc__", None)
8253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    else:
8263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        doc = None
8273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    if doc is None:
8283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        push('<dl><dt>%s</dl>\n' % base)
8293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    else:
8303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        doc = self.markup(getdoc(value), self.preformat,
8313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                          funcs, classes, mdict)
8323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        doc = '<dd><tt>%s</tt>' % doc
8333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        push('<dl><dt>%s%s</dl>\n' % (base, doc))
8343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    push('\n')
8353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return attrs
8363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
8373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        attrs = filter(lambda data: visiblename(data[0], obj=object),
8383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                       classify_class_attrs(object))
8393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        mdict = {}
8403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for key, kind, homecls, value in attrs:
8413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            mdict[key] = anchor = '#' + name + '-' + key
8423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            try:
8433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                value = getattr(object, name)
8443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            except Exception:
8453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # Some descriptors may meet a failure in their __get__.
8463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # (bug #1785)
8473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                pass
8483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            try:
8493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # The value may not be hashable (e.g., a data attr with
8503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # a dict or list value).
8513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                mdict[value] = anchor
8523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            except TypeError:
8533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                pass
8543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
8553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        while attrs:
8563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if mro:
8573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                thisclass = mro.popleft()
8583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            else:
8593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                thisclass = attrs[0][2]
8603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
8613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
8623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if thisclass is __builtin__.object:
8633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                attrs = inherited
8643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                continue
8653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif thisclass is object:
8663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                tag = 'defined here'
8673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            else:
8683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                tag = 'inherited from %s' % self.classlink(thisclass,
8693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                                           object.__module__)
8703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            tag += ':<br>\n'
8713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
8723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # Sort attrs by name.
8733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            try:
8743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                attrs.sort(key=lambda t: t[0])
8753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            except TypeError:
8763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))    # 2.3 compat
8773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
8783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # Pump out the attrs, segregated by kind.
8793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = spill('Methods %s' % tag, attrs,
8803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                          lambda t: t[1] == 'method')
8813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = spill('Class methods %s' % tag, attrs,
8823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                          lambda t: t[1] == 'class method')
8833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = spill('Static methods %s' % tag, attrs,
8843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                          lambda t: t[1] == 'static method')
8853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
8863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                     lambda t: t[1] == 'data descriptor')
8873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = spilldata('Data and other attributes %s' % tag, attrs,
8883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                              lambda t: t[1] == 'data')
8893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            assert attrs == []
8903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = inherited
8913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
8923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        contents = ''.join(contents)
8933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
8943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if name == realname:
8953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            title = '<a name="%s">class <strong>%s</strong></a>' % (
8963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                name, realname)
8973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
8983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
8993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                name, name, realname)
9003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if bases:
9013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            parents = []
9023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for base in bases:
9033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                parents.append(self.classlink(base, object.__module__))
9043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            title = title + '(%s)' % join(parents, ', ')
9053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
9063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
9073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
9093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def formatvalue(self, object):
9113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Format an argument default value as text."""
9123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return self.grey('=' + self.repr(object))
9133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docroutine(self, object, name=None, mod=None,
9153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                   funcs={}, classes={}, methods={}, cl=None):
9163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce HTML documentation for a function or method object."""
9173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        realname = object.__name__
9183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        name = name or realname
9193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        anchor = (cl and cl.__name__ or '') + '-' + name
9203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        note = ''
9213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        skipdocs = 0
9223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if inspect.ismethod(object):
9233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            imclass = object.im_class
9243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if cl:
9253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if imclass is not cl:
9263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    note = ' from ' + self.classlink(imclass, mod)
9273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            else:
9283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if object.im_self is not None:
9293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    note = ' method of %s instance' % self.classlink(
9303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        object.im_self.__class__, mod)
9313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                else:
9323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    note = ' unbound %s method' % self.classlink(imclass,mod)
9333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            object = object.im_func
9343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if name == realname:
9363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
9373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
9383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if (cl and realname in cl.__dict__ and
9393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                cl.__dict__[realname] is object):
9403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                reallink = '<a href="#%s">%s</a>' % (
9413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    cl.__name__ + '-' + realname, realname)
9423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                skipdocs = 1
9433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            else:
9443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                reallink = realname
9453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            title = '<a name="%s"><strong>%s</strong></a> = %s' % (
9463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                anchor, name, reallink)
9473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if inspect.isfunction(object):
9483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            args, varargs, varkw, defaults = inspect.getargspec(object)
9493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            argspec = inspect.formatargspec(
9503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                args, varargs, varkw, defaults, formatvalue=self.formatvalue)
9513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if realname == '<lambda>':
9523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                title = '<strong>%s</strong> <em>lambda</em> ' % name
9533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                argspec = argspec[1:-1] # remove parentheses
9543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
9553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            argspec = '(...)'
9563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        decl = title + argspec + (note and self.grey(
9583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel               '<font face="helvetica, arial">%s</font>' % note))
9593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if skipdocs:
9613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return '<dl><dt>%s</dt></dl>\n' % decl
9623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
9633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            doc = self.markup(
9643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                getdoc(object), self.preformat, funcs, classes, methods)
9653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            doc = doc and '<dd><tt>%s</tt></dd>' % doc
9663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
9673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def _docdescriptor(self, name, value, mod):
9693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        results = []
9703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        push = results.append
9713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if name:
9733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            push('<dl><dt><strong>%s</strong></dt>\n' % name)
9743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if value.__doc__ is not None:
9753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            doc = self.markup(getdoc(value), self.preformat)
9763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            push('<dd><tt>%s</tt></dd>\n' % doc)
9773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        push('</dl>\n')
9783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return ''.join(results)
9803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docproperty(self, object, name=None, mod=None, cl=None):
9823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce html documentation for a property."""
9833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return self._docdescriptor(name, object, mod)
9843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docother(self, object, name=None, mod=None, *ignored):
9863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce HTML documentation for a data object."""
9873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        lhs = name and '<strong>%s</strong> = ' % name or ''
9883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return lhs + self.repr(object)
9893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docdata(self, object, name=None, mod=None, cl=None):
9913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce html documentation for a data descriptor."""
9923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return self._docdescriptor(name, object, mod)
9933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
9943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def index(self, dir, shadowed=None):
9953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Generate an HTML index for a directory of modules."""
9963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        modpkgs = []
9973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if shadowed is None: shadowed = {}
9983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for importer, name, ispkg in pkgutil.iter_modules([dir]):
9993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            modpkgs.append((name, '', ispkg, name in shadowed))
10003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            shadowed[name] = 1
10013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        modpkgs.sort()
10033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        contents = self.multicolumn(modpkgs, self.modpkglink)
10043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
10053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# -------------------------------------------- text documentation generator
10073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielclass TextRepr(Repr):
10093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Class for safely making a text representation of a Python object."""
10103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def __init__(self):
10113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        Repr.__init__(self)
10123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.maxlist = self.maxtuple = 20
10133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.maxdict = 10
10143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.maxstring = self.maxother = 100
10153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def repr1(self, x, level):
10173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(type(x), '__name__'):
10183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            methodname = 'repr_' + join(split(type(x).__name__), '_')
10193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if hasattr(self, methodname):
10203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                return getattr(self, methodname)(x, level)
10213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return cram(stripid(repr(x)), self.maxother)
10223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def repr_string(self, x, level):
10243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        test = cram(x, self.maxstring)
10253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        testrepr = repr(test)
10263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
10273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # Backslashes are only literal in the string and are never
10283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # needed to make any special characters, so show a raw string.
10293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return 'r' + testrepr[0] + test + testrepr[0]
10303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return testrepr
10313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    repr_str = repr_string
10333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def repr_instance(self, x, level):
10353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
10363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return cram(stripid(repr(x)), self.maxstring)
10373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except:
10383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return '<%s instance>' % x.__class__.__name__
10393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielclass TextDoc(Doc):
10413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Formatter class for text documentation."""
10423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # ------------------------------------------- text formatting utilities
10443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    _repr_instance = TextRepr()
10463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    repr = _repr_instance.repr
10473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def bold(self, text):
10493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Format a string in bold by overstriking."""
10503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return join(map(lambda ch: ch + '\b' + ch, text), '')
10513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def indent(self, text, prefix='    '):
10533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Indent text by prepending a given prefix to each line."""
10543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if not text: return ''
10553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        lines = split(text, '\n')
10563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        lines = map(lambda line, prefix=prefix: prefix + line, lines)
10573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if lines: lines[-1] = rstrip(lines[-1])
10583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return join(lines, '\n')
10593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def section(self, title, contents):
10613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Format a section with a given heading."""
10623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
10633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # ---------------------------------------------- type-specific routines
10653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def formattree(self, tree, modname, parent=None, prefix=''):
10673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Render in text a class tree as returned by inspect.getclasstree()."""
10683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        result = ''
10693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for entry in tree:
10703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if type(entry) is type(()):
10713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                c, bases = entry
10723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                result = result + prefix + classname(c, modname)
10733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if bases and bases != (parent,):
10743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    parents = map(lambda c, m=modname: classname(c, m), bases)
10753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    result = result + '(%s)' % join(parents, ', ')
10763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                result = result + '\n'
10773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif type(entry) is type([]):
10783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                result = result + self.formattree(
10793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    entry, modname, c, prefix + '    ')
10803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return result
10813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docmodule(self, object, name=None, mod=None):
10833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce text documentation for a given module object."""
10843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        name = object.__name__ # ignore the passed-in name
10853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        synop, desc = splitdoc(getdoc(object))
10863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        result = self.section('NAME', name + (synop and ' - ' + synop))
10873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
10893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            all = object.__all__
10903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except AttributeError:
10913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            all = None
10923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
10943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            file = inspect.getabsfile(object)
10953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except TypeError:
10963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            file = '(built-in)'
10973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        result = result + self.section('FILE', file)
10983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
10993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        docloc = self.getdocloc(object)
11003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if docloc is not None:
11013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.section('MODULE DOCS', docloc)
11023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if desc:
11043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.section('DESCRIPTION', desc)
11053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        classes = []
11073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for key, value in inspect.getmembers(object, inspect.isclass):
11083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # if __all__ exists, believe it.  Otherwise use old heuristic.
11093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if (all is not None
11103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                or (inspect.getmodule(value) or object) is object):
11113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if visiblename(key, all, object):
11123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    classes.append((key, value))
11133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        funcs = []
11143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for key, value in inspect.getmembers(object, inspect.isroutine):
11153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # if __all__ exists, believe it.  Otherwise use old heuristic.
11163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if (all is not None or
11173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                inspect.isbuiltin(value) or inspect.getmodule(value) is object):
11183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if visiblename(key, all, object):
11193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    funcs.append((key, value))
11203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        data = []
11213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for key, value in inspect.getmembers(object, isdata):
11223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if visiblename(key, all, object):
11233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                data.append((key, value))
11243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        modpkgs = []
11263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        modpkgs_names = set()
11273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(object, '__path__'):
11283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
11293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                modpkgs_names.add(modname)
11303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if ispkg:
11313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    modpkgs.append(modname + ' (package)')
11323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                else:
11333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    modpkgs.append(modname)
11343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            modpkgs.sort()
11363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.section(
11373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                'PACKAGE CONTENTS', join(modpkgs, '\n'))
11383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # Detect submodules as sometimes created by C extensions
11403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        submodules = []
11413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for key, value in inspect.getmembers(object, inspect.ismodule):
11423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if value.__name__.startswith(name + '.') and key not in modpkgs_names:
11433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                submodules.append(key)
11443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if submodules:
11453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            submodules.sort()
11463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.section(
11473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                'SUBMODULES', join(submodules, '\n'))
11483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if classes:
11503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            classlist = map(lambda key_value: key_value[1], classes)
11513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            contents = [self.formattree(
11523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                inspect.getclasstree(classlist, 1), name)]
11533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for key, value in classes:
11543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                contents.append(self.document(value, key, name))
11553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.section('CLASSES', join(contents, '\n'))
11563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if funcs:
11583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            contents = []
11593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for key, value in funcs:
11603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                contents.append(self.document(value, key, name))
11613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.section('FUNCTIONS', join(contents, '\n'))
11623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if data:
11643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            contents = []
11653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for key, value in data:
11663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                contents.append(self.docother(value, key, name, maxlen=70))
11673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.section('DATA', join(contents, '\n'))
11683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(object, '__version__'):
11703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            version = _binstr(object.__version__)
11713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
11723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                version = strip(version[11:-1])
11733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.section('VERSION', version)
11743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(object, '__date__'):
11753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.section('DATE', _binstr(object.__date__))
11763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(object, '__author__'):
11773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.section('AUTHOR', _binstr(object.__author__))
11783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(object, '__credits__'):
11793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            result = result + self.section('CREDITS', _binstr(object.__credits__))
11803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return result
11813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docclass(self, object, name=None, mod=None, *ignored):
11833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce text documentation for a given class object."""
11843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        realname = object.__name__
11853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        name = name or realname
11863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        bases = object.__bases__
11873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def makename(c, m=object.__module__):
11893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return classname(c, m)
11903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if name == realname:
11923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            title = 'class ' + self.bold(realname)
11933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
11943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            title = self.bold(name) + ' = class ' + realname
11953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if bases:
11963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            parents = map(makename, bases)
11973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            title = title + '(%s)' % join(parents, ', ')
11983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
11993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        doc = getdoc(object)
12003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        contents = doc and [doc + '\n'] or []
12013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        push = contents.append
12023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
12033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # List the mro, if non-trivial.
12043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        mro = deque(inspect.getmro(object))
12053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if len(mro) > 2:
12063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            push("Method resolution order:")
12073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for base in mro:
12083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                push('    ' + makename(base))
12093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            push('')
12103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
12113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # Cute little class to pump out a horizontal rule between sections.
12123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        class HorizontalRule:
12133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            def __init__(self):
12143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.needone = 0
12153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            def maybe(self):
12163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if self.needone:
12173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    push('-' * 70)
12183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.needone = 1
12193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        hr = HorizontalRule()
12203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
12213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def spill(msg, attrs, predicate):
12223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            ok, attrs = _split_list(attrs, predicate)
12233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if ok:
12243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                hr.maybe()
12253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                push(msg)
12263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                for name, kind, homecls, value in ok:
12273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    try:
12283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        value = getattr(object, name)
12293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    except Exception:
12303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        # Some descriptors may meet a failure in their __get__.
12313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        # (bug #1785)
12323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        push(self._docdescriptor(name, value, mod))
12333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    else:
12343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        push(self.document(value,
12353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                        name, mod, object))
12363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return attrs
12373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
12383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def spilldescriptors(msg, attrs, predicate):
12393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            ok, attrs = _split_list(attrs, predicate)
12403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if ok:
12413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                hr.maybe()
12423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                push(msg)
12433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                for name, kind, homecls, value in ok:
12443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    push(self._docdescriptor(name, value, mod))
12453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return attrs
12463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
12473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def spilldata(msg, attrs, predicate):
12483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            ok, attrs = _split_list(attrs, predicate)
12493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if ok:
12503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                hr.maybe()
12513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                push(msg)
12523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                for name, kind, homecls, value in ok:
12533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    if (hasattr(value, '__call__') or
12543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                            inspect.isdatadescriptor(value)):
12553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        doc = getdoc(value)
12563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    else:
12573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        doc = None
12583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    push(self.docother(getattr(object, name),
12593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                       name, mod, maxlen=70, doc=doc) + '\n')
12603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return attrs
12613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
12623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        attrs = filter(lambda data: visiblename(data[0], obj=object),
12633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                       classify_class_attrs(object))
12643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        while attrs:
12653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if mro:
12663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                thisclass = mro.popleft()
12673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            else:
12683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                thisclass = attrs[0][2]
12693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
12703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
12713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if thisclass is __builtin__.object:
12723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                attrs = inherited
12733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                continue
12743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif thisclass is object:
12753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                tag = "defined here"
12763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            else:
12773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                tag = "inherited from %s" % classname(thisclass,
12783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                                      object.__module__)
12793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
12803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # Sort attrs by name.
12813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs.sort()
12823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
12833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            # Pump out the attrs, segregated by kind.
12843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = spill("Methods %s:\n" % tag, attrs,
12853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                          lambda t: t[1] == 'method')
12863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = spill("Class methods %s:\n" % tag, attrs,
12873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                          lambda t: t[1] == 'class method')
12883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = spill("Static methods %s:\n" % tag, attrs,
12893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                          lambda t: t[1] == 'static method')
12903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
12913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                     lambda t: t[1] == 'data descriptor')
12923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
12933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                              lambda t: t[1] == 'data')
12943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            assert attrs == []
12953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            attrs = inherited
12963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
12973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        contents = '\n'.join(contents)
12983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if not contents:
12993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return title + '\n'
13003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return title + '\n' + self.indent(rstrip(contents), ' |  ') + '\n'
13013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def formatvalue(self, object):
13033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Format an argument default value as text."""
13043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return '=' + self.repr(object)
13053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docroutine(self, object, name=None, mod=None, cl=None):
13073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce text documentation for a function or method object."""
13083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        realname = object.__name__
13093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        name = name or realname
13103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        note = ''
13113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        skipdocs = 0
13123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if inspect.ismethod(object):
13133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            imclass = object.im_class
13143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if cl:
13153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if imclass is not cl:
13163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    note = ' from ' + classname(imclass, mod)
13173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            else:
13183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if object.im_self is not None:
13193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    note = ' method of %s instance' % classname(
13203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        object.im_self.__class__, mod)
13213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                else:
13223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    note = ' unbound %s method' % classname(imclass,mod)
13233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            object = object.im_func
13243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if name == realname:
13263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            title = self.bold(realname)
13273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
13283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if (cl and realname in cl.__dict__ and
13293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                cl.__dict__[realname] is object):
13303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                skipdocs = 1
13313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            title = self.bold(name) + ' = ' + realname
13323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if inspect.isfunction(object):
13333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            args, varargs, varkw, defaults = inspect.getargspec(object)
13343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            argspec = inspect.formatargspec(
13353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                args, varargs, varkw, defaults, formatvalue=self.formatvalue)
13363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if realname == '<lambda>':
13373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                title = self.bold(name) + ' lambda '
13383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                argspec = argspec[1:-1] # remove parentheses
13393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
13403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            argspec = '(...)'
13413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        decl = title + argspec + note
13423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if skipdocs:
13443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return decl + '\n'
13453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
13463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            doc = getdoc(object) or ''
13473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
13483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def _docdescriptor(self, name, value, mod):
13503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        results = []
13513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        push = results.append
13523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if name:
13543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            push(self.bold(name))
13553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            push('\n')
13563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        doc = getdoc(value) or ''
13573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if doc:
13583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            push(self.indent(doc))
13593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            push('\n')
13603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return ''.join(results)
13613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docproperty(self, object, name=None, mod=None, cl=None):
13633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce text documentation for a property."""
13643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return self._docdescriptor(name, object, mod)
13653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docdata(self, object, name=None, mod=None, cl=None):
13673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce text documentation for a data descriptor."""
13683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return self._docdescriptor(name, object, mod)
13693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
13713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Produce text documentation for a data object."""
13723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        repr = self.repr(object)
13733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if maxlen:
13743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            line = (name and name + ' = ' or '') + repr
13753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            chop = maxlen - len(line)
13763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if chop < 0: repr = repr[:chop] + '...'
13773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        line = (name and self.bold(name) + ' = ' or '') + repr
13783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if doc is not None:
13793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            line += '\n' + self.indent(str(doc))
13803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return line
13813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# --------------------------------------------------------- user interfaces
13833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef pager(text):
13853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """The first time this is called, determine what kind of pager to use."""
13863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    global pager
13873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    pager = getpager()
13883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    pager(text)
13893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
13903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef getpager():
13913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Decide what method to use for paging through text."""
13923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if type(sys.stdout) is not types.FileType:
13933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return plainpager
13943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if not hasattr(sys.stdin, "isatty"):
13953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return plainpager
13963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if not sys.stdin.isatty() or not sys.stdout.isatty():
13973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return plainpager
13983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if 'PAGER' in os.environ:
13993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if sys.platform == 'win32': # pipes completely broken in Windows
14003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1401d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel        elif sys.platform == 'uefi':
1402d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel            return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
14033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        elif os.environ.get('TERM') in ('dumb', 'emacs'):
14043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return lambda text: pipepager(plain(text), os.environ['PAGER'])
14053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
14063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return lambda text: pipepager(text, os.environ['PAGER'])
14073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if os.environ.get('TERM') in ('dumb', 'emacs'):
14083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return plainpager
1409d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel    if sys.platform == 'uefi':
1410d11973f1cae1d8e25017b09734fbf419342b192aDaryl McDaniel        return plainpager
14113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if sys.platform == 'win32' or sys.platform.startswith('os2'):
14123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return lambda text: tempfilepager(plain(text), 'more <')
14133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
14143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return lambda text: pipepager(text, 'less')
14153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
14163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    import tempfile
14173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    (fd, filename) = tempfile.mkstemp()
14183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    os.close(fd)
14193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
14203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
14213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return lambda text: pipepager(text, 'more')
14223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
14233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return ttypager
14243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    finally:
14253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        os.unlink(filename)
14263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
14273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef plain(text):
14283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Remove boldface formatting from text."""
14293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return re.sub('.\b', '', text)
14303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
14313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef pipepager(text, cmd):
14323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Page through text by feeding it to another program."""
14333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    pipe = os.popen(cmd, 'w')
14343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
14353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        pipe.write(_encode(text))
14363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        pipe.close()
14373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    except IOError:
14383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        pass # Ignore broken pipes caused by quitting the pager program.
14393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
14403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef tempfilepager(text, cmd):
14413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Page through text by invoking a program on a temporary file."""
14423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    import tempfile
14433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    filename = tempfile.mktemp()
14443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    file = open(filename, 'w')
14453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    file.write(_encode(text))
14463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    file.close()
14473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
14483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        os.system(cmd + ' "' + filename + '"')
14493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    finally:
14503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        os.unlink(filename)
14513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
14523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef ttypager(text):
14533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Page through text on a text terminal."""
14543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    lines = plain(_encode(plain(text), getattr(sys.stdout, 'encoding', _encoding))).split('\n')
14553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
14563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        import tty
14573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        fd = sys.stdin.fileno()
14583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        old = tty.tcgetattr(fd)
14593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        tty.setcbreak(fd)
14603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        getchar = lambda: sys.stdin.read(1)
14613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    except (ImportError, AttributeError):
14623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        tty = None
14633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        getchar = lambda: sys.stdin.readline()[:-1][:1]
14643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
14653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
14663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
14673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            h = int(os.environ.get('LINES', 0))
14683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except ValueError:
14693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            h = 0
14703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if h <= 1:
14713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            h = 25
14723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        r = inc = h - 1
14733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        sys.stdout.write(join(lines[:inc], '\n') + '\n')
14743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        while lines[r:]:
14753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            sys.stdout.write('-- more --')
14763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            sys.stdout.flush()
14773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            c = getchar()
14783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
14793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if c in ('q', 'Q'):
14803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                sys.stdout.write('\r          \r')
14813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                break
14823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif c in ('\r', '\n'):
14833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                sys.stdout.write('\r          \r' + lines[r] + '\n')
14843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                r = r + 1
14853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                continue
14863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if c in ('b', 'B', '\x1b'):
14873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                r = r - inc - inc
14883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if r < 0: r = 0
14893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
14903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            r = r + inc
14913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
14923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    finally:
14933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if tty:
14943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            tty.tcsetattr(fd, tty.TCSAFLUSH, old)
14953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
14963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef plainpager(text):
14973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Simply print unformatted text.  This is the ultimate fallback."""
14983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    sys.stdout.write(_encode(plain(text), getattr(sys.stdout, 'encoding', _encoding)))
14993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
15003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef describe(thing):
15013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Produce a short description of the given thing."""
15023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if inspect.ismodule(thing):
15033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if thing.__name__ in sys.builtin_module_names:
15043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return 'built-in module ' + thing.__name__
15053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if hasattr(thing, '__path__'):
15063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return 'package ' + thing.__name__
15073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
15083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return 'module ' + thing.__name__
15093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if inspect.isbuiltin(thing):
15103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return 'built-in function ' + thing.__name__
15113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if inspect.isgetsetdescriptor(thing):
15123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return 'getset descriptor %s.%s.%s' % (
15133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            thing.__objclass__.__module__, thing.__objclass__.__name__,
15143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            thing.__name__)
15153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if inspect.ismemberdescriptor(thing):
15163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return 'member descriptor %s.%s.%s' % (
15173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            thing.__objclass__.__module__, thing.__objclass__.__name__,
15183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            thing.__name__)
15193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if inspect.isclass(thing):
15203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return 'class ' + thing.__name__
15213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if inspect.isfunction(thing):
15223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return 'function ' + thing.__name__
15233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if inspect.ismethod(thing):
15243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return 'method ' + thing.__name__
15253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if type(thing) is types.InstanceType:
15263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return 'instance of ' + thing.__class__.__name__
15273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return type(thing).__name__
15283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
15293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef locate(path, forceload=0):
15303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Locate an object by name or dotted path, importing as necessary."""
15313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    parts = [part for part in split(path, '.') if part]
15323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    module, n = None, 0
15333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    while n < len(parts):
15343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
15353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if nextmodule: module, n = nextmodule, n + 1
15363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else: break
15373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if module:
15383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        object = module
15393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    else:
15403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        object = __builtin__
15413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    for part in parts[n:]:
15423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
15433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            object = getattr(object, part)
15443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except AttributeError:
15453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return None
15463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return object
15473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
15483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# --------------------------------------- interactive interpreter interface
15493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
15503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieltext = TextDoc()
15513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielhtml = HTMLDoc()
15523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
15533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielclass _OldStyleClass: pass
15543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel_OLD_INSTANCE_TYPE = type(_OldStyleClass())
15553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
15563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef resolve(thing, forceload=0):
15573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Given an object or a path to an object, get the object and its name."""
15583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if isinstance(thing, str):
15593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        object = locate(thing, forceload)
15603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if object is None:
15613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            raise ImportError, 'no Python documentation found for %r' % thing
15623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return object, thing
15633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    else:
15643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        name = getattr(thing, '__name__', None)
15653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return thing, name if isinstance(name, str) else None
15663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
15673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef render_doc(thing, title='Python Library Documentation: %s', forceload=0):
15683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Render text documentation, given an object or a path to an object."""
15693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    object, name = resolve(thing, forceload)
15703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    desc = describe(object)
15713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    module = inspect.getmodule(object)
15723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if name and '.' in name:
15733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        desc += ' in ' + name[:name.rfind('.')]
15743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    elif module and module is not object:
15753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        desc += ' in module ' + module.__name__
15763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if type(object) is _OLD_INSTANCE_TYPE:
15773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # If the passed object is an instance of an old-style class,
15783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # document its available methods instead of its value.
15793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        object = object.__class__
15803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    elif not (inspect.ismodule(object) or
15813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel              inspect.isclass(object) or
15823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel              inspect.isroutine(object) or
15833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel              inspect.isgetsetdescriptor(object) or
15843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel              inspect.ismemberdescriptor(object) or
15853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel              isinstance(object, property)):
15863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # If the passed object is a piece of data or an instance,
15873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # document its available methods instead of its value.
15883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        object = type(object)
15893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        desc += ' object'
15903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return title % desc + '\n\n' + text.document(object, name)
15913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
15923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef doc(thing, title='Python Library Documentation: %s', forceload=0):
15933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Display text documentation, given an object or a path to an object."""
15943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
15953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        pager(render_doc(thing, title, forceload))
15963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    except (ImportError, ErrorDuringImport), value:
15973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        print value
15983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
15993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef writedoc(thing, forceload=0):
16003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Write HTML documentation to a file in the current directory."""
16013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
16023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        object, name = resolve(thing, forceload)
16033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        page = html.page(describe(object), html.document(object, name))
16043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        file = open(name + '.html', 'w')
16053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        file.write(page)
16063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        file.close()
16073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        print 'wrote', name + '.html'
16083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    except (ImportError, ErrorDuringImport), value:
16093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        print value
16103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
16113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef writedocs(dir, pkgpath='', done=None):
16123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Write out HTML documentation for all modules in a directory tree."""
16133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if done is None: done = {}
16143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
16153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        writedoc(modname)
16163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return
16173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
16183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielclass Helper:
16193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
16203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # These dictionaries map a topic name to either an alias, or a tuple
16213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # (label, seealso-items).  The "label" is the label of the corresponding
16223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # section in the .rst file under Doc/ and an index into the dictionary
16233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # in pydoc_data/topics.py.
16243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    #
16253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # CAUTION: if you change one of these dictionaries, be sure to adapt the
16263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    #          list of needed labels in Doc/tools/pyspecific.py and
16273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    #          regenerate the pydoc_data/topics.py file by running
16283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    #              make pydoc-topics
16293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    #          in Doc/ and copying the output file into the Lib/ directory.
16303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
16313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    keywords = {
16323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'and': 'BOOLEAN',
16333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'as': 'with',
16343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'assert': ('assert', ''),
16353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'break': ('break', 'while for'),
16363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'class': ('class', 'CLASSES SPECIALMETHODS'),
16373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'continue': ('continue', 'while for'),
16383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'def': ('function', ''),
16393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'del': ('del', 'BASICMETHODS'),
16403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'elif': 'if',
16413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'else': ('else', 'while for'),
16423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'except': 'try',
16433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'exec': ('exec', ''),
16443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'finally': 'try',
16453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'for': ('for', 'break continue while'),
16463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'from': 'import',
16473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'global': ('global', 'NAMESPACES'),
16483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'if': ('if', 'TRUTHVALUE'),
16493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'import': ('import', 'MODULES'),
16503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'in': ('in', 'SEQUENCEMETHODS2'),
16513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'is': 'COMPARISON',
16523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'lambda': ('lambda', 'FUNCTIONS'),
16533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'not': 'BOOLEAN',
16543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'or': 'BOOLEAN',
16553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'pass': ('pass', ''),
16563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'print': ('print', ''),
16573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'raise': ('raise', 'EXCEPTIONS'),
16583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'return': ('return', 'FUNCTIONS'),
16593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'try': ('try', 'EXCEPTIONS'),
16603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'while': ('while', 'break continue if TRUTHVALUE'),
16613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
16623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'yield': ('yield', ''),
16633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    }
16643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # Either add symbols to this dictionary or to the symbols dictionary
16653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # directly: Whichever is easier. They are merged later.
16663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    _symbols_inverse = {
16673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'STRINGS' : ("'", "'''", "r'", "u'", '"""', '"', 'r"', 'u"'),
16683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
16693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                       '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
16703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
16713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'UNARY' : ('-', '~'),
16723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
16733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                '^=', '<<=', '>>=', '**=', '//='),
16743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
16753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'COMPLEX' : ('j', 'J')
16763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    }
16773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    symbols = {
16783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        '%': 'OPERATORS FORMATTING',
16793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        '**': 'POWER',
16803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        ',': 'TUPLES LISTS FUNCTIONS',
16813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
16823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        '...': 'ELLIPSIS',
16833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        ':': 'SLICINGS DICTIONARYLITERALS',
16843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        '@': 'def class',
16853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        '\\': 'STRINGS',
16863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        '_': 'PRIVATENAMES',
16873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        '__': 'PRIVATENAMES SPECIALMETHODS',
16883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        '`': 'BACKQUOTES',
16893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        '(': 'TUPLES FUNCTIONS CALLS',
16903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        ')': 'TUPLES FUNCTIONS CALLS',
16913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        '[': 'LISTS SUBSCRIPTS SLICINGS',
16923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        ']': 'LISTS SUBSCRIPTS SLICINGS'
16933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    }
16943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    for topic, symbols_ in _symbols_inverse.iteritems():
16953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for symbol in symbols_:
16963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            topics = symbols.get(symbol, topic)
16973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if topic not in topics:
16983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                topics = topics + ' ' + topic
16993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            symbols[symbol] = topics
17003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
17013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    topics = {
17023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
17033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                  'FUNCTIONS CLASSES MODULES FILES inspect'),
17043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING '
17053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    'TYPES'),
17063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
17073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'FORMATTING': ('formatstrings', 'OPERATORS'),
17083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
17093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    'FORMATTING TYPES'),
17103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
17113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'INTEGER': ('integers', 'int range'),
17123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'FLOAT': ('floating', 'float math'),
17133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'COMPLEX': ('imaginary', 'complex cmath'),
17143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
17153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'MAPPINGS': 'DICTIONARIES',
17163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'FUNCTIONS': ('typesfunctions', 'def TYPES'),
17173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
17183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
17193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
17203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'FRAMEOBJECTS': 'TYPES',
17213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'TRACEBACKS': 'TYPES',
17223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'NONE': ('bltin-null-object', ''),
17233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
17243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'FILES': ('bltin-file-objects', ''),
17253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'SPECIALATTRIBUTES': ('specialattrs', ''),
17263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
17273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'MODULES': ('typesmodules', 'import'),
17283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'PACKAGES': 'import',
17293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
17303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
17313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
17323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        'LISTS DICTIONARIES BACKQUOTES'),
17333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'OPERATORS': 'EXPRESSIONS',
17343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'PRECEDENCE': 'EXPRESSIONS',
17353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'OBJECTS': ('objects', 'TYPES'),
17363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
17373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                           'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS '
17383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                           'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
17393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'BASICMETHODS': ('customization', 'cmp hash repr str SPECIALMETHODS'),
17403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
17413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
17423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'SEQUENCEMETHODS1': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 '
17433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                             'SPECIALMETHODS'),
17443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'SEQUENCEMETHODS2': ('sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 '
17453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                             'SPECIALMETHODS'),
17463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
17473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
17483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                          'SPECIALMETHODS'),
17493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
17503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'NAMESPACES': ('naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
17513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'DYNAMICFEATURES': ('dynamic-features', ''),
17523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'SCOPING': 'NAMESPACES',
17533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'FRAMES': 'NAMESPACES',
17543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'EXCEPTIONS': ('exceptions', 'try except finally raise'),
17553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'COERCIONS': ('coercion-rules','CONVERSIONS'),
17563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'CONVERSIONS': ('conversions', 'COERCIONS'),
17573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
17583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'SPECIALIDENTIFIERS': ('id-classes', ''),
17593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'PRIVATENAMES': ('atom-identifiers', ''),
17603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'LITERALS': ('atom-literals', 'STRINGS BACKQUOTES NUMBERS '
17613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                     'TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
17623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'TUPLES': 'SEQUENCES',
17633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
17643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
17653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'LISTLITERALS': ('lists', 'LISTS LITERALS'),
17663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
17673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
17683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'BACKQUOTES': ('string-conversions', 'repr str STRINGS LITERALS'),
17693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr '
17703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                       'ATTRIBUTEMETHODS'),
17713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS1'),
17723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'SLICINGS': ('slicings', 'SEQUENCEMETHODS2'),
17733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'CALLS': ('calls', 'EXPRESSIONS'),
17743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'POWER': ('power', 'EXPRESSIONS'),
17753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'UNARY': ('unary', 'EXPRESSIONS'),
17763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'BINARY': ('binary', 'EXPRESSIONS'),
17773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'SHIFTING': ('shifting', 'EXPRESSIONS'),
17783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'BITWISE': ('bitwise', 'EXPRESSIONS'),
17793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
17803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
17813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'ASSERTION': 'assert',
17823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
17833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
17843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'DELETION': 'del',
17853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'PRINTING': 'print',
17863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'RETURNING': 'return',
17873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'IMPORTING': 'import',
17883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'CONDITIONAL': 'if',
17893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'LOOPING': ('compound', 'for while break continue'),
17903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
17913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'DEBUGGING': ('debugger', 'pdb'),
17923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        'CONTEXTMANAGERS': ('context-managers', 'with'),
17933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    }
17943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
17953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def __init__(self, input=None, output=None):
17963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self._input = input
17973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self._output = output
17983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
17993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    input  = property(lambda self: self._input or sys.stdin)
18003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    output = property(lambda self: self._output or sys.stdout)
18013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def __repr__(self):
18033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if inspect.stack()[1][3] == '?':
18043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self()
18053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return ''
18063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return '<pydoc.Helper instance>'
18073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    _GoInteractive = object()
18093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def __call__(self, request=_GoInteractive):
18103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if request is not self._GoInteractive:
18113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.help(request)
18123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
18133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.intro()
18143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.interact()
18153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.output.write('''
18163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielYou are now leaving help and returning to the Python interpreter.
18173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielIf you want to ask for help on a particular object directly from the
18183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielinterpreter, you can type "help(object)".  Executing "help('string')"
18193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielhas the same effect as typing a particular string at the help> prompt.
18203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel''')
18213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def interact(self):
18233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.output.write('\n')
18243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        while True:
18253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            try:
18263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                request = self.getline('help> ')
18273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if not request: break
18283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            except (KeyboardInterrupt, EOFError):
18293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                break
18303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            request = strip(replace(request, '"', '', "'", ''))
18313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if lower(request) in ('q', 'quit'): break
18323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.help(request)
18333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def getline(self, prompt):
18353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        """Read one line, using raw_input when available."""
18363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if self.input is sys.stdin:
18373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return raw_input(prompt)
18383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
18393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.output.write(prompt)
18403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.output.flush()
18413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return self.input.readline()
18423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def help(self, request):
18443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if type(request) is type(''):
18453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            request = request.strip()
18463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if request == 'help': self.intro()
18473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif request == 'keywords': self.listkeywords()
18483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif request == 'symbols': self.listsymbols()
18493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif request == 'topics': self.listtopics()
18503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif request == 'modules': self.listmodules()
18513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif request[:8] == 'modules ':
18523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.listmodules(split(request)[1])
18533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif request in self.symbols: self.showsymbol(request)
18543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif request in self.keywords: self.showtopic(request)
18553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif request in self.topics: self.showtopic(request)
18563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            elif request: doc(request, 'Help on %s:')
18573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        elif isinstance(request, Helper): self()
18583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else: doc(request, 'Help on %s:')
18593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.output.write('\n')
18603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def intro(self):
18623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.output.write('''
18633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielWelcome to Python %s!  This is the online help utility.
18643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielIf this is your first time using Python, you should definitely check out
18663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielthe tutorial on the Internet at http://docs.python.org/%s/tutorial/.
18673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielEnter the name of any module, keyword, or topic to get help on writing
18693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielPython programs and using Python modules.  To quit this help utility and
18703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielreturn to the interpreter, just type "quit".
18713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielTo get a list of available modules, keywords, or topics, type "modules",
18733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel"keywords", or "topics".  Each module also comes with a one-line summary
18743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielof what it does; to list the modules whose summaries contain a given word
18753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielsuch as "spam", type "modules spam".
18763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel''' % tuple([sys.version[:3]]*2))
18773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def list(self, items, columns=4, width=80):
18793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        items = items[:]
18803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        items.sort()
18813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        colw = width / columns
18823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        rows = (len(items) + columns - 1) / columns
18833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for row in range(rows):
18843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            for col in range(columns):
18853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                i = col * rows + row
18863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if i < len(items):
18873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    self.output.write(items[i])
18883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    if col < columns - 1:
18893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
18903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.output.write('\n')
18913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def listkeywords(self):
18933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.output.write('''
18943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielHere is a list of the Python keywords.  Enter any keyword to get more help.
18953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel''')
18973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.list(self.keywords.keys())
18983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
18993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def listsymbols(self):
19003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.output.write('''
19013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielHere is a list of the punctuation symbols which Python assigns special meaning
19023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielto. Enter any symbol to get more help.
19033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel''')
19053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.list(self.symbols.keys())
19063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def listtopics(self):
19083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.output.write('''
19093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielHere is a list of available topics.  Enter any topic name to get more help.
19103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel''')
19123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.list(self.topics.keys())
19133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def showtopic(self, topic, more_xrefs=''):
19153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
19163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            import pydoc_data.topics
19173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except ImportError:
19183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.output.write('''
19193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielSorry, topic and keyword documentation is not available because the
19203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielmodule "pydoc_data.topics" could not be found.
19213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel''')
19223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return
19233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        target = self.topics.get(topic, self.keywords.get(topic))
19243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if not target:
19253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.output.write('no documentation found for %s\n' % repr(topic))
19263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return
19273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if type(target) is type(''):
19283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return self.showtopic(target, more_xrefs)
19293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        label, xrefs = target
19313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
19323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            doc = pydoc_data.topics.topics[label]
19333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except KeyError:
19343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.output.write('no documentation found for %s\n' % repr(topic))
19353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return
19363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        pager(strip(doc) + '\n')
19373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if more_xrefs:
19383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            xrefs = (xrefs or '') + ' ' + more_xrefs
19393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if xrefs:
19403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            import StringIO, formatter
19413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            buffer = StringIO.StringIO()
19423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            formatter.DumbWriter(buffer).send_flowing_data(
19433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                'Related help topics: ' + join(split(xrefs), ', ') + '\n')
19443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.output.write('\n%s\n' % buffer.getvalue())
19453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def showsymbol(self, symbol):
19473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        target = self.symbols[symbol]
19483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        topic, _, xrefs = target.partition(' ')
19493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.showtopic(topic, xrefs)
19503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def listmodules(self, key=''):
19523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if key:
19533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.output.write('''
19543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielHere is a list of matching modules.  Enter any module name to get more help.
19553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel''')
19573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            apropos(key)
19583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        else:
19593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.output.write('''
19603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielPlease wait a moment while I gather a list of all available modules...
19613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel''')
19633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            modules = {}
19643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            def callback(path, modname, desc, modules=modules):
19653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if modname and modname[-9:] == '.__init__':
19663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    modname = modname[:-9] + ' (package)'
19673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if find(modname, '.') < 0:
19683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    modules[modname] = 1
19693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            def onerror(modname):
19703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                callback(None, modname, None)
19713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            ModuleScanner().run(callback, onerror=onerror)
19723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.list(modules.keys())
19733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.output.write('''
19743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielEnter any module name to get more help.  Or, type "modules spam" to search
19753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielfor modules whose descriptions contain the word "spam".
19763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel''')
19773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielhelp = Helper()
19793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielclass Scanner:
19813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """A generic tree iterator."""
19823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def __init__(self, roots, children, descendp):
19833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.roots = roots[:]
19843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.state = []
19853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.children = children
19863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.descendp = descendp
19873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
19883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def next(self):
19893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if not self.state:
19903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if not self.roots:
19913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                return None
19923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            root = self.roots.pop(0)
19933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.state = [(root, self.children(root))]
19943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        node, children = self.state[-1]
19953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if not children:
19963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.state.pop()
19973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            return self.next()
19983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        child = children.pop(0)
19993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if self.descendp(child):
20003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.state.append((child, self.children(child)))
20013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        return child
20023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielclass ModuleScanner:
20053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """An interruptible scanner that searches module synopses."""
20063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def run(self, callback, key=None, completer=None, onerror=None):
20083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if key: key = lower(key)
20093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        self.quit = False
20103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        seen = {}
20113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for modname in sys.builtin_module_names:
20133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if modname != '__main__':
20143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                seen[modname] = 1
20153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if key is None:
20163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    callback(None, modname, '')
20173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                else:
20183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    desc = split(__import__(modname).__doc__ or '', '\n')[0]
20193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    if find(lower(modname + ' - ' + desc), key) >= 0:
20203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        callback(None, modname, desc)
20213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
20233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if self.quit:
20243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                break
20253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if key is None:
20263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                callback(None, modname, '')
20273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            else:
20283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                loader = importer.find_module(modname)
20293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if hasattr(loader,'get_source'):
20303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    import StringIO
20313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    desc = source_synopsis(
20323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        StringIO.StringIO(loader.get_source(modname))
20333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    ) or ''
20343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    if hasattr(loader,'get_filename'):
20353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        path = loader.get_filename(modname)
20363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    else:
20373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        path = None
20383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                else:
20393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    module = loader.load_module(modname)
20403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    desc = module.__doc__.splitlines()[0] if module.__doc__ else ''
20413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    path = getattr(module,'__file__',None)
20423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if find(lower(modname + ' - ' + desc), key) >= 0:
20433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    callback(path, modname, desc)
20443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if completer:
20463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            completer()
20473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef apropos(key):
20493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Print all the one-line module summaries that contain a substring."""
20503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def callback(path, modname, desc):
20513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if modname[-9:] == '.__init__':
20523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            modname = modname[:-9] + ' (package)'
20533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        print modname, desc and '- ' + desc
20543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    def onerror(modname):
20553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        pass
20563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    with warnings.catch_warnings():
20573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        warnings.filterwarnings('ignore') # ignore problems during import
20583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        ModuleScanner().run(callback, key, onerror=onerror)
20593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# --------------------------------------------------- web browser interface
20613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef serve(port, callback=None, completer=None):
20633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    import BaseHTTPServer, mimetools, select
20643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
20663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    class Message(mimetools.Message):
20673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def __init__(self, fp, seekable=1):
20683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            Message = self.__class__
20693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
20703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.encodingheader = self.getheader('content-transfer-encoding')
20713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.typeheader = self.getheader('content-type')
20723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.parsetype()
20733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.parseplist()
20743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
20763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def send_document(self, title, contents):
20773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            try:
20783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.send_response(200)
20793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.send_header('Content-Type', 'text/html')
20803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.end_headers()
20813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.wfile.write(html.page(title, contents))
20823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            except IOError: pass
20833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
20843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def do_GET(self):
20853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            path = self.path
20863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if path[-5:] == '.html': path = path[:-5]
20873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if path[:1] == '/': path = path[1:]
20883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if path and path != '.':
20893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                try:
20903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    obj = locate(path, forceload=1)
20913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                except ErrorDuringImport, value:
20923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    self.send_document(path, html.escape(str(value)))
20933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    return
20943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if obj:
20953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    self.send_document(describe(obj), html.document(obj, path))
20963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                else:
20973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    self.send_document(path,
20983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel'no Python documentation found for %s' % repr(path))
20993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            else:
21003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                heading = html.heading(
21013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel'<big><big><strong>Python: Index of Modules</strong></big></big>',
21023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel'#ffffff', '#7799ee')
21033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                def bltinlink(name):
21043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    return '<a href="%s.html">%s</a>' % (name, name)
21053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                names = filter(lambda x: x != '__main__',
21063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                               sys.builtin_module_names)
21073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                contents = html.multicolumn(names, bltinlink)
21083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                indices = ['<p>' + html.bigsection(
21093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    'Built-in Modules', '#ffffff', '#ee77aa', contents)]
21103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                seen = {}
21123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                for dir in sys.path:
21133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    indices.append(html.index(dir, seen))
21143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                contents = heading + join(indices) + '''<p align=right>
21153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel<font color="#909090" face="helvetica, arial"><strong>
21163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielpydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
21173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.send_document('Index of Modules', contents)
21183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def log_message(self, *args): pass
21203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    class DocServer(BaseHTTPServer.HTTPServer):
21223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def __init__(self, port, callback):
21233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            host = 'localhost'
21243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.address = (host, port)
21253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.callback = callback
21263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.base.__init__(self, self.address, self.handler)
21273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def serve_until_quit(self):
21293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            import select
21303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.quit = False
21313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            while not self.quit:
21323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
21333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if rd: self.handle_request()
21343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def server_activate(self):
21363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.base.server_activate(self)
21373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.url = 'http://%s:%d/' % (self.address[0], self.server_port)
21383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if self.callback: self.callback(self)
21393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    DocServer.base = BaseHTTPServer.HTTPServer
21413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    DocServer.handler = DocHandler
21423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    DocHandler.MessageClass = Message
21433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
21443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
21453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            DocServer(port, callback).serve_until_quit()
21463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        except (KeyboardInterrupt, select.error):
21473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            pass
21483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    finally:
21493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if completer: completer()
21503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# ----------------------------------------------------- graphical interface
21523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef gui():
21543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Graphical interface (starts web server and pops up a control window)."""
21553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    class GUI:
21563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def __init__(self, window, port=7464):
21573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window = window
21583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.server = None
21593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.scanner = None
21603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            import Tkinter
21623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.server_frm = Tkinter.Frame(window)
21633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.title_lbl = Tkinter.Label(self.server_frm,
21643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                text='Starting server...\n ')
21653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.open_btn = Tkinter.Button(self.server_frm,
21663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                text='open browser', command=self.open, state='disabled')
21673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.quit_btn = Tkinter.Button(self.server_frm,
21683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                text='quit serving', command=self.quit, state='disabled')
21693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_frm = Tkinter.Frame(window)
21713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
21723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_ent = Tkinter.Entry(self.search_frm)
21733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_ent.bind('<Return>', self.search)
21743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.stop_btn = Tkinter.Button(self.search_frm,
21753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                text='stop', pady=0, command=self.stop, state='disabled')
21763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if sys.platform == 'win32':
21773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                # Trying to hide and show this button crashes under Windows.
21783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.stop_btn.pack(side='right')
21793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window.title('pydoc')
21813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window.protocol('WM_DELETE_WINDOW', self.quit)
21823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.title_lbl.pack(side='top', fill='x')
21833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.open_btn.pack(side='left', fill='x', expand=1)
21843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.quit_btn.pack(side='right', fill='x', expand=1)
21853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.server_frm.pack(side='top', fill='x')
21863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_lbl.pack(side='left')
21883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_ent.pack(side='right', fill='x', expand=1)
21893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_frm.pack(side='top', fill='x')
21903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_ent.focus_set()
21913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
21923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            font = ('helvetica', sys.platform == 'win32' and 8 or 10)
21933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_lst = Tkinter.Listbox(window, font=font, height=6)
21943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_lst.bind('<Button-1>', self.select)
21953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_lst.bind('<Double-Button-1>', self.goto)
21963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_scr = Tkinter.Scrollbar(window,
21973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                orient='vertical', command=self.result_lst.yview)
21983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_lst.config(yscrollcommand=self.result_scr.set)
21993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_frm = Tkinter.Frame(window)
22013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.goto_btn = Tkinter.Button(self.result_frm,
22023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                text='go to selected', command=self.goto)
22033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.hide_btn = Tkinter.Button(self.result_frm,
22043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                text='hide results', command=self.hide)
22053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.goto_btn.pack(side='left', fill='x', expand=1)
22063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.hide_btn.pack(side='right', fill='x', expand=1)
22073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window.update()
22093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.minwidth = self.window.winfo_width()
22103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.minheight = self.window.winfo_height()
22113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.bigminheight = (self.server_frm.winfo_reqheight() +
22123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                 self.search_frm.winfo_reqheight() +
22133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                 self.result_lst.winfo_reqheight() +
22143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                                 self.result_frm.winfo_reqheight())
22153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
22163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.expanded = 0
22173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
22183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window.wm_minsize(self.minwidth, self.minheight)
22193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window.tk.willdispatch()
22203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            import threading
22223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            threading.Thread(
22233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                target=serve, args=(port, self.ready, self.quit)).start()
22243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def ready(self, server):
22263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.server = server
22273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.title_lbl.config(
22283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                text='Python documentation server at\n' + server.url)
22293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.open_btn.config(state='normal')
22303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.quit_btn.config(state='normal')
22313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def open(self, event=None, url=None):
22333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            url = url or self.server.url
22343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            try:
22353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                import webbrowser
22363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                webbrowser.open(url)
22373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            except ImportError: # pre-webbrowser.py compatibility
22383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if sys.platform == 'win32':
22393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    os.system('start "%s"' % url)
22403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                else:
22413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    rc = os.system('netscape -remote "openURL(%s)" &' % url)
22423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    if rc: os.system('netscape "%s" &' % url)
22433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def quit(self, event=None):
22453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if self.server:
22463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.server.quit = 1
22473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window.quit()
22483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def search(self, event=None):
22503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            key = self.search_ent.get()
22513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.stop_btn.pack(side='right')
22523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.stop_btn.config(state='normal')
22533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_lbl.config(text='Searching for "%s"...' % key)
22543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_ent.forget()
22553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_lbl.pack(side='left')
22563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_lst.delete(0, 'end')
22573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.goto_btn.config(state='disabled')
22583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.expand()
22593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            import threading
22613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if self.scanner:
22623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.scanner.quit = 1
22633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.scanner = ModuleScanner()
22643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            threading.Thread(target=self.scanner.run,
22653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                             args=(self.update, key, self.done)).start()
22663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def update(self, path, modname, desc):
22683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if modname[-9:] == '.__init__':
22693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                modname = modname[:-9] + ' (package)'
22703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_lst.insert('end',
22713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                modname + ' - ' + (desc or '(no description)'))
22723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def stop(self, event=None):
22743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if self.scanner:
22753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.scanner.quit = 1
22763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.scanner = None
22773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def done(self):
22793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.scanner = None
22803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_lbl.config(text='Search for')
22813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_lbl.pack(side='left')
22823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.search_ent.pack(side='right', fill='x', expand=1)
22833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if sys.platform != 'win32': self.stop_btn.forget()
22843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.stop_btn.config(state='disabled')
22853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def select(self, event=None):
22873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.goto_btn.config(state='normal')
22883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def goto(self, event=None):
22903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            selection = self.result_lst.curselection()
22913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if selection:
22923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                modname = split(self.result_lst.get(selection[0]))[0]
22933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                self.open(url=self.server.url + modname + '.html')
22943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
22953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def collapse(self):
22963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if not self.expanded: return
22973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_frm.forget()
22983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_scr.forget()
22993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_lst.forget()
23003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.bigwidth = self.window.winfo_width()
23013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.bigheight = self.window.winfo_height()
23023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
23033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window.wm_minsize(self.minwidth, self.minheight)
23043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.expanded = 0
23053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def expand(self):
23073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if self.expanded: return
23083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_frm.pack(side='bottom', fill='x')
23093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_scr.pack(side='right', fill='y')
23103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.result_lst.pack(side='top', fill='both', expand=1)
23113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
23123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.window.wm_minsize(self.minwidth, self.bigminheight)
23133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.expanded = 1
23143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        def hide(self, event=None):
23163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.stop()
23173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            self.collapse()
23183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    import Tkinter
23203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
23213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        root = Tkinter.Tk()
23223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # Tk will crash if pythonw.exe has an XP .manifest
23233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # file and the root has is not destroyed explicitly.
23243ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # If the problem is ever fixed in Tk, the explicit
23253ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        # destroy can go.
23263ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        try:
23273ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            gui = GUI(root)
23283ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            root.mainloop()
23293ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        finally:
23303ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            root.destroy()
23313ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    except KeyboardInterrupt:
23323ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        pass
23333ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23343ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel# -------------------------------------------------- command-line interface
23353ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23363ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef ispath(x):
23373ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    return isinstance(x, str) and find(x, os.sep) >= 0
23383ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23393ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanieldef cli():
23403ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    """Command-line interface (looks at sys.argv to decide what to do)."""
23413ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    import getopt
23423ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    class BadUsage: pass
23433ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23443ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # Scripts don't get the current directory in their path by default
23453ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    # unless they are run with the '-m' switch
23463ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    if '' not in sys.path:
23473ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        scriptdir = os.path.dirname(sys.argv[0])
23483ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if scriptdir in sys.path:
23493ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            sys.path.remove(scriptdir)
23503ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        sys.path.insert(0, '.')
23513ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23523ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    try:
23533ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
23543ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        writing = 0
23553ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23563ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for opt, val in opts:
23573ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if opt == '-g':
23583ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                gui()
23593ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                return
23603ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if opt == '-k':
23613ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                apropos(val)
23623ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                return
23633ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if opt == '-p':
23643ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                try:
23653ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    port = int(val)
23663ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                except ValueError:
23673ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    raise BadUsage
23683ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                def ready(server):
23693ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    print 'pydoc server ready at %s' % server.url
23703ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                def stopped():
23713ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    print 'pydoc server stopped'
23723ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                serve(port, ready, stopped)
23733ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                return
23743ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if opt == '-w':
23753ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                writing = 1
23763ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23773ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        if not args: raise BadUsage
23783ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        for arg in args:
23793ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            if ispath(arg) and not os.path.exists(arg):
23803ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                print 'file %r does not exist' % arg
23813ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                break
23823ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            try:
23833ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if ispath(arg) and os.path.isfile(arg):
23843ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    arg = importfile(arg)
23853ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                if writing:
23863ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    if ispath(arg) and os.path.isdir(arg):
23873ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        writedocs(arg)
23883ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    else:
23893ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                        writedoc(arg)
23903ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                else:
23913ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                    help.help(arg)
23923ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel            except ErrorDuringImport, value:
23933ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel                print value
23943ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23953ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    except (getopt.error, BadUsage):
23963ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        cmd = os.path.basename(sys.argv[0])
23973ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel        print """pydoc - the Python documentation tool
23983ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
23993ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel%s <name> ...
24003ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    Show text documentation on something.  <name> may be the name of a
24013ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    Python keyword, topic, function, module, or package, or a dotted
24023ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    reference to a class or function within a module or module in a
24033ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    package.  If <name> contains a '%s', it is used as the path to a
24043ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    Python source file to document. If name is 'keywords', 'topics',
24053ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    or 'modules', a listing of these things is displayed.
24063ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
24073ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel%s -k <keyword>
24083ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    Search for a keyword in the synopsis lines of all available modules.
24093ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
24103ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel%s -p <port>
24113ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    Start an HTTP server on the given port on the local machine.  Port
24123ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    number 0 can be used to get an arbitrary unused port.
24133ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
24143ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel%s -g
24153ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    Pop up a graphical interface for finding and serving documentation.
24163ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
24173ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel%s -w <name> ...
24183ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    Write out the HTML documentation for a module to a file in the current
24193ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    directory.  If <name> contains a '%s', it is treated as a filename; if
24203ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel    it names a directory, documentation is written for all the contents.
24213ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
24223ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDaniel
24233ec97ca490009ed5604ccd7f2653e5a9ecbf3474Daryl McDanielif __name__ == '__main__': cli()
2424