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