blob: 94548e296930825399f3742bd4d74842c8a9eb26 [file] [log] [blame]
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001#!/usr/bin/env python
Guido van Rossumfce538c2002-08-06 17:29:38 +00002# -*- coding: Latin-1 -*-
Ka-Ping Yee1d384632001-03-01 00:24:32 +00003"""Generate Python documentation in HTML or text for interactive use.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00004
Ka-Ping Yeedd175342001-02-27 14:43:46 +00005In the Python interpreter, do "from pydoc import help" to provide online
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00006help. Calling help(thing) on a Python object documents the object.
7
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00008Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00009
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000010Run "pydoc <name>" to show documentation on something. <name> may be
11the name of a function, module, package, or a dotted reference to a
12class or function within a module or module in a package. If the
13argument contains a path segment delimiter (e.g. slash on Unix,
14backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000015
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000016Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000018
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000019Run "pydoc -p <port>" to start an HTTP server on a given port on the
20local machine to generate documentation web pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000021
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000022For platforms without a command line, "pydoc -g" starts the HTTP server
23and also pops up a little window for controlling it.
24
25Run "pydoc -w <name>" to write out the HTML documentation for a module
26to a file named "<name>.html".
Skip Montanaro4997a692003-09-10 16:47:51 +000027
28Module docs for core modules are assumed to be in
29
30 http://www.python.org/doc/current/lib/
31
32This can be overridden by setting the PYTHONDOCS environment variable
33to a different URL or to a local directory containing the Library
34Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000035"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000036
37__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000038__date__ = "26 February 2001"
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000039__version__ = "$Revision$"
Martin v. Löwis6fe8f192004-11-14 10:21:04 +000040__credits__ = """Guido van Rossum, for an excellent programming language.
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000041Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000042Paul Prescod, for all his work on onlinehelp.
43Richard Chamberlain, for the first implementation of textdoc.
Raymond Hettingered2dbe32005-01-01 07:51:01 +000044"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000045
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000046# Known bugs that can't be fixed here:
47# - imp.load_module() cannot be prevented from clobbering existing
48# loaded modules, so calling synopsis() on a binary module file
49# changes the contents of any existing module with the same name.
50# - If the __file__ attribute on a module is a relative path and
51# the current directory is changed with os.chdir(), an incorrect
52# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000053
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +000054import sys, imp, os, re, types, inspect, __builtin__
Ka-Ping Yeedd175342001-02-27 14:43:46 +000055from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000056from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
Raymond Hettinger756b3f32004-01-29 06:37:52 +000057from collections import deque
Ka-Ping Yeedd175342001-02-27 14:43:46 +000058
59# --------------------------------------------------------- common routines
60
Ka-Ping Yeedd175342001-02-27 14:43:46 +000061def pathdirs():
62 """Convert sys.path into a list of absolute, existing, unique paths."""
63 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000064 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000065 for dir in sys.path:
66 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000067 normdir = os.path.normcase(dir)
68 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000069 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000070 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000071 return dirs
72
73def getdoc(object):
74 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000075 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000076 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000077
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000078def splitdoc(doc):
79 """Split a doc string into a synopsis line (if any) and the rest."""
80 lines = split(strip(doc), '\n')
81 if len(lines) == 1:
82 return lines[0], ''
83 elif len(lines) >= 2 and not rstrip(lines[1]):
84 return lines[0], join(lines[2:], '\n')
85 return '', join(lines, '\n')
86
Ka-Ping Yeedd175342001-02-27 14:43:46 +000087def classname(object, modname):
88 """Get a class name and qualify it with a module name if necessary."""
89 name = object.__name__
90 if object.__module__ != modname:
91 name = object.__module__ + '.' + name
92 return name
93
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000094def isdata(object):
95 """Check if an object is of a type that probably means it's data."""
96 return not (inspect.ismodule(object) or inspect.isclass(object) or
97 inspect.isroutine(object) or inspect.isframe(object) or
98 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +000099
100def replace(text, *pairs):
101 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000102 while pairs:
103 text = join(split(text, pairs[0]), pairs[1])
104 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000105 return text
106
107def cram(text, maxlen):
108 """Omit part of a string if needed to make it fit in a maximum length."""
109 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000110 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000111 post = max(0, maxlen-3-pre)
112 return text[:pre] + '...' + text[len(text)-post:]
113 return text
114
Brett Cannon84601f12004-06-19 01:22:48 +0000115_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000116def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000117 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000118 # The behaviour of %p is implementation-dependent in terms of case.
119 if _re_stripid.search(repr(Exception)):
120 return _re_stripid.sub(r'\1', text)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000121 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000122
Brett Cannonc6c1f472004-06-19 01:02:51 +0000123def _is_some_method(obj):
124 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000125
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000126def allmethods(cl):
127 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000128 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000129 methods[key] = 1
130 for base in cl.__bases__:
131 methods.update(allmethods(base)) # all your base are belong to us
132 for key in methods.keys():
133 methods[key] = getattr(cl, key)
134 return methods
135
Tim Petersfa26f7c2001-09-24 08:05:11 +0000136def _split_list(s, predicate):
137 """Split sequence s via predicate, and return pair ([true], [false]).
138
139 The return value is a 2-tuple of lists,
140 ([x for x in s if predicate(x)],
141 [x for x in s if not predicate(x)])
142 """
143
Tim Peters28355492001-09-23 21:29:55 +0000144 yes = []
145 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000146 for x in s:
147 if predicate(x):
148 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000149 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000150 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000151 return yes, no
152
Skip Montanaroa5616d22004-06-11 04:46:12 +0000153def visiblename(name, all=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000154 """Decide whether to show documentation on a variable."""
155 # Certain special names are redundant.
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000156 if name in ('__builtins__', '__doc__', '__file__', '__path__',
157 '__module__', '__name__', '__slots__'): return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000158 # Private names are hidden, but special names are displayed.
159 if name.startswith('__') and name.endswith('__'): return 1
Skip Montanaroa5616d22004-06-11 04:46:12 +0000160 if all is not None:
161 # only document that which the programmer exported in __all__
162 return name in all
163 else:
164 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000165
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000166def classify_class_attrs(object):
167 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
168 def fixup((name, kind, cls, value)):
169 if inspect.isdatadescriptor(value):
170 kind = 'data descriptor'
171 return name, kind, cls, value
172 return map(fixup, inspect.classify_class_attrs(object))
173
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000174# ----------------------------------------------------- module manipulation
175
176def ispackage(path):
177 """Guess whether a path refers to a package directory."""
178 if os.path.isdir(path):
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000179 for ext in ('.py', '.pyc', '.pyo'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000180 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000181 return True
182 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000183
184def synopsis(filename, cache={}):
185 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000186 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000187 lastupdate, result = cache.get(filename, (0, None))
188 if lastupdate < mtime:
189 info = inspect.getmoduleinfo(filename)
190 file = open(filename)
191 if info and 'b' in info[2]: # binary modules have to be imported
192 try: module = imp.load_module('__temp__', file, filename, info[1:])
193 except: return None
194 result = split(module.__doc__ or '', '\n')[0]
195 del sys.modules['__temp__']
196 else: # text modules can be directly examined
197 line = file.readline()
198 while line[:1] == '#' or not strip(line):
199 line = file.readline()
200 if not line: break
201 line = strip(line)
202 if line[:4] == 'r"""': line = line[1:]
203 if line[:3] == '"""':
204 line = line[3:]
205 if line[-1:] == '\\': line = line[:-1]
206 while not strip(line):
207 line = file.readline()
208 if not line: break
209 result = strip(split(line, '"""')[0])
210 else: result = None
211 file.close()
212 cache[filename] = (mtime, result)
213 return result
214
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000215class ErrorDuringImport(Exception):
216 """Errors that occurred while trying to import something to document it."""
217 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000218 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000219 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000220 self.value = value
221 self.tb = tb
222
223 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000224 exc = self.exc
225 if type(exc) is types.ClassType:
226 exc = exc.__name__
227 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000228
229def importfile(path):
230 """Import a Python source file or compiled file given its path."""
231 magic = imp.get_magic()
232 file = open(path, 'r')
233 if file.read(len(magic)) == magic:
234 kind = imp.PY_COMPILED
235 else:
236 kind = imp.PY_SOURCE
237 file.close()
238 filename = os.path.basename(path)
239 name, ext = os.path.splitext(filename)
240 file = open(path, 'r')
241 try:
242 module = imp.load_module(name, file, path, (ext, 'r', kind))
243 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000244 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000245 file.close()
246 return module
247
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000248def safeimport(path, forceload=0, cache={}):
249 """Import a module; handle errors; return None if the module isn't found.
250
251 If the module *is* found but an exception occurs, it's wrapped in an
252 ErrorDuringImport exception and reraised. Unlike __import__, if a
253 package path is specified, the module at the end of the path is returned,
254 not the package at the beginning. If the optional 'forceload' argument
255 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000256 if forceload and path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000257 # This is the only way to be sure. Checking the mtime of the file
258 # isn't good enough (e.g. what if the module contains a class that
259 # inherits from another module that has changed?).
260 if path not in sys.builtin_module_names:
261 # Python never loads a dynamic extension a second time from the
262 # same path, even if the file is changed or missing. Deleting
263 # the entry in sys.modules doesn't help for dynamic extensions,
264 # so we're not even going to try to keep them up to date.
265 info = inspect.getmoduleinfo(sys.modules[path].__file__)
266 if info[3] != imp.C_EXTENSION:
267 cache[path] = sys.modules[path] # prevent module from clearing
268 del sys.modules[path]
269 try:
270 module = __import__(path)
271 except:
272 # Did the error occur before or after the module was found?
273 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000274 if path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000275 # An error occured while executing the imported module.
276 raise ErrorDuringImport(sys.modules[path].__file__, info)
277 elif exc is SyntaxError:
278 # A SyntaxError occurred before we could execute the module.
279 raise ErrorDuringImport(value.filename, info)
280 elif exc is ImportError and \
281 split(lower(str(value)))[:2] == ['no', 'module']:
282 # The module was not found.
283 return None
284 else:
285 # Some other error occurred during the importing process.
286 raise ErrorDuringImport(path, sys.exc_info())
287 for part in split(path, '.')[1:]:
288 try: module = getattr(module, part)
289 except AttributeError: return None
290 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000291
292# ---------------------------------------------------- formatter base class
293
294class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000295 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000296 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000297 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000298 # 'try' clause is to attempt to handle the possibility that inspect
299 # identifies something in a way that pydoc itself has issues handling;
300 # think 'super' and how it is a descriptor (which raises the exception
301 # by lacking a __name__ attribute) and an instance.
302 try:
303 if inspect.ismodule(object): return self.docmodule(*args)
304 if inspect.isclass(object): return self.docclass(*args)
305 if inspect.isroutine(object): return self.docroutine(*args)
306 except AttributeError:
307 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000308 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000309 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000310
311 def fail(self, object, name=None, *args):
312 """Raise an exception for unimplemented types."""
313 message = "don't know how to document object%s of type %s" % (
314 name and ' ' + repr(name), type(object).__name__)
315 raise TypeError, message
316
317 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000318
Skip Montanaro4997a692003-09-10 16:47:51 +0000319 def getdocloc(self, object):
320 """Return the location of module docs or None"""
321
322 try:
323 file = inspect.getabsfile(object)
324 except TypeError:
325 file = '(built-in)'
326
327 docloc = os.environ.get("PYTHONDOCS",
328 "http://www.python.org/doc/current/lib")
329 basedir = os.path.join(sys.exec_prefix, "lib",
330 "python"+sys.version[0:3])
331 if (isinstance(object, type(os)) and
332 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
333 'marshal', 'posix', 'signal', 'sys',
334 'thread', 'zipimport') or
335 (file.startswith(basedir) and
336 not file.startswith(os.path.join(basedir, 'site-packages'))))):
Skip Montanarof2134842004-06-07 02:40:05 +0000337 htmlfile = "module-%s.html" % object.__name__
Skip Montanaro4997a692003-09-10 16:47:51 +0000338 if docloc.startswith("http://"):
Skip Montanarof2134842004-06-07 02:40:05 +0000339 docloc = "%s/%s" % (docloc.rstrip("/"), htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000340 else:
Skip Montanarof2134842004-06-07 02:40:05 +0000341 docloc = os.path.join(docloc, htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000342 else:
343 docloc = None
344 return docloc
345
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000346# -------------------------------------------- HTML documentation generator
347
348class HTMLRepr(Repr):
349 """Class for safely making an HTML representation of a Python object."""
350 def __init__(self):
351 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000352 self.maxlist = self.maxtuple = 20
353 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000354 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000355
356 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000357 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000358
359 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000360 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000361
362 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000363 if hasattr(type(x), '__name__'):
364 methodname = 'repr_' + join(split(type(x).__name__), '_')
365 if hasattr(self, methodname):
366 return getattr(self, methodname)(x, level)
367 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000368
369 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000370 test = cram(x, self.maxstring)
371 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000372 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000373 # Backslashes are only literal in the string and are never
374 # needed to make any special characters, so show a raw string.
375 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000376 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000377 r'<font color="#c040c0">\1</font>',
378 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000379
Skip Montanarodf708782002-03-07 22:58:02 +0000380 repr_str = repr_string
381
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000382 def repr_instance(self, x, level):
383 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000384 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000385 except:
386 return self.escape('<%s instance>' % x.__class__.__name__)
387
388 repr_unicode = repr_string
389
390class HTMLDoc(Doc):
391 """Formatter class for HTML documentation."""
392
393 # ------------------------------------------- HTML formatting utilities
394
395 _repr_instance = HTMLRepr()
396 repr = _repr_instance.repr
397 escape = _repr_instance.escape
398
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000399 def page(self, title, contents):
400 """Format an HTML page."""
401 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000402<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000403<html><head><title>Python: %s</title>
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000404</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000405%s
406</body></html>''' % (title, contents)
407
408 def heading(self, title, fgcol, bgcol, extras=''):
409 """Format a page heading."""
410 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000411<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000412<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000413<td valign=bottom>&nbsp;<br>
414<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000415><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000416><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000417 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
418
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000419 def section(self, title, fgcol, bgcol, contents, width=6,
420 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000421 """Format a section with a heading."""
422 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000423 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000424 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000425<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000426<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000427<td colspan=3 valign=bottom>&nbsp;<br>
428<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000429 ''' % (bgcol, fgcol, title)
430 if prelude:
431 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000432<tr bgcolor="%s"><td rowspan=2>%s</td>
433<td colspan=2>%s</td></tr>
434<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
435 else:
436 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000437<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000438
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000439 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000440
441 def bigsection(self, title, *args):
442 """Format a section with a big heading."""
443 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000444 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000445
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000446 def preformat(self, text):
447 """Format literal preformatted text."""
448 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000449 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
450 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000451
452 def multicolumn(self, list, format, cols=4):
453 """Format a list of items into a multi-column list."""
454 result = ''
455 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000456 for col in range(cols):
457 result = result + '<td width="%d%%" valign=top>' % (100/cols)
458 for i in range(rows*col, rows*col+rows):
459 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000460 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000461 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000462 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000463
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000464 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000465
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000466 def namelink(self, name, *dicts):
467 """Make a link for an identifier, given name-to-URL mappings."""
468 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000469 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000470 return '<a href="%s">%s</a>' % (dict[name], name)
471 return name
472
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000473 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000474 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000475 name, module = object.__name__, sys.modules.get(object.__module__)
476 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000477 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000478 module.__name__, name, classname(object, modname))
479 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000480
481 def modulelink(self, object):
482 """Make a link for a module."""
483 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
484
485 def modpkglink(self, (name, path, ispackage, shadowed)):
486 """Make a link for a module or package to display in an index."""
487 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000488 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000489 if path:
490 url = '%s.%s.html' % (path, name)
491 else:
492 url = '%s.html' % name
493 if ispackage:
494 text = '<strong>%s</strong>&nbsp;(package)' % name
495 else:
496 text = name
497 return '<a href="%s">%s</a>' % (url, text)
498
499 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
500 """Mark up some plain text, given a context of symbols to look for.
501 Each context dictionary maps object names to anchor names."""
502 escape = escape or self.escape
503 results = []
504 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000505 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
506 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000507 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000508 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000509 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000510 match = pattern.search(text, here)
511 if not match: break
512 start, end = match.span()
513 results.append(escape(text[here:start]))
514
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000515 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000516 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000517 url = escape(all).replace('"', '&quot;')
518 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000519 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000520 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
521 results.append('<a href="%s">%s</a>' % (url, escape(all)))
522 elif pep:
523 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000524 results.append('<a href="%s">%s</a>' % (url, escape(all)))
525 elif text[end:end+1] == '(':
526 results.append(self.namelink(name, methods, funcs, classes))
527 elif selfdot:
528 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000529 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000530 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000531 here = end
532 results.append(escape(text[here:]))
533 return join(results, '')
534
535 # ---------------------------------------------- type-specific routines
536
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000537 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000538 """Produce HTML for a class tree as given by inspect.getclasstree()."""
539 result = ''
540 for entry in tree:
541 if type(entry) is type(()):
542 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000543 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000544 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000545 if bases and bases != (parent,):
546 parents = []
547 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000548 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000549 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000550 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000551 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000552 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000553 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000554 return '<dl>\n%s</dl>\n' % result
555
Tim Peters8dd7ade2001-10-18 19:56:17 +0000556 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000557 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000558 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000559 try:
560 all = object.__all__
561 except AttributeError:
562 all = None
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000563 parts = split(name, '.')
564 links = []
565 for i in range(len(parts)-1):
566 links.append(
567 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
568 (join(parts[:i+1], '.'), parts[i]))
569 linkedname = join(links + parts[-1:], '.')
570 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000571 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000572 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000573 url = path
574 if sys.platform == 'win32':
575 import nturl2path
576 url = nturl2path.pathname2url(path)
577 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000578 except TypeError:
579 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000580 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000581 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000582 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000583 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
584 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000585 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000586 if hasattr(object, '__date__'):
587 info.append(self.escape(str(object.__date__)))
588 if info:
589 head = head + ' (%s)' % join(info, ', ')
Skip Montanaro4997a692003-09-10 16:47:51 +0000590 docloc = self.getdocloc(object)
591 if docloc is not None:
592 docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
593 else:
594 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000595 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000596 head, '#ffffff', '#7799ee',
597 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000598
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000599 modules = inspect.getmembers(object, inspect.ismodule)
600
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000601 classes, cdict = [], {}
602 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000603 # if __all__ exists, believe it. Otherwise use old heuristic.
604 if (all is not None or
605 (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000606 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000607 classes.append((key, value))
608 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000609 for key, value in classes:
610 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000611 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000612 module = sys.modules.get(modname)
613 if modname != name and module and hasattr(module, key):
614 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000615 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000616 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000617 funcs, fdict = [], {}
618 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000619 # if __all__ exists, believe it. Otherwise use old heuristic.
620 if (all is not None or
621 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000622 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000623 funcs.append((key, value))
624 fdict[key] = '#-' + key
625 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000626 data = []
627 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000628 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000629 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000630
631 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
632 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000633 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000634
635 if hasattr(object, '__path__'):
636 modpkgs = []
637 modnames = []
638 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000639 path = os.path.join(object.__path__[0], file)
640 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000641 if modname != '__init__':
642 if modname and modname not in modnames:
643 modpkgs.append((modname, name, 0, 0))
644 modnames.append(modname)
645 elif ispackage(path):
646 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000647 modpkgs.sort()
648 contents = self.multicolumn(modpkgs, self.modpkglink)
649 result = result + self.bigsection(
650 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000651 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000652 contents = self.multicolumn(
653 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000654 result = result + self.bigsection(
655 'Modules', '#fffff', '#aa55cc', contents)
656
657 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000658 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000659 contents = [
660 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000661 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000662 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000663 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000664 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000665 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000666 contents = []
667 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000668 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000669 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000670 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000671 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000672 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000673 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000674 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000675 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000676 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000677 if hasattr(object, '__author__'):
678 contents = self.markup(str(object.__author__), self.preformat)
679 result = result + self.bigsection(
680 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000681 if hasattr(object, '__credits__'):
682 contents = self.markup(str(object.__credits__), self.preformat)
683 result = result + self.bigsection(
684 'Credits', '#ffffff', '#7799ee', contents)
685
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000686 return result
687
Tim Peters8dd7ade2001-10-18 19:56:17 +0000688 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
689 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000690 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000691 realname = object.__name__
692 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000693 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000694
Tim Petersb47879b2001-09-24 04:47:19 +0000695 contents = []
696 push = contents.append
697
Tim Petersfa26f7c2001-09-24 08:05:11 +0000698 # Cute little class to pump out a horizontal rule between sections.
699 class HorizontalRule:
700 def __init__(self):
701 self.needone = 0
702 def maybe(self):
703 if self.needone:
704 push('<hr>\n')
705 self.needone = 1
706 hr = HorizontalRule()
707
Tim Petersc86f6ca2001-09-26 21:31:51 +0000708 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000709 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000710 if len(mro) > 2:
711 hr.maybe()
712 push('<dl><dt>Method resolution order:</dt>\n')
713 for base in mro:
714 push('<dd>%s</dd>\n' % self.classlink(base,
715 object.__module__))
716 push('</dl>\n')
717
Tim Petersb47879b2001-09-24 04:47:19 +0000718 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000719 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000720 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000721 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000722 push(msg)
723 for name, kind, homecls, value in ok:
724 push(self.document(getattr(object, name), name, mod,
725 funcs, classes, mdict, object))
726 push('\n')
727 return attrs
728
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000729 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000730 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000731 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000732 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000733 push(msg)
734 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000735 push(self._docdescriptor(name, value, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000736 return attrs
737
Tim Petersfa26f7c2001-09-24 08:05:11 +0000738 def spilldata(msg, attrs, predicate):
739 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000740 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000741 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000742 push(msg)
743 for name, kind, homecls, value in ok:
744 base = self.docother(getattr(object, name), name, mod)
Martin v. Löwise59e2ba2003-05-03 09:09:02 +0000745 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000746 doc = getattr(value, "__doc__", None)
747 else:
748 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000749 if doc is None:
750 push('<dl><dt>%s</dl>\n' % base)
751 else:
752 doc = self.markup(getdoc(value), self.preformat,
753 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000754 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000755 push('<dl><dt>%s%s</dl>\n' % (base, doc))
756 push('\n')
757 return attrs
758
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000759 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000760 classify_class_attrs(object))
Tim Petersb47879b2001-09-24 04:47:19 +0000761 mdict = {}
762 for key, kind, homecls, value in attrs:
763 mdict[key] = anchor = '#' + name + '-' + key
764 value = getattr(object, key)
765 try:
766 # The value may not be hashable (e.g., a data attr with
767 # a dict or list value).
768 mdict[value] = anchor
769 except TypeError:
770 pass
771
Tim Petersfa26f7c2001-09-24 08:05:11 +0000772 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000773 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000774 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000775 else:
776 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000777 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
778
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000779 if thisclass is __builtin__.object:
780 attrs = inherited
781 continue
782 elif thisclass is object:
783 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000784 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000785 tag = 'inherited from %s' % self.classlink(thisclass,
786 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000787 tag += ':<br>\n'
788
789 # Sort attrs by name.
Raymond Hettinger6b59f5f2003-10-16 05:53:16 +0000790 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000791
792 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000793 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000794 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000795 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000796 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000797 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000798 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000799 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
800 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000801 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000802 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000803 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000804 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000805
806 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000807
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000808 if name == realname:
809 title = '<a name="%s">class <strong>%s</strong></a>' % (
810 name, realname)
811 else:
812 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
813 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000814 if bases:
815 parents = []
816 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000817 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000818 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000819 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000820 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000821
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000822 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000823
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000824 def formatvalue(self, object):
825 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000826 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000827
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000828 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000829 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000830 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000831 realname = object.__name__
832 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000833 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000834 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000835 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000836 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000837 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000838 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000839 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000840 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000841 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000842 if object.im_self:
843 note = ' method of %s instance' % self.classlink(
844 object.im_self.__class__, mod)
845 else:
846 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000847 object = object.im_func
848
849 if name == realname:
850 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
851 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000852 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000853 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000854 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000855 cl.__name__ + '-' + realname, realname)
856 skipdocs = 1
857 else:
858 reallink = realname
859 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
860 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000861 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000862 args, varargs, varkw, defaults = inspect.getargspec(object)
863 argspec = inspect.formatargspec(
864 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000865 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000866 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000867 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000868 else:
869 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000870
Tim Peters2306d242001-09-25 03:18:32 +0000871 decl = title + argspec + (note and self.grey(
872 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000873
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000874 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000875 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000876 else:
877 doc = self.markup(
878 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000879 doc = doc and '<dd><tt>%s</tt></dd>' % doc
880 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000881
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000882 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000883 results = []
884 push = results.append
885
886 if name:
887 push('<dl><dt><strong>%s</strong></dt>\n' % name)
888 if value.__doc__ is not None:
889 doc = self.markup(value.__doc__, self.preformat)
890 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000891 push('</dl>\n')
892
893 return ''.join(results)
894
895 def docproperty(self, object, name=None, mod=None, cl=None):
896 """Produce html documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000897 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000898
Tim Peters8dd7ade2001-10-18 19:56:17 +0000899 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000900 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000901 lhs = name and '<strong>%s</strong> = ' % name or ''
902 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000903
904 def index(self, dir, shadowed=None):
905 """Generate an HTML index for a directory of modules."""
906 modpkgs = []
907 if shadowed is None: shadowed = {}
908 seen = {}
909 files = os.listdir(dir)
910
911 def found(name, ispackage,
912 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
Raymond Hettinger4f759d82002-11-02 02:02:46 +0000913 if name not in seen:
914 modpkgs.append((name, '', ispackage, name in shadowed))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000915 seen[name] = 1
916 shadowed[name] = 1
917
918 # Package spam/__init__.py takes precedence over module spam.py.
919 for file in files:
920 path = os.path.join(dir, file)
921 if ispackage(path): found(file, 1)
922 for file in files:
923 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000924 if os.path.isfile(path):
925 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000926 if modname: found(modname, 0)
927
928 modpkgs.sort()
929 contents = self.multicolumn(modpkgs, self.modpkglink)
930 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
931
932# -------------------------------------------- text documentation generator
933
934class TextRepr(Repr):
935 """Class for safely making a text representation of a Python object."""
936 def __init__(self):
937 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000938 self.maxlist = self.maxtuple = 20
939 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000940 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000941
942 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000943 if hasattr(type(x), '__name__'):
944 methodname = 'repr_' + join(split(type(x).__name__), '_')
945 if hasattr(self, methodname):
946 return getattr(self, methodname)(x, level)
947 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000948
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000949 def repr_string(self, x, level):
950 test = cram(x, self.maxstring)
951 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000952 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000953 # Backslashes are only literal in the string and are never
954 # needed to make any special characters, so show a raw string.
955 return 'r' + testrepr[0] + test + testrepr[0]
956 return testrepr
957
Skip Montanarodf708782002-03-07 22:58:02 +0000958 repr_str = repr_string
959
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000960 def repr_instance(self, x, level):
961 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000962 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000963 except:
964 return '<%s instance>' % x.__class__.__name__
965
966class TextDoc(Doc):
967 """Formatter class for text documentation."""
968
969 # ------------------------------------------- text formatting utilities
970
971 _repr_instance = TextRepr()
972 repr = _repr_instance.repr
973
974 def bold(self, text):
975 """Format a string in bold by overstriking."""
976 return join(map(lambda ch: ch + '\b' + ch, text), '')
977
978 def indent(self, text, prefix=' '):
979 """Indent text by prepending a given prefix to each line."""
980 if not text: return ''
981 lines = split(text, '\n')
982 lines = map(lambda line, prefix=prefix: prefix + line, lines)
983 if lines: lines[-1] = rstrip(lines[-1])
984 return join(lines, '\n')
985
986 def section(self, title, contents):
987 """Format a section with a given heading."""
988 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
989
990 # ---------------------------------------------- type-specific routines
991
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000992 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000993 """Render in text a class tree as returned by inspect.getclasstree()."""
994 result = ''
995 for entry in tree:
996 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000997 c, bases = entry
998 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000999 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001000 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001001 result = result + '(%s)' % join(parents, ', ')
1002 result = result + '\n'
1003 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001004 result = result + self.formattree(
1005 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001006 return result
1007
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001008 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001009 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001010 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001011 synop, desc = splitdoc(getdoc(object))
1012 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001013
1014 try:
Skip Montanaroa5616d22004-06-11 04:46:12 +00001015 all = object.__all__
1016 except AttributeError:
1017 all = None
1018
1019 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001020 file = inspect.getabsfile(object)
1021 except TypeError:
1022 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001023 result = result + self.section('FILE', file)
Skip Montanaro4997a692003-09-10 16:47:51 +00001024
1025 docloc = self.getdocloc(object)
1026 if docloc is not None:
1027 result = result + self.section('MODULE DOCS', docloc)
1028
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001029 if desc:
1030 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001031
1032 classes = []
1033 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001034 # if __all__ exists, believe it. Otherwise use old heuristic.
1035 if (all is not None
1036 or (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001037 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001038 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001039 funcs = []
1040 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001041 # if __all__ exists, believe it. Otherwise use old heuristic.
1042 if (all is not None or
1043 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001044 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001045 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001046 data = []
1047 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001048 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001049 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001050
1051 if hasattr(object, '__path__'):
1052 modpkgs = []
1053 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001054 path = os.path.join(object.__path__[0], file)
1055 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001056 if modname != '__init__':
1057 if modname and modname not in modpkgs:
1058 modpkgs.append(modname)
1059 elif ispackage(path):
1060 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001061 modpkgs.sort()
1062 result = result + self.section(
1063 'PACKAGE CONTENTS', join(modpkgs, '\n'))
1064
1065 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001066 classlist = map(lambda (key, value): value, classes)
1067 contents = [self.formattree(
1068 inspect.getclasstree(classlist, 1), name)]
1069 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001070 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001071 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001072
1073 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001074 contents = []
1075 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001076 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001077 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001078
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001079 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001080 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001081 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001082 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001083 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001084
1085 if hasattr(object, '__version__'):
1086 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001087 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1088 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001089 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001090 if hasattr(object, '__date__'):
1091 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001092 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001093 result = result + self.section('AUTHOR', str(object.__author__))
1094 if hasattr(object, '__credits__'):
1095 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001096 return result
1097
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001098 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001099 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001100 realname = object.__name__
1101 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001102 bases = object.__bases__
1103
Tim Petersc86f6ca2001-09-26 21:31:51 +00001104 def makename(c, m=object.__module__):
1105 return classname(c, m)
1106
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001107 if name == realname:
1108 title = 'class ' + self.bold(realname)
1109 else:
1110 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001111 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001112 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001113 title = title + '(%s)' % join(parents, ', ')
1114
1115 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001116 contents = doc and [doc + '\n'] or []
1117 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001118
Tim Petersc86f6ca2001-09-26 21:31:51 +00001119 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001120 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001121 if len(mro) > 2:
1122 push("Method resolution order:")
1123 for base in mro:
1124 push(' ' + makename(base))
1125 push('')
1126
Tim Petersf4aad8e2001-09-24 22:40:47 +00001127 # Cute little class to pump out a horizontal rule between sections.
1128 class HorizontalRule:
1129 def __init__(self):
1130 self.needone = 0
1131 def maybe(self):
1132 if self.needone:
1133 push('-' * 70)
1134 self.needone = 1
1135 hr = HorizontalRule()
1136
Tim Peters28355492001-09-23 21:29:55 +00001137 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001138 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001139 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001140 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001141 push(msg)
1142 for name, kind, homecls, value in ok:
1143 push(self.document(getattr(object, name),
1144 name, mod, object))
1145 return attrs
1146
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001147 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001148 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001149 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001150 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001151 push(msg)
1152 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001153 push(self._docdescriptor(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001154 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001155
Tim Petersfa26f7c2001-09-24 08:05:11 +00001156 def spilldata(msg, attrs, predicate):
1157 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001158 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001159 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001160 push(msg)
1161 for name, kind, homecls, value in ok:
Martin v. Löwise59e2ba2003-05-03 09:09:02 +00001162 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +00001163 doc = getattr(value, "__doc__", None)
1164 else:
1165 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001166 push(self.docother(getattr(object, name),
1167 name, mod, 70, doc) + '\n')
1168 return attrs
1169
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001170 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001171 classify_class_attrs(object))
Tim Petersfa26f7c2001-09-24 08:05:11 +00001172 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001173 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001174 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001175 else:
1176 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001177 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1178
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001179 if thisclass is __builtin__.object:
1180 attrs = inherited
1181 continue
1182 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001183 tag = "defined here"
1184 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001185 tag = "inherited from %s" % classname(thisclass,
1186 object.__module__)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001187 filter(lambda t: not t[0].startswith('_'), attrs)
Tim Peters28355492001-09-23 21:29:55 +00001188
1189 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001190 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001191
1192 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001193 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001194 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001195 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001196 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001197 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001198 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001199 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1200 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001201 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1202 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001203 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001204 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001205
1206 contents = '\n'.join(contents)
1207 if not contents:
1208 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001209 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1210
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001211 def formatvalue(self, object):
1212 """Format an argument default value as text."""
1213 return '=' + self.repr(object)
1214
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001215 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001216 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001217 realname = object.__name__
1218 name = name or realname
1219 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001220 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001221 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001222 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001223 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001224 if imclass is not cl:
1225 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001226 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001227 if object.im_self:
1228 note = ' method of %s instance' % classname(
1229 object.im_self.__class__, mod)
1230 else:
1231 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001232 object = object.im_func
1233
1234 if name == realname:
1235 title = self.bold(realname)
1236 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001237 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001238 cl.__dict__[realname] is object):
1239 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001240 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001241 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001242 args, varargs, varkw, defaults = inspect.getargspec(object)
1243 argspec = inspect.formatargspec(
1244 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001245 if realname == '<lambda>':
1246 title = 'lambda'
1247 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001248 else:
1249 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001250 decl = title + argspec + note
1251
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001252 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001253 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001254 else:
1255 doc = getdoc(object) or ''
1256 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001257
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001258 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001259 results = []
1260 push = results.append
1261
1262 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001263 push(self.bold(name))
1264 push('\n')
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001265 doc = getdoc(value) or ''
1266 if doc:
1267 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001268 push('\n')
1269 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001270
1271 def docproperty(self, object, name=None, mod=None, cl=None):
1272 """Produce text documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001273 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001274
Tim Peters28355492001-09-23 21:29:55 +00001275 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001276 """Produce text documentation for a data object."""
1277 repr = self.repr(object)
1278 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001279 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001280 chop = maxlen - len(line)
1281 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001282 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001283 if doc is not None:
1284 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001285 return line
1286
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001287# --------------------------------------------------------- user interfaces
1288
1289def pager(text):
1290 """The first time this is called, determine what kind of pager to use."""
1291 global pager
1292 pager = getpager()
1293 pager(text)
1294
1295def getpager():
1296 """Decide what method to use for paging through text."""
1297 if type(sys.stdout) is not types.FileType:
1298 return plainpager
1299 if not sys.stdin.isatty() or not sys.stdout.isatty():
1300 return plainpager
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001301 if os.environ.get('TERM') in ('dumb', 'emacs'):
Fred Drake5e9eb982001-07-23 19:48:10 +00001302 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001303 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001304 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001305 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001306 elif os.environ.get('TERM') in ('dumb', 'emacs'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001307 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001308 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001309 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001310 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001311 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001312 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001313 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001314
1315 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001316 (fd, filename) = tempfile.mkstemp()
1317 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001318 try:
1319 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1320 return lambda text: pipepager(text, 'more')
1321 else:
1322 return ttypager
1323 finally:
1324 os.unlink(filename)
1325
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001326def plain(text):
1327 """Remove boldface formatting from text."""
1328 return re.sub('.\b', '', text)
1329
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001330def pipepager(text, cmd):
1331 """Page through text by feeding it to another program."""
1332 pipe = os.popen(cmd, 'w')
1333 try:
1334 pipe.write(text)
1335 pipe.close()
1336 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001337 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001338
1339def tempfilepager(text, cmd):
1340 """Page through text by invoking a program on a temporary file."""
1341 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001342 filename = tempfile.mktemp()
1343 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001344 file.write(text)
1345 file.close()
1346 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001347 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001348 finally:
1349 os.unlink(filename)
1350
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001351def ttypager(text):
1352 """Page through text on a text terminal."""
1353 lines = split(plain(text), '\n')
1354 try:
1355 import tty
1356 fd = sys.stdin.fileno()
1357 old = tty.tcgetattr(fd)
1358 tty.setcbreak(fd)
1359 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001360 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001361 tty = None
1362 getchar = lambda: sys.stdin.readline()[:-1][:1]
1363
1364 try:
1365 r = inc = os.environ.get('LINES', 25) - 1
1366 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1367 while lines[r:]:
1368 sys.stdout.write('-- more --')
1369 sys.stdout.flush()
1370 c = getchar()
1371
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001372 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001373 sys.stdout.write('\r \r')
1374 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001375 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001376 sys.stdout.write('\r \r' + lines[r] + '\n')
1377 r = r + 1
1378 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001379 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001380 r = r - inc - inc
1381 if r < 0: r = 0
1382 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1383 r = r + inc
1384
1385 finally:
1386 if tty:
1387 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1388
1389def plainpager(text):
1390 """Simply print unformatted text. This is the ultimate fallback."""
1391 sys.stdout.write(plain(text))
1392
1393def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001394 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001395 if inspect.ismodule(thing):
1396 if thing.__name__ in sys.builtin_module_names:
1397 return 'built-in module ' + thing.__name__
1398 if hasattr(thing, '__path__'):
1399 return 'package ' + thing.__name__
1400 else:
1401 return 'module ' + thing.__name__
1402 if inspect.isbuiltin(thing):
1403 return 'built-in function ' + thing.__name__
1404 if inspect.isclass(thing):
1405 return 'class ' + thing.__name__
1406 if inspect.isfunction(thing):
1407 return 'function ' + thing.__name__
1408 if inspect.ismethod(thing):
1409 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001410 if type(thing) is types.InstanceType:
1411 return 'instance of ' + thing.__class__.__name__
1412 return type(thing).__name__
1413
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001414def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001415 """Locate an object by name or dotted path, importing as necessary."""
Guido van Rossum97dede02003-02-16 01:12:32 +00001416 parts = [part for part in split(path, '.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001417 module, n = None, 0
1418 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001419 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001420 if nextmodule: module, n = nextmodule, n + 1
1421 else: break
1422 if module:
1423 object = module
1424 for part in parts[n:]:
1425 try: object = getattr(object, part)
1426 except AttributeError: return None
1427 return object
1428 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001429 if hasattr(__builtin__, path):
1430 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001431
1432# --------------------------------------- interactive interpreter interface
1433
1434text = TextDoc()
1435html = HTMLDoc()
1436
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001437def resolve(thing, forceload=0):
1438 """Given an object or a path to an object, get the object and its name."""
1439 if isinstance(thing, str):
1440 object = locate(thing, forceload)
1441 if not object:
1442 raise ImportError, 'no Python documentation found for %r' % thing
1443 return object, thing
1444 else:
1445 return thing, getattr(thing, '__name__', None)
1446
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001447def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001448 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001449 try:
1450 object, name = resolve(thing, forceload)
1451 desc = describe(object)
1452 module = inspect.getmodule(object)
1453 if name and '.' in name:
1454 desc += ' in ' + name[:name.rfind('.')]
1455 elif module and module is not object:
1456 desc += ' in module ' + module.__name__
1457 pager(title % desc + '\n\n' + text.document(object, name))
1458 except (ImportError, ErrorDuringImport), value:
1459 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001460
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001461def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001462 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001463 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001464 object, name = resolve(thing, forceload)
1465 page = html.page(describe(object), html.document(object, name))
1466 file = open(name + '.html', 'w')
1467 file.write(page)
1468 file.close()
1469 print 'wrote', name + '.html'
1470 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001471 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001472
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001473def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001474 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001475 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001476 for file in os.listdir(dir):
1477 path = os.path.join(dir, file)
1478 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001479 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001480 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001481 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001482 if modname:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001483 if modname == '__init__':
1484 modname = pkgpath[:-1] # remove trailing period
1485 else:
1486 modname = pkgpath + modname
1487 if modname not in done:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001488 done[modname] = 1
1489 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001490
1491class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001492 keywords = {
1493 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001494 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001495 'break': ('ref/break', 'while for'),
1496 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1497 'continue': ('ref/continue', 'while for'),
1498 'def': ('ref/function', ''),
1499 'del': ('ref/del', 'BASICMETHODS'),
1500 'elif': 'if',
1501 'else': ('ref/if', 'while for'),
1502 'except': 'try',
1503 'exec': ('ref/exec', ''),
1504 'finally': 'try',
1505 'for': ('ref/for', 'break continue while'),
1506 'from': 'import',
1507 'global': ('ref/global', 'NAMESPACES'),
1508 'if': ('ref/if', 'TRUTHVALUE'),
1509 'import': ('ref/import', 'MODULES'),
1510 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1511 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001512 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001513 'not': 'BOOLEAN',
1514 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001515 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001516 'print': ('ref/print', ''),
1517 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001518 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001519 'try': ('ref/try', 'EXCEPTIONS'),
1520 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001521 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001522 }
1523
1524 topics = {
1525 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001526 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001527 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1528 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001529 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001530 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1531 'INTEGER': ('ref/integers', 'int range'),
1532 'FLOAT': ('ref/floating', 'float math'),
1533 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001534 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001535 'MAPPINGS': 'DICTIONARIES',
1536 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1537 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1538 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001539 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001540 'FRAMEOBJECTS': 'TYPES',
1541 'TRACEBACKS': 'TYPES',
1542 'NONE': ('lib/bltin-null-object', ''),
1543 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1544 'FILES': ('lib/bltin-file-objects', ''),
1545 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1546 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1547 'MODULES': ('lib/typesmodules', 'import'),
1548 'PACKAGES': 'import',
1549 'EXPRESSIONS': ('ref/summary', 'lambda or and not in is BOOLEAN COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES LISTS DICTIONARIES BACKQUOTES'),
1550 'OPERATORS': 'EXPRESSIONS',
1551 'PRECEDENCE': 'EXPRESSIONS',
1552 'OBJECTS': ('ref/objects', 'TYPES'),
1553 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001554 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1555 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1556 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1557 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1558 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1559 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1560 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001561 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1562 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1563 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001564 'SCOPING': 'NAMESPACES',
1565 'FRAMES': 'NAMESPACES',
1566 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001567 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1568 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001569 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1570 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001571 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001572 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1573 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001574 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001575 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001576 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001577 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001578 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1579 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001580 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1581 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1582 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1583 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1584 'POWER': ('ref/power', 'EXPRESSIONS'),
1585 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1586 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1587 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1588 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1589 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001590 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001591 'ASSERTION': 'assert',
1592 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001593 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001594 'DELETION': 'del',
1595 'PRINTING': 'print',
1596 'RETURNING': 'return',
1597 'IMPORTING': 'import',
1598 'CONDITIONAL': 'if',
1599 'LOOPING': ('ref/compound', 'for while break continue'),
1600 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001601 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001602 }
1603
1604 def __init__(self, input, output):
1605 self.input = input
1606 self.output = output
1607 self.docdir = None
1608 execdir = os.path.dirname(sys.executable)
1609 homedir = os.environ.get('PYTHONHOME')
1610 for dir in [os.environ.get('PYTHONDOCS'),
1611 homedir and os.path.join(homedir, 'doc'),
1612 os.path.join(execdir, 'doc'),
1613 '/usr/doc/python-docs-' + split(sys.version)[0],
1614 '/usr/doc/python-' + split(sys.version)[0],
1615 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001616 '/usr/doc/python-' + sys.version[:3],
1617 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001618 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1619 self.docdir = dir
1620
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001621 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001622 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001623 self()
1624 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001625 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001626
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001627 def __call__(self, request=None):
1628 if request is not None:
1629 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001630 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001631 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001632 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001633 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001634You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001635If you want to ask for help on a particular object directly from the
1636interpreter, you can type "help(object)". Executing "help('string')"
1637has the same effect as typing a particular string at the help> prompt.
1638''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001639
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001640 def interact(self):
1641 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001642 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001643 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001644 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001645 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001646 except (KeyboardInterrupt, EOFError):
1647 break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001648 request = strip(replace(request, '"', '', "'", ''))
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001649 if lower(request) in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001650 self.help(request)
1651
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001652 def getline(self, prompt):
1653 """Read one line, using raw_input when available."""
1654 if self.input is sys.stdin:
1655 return raw_input(prompt)
1656 else:
1657 self.output.write(prompt)
1658 self.output.flush()
1659 return self.input.readline()
1660
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001661 def help(self, request):
1662 if type(request) is type(''):
1663 if request == 'help': self.intro()
1664 elif request == 'keywords': self.listkeywords()
1665 elif request == 'topics': self.listtopics()
1666 elif request == 'modules': self.listmodules()
1667 elif request[:8] == 'modules ':
1668 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001669 elif request in self.keywords: self.showtopic(request)
1670 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001671 elif request: doc(request, 'Help on %s:')
1672 elif isinstance(request, Helper): self()
1673 else: doc(request, 'Help on %s:')
1674 self.output.write('\n')
1675
1676 def intro(self):
1677 self.output.write('''
1678Welcome to Python %s! This is the online help utility.
1679
1680If this is your first time using Python, you should definitely check out
1681the tutorial on the Internet at http://www.python.org/doc/tut/.
1682
1683Enter the name of any module, keyword, or topic to get help on writing
1684Python programs and using Python modules. To quit this help utility and
1685return to the interpreter, just type "quit".
1686
1687To get a list of available modules, keywords, or topics, type "modules",
1688"keywords", or "topics". Each module also comes with a one-line summary
1689of what it does; to list the modules whose summaries contain a given word
1690such as "spam", type "modules spam".
1691''' % sys.version[:3])
1692
1693 def list(self, items, columns=4, width=80):
1694 items = items[:]
1695 items.sort()
1696 colw = width / columns
1697 rows = (len(items) + columns - 1) / columns
1698 for row in range(rows):
1699 for col in range(columns):
1700 i = col * rows + row
1701 if i < len(items):
1702 self.output.write(items[i])
1703 if col < columns - 1:
1704 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1705 self.output.write('\n')
1706
1707 def listkeywords(self):
1708 self.output.write('''
1709Here is a list of the Python keywords. Enter any keyword to get more help.
1710
1711''')
1712 self.list(self.keywords.keys())
1713
1714 def listtopics(self):
1715 self.output.write('''
1716Here is a list of available topics. Enter any topic name to get more help.
1717
1718''')
1719 self.list(self.topics.keys())
1720
1721 def showtopic(self, topic):
1722 if not self.docdir:
1723 self.output.write('''
1724Sorry, topic and keyword documentation is not available because the Python
1725HTML documentation files could not be found. If you have installed them,
1726please set the environment variable PYTHONDOCS to indicate their location.
1727''')
1728 return
1729 target = self.topics.get(topic, self.keywords.get(topic))
1730 if not target:
1731 self.output.write('no documentation found for %s\n' % repr(topic))
1732 return
1733 if type(target) is type(''):
1734 return self.showtopic(target)
1735
1736 filename, xrefs = target
1737 filename = self.docdir + '/' + filename + '.html'
1738 try:
1739 file = open(filename)
1740 except:
1741 self.output.write('could not read docs from %s\n' % filename)
1742 return
1743
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001744 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1745 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001746 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1747 file.close()
1748
1749 import htmllib, formatter, StringIO
1750 buffer = StringIO.StringIO()
1751 parser = htmllib.HTMLParser(
1752 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1753 parser.start_table = parser.do_p
1754 parser.end_table = lambda parser=parser: parser.do_p({})
1755 parser.start_tr = parser.do_br
1756 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1757 parser.feed(document)
1758 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1759 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001760 if xrefs:
1761 buffer = StringIO.StringIO()
1762 formatter.DumbWriter(buffer).send_flowing_data(
1763 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1764 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001765
1766 def listmodules(self, key=''):
1767 if key:
1768 self.output.write('''
1769Here is a list of matching modules. Enter any module name to get more help.
1770
1771''')
1772 apropos(key)
1773 else:
1774 self.output.write('''
1775Please wait a moment while I gather a list of all available modules...
1776
1777''')
1778 modules = {}
1779 def callback(path, modname, desc, modules=modules):
1780 if modname and modname[-9:] == '.__init__':
1781 modname = modname[:-9] + ' (package)'
1782 if find(modname, '.') < 0:
1783 modules[modname] = 1
1784 ModuleScanner().run(callback)
1785 self.list(modules.keys())
1786 self.output.write('''
1787Enter any module name to get more help. Or, type "modules spam" to search
1788for modules whose descriptions contain the word "spam".
1789''')
1790
1791help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001792
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001793class Scanner:
1794 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001795 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001796 self.roots = roots[:]
1797 self.state = []
1798 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001799 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001800
1801 def next(self):
1802 if not self.state:
1803 if not self.roots:
1804 return None
1805 root = self.roots.pop(0)
1806 self.state = [(root, self.children(root))]
1807 node, children = self.state[-1]
1808 if not children:
1809 self.state.pop()
1810 return self.next()
1811 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001812 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001813 self.state.append((child, self.children(child)))
1814 return child
1815
1816class ModuleScanner(Scanner):
1817 """An interruptible scanner that searches module synopses."""
1818 def __init__(self):
1819 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001820 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001821 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001822
1823 def submodules(self, (dir, package)):
1824 children = []
1825 for file in os.listdir(dir):
1826 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001827 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001828 children.append((path, package + (package and '.') + file))
1829 else:
1830 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001831 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001832 return children
1833
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001834 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001835 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001836 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001837 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001838 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001839 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001840
Ka-Ping Yee66246962001-04-12 11:59:50 +00001841 def run(self, callback, key=None, completer=None):
1842 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001843 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001844 seen = {}
1845
1846 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001847 if modname != '__main__':
1848 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001849 if key is None:
1850 callback(None, modname, '')
1851 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001852 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001853 if find(lower(modname + ' - ' + desc), key) >= 0:
1854 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001855
1856 while not self.quit:
1857 node = self.next()
1858 if not node: break
1859 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001860 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001861 if os.path.isfile(path) and modname:
1862 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001863 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001864 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001865 if key is None:
1866 callback(path, modname, '')
1867 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001868 desc = synopsis(path) or ''
1869 if find(lower(modname + ' - ' + desc), key) >= 0:
1870 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001871 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001872
1873def apropos(key):
1874 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001875 def callback(path, modname, desc):
1876 if modname[-9:] == '.__init__':
1877 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001878 print modname, desc and '- ' + desc
1879 try: import warnings
1880 except ImportError: pass
1881 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001882 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001883
1884# --------------------------------------------------- web browser interface
1885
Ka-Ping Yee66246962001-04-12 11:59:50 +00001886def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001887 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001888
1889 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1890 class Message(mimetools.Message):
1891 def __init__(self, fp, seekable=1):
1892 Message = self.__class__
1893 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1894 self.encodingheader = self.getheader('content-transfer-encoding')
1895 self.typeheader = self.getheader('content-type')
1896 self.parsetype()
1897 self.parseplist()
1898
1899 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1900 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001901 try:
1902 self.send_response(200)
1903 self.send_header('Content-Type', 'text/html')
1904 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001905 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001906 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001907
1908 def do_GET(self):
1909 path = self.path
1910 if path[-5:] == '.html': path = path[:-5]
1911 if path[:1] == '/': path = path[1:]
1912 if path and path != '.':
1913 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001914 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001915 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001916 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001917 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001918 if obj:
1919 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001920 else:
1921 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001922'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001923 else:
1924 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001925'<big><big><strong>Python: Index of Modules</strong></big></big>',
1926'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001927 def bltinlink(name):
1928 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001929 names = filter(lambda x: x != '__main__',
1930 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001931 contents = html.multicolumn(names, bltinlink)
1932 indices = ['<p>' + html.bigsection(
1933 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1934
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001935 seen = {}
1936 for dir in pathdirs():
1937 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001938 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001939<font color="#909090" face="helvetica, arial"><strong>
1940pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001941 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001942
1943 def log_message(self, *args): pass
1944
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001945 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001946 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001947 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001948 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001949 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001950 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001951 self.base.__init__(self, self.address, self.handler)
1952
1953 def serve_until_quit(self):
1954 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001955 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001956 while not self.quit:
1957 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1958 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001959
1960 def server_activate(self):
1961 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001962 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001963
1964 DocServer.base = BaseHTTPServer.HTTPServer
1965 DocServer.handler = DocHandler
1966 DocHandler.MessageClass = Message
1967 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001968 try:
1969 DocServer(port, callback).serve_until_quit()
1970 except (KeyboardInterrupt, select.error):
1971 pass
1972 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001973 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001974
1975# ----------------------------------------------------- graphical interface
1976
1977def gui():
1978 """Graphical interface (starts web server and pops up a control window)."""
1979 class GUI:
1980 def __init__(self, window, port=7464):
1981 self.window = window
1982 self.server = None
1983 self.scanner = None
1984
1985 import Tkinter
1986 self.server_frm = Tkinter.Frame(window)
1987 self.title_lbl = Tkinter.Label(self.server_frm,
1988 text='Starting server...\n ')
1989 self.open_btn = Tkinter.Button(self.server_frm,
1990 text='open browser', command=self.open, state='disabled')
1991 self.quit_btn = Tkinter.Button(self.server_frm,
1992 text='quit serving', command=self.quit, state='disabled')
1993
1994 self.search_frm = Tkinter.Frame(window)
1995 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1996 self.search_ent = Tkinter.Entry(self.search_frm)
1997 self.search_ent.bind('<Return>', self.search)
1998 self.stop_btn = Tkinter.Button(self.search_frm,
1999 text='stop', pady=0, command=self.stop, state='disabled')
2000 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002001 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002002 self.stop_btn.pack(side='right')
2003
2004 self.window.title('pydoc')
2005 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2006 self.title_lbl.pack(side='top', fill='x')
2007 self.open_btn.pack(side='left', fill='x', expand=1)
2008 self.quit_btn.pack(side='right', fill='x', expand=1)
2009 self.server_frm.pack(side='top', fill='x')
2010
2011 self.search_lbl.pack(side='left')
2012 self.search_ent.pack(side='right', fill='x', expand=1)
2013 self.search_frm.pack(side='top', fill='x')
2014 self.search_ent.focus_set()
2015
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002016 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002017 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002018 self.result_lst.bind('<Button-1>', self.select)
2019 self.result_lst.bind('<Double-Button-1>', self.goto)
2020 self.result_scr = Tkinter.Scrollbar(window,
2021 orient='vertical', command=self.result_lst.yview)
2022 self.result_lst.config(yscrollcommand=self.result_scr.set)
2023
2024 self.result_frm = Tkinter.Frame(window)
2025 self.goto_btn = Tkinter.Button(self.result_frm,
2026 text='go to selected', command=self.goto)
2027 self.hide_btn = Tkinter.Button(self.result_frm,
2028 text='hide results', command=self.hide)
2029 self.goto_btn.pack(side='left', fill='x', expand=1)
2030 self.hide_btn.pack(side='right', fill='x', expand=1)
2031
2032 self.window.update()
2033 self.minwidth = self.window.winfo_width()
2034 self.minheight = self.window.winfo_height()
2035 self.bigminheight = (self.server_frm.winfo_reqheight() +
2036 self.search_frm.winfo_reqheight() +
2037 self.result_lst.winfo_reqheight() +
2038 self.result_frm.winfo_reqheight())
2039 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2040 self.expanded = 0
2041 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2042 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002043 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002044
2045 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002046 threading.Thread(
2047 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002048
2049 def ready(self, server):
2050 self.server = server
2051 self.title_lbl.config(
2052 text='Python documentation server at\n' + server.url)
2053 self.open_btn.config(state='normal')
2054 self.quit_btn.config(state='normal')
2055
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002056 def open(self, event=None, url=None):
2057 url = url or self.server.url
2058 try:
2059 import webbrowser
2060 webbrowser.open(url)
2061 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002062 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002063 os.system('start "%s"' % url)
2064 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002065 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002066 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002067 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002068 else:
2069 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2070 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002071
2072 def quit(self, event=None):
2073 if self.server:
2074 self.server.quit = 1
2075 self.window.quit()
2076
2077 def search(self, event=None):
2078 key = self.search_ent.get()
2079 self.stop_btn.pack(side='right')
2080 self.stop_btn.config(state='normal')
2081 self.search_lbl.config(text='Searching for "%s"...' % key)
2082 self.search_ent.forget()
2083 self.search_lbl.pack(side='left')
2084 self.result_lst.delete(0, 'end')
2085 self.goto_btn.config(state='disabled')
2086 self.expand()
2087
2088 import threading
2089 if self.scanner:
2090 self.scanner.quit = 1
2091 self.scanner = ModuleScanner()
2092 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002093 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002094
2095 def update(self, path, modname, desc):
2096 if modname[-9:] == '.__init__':
2097 modname = modname[:-9] + ' (package)'
2098 self.result_lst.insert('end',
2099 modname + ' - ' + (desc or '(no description)'))
2100
2101 def stop(self, event=None):
2102 if self.scanner:
2103 self.scanner.quit = 1
2104 self.scanner = None
2105
2106 def done(self):
2107 self.scanner = None
2108 self.search_lbl.config(text='Search for')
2109 self.search_lbl.pack(side='left')
2110 self.search_ent.pack(side='right', fill='x', expand=1)
2111 if sys.platform != 'win32': self.stop_btn.forget()
2112 self.stop_btn.config(state='disabled')
2113
2114 def select(self, event=None):
2115 self.goto_btn.config(state='normal')
2116
2117 def goto(self, event=None):
2118 selection = self.result_lst.curselection()
2119 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002120 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002121 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002122
2123 def collapse(self):
2124 if not self.expanded: return
2125 self.result_frm.forget()
2126 self.result_scr.forget()
2127 self.result_lst.forget()
2128 self.bigwidth = self.window.winfo_width()
2129 self.bigheight = self.window.winfo_height()
2130 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2131 self.window.wm_minsize(self.minwidth, self.minheight)
2132 self.expanded = 0
2133
2134 def expand(self):
2135 if self.expanded: return
2136 self.result_frm.pack(side='bottom', fill='x')
2137 self.result_scr.pack(side='right', fill='y')
2138 self.result_lst.pack(side='top', fill='both', expand=1)
2139 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2140 self.window.wm_minsize(self.minwidth, self.bigminheight)
2141 self.expanded = 1
2142
2143 def hide(self, event=None):
2144 self.stop()
2145 self.collapse()
2146
2147 import Tkinter
2148 try:
Martin v. Löwise09bd932004-08-22 16:13:26 +00002149 root = Tkinter.Tk()
2150 # Tk will crash if pythonw.exe has an XP .manifest
2151 # file and the root has is not destroyed explicitly.
2152 # If the problem is ever fixed in Tk, the explicit
2153 # destroy can go.
2154 try:
2155 gui = GUI(root)
2156 root.mainloop()
2157 finally:
2158 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002159 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002160 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002161
2162# -------------------------------------------------- command-line interface
2163
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002164def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002165 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002166
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002167def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002168 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002169 import getopt
2170 class BadUsage: pass
2171
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002172 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002173 scriptdir = os.path.dirname(sys.argv[0])
2174 if scriptdir in sys.path:
2175 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002176 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002177
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002178 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002179 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002180 writing = 0
2181
2182 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002183 if opt == '-g':
2184 gui()
2185 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002186 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002187 apropos(val)
2188 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002189 if opt == '-p':
2190 try:
2191 port = int(val)
2192 except ValueError:
2193 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002194 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002195 print 'pydoc server ready at %s' % server.url
2196 def stopped():
2197 print 'pydoc server stopped'
2198 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002199 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002200 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002201 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002202
2203 if not args: raise BadUsage
2204 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002205 if ispath(arg) and not os.path.exists(arg):
2206 print 'file %r does not exist' % arg
2207 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002208 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002209 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002210 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002211 if writing:
2212 if ispath(arg) and os.path.isdir(arg):
2213 writedocs(arg)
2214 else:
2215 writedoc(arg)
2216 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002217 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002218 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002219 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002220
2221 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002222 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002223 print """pydoc - the Python documentation tool
2224
2225%s <name> ...
2226 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002227 Python keyword, topic, function, module, or package, or a dotted
2228 reference to a class or function within a module or module in a
2229 package. If <name> contains a '%s', it is used as the path to a
2230 Python source file to document. If name is 'keywords', 'topics',
2231 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002232
2233%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002234 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002235
2236%s -p <port>
2237 Start an HTTP server on the given port on the local machine.
2238
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002239%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002240 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002241
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002242%s -w <name> ...
2243 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002244 directory. If <name> contains a '%s', it is treated as a filename; if
2245 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002246""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002247
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002248if __name__ == '__main__': cli()