blob: c02c1407f74467f43085d5199cd477da6117117d [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$"
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000040__credits__ = """Guido van Rossum, for an excellent programming language.
41Tommy 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.
44
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000045Mynd you, møøse bites Kan be pretty nasti..."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000046
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000047# Known bugs that can't be fixed here:
48# - imp.load_module() cannot be prevented from clobbering existing
49# loaded modules, so calling synopsis() on a binary module file
50# changes the contents of any existing module with the same name.
51# - If the __file__ attribute on a module is a relative path and
52# the current directory is changed with os.chdir(), an incorrect
53# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000054
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +000055import sys, imp, os, re, types, inspect, __builtin__
Ka-Ping Yeedd175342001-02-27 14:43:46 +000056from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000057from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
Raymond Hettinger756b3f32004-01-29 06:37:52 +000058from collections import deque
Ka-Ping Yeedd175342001-02-27 14:43:46 +000059
60# --------------------------------------------------------- common routines
61
Ka-Ping Yeedd175342001-02-27 14:43:46 +000062def pathdirs():
63 """Convert sys.path into a list of absolute, existing, unique paths."""
64 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000065 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000066 for dir in sys.path:
67 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000068 normdir = os.path.normcase(dir)
69 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000070 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000071 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000072 return dirs
73
74def getdoc(object):
75 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000076 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000077 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000078
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000079def splitdoc(doc):
80 """Split a doc string into a synopsis line (if any) and the rest."""
81 lines = split(strip(doc), '\n')
82 if len(lines) == 1:
83 return lines[0], ''
84 elif len(lines) >= 2 and not rstrip(lines[1]):
85 return lines[0], join(lines[2:], '\n')
86 return '', join(lines, '\n')
87
Ka-Ping Yeedd175342001-02-27 14:43:46 +000088def classname(object, modname):
89 """Get a class name and qualify it with a module name if necessary."""
90 name = object.__name__
91 if object.__module__ != modname:
92 name = object.__module__ + '.' + name
93 return name
94
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000095def isdata(object):
96 """Check if an object is of a type that probably means it's data."""
97 return not (inspect.ismodule(object) or inspect.isclass(object) or
98 inspect.isroutine(object) or inspect.isframe(object) or
99 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000100
101def replace(text, *pairs):
102 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000103 while pairs:
104 text = join(split(text, pairs[0]), pairs[1])
105 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000106 return text
107
108def cram(text, maxlen):
109 """Omit part of a string if needed to make it fit in a maximum length."""
110 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000111 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000112 post = max(0, maxlen-3-pre)
113 return text[:pre] + '...' + text[len(text)-post:]
114 return text
115
Brett Cannon84601f12004-06-19 01:22:48 +0000116_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000117def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000118 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000119 # The behaviour of %p is implementation-dependent in terms of case.
120 if _re_stripid.search(repr(Exception)):
121 return _re_stripid.sub(r'\1', text)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000122 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000123
Brett Cannonc6c1f472004-06-19 01:02:51 +0000124def _is_some_method(obj):
125 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000126
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000127def allmethods(cl):
128 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000129 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000130 methods[key] = 1
131 for base in cl.__bases__:
132 methods.update(allmethods(base)) # all your base are belong to us
133 for key in methods.keys():
134 methods[key] = getattr(cl, key)
135 return methods
136
Tim Petersfa26f7c2001-09-24 08:05:11 +0000137def _split_list(s, predicate):
138 """Split sequence s via predicate, and return pair ([true], [false]).
139
140 The return value is a 2-tuple of lists,
141 ([x for x in s if predicate(x)],
142 [x for x in s if not predicate(x)])
143 """
144
Tim Peters28355492001-09-23 21:29:55 +0000145 yes = []
146 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000147 for x in s:
148 if predicate(x):
149 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000150 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000151 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000152 return yes, no
153
Skip Montanaroa5616d22004-06-11 04:46:12 +0000154def visiblename(name, all=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000155 """Decide whether to show documentation on a variable."""
156 # Certain special names are redundant.
157 if name in ['__builtins__', '__doc__', '__file__', '__path__',
158 '__module__', '__name__']: return 0
159 # Private names are hidden, but special names are displayed.
160 if name.startswith('__') and name.endswith('__'): return 1
Skip Montanaroa5616d22004-06-11 04:46:12 +0000161 if all is not None:
162 # only document that which the programmer exported in __all__
163 return name in all
164 else:
165 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000166
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000167# ----------------------------------------------------- module manipulation
168
169def ispackage(path):
170 """Guess whether a path refers to a package directory."""
171 if os.path.isdir(path):
172 for ext in ['.py', '.pyc', '.pyo']:
173 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000174 return True
175 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000176
177def synopsis(filename, cache={}):
178 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000179 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000180 lastupdate, result = cache.get(filename, (0, None))
181 if lastupdate < mtime:
182 info = inspect.getmoduleinfo(filename)
183 file = open(filename)
184 if info and 'b' in info[2]: # binary modules have to be imported
185 try: module = imp.load_module('__temp__', file, filename, info[1:])
186 except: return None
187 result = split(module.__doc__ or '', '\n')[0]
188 del sys.modules['__temp__']
189 else: # text modules can be directly examined
190 line = file.readline()
191 while line[:1] == '#' or not strip(line):
192 line = file.readline()
193 if not line: break
194 line = strip(line)
195 if line[:4] == 'r"""': line = line[1:]
196 if line[:3] == '"""':
197 line = line[3:]
198 if line[-1:] == '\\': line = line[:-1]
199 while not strip(line):
200 line = file.readline()
201 if not line: break
202 result = strip(split(line, '"""')[0])
203 else: result = None
204 file.close()
205 cache[filename] = (mtime, result)
206 return result
207
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000208class ErrorDuringImport(Exception):
209 """Errors that occurred while trying to import something to document it."""
210 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000211 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000212 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000213 self.value = value
214 self.tb = tb
215
216 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000217 exc = self.exc
218 if type(exc) is types.ClassType:
219 exc = exc.__name__
220 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000221
222def importfile(path):
223 """Import a Python source file or compiled file given its path."""
224 magic = imp.get_magic()
225 file = open(path, 'r')
226 if file.read(len(magic)) == magic:
227 kind = imp.PY_COMPILED
228 else:
229 kind = imp.PY_SOURCE
230 file.close()
231 filename = os.path.basename(path)
232 name, ext = os.path.splitext(filename)
233 file = open(path, 'r')
234 try:
235 module = imp.load_module(name, file, path, (ext, 'r', kind))
236 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000237 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000238 file.close()
239 return module
240
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000241def safeimport(path, forceload=0, cache={}):
242 """Import a module; handle errors; return None if the module isn't found.
243
244 If the module *is* found but an exception occurs, it's wrapped in an
245 ErrorDuringImport exception and reraised. Unlike __import__, if a
246 package path is specified, the module at the end of the path is returned,
247 not the package at the beginning. If the optional 'forceload' argument
248 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000249 if forceload and path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000250 # This is the only way to be sure. Checking the mtime of the file
251 # isn't good enough (e.g. what if the module contains a class that
252 # inherits from another module that has changed?).
253 if path not in sys.builtin_module_names:
254 # Python never loads a dynamic extension a second time from the
255 # same path, even if the file is changed or missing. Deleting
256 # the entry in sys.modules doesn't help for dynamic extensions,
257 # so we're not even going to try to keep them up to date.
258 info = inspect.getmoduleinfo(sys.modules[path].__file__)
259 if info[3] != imp.C_EXTENSION:
260 cache[path] = sys.modules[path] # prevent module from clearing
261 del sys.modules[path]
262 try:
263 module = __import__(path)
264 except:
265 # Did the error occur before or after the module was found?
266 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000267 if path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000268 # An error occured while executing the imported module.
269 raise ErrorDuringImport(sys.modules[path].__file__, info)
270 elif exc is SyntaxError:
271 # A SyntaxError occurred before we could execute the module.
272 raise ErrorDuringImport(value.filename, info)
273 elif exc is ImportError and \
274 split(lower(str(value)))[:2] == ['no', 'module']:
275 # The module was not found.
276 return None
277 else:
278 # Some other error occurred during the importing process.
279 raise ErrorDuringImport(path, sys.exc_info())
280 for part in split(path, '.')[1:]:
281 try: module = getattr(module, part)
282 except AttributeError: return None
283 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000284
285# ---------------------------------------------------- formatter base class
286
287class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000288 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000289 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000290 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000291 # 'try' clause is to attempt to handle the possibility that inspect
292 # identifies something in a way that pydoc itself has issues handling;
293 # think 'super' and how it is a descriptor (which raises the exception
294 # by lacking a __name__ attribute) and an instance.
295 try:
296 if inspect.ismodule(object): return self.docmodule(*args)
297 if inspect.isclass(object): return self.docclass(*args)
298 if inspect.isroutine(object): return self.docroutine(*args)
299 except AttributeError:
300 pass
Guido van Rossum68468eb2003-02-27 20:14:51 +0000301 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000302
303 def fail(self, object, name=None, *args):
304 """Raise an exception for unimplemented types."""
305 message = "don't know how to document object%s of type %s" % (
306 name and ' ' + repr(name), type(object).__name__)
307 raise TypeError, message
308
309 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000310
Skip Montanaro4997a692003-09-10 16:47:51 +0000311 def getdocloc(self, object):
312 """Return the location of module docs or None"""
313
314 try:
315 file = inspect.getabsfile(object)
316 except TypeError:
317 file = '(built-in)'
318
319 docloc = os.environ.get("PYTHONDOCS",
320 "http://www.python.org/doc/current/lib")
321 basedir = os.path.join(sys.exec_prefix, "lib",
322 "python"+sys.version[0:3])
323 if (isinstance(object, type(os)) and
324 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
325 'marshal', 'posix', 'signal', 'sys',
326 'thread', 'zipimport') or
327 (file.startswith(basedir) and
328 not file.startswith(os.path.join(basedir, 'site-packages'))))):
Skip Montanarof2134842004-06-07 02:40:05 +0000329 htmlfile = "module-%s.html" % object.__name__
Skip Montanaro4997a692003-09-10 16:47:51 +0000330 if docloc.startswith("http://"):
Skip Montanarof2134842004-06-07 02:40:05 +0000331 docloc = "%s/%s" % (docloc.rstrip("/"), htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000332 else:
Skip Montanarof2134842004-06-07 02:40:05 +0000333 docloc = os.path.join(docloc, htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000334 else:
335 docloc = None
336 return docloc
337
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000338# -------------------------------------------- HTML documentation generator
339
340class HTMLRepr(Repr):
341 """Class for safely making an HTML representation of a Python object."""
342 def __init__(self):
343 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000344 self.maxlist = self.maxtuple = 20
345 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000346 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000347
348 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000349 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000350
351 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000352 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000353
354 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000355 if hasattr(type(x), '__name__'):
356 methodname = 'repr_' + join(split(type(x).__name__), '_')
357 if hasattr(self, methodname):
358 return getattr(self, methodname)(x, level)
359 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000360
361 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000362 test = cram(x, self.maxstring)
363 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000364 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000365 # Backslashes are only literal in the string and are never
366 # needed to make any special characters, so show a raw string.
367 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000368 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000369 r'<font color="#c040c0">\1</font>',
370 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000371
Skip Montanarodf708782002-03-07 22:58:02 +0000372 repr_str = repr_string
373
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000374 def repr_instance(self, x, level):
375 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000376 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000377 except:
378 return self.escape('<%s instance>' % x.__class__.__name__)
379
380 repr_unicode = repr_string
381
382class HTMLDoc(Doc):
383 """Formatter class for HTML documentation."""
384
385 # ------------------------------------------- HTML formatting utilities
386
387 _repr_instance = HTMLRepr()
388 repr = _repr_instance.repr
389 escape = _repr_instance.escape
390
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000391 def page(self, title, contents):
392 """Format an HTML page."""
393 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000394<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000395<html><head><title>Python: %s</title>
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000396</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000397%s
398</body></html>''' % (title, contents)
399
400 def heading(self, title, fgcol, bgcol, extras=''):
401 """Format a page heading."""
402 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000403<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000404<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000405<td valign=bottom>&nbsp;<br>
406<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000407><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000408><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000409 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
410
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000411 def section(self, title, fgcol, bgcol, contents, width=6,
412 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000413 """Format a section with a heading."""
414 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000415 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000416 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000417<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000418<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000419<td colspan=3 valign=bottom>&nbsp;<br>
420<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000421 ''' % (bgcol, fgcol, title)
422 if prelude:
423 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000424<tr bgcolor="%s"><td rowspan=2>%s</td>
425<td colspan=2>%s</td></tr>
426<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
427 else:
428 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000429<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000430
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000431 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000432
433 def bigsection(self, title, *args):
434 """Format a section with a big heading."""
435 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000436 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000437
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000438 def preformat(self, text):
439 """Format literal preformatted text."""
440 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000441 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
442 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000443
444 def multicolumn(self, list, format, cols=4):
445 """Format a list of items into a multi-column list."""
446 result = ''
447 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000448 for col in range(cols):
449 result = result + '<td width="%d%%" valign=top>' % (100/cols)
450 for i in range(rows*col, rows*col+rows):
451 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000452 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000453 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000454 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000455
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000456 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000457
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000458 def namelink(self, name, *dicts):
459 """Make a link for an identifier, given name-to-URL mappings."""
460 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000461 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000462 return '<a href="%s">%s</a>' % (dict[name], name)
463 return name
464
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000465 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000466 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000467 name, module = object.__name__, sys.modules.get(object.__module__)
468 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000469 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000470 module.__name__, name, classname(object, modname))
471 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000472
473 def modulelink(self, object):
474 """Make a link for a module."""
475 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
476
477 def modpkglink(self, (name, path, ispackage, shadowed)):
478 """Make a link for a module or package to display in an index."""
479 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000480 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000481 if path:
482 url = '%s.%s.html' % (path, name)
483 else:
484 url = '%s.html' % name
485 if ispackage:
486 text = '<strong>%s</strong>&nbsp;(package)' % name
487 else:
488 text = name
489 return '<a href="%s">%s</a>' % (url, text)
490
491 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
492 """Mark up some plain text, given a context of symbols to look for.
493 Each context dictionary maps object names to anchor names."""
494 escape = escape or self.escape
495 results = []
496 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000497 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
498 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000499 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000500 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000501 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000502 match = pattern.search(text, here)
503 if not match: break
504 start, end = match.span()
505 results.append(escape(text[here:start]))
506
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000507 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000508 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000509 url = escape(all).replace('"', '&quot;')
510 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000511 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000512 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
513 results.append('<a href="%s">%s</a>' % (url, escape(all)))
514 elif pep:
515 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000516 results.append('<a href="%s">%s</a>' % (url, escape(all)))
517 elif text[end:end+1] == '(':
518 results.append(self.namelink(name, methods, funcs, classes))
519 elif selfdot:
520 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000521 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000522 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000523 here = end
524 results.append(escape(text[here:]))
525 return join(results, '')
526
527 # ---------------------------------------------- type-specific routines
528
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000529 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000530 """Produce HTML for a class tree as given by inspect.getclasstree()."""
531 result = ''
532 for entry in tree:
533 if type(entry) is type(()):
534 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000535 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000536 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000537 if bases and bases != (parent,):
538 parents = []
539 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000540 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000541 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000542 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000543 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000544 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000545 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000546 return '<dl>\n%s</dl>\n' % result
547
Tim Peters8dd7ade2001-10-18 19:56:17 +0000548 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000549 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000550 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000551 try:
552 all = object.__all__
553 except AttributeError:
554 all = None
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000555 parts = split(name, '.')
556 links = []
557 for i in range(len(parts)-1):
558 links.append(
559 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
560 (join(parts[:i+1], '.'), parts[i]))
561 linkedname = join(links + parts[-1:], '.')
562 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000563 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000564 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000565 url = path
566 if sys.platform == 'win32':
567 import nturl2path
568 url = nturl2path.pathname2url(path)
569 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000570 except TypeError:
571 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000572 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000573 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000574 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000575 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
576 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000577 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000578 if hasattr(object, '__date__'):
579 info.append(self.escape(str(object.__date__)))
580 if info:
581 head = head + ' (%s)' % join(info, ', ')
Skip Montanaro4997a692003-09-10 16:47:51 +0000582 docloc = self.getdocloc(object)
583 if docloc is not None:
584 docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
585 else:
586 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000587 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000588 head, '#ffffff', '#7799ee',
589 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000590
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000591 modules = inspect.getmembers(object, inspect.ismodule)
592
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000593 classes, cdict = [], {}
594 for key, value in inspect.getmembers(object, inspect.isclass):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000595 if (inspect.getmodule(value) or object) is object:
Skip Montanaroa5616d22004-06-11 04:46:12 +0000596 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000597 classes.append((key, value))
598 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000599 for key, value in classes:
600 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000601 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000602 module = sys.modules.get(modname)
603 if modname != name and module and hasattr(module, key):
604 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000605 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000606 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000607 funcs, fdict = [], {}
608 for key, value in inspect.getmembers(object, inspect.isroutine):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000609 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Skip Montanaroa5616d22004-06-11 04:46:12 +0000610 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000611 funcs.append((key, value))
612 fdict[key] = '#-' + key
613 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000614 data = []
615 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000616 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000617 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000618
619 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
620 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000621 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000622
623 if hasattr(object, '__path__'):
624 modpkgs = []
625 modnames = []
626 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000627 path = os.path.join(object.__path__[0], file)
628 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000629 if modname != '__init__':
630 if modname and modname not in modnames:
631 modpkgs.append((modname, name, 0, 0))
632 modnames.append(modname)
633 elif ispackage(path):
634 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000635 modpkgs.sort()
636 contents = self.multicolumn(modpkgs, self.modpkglink)
637 result = result + self.bigsection(
638 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000639 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000640 contents = self.multicolumn(
641 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000642 result = result + self.bigsection(
643 'Modules', '#fffff', '#aa55cc', contents)
644
645 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000646 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000647 contents = [
648 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000649 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000650 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000651 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000652 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000653 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000654 contents = []
655 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000656 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000657 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000658 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000659 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000660 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000661 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000662 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000663 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000664 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000665 if hasattr(object, '__author__'):
666 contents = self.markup(str(object.__author__), self.preformat)
667 result = result + self.bigsection(
668 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000669 if hasattr(object, '__credits__'):
670 contents = self.markup(str(object.__credits__), self.preformat)
671 result = result + self.bigsection(
672 'Credits', '#ffffff', '#7799ee', contents)
673
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000674 return result
675
Tim Peters8dd7ade2001-10-18 19:56:17 +0000676 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
677 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000678 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000679 realname = object.__name__
680 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000681 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000682
Tim Petersb47879b2001-09-24 04:47:19 +0000683 contents = []
684 push = contents.append
685
Tim Petersfa26f7c2001-09-24 08:05:11 +0000686 # Cute little class to pump out a horizontal rule between sections.
687 class HorizontalRule:
688 def __init__(self):
689 self.needone = 0
690 def maybe(self):
691 if self.needone:
692 push('<hr>\n')
693 self.needone = 1
694 hr = HorizontalRule()
695
Tim Petersc86f6ca2001-09-26 21:31:51 +0000696 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000697 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000698 if len(mro) > 2:
699 hr.maybe()
700 push('<dl><dt>Method resolution order:</dt>\n')
701 for base in mro:
702 push('<dd>%s</dd>\n' % self.classlink(base,
703 object.__module__))
704 push('</dl>\n')
705
Tim Petersb47879b2001-09-24 04:47:19 +0000706 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000707 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000708 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000709 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000710 push(msg)
711 for name, kind, homecls, value in ok:
712 push(self.document(getattr(object, name), name, mod,
713 funcs, classes, mdict, object))
714 push('\n')
715 return attrs
716
Tim Petersfa26f7c2001-09-24 08:05:11 +0000717 def spillproperties(msg, attrs, predicate):
718 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000719 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000720 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000721 push(msg)
722 for name, kind, homecls, value in ok:
Tim Peters3e767d12001-09-25 00:01:06 +0000723 push('<dl><dt><strong>%s</strong></dt>\n' % name)
724 if value.__doc__ is not None:
725 doc = self.markup(value.__doc__, self.preformat,
726 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000727 push('<dd><tt>%s</tt></dd>\n' % doc)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000728 for attr, tag in [('fget', '<em>get</em>'),
729 ('fset', '<em>set</em>'),
730 ('fdel', '<em>delete</em>')]:
Tim Peters3e767d12001-09-25 00:01:06 +0000731 func = getattr(value, attr)
732 if func is not None:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000733 base = self.document(func, tag, mod,
Tim Peters3e767d12001-09-25 00:01:06 +0000734 funcs, classes, mdict, object)
735 push('<dd>%s</dd>\n' % base)
736 push('</dl>\n')
Tim Petersb47879b2001-09-24 04:47:19 +0000737 return attrs
738
Tim Petersfa26f7c2001-09-24 08:05:11 +0000739 def spilldata(msg, attrs, predicate):
740 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000741 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000742 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000743 push(msg)
744 for name, kind, homecls, value in ok:
745 base = self.docother(getattr(object, name), name, mod)
Martin v. Löwise59e2ba2003-05-03 09:09:02 +0000746 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000747 doc = getattr(value, "__doc__", None)
748 else:
749 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000750 if doc is None:
751 push('<dl><dt>%s</dl>\n' % base)
752 else:
753 doc = self.markup(getdoc(value), self.preformat,
754 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000755 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000756 push('<dl><dt>%s%s</dl>\n' % (base, doc))
757 push('\n')
758 return attrs
759
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000760 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
761 inspect.classify_class_attrs(object))
Tim Petersb47879b2001-09-24 04:47:19 +0000762 mdict = {}
763 for key, kind, homecls, value in attrs:
764 mdict[key] = anchor = '#' + name + '-' + key
765 value = getattr(object, key)
766 try:
767 # The value may not be hashable (e.g., a data attr with
768 # a dict or list value).
769 mdict[value] = anchor
770 except TypeError:
771 pass
772
Tim Petersfa26f7c2001-09-24 08:05:11 +0000773 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000774 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000775 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000776 else:
777 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000778 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
779
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000780 if thisclass is __builtin__.object:
781 attrs = inherited
782 continue
783 elif thisclass is object:
784 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000785 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000786 tag = 'inherited from %s' % self.classlink(thisclass,
787 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000788 tag += ':<br>\n'
789
790 # Sort attrs by name.
Raymond Hettinger6b59f5f2003-10-16 05:53:16 +0000791 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000792
793 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000794 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000795 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000796 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000797 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000798 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000799 lambda t: t[1] == 'static method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000800 attrs = spillproperties('Properties %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000801 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000802 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000803 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000804 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000805 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000806
807 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000808
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000809 if name == realname:
810 title = '<a name="%s">class <strong>%s</strong></a>' % (
811 name, realname)
812 else:
813 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
814 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000815 if bases:
816 parents = []
817 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000818 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000819 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000820 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000821 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000822
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000823 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000824
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000825 def formatvalue(self, object):
826 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000827 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000828
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000829 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000830 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000831 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000832 realname = object.__name__
833 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000834 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000835 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000836 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000837 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000838 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000839 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000840 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000841 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000842 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000843 if object.im_self:
844 note = ' method of %s instance' % self.classlink(
845 object.im_self.__class__, mod)
846 else:
847 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000848 object = object.im_func
849
850 if name == realname:
851 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
852 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000853 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000854 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000855 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000856 cl.__name__ + '-' + realname, realname)
857 skipdocs = 1
858 else:
859 reallink = realname
860 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
861 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000862 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000863 args, varargs, varkw, defaults = inspect.getargspec(object)
864 argspec = inspect.formatargspec(
865 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000866 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000867 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000868 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000869 else:
870 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000871
Tim Peters2306d242001-09-25 03:18:32 +0000872 decl = title + argspec + (note and self.grey(
873 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000874
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000875 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000876 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000877 else:
878 doc = self.markup(
879 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000880 doc = doc and '<dd><tt>%s</tt></dd>' % doc
881 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000882
Tim Peters8dd7ade2001-10-18 19:56:17 +0000883 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000884 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000885 lhs = name and '<strong>%s</strong> = ' % name or ''
886 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000887
888 def index(self, dir, shadowed=None):
889 """Generate an HTML index for a directory of modules."""
890 modpkgs = []
891 if shadowed is None: shadowed = {}
892 seen = {}
893 files = os.listdir(dir)
894
895 def found(name, ispackage,
896 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
Raymond Hettinger4f759d82002-11-02 02:02:46 +0000897 if name not in seen:
898 modpkgs.append((name, '', ispackage, name in shadowed))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000899 seen[name] = 1
900 shadowed[name] = 1
901
902 # Package spam/__init__.py takes precedence over module spam.py.
903 for file in files:
904 path = os.path.join(dir, file)
905 if ispackage(path): found(file, 1)
906 for file in files:
907 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000908 if os.path.isfile(path):
909 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000910 if modname: found(modname, 0)
911
912 modpkgs.sort()
913 contents = self.multicolumn(modpkgs, self.modpkglink)
914 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
915
916# -------------------------------------------- text documentation generator
917
918class TextRepr(Repr):
919 """Class for safely making a text representation of a Python object."""
920 def __init__(self):
921 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000922 self.maxlist = self.maxtuple = 20
923 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000924 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000925
926 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000927 if hasattr(type(x), '__name__'):
928 methodname = 'repr_' + join(split(type(x).__name__), '_')
929 if hasattr(self, methodname):
930 return getattr(self, methodname)(x, level)
931 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000932
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000933 def repr_string(self, x, level):
934 test = cram(x, self.maxstring)
935 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000936 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000937 # Backslashes are only literal in the string and are never
938 # needed to make any special characters, so show a raw string.
939 return 'r' + testrepr[0] + test + testrepr[0]
940 return testrepr
941
Skip Montanarodf708782002-03-07 22:58:02 +0000942 repr_str = repr_string
943
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000944 def repr_instance(self, x, level):
945 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000946 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000947 except:
948 return '<%s instance>' % x.__class__.__name__
949
950class TextDoc(Doc):
951 """Formatter class for text documentation."""
952
953 # ------------------------------------------- text formatting utilities
954
955 _repr_instance = TextRepr()
956 repr = _repr_instance.repr
957
958 def bold(self, text):
959 """Format a string in bold by overstriking."""
960 return join(map(lambda ch: ch + '\b' + ch, text), '')
961
962 def indent(self, text, prefix=' '):
963 """Indent text by prepending a given prefix to each line."""
964 if not text: return ''
965 lines = split(text, '\n')
966 lines = map(lambda line, prefix=prefix: prefix + line, lines)
967 if lines: lines[-1] = rstrip(lines[-1])
968 return join(lines, '\n')
969
970 def section(self, title, contents):
971 """Format a section with a given heading."""
972 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
973
974 # ---------------------------------------------- type-specific routines
975
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000976 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000977 """Render in text a class tree as returned by inspect.getclasstree()."""
978 result = ''
979 for entry in tree:
980 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000981 c, bases = entry
982 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000983 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000984 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000985 result = result + '(%s)' % join(parents, ', ')
986 result = result + '\n'
987 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000988 result = result + self.formattree(
989 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000990 return result
991
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000992 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000993 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000994 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000995 synop, desc = splitdoc(getdoc(object))
996 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000997
998 try:
Skip Montanaroa5616d22004-06-11 04:46:12 +0000999 all = object.__all__
1000 except AttributeError:
1001 all = None
1002
1003 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001004 file = inspect.getabsfile(object)
1005 except TypeError:
1006 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001007 result = result + self.section('FILE', file)
Skip Montanaro4997a692003-09-10 16:47:51 +00001008
1009 docloc = self.getdocloc(object)
1010 if docloc is not None:
1011 result = result + self.section('MODULE DOCS', docloc)
1012
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001013 if desc:
1014 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001015
1016 classes = []
1017 for key, value in inspect.getmembers(object, inspect.isclass):
1018 if (inspect.getmodule(value) or object) is object:
Skip Montanaroa5616d22004-06-11 04:46:12 +00001019 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001020 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001021 funcs = []
1022 for key, value in inspect.getmembers(object, inspect.isroutine):
1023 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Skip Montanaroa5616d22004-06-11 04:46:12 +00001024 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001025 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001026 data = []
1027 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001028 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001029 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001030
1031 if hasattr(object, '__path__'):
1032 modpkgs = []
1033 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001034 path = os.path.join(object.__path__[0], file)
1035 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001036 if modname != '__init__':
1037 if modname and modname not in modpkgs:
1038 modpkgs.append(modname)
1039 elif ispackage(path):
1040 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001041 modpkgs.sort()
1042 result = result + self.section(
1043 'PACKAGE CONTENTS', join(modpkgs, '\n'))
1044
1045 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001046 classlist = map(lambda (key, value): value, classes)
1047 contents = [self.formattree(
1048 inspect.getclasstree(classlist, 1), name)]
1049 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001050 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001051 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001052
1053 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001054 contents = []
1055 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001056 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001057 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001058
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001059 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001060 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001061 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001062 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001063 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001064
1065 if hasattr(object, '__version__'):
1066 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001067 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1068 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001069 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001070 if hasattr(object, '__date__'):
1071 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001072 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001073 result = result + self.section('AUTHOR', str(object.__author__))
1074 if hasattr(object, '__credits__'):
1075 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001076 return result
1077
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001078 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001079 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001080 realname = object.__name__
1081 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001082 bases = object.__bases__
1083
Tim Petersc86f6ca2001-09-26 21:31:51 +00001084 def makename(c, m=object.__module__):
1085 return classname(c, m)
1086
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001087 if name == realname:
1088 title = 'class ' + self.bold(realname)
1089 else:
1090 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001091 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001092 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001093 title = title + '(%s)' % join(parents, ', ')
1094
1095 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001096 contents = doc and [doc + '\n'] or []
1097 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001098
Tim Petersc86f6ca2001-09-26 21:31:51 +00001099 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001100 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001101 if len(mro) > 2:
1102 push("Method resolution order:")
1103 for base in mro:
1104 push(' ' + makename(base))
1105 push('')
1106
Tim Petersf4aad8e2001-09-24 22:40:47 +00001107 # Cute little class to pump out a horizontal rule between sections.
1108 class HorizontalRule:
1109 def __init__(self):
1110 self.needone = 0
1111 def maybe(self):
1112 if self.needone:
1113 push('-' * 70)
1114 self.needone = 1
1115 hr = HorizontalRule()
1116
Tim Peters28355492001-09-23 21:29:55 +00001117 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001118 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001119 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001120 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001121 push(msg)
1122 for name, kind, homecls, value in ok:
1123 push(self.document(getattr(object, name),
1124 name, mod, object))
1125 return attrs
1126
Tim Petersfa26f7c2001-09-24 08:05:11 +00001127 def spillproperties(msg, attrs, predicate):
1128 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001129 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001130 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001131 push(msg)
1132 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001133 push(name)
1134 need_blank_after_doc = 0
1135 doc = getdoc(value) or ''
1136 if doc:
1137 push(self.indent(doc))
1138 need_blank_after_doc = 1
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001139 for attr, tag in [('fget', '<get>'),
1140 ('fset', '<set>'),
1141 ('fdel', '<delete>')]:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001142 func = getattr(value, attr)
1143 if func is not None:
1144 if need_blank_after_doc:
1145 push('')
1146 need_blank_after_doc = 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001147 base = self.document(func, tag, mod)
Tim Petersf4aad8e2001-09-24 22:40:47 +00001148 push(self.indent(base))
Tim Peters28355492001-09-23 21:29:55 +00001149 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001150
Tim Petersfa26f7c2001-09-24 08:05:11 +00001151 def spilldata(msg, attrs, predicate):
1152 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001153 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001154 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001155 push(msg)
1156 for name, kind, homecls, value in ok:
Martin v. Löwise59e2ba2003-05-03 09:09:02 +00001157 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +00001158 doc = getattr(value, "__doc__", None)
1159 else:
1160 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001161 push(self.docother(getattr(object, name),
1162 name, mod, 70, doc) + '\n')
1163 return attrs
1164
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001165 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
1166 inspect.classify_class_attrs(object))
Tim Petersfa26f7c2001-09-24 08:05:11 +00001167 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001168 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001169 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001170 else:
1171 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001172 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1173
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001174 if thisclass is __builtin__.object:
1175 attrs = inherited
1176 continue
1177 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001178 tag = "defined here"
1179 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001180 tag = "inherited from %s" % classname(thisclass,
1181 object.__module__)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001182 filter(lambda t: not t[0].startswith('_'), attrs)
Tim Peters28355492001-09-23 21:29:55 +00001183
1184 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001185 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001186
1187 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001188 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001189 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001190 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001191 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001192 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001193 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001194 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001195 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001196 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1197 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001198 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001199 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001200
1201 contents = '\n'.join(contents)
1202 if not contents:
1203 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001204 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1205
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001206 def formatvalue(self, object):
1207 """Format an argument default value as text."""
1208 return '=' + self.repr(object)
1209
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001210 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001211 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001212 realname = object.__name__
1213 name = name or realname
1214 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001215 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001216 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001217 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001218 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001219 if imclass is not cl:
1220 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001221 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001222 if object.im_self:
1223 note = ' method of %s instance' % classname(
1224 object.im_self.__class__, mod)
1225 else:
1226 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001227 object = object.im_func
1228
1229 if name == realname:
1230 title = self.bold(realname)
1231 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001232 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001233 cl.__dict__[realname] is object):
1234 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001235 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001236 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001237 args, varargs, varkw, defaults = inspect.getargspec(object)
1238 argspec = inspect.formatargspec(
1239 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001240 if realname == '<lambda>':
1241 title = 'lambda'
1242 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001243 else:
1244 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001245 decl = title + argspec + note
1246
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001247 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001248 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001249 else:
1250 doc = getdoc(object) or ''
1251 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001252
Tim Peters28355492001-09-23 21:29:55 +00001253 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001254 """Produce text documentation for a data object."""
1255 repr = self.repr(object)
1256 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001257 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001258 chop = maxlen - len(line)
1259 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001260 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001261 if doc is not None:
1262 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001263 return line
1264
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001265# --------------------------------------------------------- user interfaces
1266
1267def pager(text):
1268 """The first time this is called, determine what kind of pager to use."""
1269 global pager
1270 pager = getpager()
1271 pager(text)
1272
1273def getpager():
1274 """Decide what method to use for paging through text."""
1275 if type(sys.stdout) is not types.FileType:
1276 return plainpager
1277 if not sys.stdin.isatty() or not sys.stdout.isatty():
1278 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001279 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001280 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001281 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001282 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001283 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1284 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1285 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001286 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001287 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001288 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001289 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001290 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001291 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001292
1293 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001294 (fd, filename) = tempfile.mkstemp()
1295 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001296 try:
1297 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1298 return lambda text: pipepager(text, 'more')
1299 else:
1300 return ttypager
1301 finally:
1302 os.unlink(filename)
1303
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001304def plain(text):
1305 """Remove boldface formatting from text."""
1306 return re.sub('.\b', '', text)
1307
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001308def pipepager(text, cmd):
1309 """Page through text by feeding it to another program."""
1310 pipe = os.popen(cmd, 'w')
1311 try:
1312 pipe.write(text)
1313 pipe.close()
1314 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001315 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001316
1317def tempfilepager(text, cmd):
1318 """Page through text by invoking a program on a temporary file."""
1319 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001320 filename = tempfile.mktemp()
1321 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001322 file.write(text)
1323 file.close()
1324 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001325 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001326 finally:
1327 os.unlink(filename)
1328
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001329def ttypager(text):
1330 """Page through text on a text terminal."""
1331 lines = split(plain(text), '\n')
1332 try:
1333 import tty
1334 fd = sys.stdin.fileno()
1335 old = tty.tcgetattr(fd)
1336 tty.setcbreak(fd)
1337 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001338 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001339 tty = None
1340 getchar = lambda: sys.stdin.readline()[:-1][:1]
1341
1342 try:
1343 r = inc = os.environ.get('LINES', 25) - 1
1344 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1345 while lines[r:]:
1346 sys.stdout.write('-- more --')
1347 sys.stdout.flush()
1348 c = getchar()
1349
1350 if c in ['q', 'Q']:
1351 sys.stdout.write('\r \r')
1352 break
1353 elif c in ['\r', '\n']:
1354 sys.stdout.write('\r \r' + lines[r] + '\n')
1355 r = r + 1
1356 continue
1357 if c in ['b', 'B', '\x1b']:
1358 r = r - inc - inc
1359 if r < 0: r = 0
1360 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1361 r = r + inc
1362
1363 finally:
1364 if tty:
1365 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1366
1367def plainpager(text):
1368 """Simply print unformatted text. This is the ultimate fallback."""
1369 sys.stdout.write(plain(text))
1370
1371def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001372 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001373 if inspect.ismodule(thing):
1374 if thing.__name__ in sys.builtin_module_names:
1375 return 'built-in module ' + thing.__name__
1376 if hasattr(thing, '__path__'):
1377 return 'package ' + thing.__name__
1378 else:
1379 return 'module ' + thing.__name__
1380 if inspect.isbuiltin(thing):
1381 return 'built-in function ' + thing.__name__
1382 if inspect.isclass(thing):
1383 return 'class ' + thing.__name__
1384 if inspect.isfunction(thing):
1385 return 'function ' + thing.__name__
1386 if inspect.ismethod(thing):
1387 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001388 if type(thing) is types.InstanceType:
1389 return 'instance of ' + thing.__class__.__name__
1390 return type(thing).__name__
1391
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001392def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001393 """Locate an object by name or dotted path, importing as necessary."""
Guido van Rossum97dede02003-02-16 01:12:32 +00001394 parts = [part for part in split(path, '.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001395 module, n = None, 0
1396 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001397 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001398 if nextmodule: module, n = nextmodule, n + 1
1399 else: break
1400 if module:
1401 object = module
1402 for part in parts[n:]:
1403 try: object = getattr(object, part)
1404 except AttributeError: return None
1405 return object
1406 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001407 if hasattr(__builtin__, path):
1408 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001409
1410# --------------------------------------- interactive interpreter interface
1411
1412text = TextDoc()
1413html = HTMLDoc()
1414
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001415def resolve(thing, forceload=0):
1416 """Given an object or a path to an object, get the object and its name."""
1417 if isinstance(thing, str):
1418 object = locate(thing, forceload)
1419 if not object:
1420 raise ImportError, 'no Python documentation found for %r' % thing
1421 return object, thing
1422 else:
1423 return thing, getattr(thing, '__name__', None)
1424
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001425def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001426 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001427 try:
1428 object, name = resolve(thing, forceload)
1429 desc = describe(object)
1430 module = inspect.getmodule(object)
1431 if name and '.' in name:
1432 desc += ' in ' + name[:name.rfind('.')]
1433 elif module and module is not object:
1434 desc += ' in module ' + module.__name__
1435 pager(title % desc + '\n\n' + text.document(object, name))
1436 except (ImportError, ErrorDuringImport), value:
1437 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001438
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001439def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001440 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001441 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001442 object, name = resolve(thing, forceload)
1443 page = html.page(describe(object), html.document(object, name))
1444 file = open(name + '.html', 'w')
1445 file.write(page)
1446 file.close()
1447 print 'wrote', name + '.html'
1448 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001449 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001450
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001451def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001452 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001453 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001454 for file in os.listdir(dir):
1455 path = os.path.join(dir, file)
1456 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001457 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001458 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001459 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001460 if modname:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001461 if modname == '__init__':
1462 modname = pkgpath[:-1] # remove trailing period
1463 else:
1464 modname = pkgpath + modname
1465 if modname not in done:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001466 done[modname] = 1
1467 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001468
1469class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001470 keywords = {
1471 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001472 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001473 'break': ('ref/break', 'while for'),
1474 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1475 'continue': ('ref/continue', 'while for'),
1476 'def': ('ref/function', ''),
1477 'del': ('ref/del', 'BASICMETHODS'),
1478 'elif': 'if',
1479 'else': ('ref/if', 'while for'),
1480 'except': 'try',
1481 'exec': ('ref/exec', ''),
1482 'finally': 'try',
1483 'for': ('ref/for', 'break continue while'),
1484 'from': 'import',
1485 'global': ('ref/global', 'NAMESPACES'),
1486 'if': ('ref/if', 'TRUTHVALUE'),
1487 'import': ('ref/import', 'MODULES'),
1488 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1489 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001490 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001491 'not': 'BOOLEAN',
1492 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001493 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001494 'print': ('ref/print', ''),
1495 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001496 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001497 'try': ('ref/try', 'EXCEPTIONS'),
1498 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001499 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001500 }
1501
1502 topics = {
1503 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001504 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001505 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1506 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001507 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001508 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1509 'INTEGER': ('ref/integers', 'int range'),
1510 'FLOAT': ('ref/floating', 'float math'),
1511 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001512 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001513 'MAPPINGS': 'DICTIONARIES',
1514 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1515 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1516 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001517 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001518 'FRAMEOBJECTS': 'TYPES',
1519 'TRACEBACKS': 'TYPES',
1520 'NONE': ('lib/bltin-null-object', ''),
1521 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1522 'FILES': ('lib/bltin-file-objects', ''),
1523 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1524 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1525 'MODULES': ('lib/typesmodules', 'import'),
1526 'PACKAGES': 'import',
1527 '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'),
1528 'OPERATORS': 'EXPRESSIONS',
1529 'PRECEDENCE': 'EXPRESSIONS',
1530 'OBJECTS': ('ref/objects', 'TYPES'),
1531 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001532 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1533 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1534 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1535 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1536 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1537 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1538 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001539 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1540 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1541 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001542 'SCOPING': 'NAMESPACES',
1543 'FRAMES': 'NAMESPACES',
1544 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001545 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1546 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001547 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1548 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001549 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001550 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1551 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001552 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001553 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001554 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001555 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001556 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1557 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001558 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1559 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1560 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1561 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1562 'POWER': ('ref/power', 'EXPRESSIONS'),
1563 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1564 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1565 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1566 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1567 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001568 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001569 'ASSERTION': 'assert',
1570 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001571 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001572 'DELETION': 'del',
1573 'PRINTING': 'print',
1574 'RETURNING': 'return',
1575 'IMPORTING': 'import',
1576 'CONDITIONAL': 'if',
1577 'LOOPING': ('ref/compound', 'for while break continue'),
1578 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001579 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001580 }
1581
1582 def __init__(self, input, output):
1583 self.input = input
1584 self.output = output
1585 self.docdir = None
1586 execdir = os.path.dirname(sys.executable)
1587 homedir = os.environ.get('PYTHONHOME')
1588 for dir in [os.environ.get('PYTHONDOCS'),
1589 homedir and os.path.join(homedir, 'doc'),
1590 os.path.join(execdir, 'doc'),
1591 '/usr/doc/python-docs-' + split(sys.version)[0],
1592 '/usr/doc/python-' + split(sys.version)[0],
1593 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001594 '/usr/doc/python-' + sys.version[:3],
1595 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001596 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1597 self.docdir = dir
1598
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001599 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001600 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001601 self()
1602 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001603 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001604
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001605 def __call__(self, request=None):
1606 if request is not None:
1607 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001608 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001609 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001610 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001611 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001612You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001613If you want to ask for help on a particular object directly from the
1614interpreter, you can type "help(object)". Executing "help('string')"
1615has the same effect as typing a particular string at the help> prompt.
1616''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001617
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001618 def interact(self):
1619 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001620 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001621 self.output.write('help> ')
1622 self.output.flush()
1623 try:
1624 request = self.input.readline()
1625 if not request: break
1626 except KeyboardInterrupt: break
1627 request = strip(replace(request, '"', '', "'", ''))
1628 if lower(request) in ['q', 'quit']: break
1629 self.help(request)
1630
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001631 def help(self, request):
1632 if type(request) is type(''):
1633 if request == 'help': self.intro()
1634 elif request == 'keywords': self.listkeywords()
1635 elif request == 'topics': self.listtopics()
1636 elif request == 'modules': self.listmodules()
1637 elif request[:8] == 'modules ':
1638 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001639 elif request in self.keywords: self.showtopic(request)
1640 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001641 elif request: doc(request, 'Help on %s:')
1642 elif isinstance(request, Helper): self()
1643 else: doc(request, 'Help on %s:')
1644 self.output.write('\n')
1645
1646 def intro(self):
1647 self.output.write('''
1648Welcome to Python %s! This is the online help utility.
1649
1650If this is your first time using Python, you should definitely check out
1651the tutorial on the Internet at http://www.python.org/doc/tut/.
1652
1653Enter the name of any module, keyword, or topic to get help on writing
1654Python programs and using Python modules. To quit this help utility and
1655return to the interpreter, just type "quit".
1656
1657To get a list of available modules, keywords, or topics, type "modules",
1658"keywords", or "topics". Each module also comes with a one-line summary
1659of what it does; to list the modules whose summaries contain a given word
1660such as "spam", type "modules spam".
1661''' % sys.version[:3])
1662
1663 def list(self, items, columns=4, width=80):
1664 items = items[:]
1665 items.sort()
1666 colw = width / columns
1667 rows = (len(items) + columns - 1) / columns
1668 for row in range(rows):
1669 for col in range(columns):
1670 i = col * rows + row
1671 if i < len(items):
1672 self.output.write(items[i])
1673 if col < columns - 1:
1674 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1675 self.output.write('\n')
1676
1677 def listkeywords(self):
1678 self.output.write('''
1679Here is a list of the Python keywords. Enter any keyword to get more help.
1680
1681''')
1682 self.list(self.keywords.keys())
1683
1684 def listtopics(self):
1685 self.output.write('''
1686Here is a list of available topics. Enter any topic name to get more help.
1687
1688''')
1689 self.list(self.topics.keys())
1690
1691 def showtopic(self, topic):
1692 if not self.docdir:
1693 self.output.write('''
1694Sorry, topic and keyword documentation is not available because the Python
1695HTML documentation files could not be found. If you have installed them,
1696please set the environment variable PYTHONDOCS to indicate their location.
1697''')
1698 return
1699 target = self.topics.get(topic, self.keywords.get(topic))
1700 if not target:
1701 self.output.write('no documentation found for %s\n' % repr(topic))
1702 return
1703 if type(target) is type(''):
1704 return self.showtopic(target)
1705
1706 filename, xrefs = target
1707 filename = self.docdir + '/' + filename + '.html'
1708 try:
1709 file = open(filename)
1710 except:
1711 self.output.write('could not read docs from %s\n' % filename)
1712 return
1713
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001714 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1715 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001716 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1717 file.close()
1718
1719 import htmllib, formatter, StringIO
1720 buffer = StringIO.StringIO()
1721 parser = htmllib.HTMLParser(
1722 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1723 parser.start_table = parser.do_p
1724 parser.end_table = lambda parser=parser: parser.do_p({})
1725 parser.start_tr = parser.do_br
1726 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1727 parser.feed(document)
1728 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1729 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001730 if xrefs:
1731 buffer = StringIO.StringIO()
1732 formatter.DumbWriter(buffer).send_flowing_data(
1733 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1734 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001735
1736 def listmodules(self, key=''):
1737 if key:
1738 self.output.write('''
1739Here is a list of matching modules. Enter any module name to get more help.
1740
1741''')
1742 apropos(key)
1743 else:
1744 self.output.write('''
1745Please wait a moment while I gather a list of all available modules...
1746
1747''')
1748 modules = {}
1749 def callback(path, modname, desc, modules=modules):
1750 if modname and modname[-9:] == '.__init__':
1751 modname = modname[:-9] + ' (package)'
1752 if find(modname, '.') < 0:
1753 modules[modname] = 1
1754 ModuleScanner().run(callback)
1755 self.list(modules.keys())
1756 self.output.write('''
1757Enter any module name to get more help. Or, type "modules spam" to search
1758for modules whose descriptions contain the word "spam".
1759''')
1760
1761help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001762
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001763class Scanner:
1764 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001765 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001766 self.roots = roots[:]
1767 self.state = []
1768 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001769 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001770
1771 def next(self):
1772 if not self.state:
1773 if not self.roots:
1774 return None
1775 root = self.roots.pop(0)
1776 self.state = [(root, self.children(root))]
1777 node, children = self.state[-1]
1778 if not children:
1779 self.state.pop()
1780 return self.next()
1781 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001782 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001783 self.state.append((child, self.children(child)))
1784 return child
1785
1786class ModuleScanner(Scanner):
1787 """An interruptible scanner that searches module synopses."""
1788 def __init__(self):
1789 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001790 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001791 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001792
1793 def submodules(self, (dir, package)):
1794 children = []
1795 for file in os.listdir(dir):
1796 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001797 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001798 children.append((path, package + (package and '.') + file))
1799 else:
1800 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001801 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001802 return children
1803
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001804 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001805 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001806 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001807 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001808 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001809 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001810
Ka-Ping Yee66246962001-04-12 11:59:50 +00001811 def run(self, callback, key=None, completer=None):
1812 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001813 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001814 seen = {}
1815
1816 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001817 if modname != '__main__':
1818 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001819 if key is None:
1820 callback(None, modname, '')
1821 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001822 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001823 if find(lower(modname + ' - ' + desc), key) >= 0:
1824 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001825
1826 while not self.quit:
1827 node = self.next()
1828 if not node: break
1829 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001830 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001831 if os.path.isfile(path) and modname:
1832 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001833 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001834 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001835 if key is None:
1836 callback(path, modname, '')
1837 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001838 desc = synopsis(path) or ''
1839 if find(lower(modname + ' - ' + desc), key) >= 0:
1840 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001841 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001842
1843def apropos(key):
1844 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001845 def callback(path, modname, desc):
1846 if modname[-9:] == '.__init__':
1847 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001848 print modname, desc and '- ' + desc
1849 try: import warnings
1850 except ImportError: pass
1851 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001852 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001853
1854# --------------------------------------------------- web browser interface
1855
Ka-Ping Yee66246962001-04-12 11:59:50 +00001856def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001857 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001858
1859 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1860 class Message(mimetools.Message):
1861 def __init__(self, fp, seekable=1):
1862 Message = self.__class__
1863 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1864 self.encodingheader = self.getheader('content-transfer-encoding')
1865 self.typeheader = self.getheader('content-type')
1866 self.parsetype()
1867 self.parseplist()
1868
1869 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1870 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001871 try:
1872 self.send_response(200)
1873 self.send_header('Content-Type', 'text/html')
1874 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001875 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001876 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001877
1878 def do_GET(self):
1879 path = self.path
1880 if path[-5:] == '.html': path = path[:-5]
1881 if path[:1] == '/': path = path[1:]
1882 if path and path != '.':
1883 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001884 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001885 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001886 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001887 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001888 if obj:
1889 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001890 else:
1891 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001892'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001893 else:
1894 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001895'<big><big><strong>Python: Index of Modules</strong></big></big>',
1896'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001897 def bltinlink(name):
1898 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001899 names = filter(lambda x: x != '__main__',
1900 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001901 contents = html.multicolumn(names, bltinlink)
1902 indices = ['<p>' + html.bigsection(
1903 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1904
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001905 seen = {}
1906 for dir in pathdirs():
1907 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001908 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001909<font color="#909090" face="helvetica, arial"><strong>
1910pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001911 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001912
1913 def log_message(self, *args): pass
1914
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001915 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001916 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001917 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001918 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001919 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001920 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001921 self.base.__init__(self, self.address, self.handler)
1922
1923 def serve_until_quit(self):
1924 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001925 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001926 while not self.quit:
1927 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1928 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001929
1930 def server_activate(self):
1931 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001932 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001933
1934 DocServer.base = BaseHTTPServer.HTTPServer
1935 DocServer.handler = DocHandler
1936 DocHandler.MessageClass = Message
1937 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001938 try:
1939 DocServer(port, callback).serve_until_quit()
1940 except (KeyboardInterrupt, select.error):
1941 pass
1942 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001943 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001944
1945# ----------------------------------------------------- graphical interface
1946
1947def gui():
1948 """Graphical interface (starts web server and pops up a control window)."""
1949 class GUI:
1950 def __init__(self, window, port=7464):
1951 self.window = window
1952 self.server = None
1953 self.scanner = None
1954
1955 import Tkinter
1956 self.server_frm = Tkinter.Frame(window)
1957 self.title_lbl = Tkinter.Label(self.server_frm,
1958 text='Starting server...\n ')
1959 self.open_btn = Tkinter.Button(self.server_frm,
1960 text='open browser', command=self.open, state='disabled')
1961 self.quit_btn = Tkinter.Button(self.server_frm,
1962 text='quit serving', command=self.quit, state='disabled')
1963
1964 self.search_frm = Tkinter.Frame(window)
1965 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1966 self.search_ent = Tkinter.Entry(self.search_frm)
1967 self.search_ent.bind('<Return>', self.search)
1968 self.stop_btn = Tkinter.Button(self.search_frm,
1969 text='stop', pady=0, command=self.stop, state='disabled')
1970 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001971 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001972 self.stop_btn.pack(side='right')
1973
1974 self.window.title('pydoc')
1975 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1976 self.title_lbl.pack(side='top', fill='x')
1977 self.open_btn.pack(side='left', fill='x', expand=1)
1978 self.quit_btn.pack(side='right', fill='x', expand=1)
1979 self.server_frm.pack(side='top', fill='x')
1980
1981 self.search_lbl.pack(side='left')
1982 self.search_ent.pack(side='right', fill='x', expand=1)
1983 self.search_frm.pack(side='top', fill='x')
1984 self.search_ent.focus_set()
1985
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001986 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001987 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001988 self.result_lst.bind('<Button-1>', self.select)
1989 self.result_lst.bind('<Double-Button-1>', self.goto)
1990 self.result_scr = Tkinter.Scrollbar(window,
1991 orient='vertical', command=self.result_lst.yview)
1992 self.result_lst.config(yscrollcommand=self.result_scr.set)
1993
1994 self.result_frm = Tkinter.Frame(window)
1995 self.goto_btn = Tkinter.Button(self.result_frm,
1996 text='go to selected', command=self.goto)
1997 self.hide_btn = Tkinter.Button(self.result_frm,
1998 text='hide results', command=self.hide)
1999 self.goto_btn.pack(side='left', fill='x', expand=1)
2000 self.hide_btn.pack(side='right', fill='x', expand=1)
2001
2002 self.window.update()
2003 self.minwidth = self.window.winfo_width()
2004 self.minheight = self.window.winfo_height()
2005 self.bigminheight = (self.server_frm.winfo_reqheight() +
2006 self.search_frm.winfo_reqheight() +
2007 self.result_lst.winfo_reqheight() +
2008 self.result_frm.winfo_reqheight())
2009 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2010 self.expanded = 0
2011 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2012 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002013 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002014
2015 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002016 threading.Thread(
2017 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002018
2019 def ready(self, server):
2020 self.server = server
2021 self.title_lbl.config(
2022 text='Python documentation server at\n' + server.url)
2023 self.open_btn.config(state='normal')
2024 self.quit_btn.config(state='normal')
2025
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002026 def open(self, event=None, url=None):
2027 url = url or self.server.url
2028 try:
2029 import webbrowser
2030 webbrowser.open(url)
2031 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002032 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002033 os.system('start "%s"' % url)
2034 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002035 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002036 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002037 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002038 else:
2039 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2040 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002041
2042 def quit(self, event=None):
2043 if self.server:
2044 self.server.quit = 1
2045 self.window.quit()
2046
2047 def search(self, event=None):
2048 key = self.search_ent.get()
2049 self.stop_btn.pack(side='right')
2050 self.stop_btn.config(state='normal')
2051 self.search_lbl.config(text='Searching for "%s"...' % key)
2052 self.search_ent.forget()
2053 self.search_lbl.pack(side='left')
2054 self.result_lst.delete(0, 'end')
2055 self.goto_btn.config(state='disabled')
2056 self.expand()
2057
2058 import threading
2059 if self.scanner:
2060 self.scanner.quit = 1
2061 self.scanner = ModuleScanner()
2062 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002063 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002064
2065 def update(self, path, modname, desc):
2066 if modname[-9:] == '.__init__':
2067 modname = modname[:-9] + ' (package)'
2068 self.result_lst.insert('end',
2069 modname + ' - ' + (desc or '(no description)'))
2070
2071 def stop(self, event=None):
2072 if self.scanner:
2073 self.scanner.quit = 1
2074 self.scanner = None
2075
2076 def done(self):
2077 self.scanner = None
2078 self.search_lbl.config(text='Search for')
2079 self.search_lbl.pack(side='left')
2080 self.search_ent.pack(side='right', fill='x', expand=1)
2081 if sys.platform != 'win32': self.stop_btn.forget()
2082 self.stop_btn.config(state='disabled')
2083
2084 def select(self, event=None):
2085 self.goto_btn.config(state='normal')
2086
2087 def goto(self, event=None):
2088 selection = self.result_lst.curselection()
2089 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002090 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002091 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002092
2093 def collapse(self):
2094 if not self.expanded: return
2095 self.result_frm.forget()
2096 self.result_scr.forget()
2097 self.result_lst.forget()
2098 self.bigwidth = self.window.winfo_width()
2099 self.bigheight = self.window.winfo_height()
2100 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2101 self.window.wm_minsize(self.minwidth, self.minheight)
2102 self.expanded = 0
2103
2104 def expand(self):
2105 if self.expanded: return
2106 self.result_frm.pack(side='bottom', fill='x')
2107 self.result_scr.pack(side='right', fill='y')
2108 self.result_lst.pack(side='top', fill='both', expand=1)
2109 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2110 self.window.wm_minsize(self.minwidth, self.bigminheight)
2111 self.expanded = 1
2112
2113 def hide(self, event=None):
2114 self.stop()
2115 self.collapse()
2116
2117 import Tkinter
2118 try:
2119 gui = GUI(Tkinter.Tk())
2120 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002121 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002122 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002123
2124# -------------------------------------------------- command-line interface
2125
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002126def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002127 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002128
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002129def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002130 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002131 import getopt
2132 class BadUsage: pass
2133
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002134 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002135 scriptdir = os.path.dirname(sys.argv[0])
2136 if scriptdir in sys.path:
2137 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002138 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002139
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002140 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002141 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002142 writing = 0
2143
2144 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002145 if opt == '-g':
2146 gui()
2147 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002148 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002149 apropos(val)
2150 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002151 if opt == '-p':
2152 try:
2153 port = int(val)
2154 except ValueError:
2155 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002156 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002157 print 'pydoc server ready at %s' % server.url
2158 def stopped():
2159 print 'pydoc server stopped'
2160 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002161 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002162 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002163 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002164
2165 if not args: raise BadUsage
2166 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002167 if ispath(arg) and not os.path.exists(arg):
2168 print 'file %r does not exist' % arg
2169 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002170 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002171 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002172 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002173 if writing:
2174 if ispath(arg) and os.path.isdir(arg):
2175 writedocs(arg)
2176 else:
2177 writedoc(arg)
2178 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002179 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002180 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002181 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002182
2183 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002184 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002185 print """pydoc - the Python documentation tool
2186
2187%s <name> ...
2188 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002189 Python keyword, topic, function, module, or package, or a dotted
2190 reference to a class or function within a module or module in a
2191 package. If <name> contains a '%s', it is used as the path to a
2192 Python source file to document. If name is 'keywords', 'topics',
2193 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002194
2195%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002196 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002197
2198%s -p <port>
2199 Start an HTTP server on the given port on the local machine.
2200
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002201%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002202 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002203
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002204%s -w <name> ...
2205 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002206 directory. If <name> contains a '%s', it is treated as a filename; if
2207 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002208""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002209
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002210if __name__ == '__main__': cli()