blob: cf3863001aeeb5db4562d109996954265c5d4136 [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"
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000039
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000040__version__ = "$Revision$"
Martin v. Löwis6fe8f192004-11-14 10:21:04 +000041__credits__ = """Guido van Rossum, for an excellent programming language.
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000042Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000043Paul Prescod, for all his work on onlinehelp.
44Richard Chamberlain, for the first implementation of textdoc.
Raymond Hettingered2dbe32005-01-01 07:51:01 +000045"""
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
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000055import sys, imp, os, re, types, inspect, __builtin__, pkgutil
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
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000058try:
59 from collections import deque
60except ImportError:
61 # Python 2.3 compatibility
62 class deque(list):
63 def popleft(self):
64 return self.pop(0)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000065
66# --------------------------------------------------------- common routines
67
Ka-Ping Yeedd175342001-02-27 14:43:46 +000068def pathdirs():
69 """Convert sys.path into a list of absolute, existing, unique paths."""
70 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000071 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000072 for dir in sys.path:
73 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000074 normdir = os.path.normcase(dir)
75 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000076 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000077 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000078 return dirs
79
80def getdoc(object):
81 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000082 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000083 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000084
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000085def splitdoc(doc):
86 """Split a doc string into a synopsis line (if any) and the rest."""
87 lines = split(strip(doc), '\n')
88 if len(lines) == 1:
89 return lines[0], ''
90 elif len(lines) >= 2 and not rstrip(lines[1]):
91 return lines[0], join(lines[2:], '\n')
92 return '', join(lines, '\n')
93
Ka-Ping Yeedd175342001-02-27 14:43:46 +000094def classname(object, modname):
95 """Get a class name and qualify it with a module name if necessary."""
96 name = object.__name__
97 if object.__module__ != modname:
98 name = object.__module__ + '.' + name
99 return name
100
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000101def isdata(object):
Georg Brandl94432422005-07-22 21:52:25 +0000102 """Check if an object is of a type that probably means it's data."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000103 return not (inspect.ismodule(object) or inspect.isclass(object) or
104 inspect.isroutine(object) or inspect.isframe(object) or
105 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000106
107def replace(text, *pairs):
108 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000109 while pairs:
110 text = join(split(text, pairs[0]), pairs[1])
111 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000112 return text
113
114def cram(text, maxlen):
115 """Omit part of a string if needed to make it fit in a maximum length."""
116 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000117 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000118 post = max(0, maxlen-3-pre)
119 return text[:pre] + '...' + text[len(text)-post:]
120 return text
121
Brett Cannon84601f12004-06-19 01:22:48 +0000122_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000123def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000124 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000125 # The behaviour of %p is implementation-dependent in terms of case.
126 if _re_stripid.search(repr(Exception)):
127 return _re_stripid.sub(r'\1', text)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000128 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000129
Brett Cannonc6c1f472004-06-19 01:02:51 +0000130def _is_some_method(obj):
131 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000132
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000133def allmethods(cl):
134 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000135 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000136 methods[key] = 1
137 for base in cl.__bases__:
138 methods.update(allmethods(base)) # all your base are belong to us
139 for key in methods.keys():
140 methods[key] = getattr(cl, key)
141 return methods
142
Tim Petersfa26f7c2001-09-24 08:05:11 +0000143def _split_list(s, predicate):
144 """Split sequence s via predicate, and return pair ([true], [false]).
145
146 The return value is a 2-tuple of lists,
147 ([x for x in s if predicate(x)],
148 [x for x in s if not predicate(x)])
149 """
150
Tim Peters28355492001-09-23 21:29:55 +0000151 yes = []
152 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000153 for x in s:
154 if predicate(x):
155 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000156 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000157 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000158 return yes, no
159
Skip Montanaroa5616d22004-06-11 04:46:12 +0000160def visiblename(name, all=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000161 """Decide whether to show documentation on a variable."""
162 # Certain special names are redundant.
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000163 if name in ('__builtins__', '__doc__', '__file__', '__path__',
164 '__module__', '__name__', '__slots__'): return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000165 # Private names are hidden, but special names are displayed.
166 if name.startswith('__') and name.endswith('__'): return 1
Skip Montanaroa5616d22004-06-11 04:46:12 +0000167 if all is not None:
168 # only document that which the programmer exported in __all__
169 return name in all
170 else:
171 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000172
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000173def classify_class_attrs(object):
174 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
175 def fixup((name, kind, cls, value)):
176 if inspect.isdatadescriptor(value):
177 kind = 'data descriptor'
178 return name, kind, cls, value
179 return map(fixup, inspect.classify_class_attrs(object))
180
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000181# ----------------------------------------------------- module manipulation
182
183def ispackage(path):
184 """Guess whether a path refers to a package directory."""
185 if os.path.isdir(path):
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000186 for ext in ('.py', '.pyc', '.pyo'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000187 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000188 return True
189 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000190
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000191def source_synopsis(file):
192 line = file.readline()
193 while line[:1] == '#' or not strip(line):
194 line = file.readline()
195 if not line: break
196 line = strip(line)
197 if line[:4] == 'r"""': line = line[1:]
198 if line[:3] == '"""':
199 line = line[3:]
200 if line[-1:] == '\\': line = line[:-1]
201 while not strip(line):
202 line = file.readline()
203 if not line: break
204 result = strip(split(line, '"""')[0])
205 else: result = None
206 return result
207
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000208def synopsis(filename, cache={}):
209 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000210 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000211 lastupdate, result = cache.get(filename, (0, None))
212 if lastupdate < mtime:
213 info = inspect.getmoduleinfo(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000214 try:
215 file = open(filename)
216 except IOError:
217 # module can't be opened, so skip it
218 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000219 if info and 'b' in info[2]: # binary modules have to be imported
220 try: module = imp.load_module('__temp__', file, filename, info[1:])
221 except: return None
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000222 result = (module.__doc__ or '').splitlines()[0]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000223 del sys.modules['__temp__']
224 else: # text modules can be directly examined
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000225 result = source_synopsis(file)
226 file.close()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000227 cache[filename] = (mtime, result)
228 return result
229
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000230class ErrorDuringImport(Exception):
231 """Errors that occurred while trying to import something to document it."""
232 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000233 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000234 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000235 self.value = value
236 self.tb = tb
237
238 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000239 exc = self.exc
240 if type(exc) is types.ClassType:
241 exc = exc.__name__
242 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000243
244def importfile(path):
245 """Import a Python source file or compiled file given its path."""
246 magic = imp.get_magic()
247 file = open(path, 'r')
248 if file.read(len(magic)) == magic:
249 kind = imp.PY_COMPILED
250 else:
251 kind = imp.PY_SOURCE
252 file.close()
253 filename = os.path.basename(path)
254 name, ext = os.path.splitext(filename)
255 file = open(path, 'r')
256 try:
257 module = imp.load_module(name, file, path, (ext, 'r', kind))
258 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000259 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000260 file.close()
261 return module
262
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000263def safeimport(path, forceload=0, cache={}):
264 """Import a module; handle errors; return None if the module isn't found.
265
266 If the module *is* found but an exception occurs, it's wrapped in an
267 ErrorDuringImport exception and reraised. Unlike __import__, if a
268 package path is specified, the module at the end of the path is returned,
269 not the package at the beginning. If the optional 'forceload' argument
270 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000271 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000272 # If forceload is 1 and the module has been previously loaded from
273 # disk, we always have to reload the module. Checking the file's
274 # mtime isn't good enough (e.g. the module could contain a class
275 # that inherits from another module that has changed).
276 if forceload and path in sys.modules:
277 if path not in sys.builtin_module_names:
278 # Avoid simply calling reload() because it leaves names in
279 # the currently loaded module lying around if they're not
280 # defined in the new source file. Instead, remove the
281 # module from sys.modules and re-import. Also remove any
282 # submodules because they won't appear in the newly loaded
283 # module's namespace if they're already in sys.modules.
284 subs = [m for m in sys.modules if m.startswith(path + '.')]
285 for key in [path] + subs:
286 # Prevent garbage collection.
287 cache[key] = sys.modules[key]
288 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000289 module = __import__(path)
290 except:
291 # Did the error occur before or after the module was found?
292 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000293 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000294 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000295 raise ErrorDuringImport(sys.modules[path].__file__, info)
296 elif exc is SyntaxError:
297 # A SyntaxError occurred before we could execute the module.
298 raise ErrorDuringImport(value.filename, info)
299 elif exc is ImportError and \
300 split(lower(str(value)))[:2] == ['no', 'module']:
301 # The module was not found.
302 return None
303 else:
304 # Some other error occurred during the importing process.
305 raise ErrorDuringImport(path, sys.exc_info())
306 for part in split(path, '.')[1:]:
307 try: module = getattr(module, part)
308 except AttributeError: return None
309 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000310
311# ---------------------------------------------------- formatter base class
312
313class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000314 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000315 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000316 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000317 # 'try' clause is to attempt to handle the possibility that inspect
318 # identifies something in a way that pydoc itself has issues handling;
319 # think 'super' and how it is a descriptor (which raises the exception
320 # by lacking a __name__ attribute) and an instance.
321 try:
322 if inspect.ismodule(object): return self.docmodule(*args)
323 if inspect.isclass(object): return self.docclass(*args)
324 if inspect.isroutine(object): return self.docroutine(*args)
325 except AttributeError:
326 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000327 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000328 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000329
330 def fail(self, object, name=None, *args):
331 """Raise an exception for unimplemented types."""
332 message = "don't know how to document object%s of type %s" % (
333 name and ' ' + repr(name), type(object).__name__)
334 raise TypeError, message
335
336 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000337
Skip Montanaro4997a692003-09-10 16:47:51 +0000338 def getdocloc(self, object):
339 """Return the location of module docs or None"""
340
341 try:
342 file = inspect.getabsfile(object)
343 except TypeError:
344 file = '(built-in)'
345
346 docloc = os.environ.get("PYTHONDOCS",
347 "http://www.python.org/doc/current/lib")
348 basedir = os.path.join(sys.exec_prefix, "lib",
349 "python"+sys.version[0:3])
350 if (isinstance(object, type(os)) and
351 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
352 'marshal', 'posix', 'signal', 'sys',
353 'thread', 'zipimport') or
354 (file.startswith(basedir) and
355 not file.startswith(os.path.join(basedir, 'site-packages'))))):
Skip Montanarof2134842004-06-07 02:40:05 +0000356 htmlfile = "module-%s.html" % object.__name__
Skip Montanaro4997a692003-09-10 16:47:51 +0000357 if docloc.startswith("http://"):
Skip Montanarof2134842004-06-07 02:40:05 +0000358 docloc = "%s/%s" % (docloc.rstrip("/"), htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000359 else:
Skip Montanarof2134842004-06-07 02:40:05 +0000360 docloc = os.path.join(docloc, htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000361 else:
362 docloc = None
363 return docloc
364
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000365# -------------------------------------------- HTML documentation generator
366
367class HTMLRepr(Repr):
368 """Class for safely making an HTML representation of a Python object."""
369 def __init__(self):
370 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000371 self.maxlist = self.maxtuple = 20
372 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000373 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000374
375 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000376 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000377
378 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000379 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000380
381 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000382 if hasattr(type(x), '__name__'):
383 methodname = 'repr_' + join(split(type(x).__name__), '_')
384 if hasattr(self, methodname):
385 return getattr(self, methodname)(x, level)
386 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000387
388 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000389 test = cram(x, self.maxstring)
390 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000391 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000392 # Backslashes are only literal in the string and are never
393 # needed to make any special characters, so show a raw string.
394 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000395 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000396 r'<font color="#c040c0">\1</font>',
397 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000398
Skip Montanarodf708782002-03-07 22:58:02 +0000399 repr_str = repr_string
400
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000401 def repr_instance(self, x, level):
402 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000403 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000404 except:
405 return self.escape('<%s instance>' % x.__class__.__name__)
406
407 repr_unicode = repr_string
408
409class HTMLDoc(Doc):
410 """Formatter class for HTML documentation."""
411
412 # ------------------------------------------- HTML formatting utilities
413
414 _repr_instance = HTMLRepr()
415 repr = _repr_instance.repr
416 escape = _repr_instance.escape
417
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000418 def page(self, title, contents):
419 """Format an HTML page."""
420 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000421<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000422<html><head><title>Python: %s</title>
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000423</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000424%s
425</body></html>''' % (title, contents)
426
427 def heading(self, title, fgcol, bgcol, extras=''):
428 """Format a page heading."""
429 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000430<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000431<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000432<td valign=bottom>&nbsp;<br>
433<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000434><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000435><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000436 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
437
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000438 def section(self, title, fgcol, bgcol, contents, width=6,
439 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000440 """Format a section with a heading."""
441 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000442 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000443 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000444<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000445<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000446<td colspan=3 valign=bottom>&nbsp;<br>
447<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000448 ''' % (bgcol, fgcol, title)
449 if prelude:
450 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000451<tr bgcolor="%s"><td rowspan=2>%s</td>
452<td colspan=2>%s</td></tr>
453<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
454 else:
455 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000456<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000457
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000458 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000459
460 def bigsection(self, title, *args):
461 """Format a section with a big heading."""
462 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000463 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000464
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000465 def preformat(self, text):
466 """Format literal preformatted text."""
467 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000468 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
469 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000470
471 def multicolumn(self, list, format, cols=4):
472 """Format a list of items into a multi-column list."""
473 result = ''
474 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000475 for col in range(cols):
476 result = result + '<td width="%d%%" valign=top>' % (100/cols)
477 for i in range(rows*col, rows*col+rows):
478 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000479 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000480 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000481 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000482
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000483 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000484
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000485 def namelink(self, name, *dicts):
486 """Make a link for an identifier, given name-to-URL mappings."""
487 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000488 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000489 return '<a href="%s">%s</a>' % (dict[name], name)
490 return name
491
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000492 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000493 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000494 name, module = object.__name__, sys.modules.get(object.__module__)
495 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000496 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000497 module.__name__, name, classname(object, modname))
498 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000499
500 def modulelink(self, object):
501 """Make a link for a module."""
502 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
503
504 def modpkglink(self, (name, path, ispackage, shadowed)):
505 """Make a link for a module or package to display in an index."""
506 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000507 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000508 if path:
509 url = '%s.%s.html' % (path, name)
510 else:
511 url = '%s.html' % name
512 if ispackage:
513 text = '<strong>%s</strong>&nbsp;(package)' % name
514 else:
515 text = name
516 return '<a href="%s">%s</a>' % (url, text)
517
518 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
519 """Mark up some plain text, given a context of symbols to look for.
520 Each context dictionary maps object names to anchor names."""
521 escape = escape or self.escape
522 results = []
523 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000524 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
525 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000526 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000527 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000528 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000529 match = pattern.search(text, here)
530 if not match: break
531 start, end = match.span()
532 results.append(escape(text[here:start]))
533
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000534 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000535 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000536 url = escape(all).replace('"', '&quot;')
537 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000538 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000539 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
540 results.append('<a href="%s">%s</a>' % (url, escape(all)))
541 elif pep:
542 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000543 results.append('<a href="%s">%s</a>' % (url, escape(all)))
544 elif text[end:end+1] == '(':
545 results.append(self.namelink(name, methods, funcs, classes))
546 elif selfdot:
547 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000548 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000549 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000550 here = end
551 results.append(escape(text[here:]))
552 return join(results, '')
553
554 # ---------------------------------------------- type-specific routines
555
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000556 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000557 """Produce HTML for a class tree as given by inspect.getclasstree()."""
558 result = ''
559 for entry in tree:
560 if type(entry) is type(()):
561 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000562 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000563 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000564 if bases and bases != (parent,):
565 parents = []
566 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000567 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000568 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000569 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000570 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000571 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000572 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000573 return '<dl>\n%s</dl>\n' % result
574
Tim Peters8dd7ade2001-10-18 19:56:17 +0000575 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000576 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000577 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000578 try:
579 all = object.__all__
580 except AttributeError:
581 all = None
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000582 parts = split(name, '.')
583 links = []
584 for i in range(len(parts)-1):
585 links.append(
586 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
587 (join(parts[:i+1], '.'), parts[i]))
588 linkedname = join(links + parts[-1:], '.')
589 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000590 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000591 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000592 url = path
593 if sys.platform == 'win32':
594 import nturl2path
595 url = nturl2path.pathname2url(path)
596 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000597 except TypeError:
598 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000599 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000600 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000601 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000602 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
603 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000604 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000605 if hasattr(object, '__date__'):
606 info.append(self.escape(str(object.__date__)))
607 if info:
608 head = head + ' (%s)' % join(info, ', ')
Skip Montanaro4997a692003-09-10 16:47:51 +0000609 docloc = self.getdocloc(object)
610 if docloc is not None:
611 docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
612 else:
613 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000614 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000615 head, '#ffffff', '#7799ee',
616 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000617
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000618 modules = inspect.getmembers(object, inspect.ismodule)
619
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000620 classes, cdict = [], {}
621 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000622 # if __all__ exists, believe it. Otherwise use old heuristic.
623 if (all is not None or
624 (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000625 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000626 classes.append((key, value))
627 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000628 for key, value in classes:
629 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000630 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000631 module = sys.modules.get(modname)
632 if modname != name and module and hasattr(module, key):
633 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000634 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000635 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000636 funcs, fdict = [], {}
637 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000638 # if __all__ exists, believe it. Otherwise use old heuristic.
639 if (all is not None or
640 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000641 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000642 funcs.append((key, value))
643 fdict[key] = '#-' + key
644 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000645 data = []
646 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000647 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000648 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000649
650 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
651 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000652 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000653
654 if hasattr(object, '__path__'):
655 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000656 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
657 modpkgs.append((modname, name, ispkg, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000658 modpkgs.sort()
659 contents = self.multicolumn(modpkgs, self.modpkglink)
660 result = result + self.bigsection(
661 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000662 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000663 contents = self.multicolumn(
664 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000665 result = result + self.bigsection(
666 'Modules', '#fffff', '#aa55cc', contents)
667
668 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000669 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000670 contents = [
671 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000672 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000673 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000674 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000675 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000676 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000677 contents = []
678 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000679 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000680 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000681 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000682 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000683 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000684 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000685 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000686 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000687 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000688 if hasattr(object, '__author__'):
689 contents = self.markup(str(object.__author__), self.preformat)
690 result = result + self.bigsection(
691 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000692 if hasattr(object, '__credits__'):
693 contents = self.markup(str(object.__credits__), self.preformat)
694 result = result + self.bigsection(
695 'Credits', '#ffffff', '#7799ee', contents)
696
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000697 return result
698
Tim Peters8dd7ade2001-10-18 19:56:17 +0000699 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
700 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000701 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000702 realname = object.__name__
703 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000704 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000705
Tim Petersb47879b2001-09-24 04:47:19 +0000706 contents = []
707 push = contents.append
708
Tim Petersfa26f7c2001-09-24 08:05:11 +0000709 # Cute little class to pump out a horizontal rule between sections.
710 class HorizontalRule:
711 def __init__(self):
712 self.needone = 0
713 def maybe(self):
714 if self.needone:
715 push('<hr>\n')
716 self.needone = 1
717 hr = HorizontalRule()
718
Tim Petersc86f6ca2001-09-26 21:31:51 +0000719 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000720 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000721 if len(mro) > 2:
722 hr.maybe()
723 push('<dl><dt>Method resolution order:</dt>\n')
724 for base in mro:
725 push('<dd>%s</dd>\n' % self.classlink(base,
726 object.__module__))
727 push('</dl>\n')
728
Tim Petersb47879b2001-09-24 04:47:19 +0000729 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000730 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000731 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000732 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000733 push(msg)
734 for name, kind, homecls, value in ok:
735 push(self.document(getattr(object, name), name, mod,
736 funcs, classes, mdict, object))
737 push('\n')
738 return attrs
739
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000740 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000741 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000742 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000743 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000744 push(msg)
745 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000746 push(self._docdescriptor(name, value, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000747 return attrs
748
Tim Petersfa26f7c2001-09-24 08:05:11 +0000749 def spilldata(msg, attrs, predicate):
750 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000751 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000752 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000753 push(msg)
754 for name, kind, homecls, value in ok:
755 base = self.docother(getattr(object, name), name, mod)
Martin v. Löwise59e2ba2003-05-03 09:09:02 +0000756 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000757 doc = getattr(value, "__doc__", None)
758 else:
759 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000760 if doc is None:
761 push('<dl><dt>%s</dl>\n' % base)
762 else:
763 doc = self.markup(getdoc(value), self.preformat,
764 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000765 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000766 push('<dl><dt>%s%s</dl>\n' % (base, doc))
767 push('\n')
768 return attrs
769
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000770 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000771 classify_class_attrs(object))
Tim Petersb47879b2001-09-24 04:47:19 +0000772 mdict = {}
773 for key, kind, homecls, value in attrs:
774 mdict[key] = anchor = '#' + name + '-' + key
775 value = getattr(object, key)
776 try:
777 # The value may not be hashable (e.g., a data attr with
778 # a dict or list value).
779 mdict[value] = anchor
780 except TypeError:
781 pass
782
Tim Petersfa26f7c2001-09-24 08:05:11 +0000783 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000784 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000785 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000786 else:
787 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000788 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
789
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000790 if thisclass is __builtin__.object:
791 attrs = inherited
792 continue
793 elif thisclass is object:
794 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000795 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000796 tag = 'inherited from %s' % self.classlink(thisclass,
797 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000798 tag += ':<br>\n'
799
800 # Sort attrs by name.
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000801 try:
802 attrs.sort(key=lambda t: t[0])
803 except TypeError:
804 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0])) # 2.3 compat
Tim Petersb47879b2001-09-24 04:47:19 +0000805
806 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000807 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000808 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000809 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000810 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000811 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000812 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000813 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
814 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000815 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000816 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000817 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000818 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000819
820 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000821
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000822 if name == realname:
823 title = '<a name="%s">class <strong>%s</strong></a>' % (
824 name, realname)
825 else:
826 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
827 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000828 if bases:
829 parents = []
830 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000831 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000832 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000833 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000834 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000835
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000836 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000837
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000838 def formatvalue(self, object):
839 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000840 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000841
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000842 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000843 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000844 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000845 realname = object.__name__
846 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000847 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000848 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000849 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000850 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000851 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000852 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000853 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000854 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000855 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000856 if object.im_self:
857 note = ' method of %s instance' % self.classlink(
858 object.im_self.__class__, mod)
859 else:
860 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000861 object = object.im_func
862
863 if name == realname:
864 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
865 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000866 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000867 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000868 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000869 cl.__name__ + '-' + realname, realname)
870 skipdocs = 1
871 else:
872 reallink = realname
873 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
874 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000875 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000876 args, varargs, varkw, defaults = inspect.getargspec(object)
877 argspec = inspect.formatargspec(
878 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000879 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000880 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000881 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000882 else:
883 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000884
Tim Peters2306d242001-09-25 03:18:32 +0000885 decl = title + argspec + (note and self.grey(
886 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000887
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000888 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000889 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000890 else:
891 doc = self.markup(
892 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000893 doc = doc and '<dd><tt>%s</tt></dd>' % doc
894 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000895
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000896 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000897 results = []
898 push = results.append
899
900 if name:
901 push('<dl><dt><strong>%s</strong></dt>\n' % name)
902 if value.__doc__ is not None:
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +0000903 doc = self.markup(getdoc(value), self.preformat)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000904 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000905 push('</dl>\n')
906
907 return ''.join(results)
908
909 def docproperty(self, object, name=None, mod=None, cl=None):
910 """Produce html documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000911 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000912
Tim Peters8dd7ade2001-10-18 19:56:17 +0000913 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000914 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000915 lhs = name and '<strong>%s</strong> = ' % name or ''
916 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000917
918 def index(self, dir, shadowed=None):
919 """Generate an HTML index for a directory of modules."""
920 modpkgs = []
921 if shadowed is None: shadowed = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000922 for importer, name, ispkg in pkgutil.iter_modules([dir]):
923 modpkgs.append((name, '', ispkg, name in shadowed))
924 shadowed[name] = 1
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000925
926 modpkgs.sort()
927 contents = self.multicolumn(modpkgs, self.modpkglink)
928 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
929
930# -------------------------------------------- text documentation generator
931
932class TextRepr(Repr):
933 """Class for safely making a text representation of a Python object."""
934 def __init__(self):
935 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000936 self.maxlist = self.maxtuple = 20
937 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000938 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000939
940 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000941 if hasattr(type(x), '__name__'):
942 methodname = 'repr_' + join(split(type(x).__name__), '_')
943 if hasattr(self, methodname):
944 return getattr(self, methodname)(x, level)
945 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000946
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000947 def repr_string(self, x, level):
948 test = cram(x, self.maxstring)
949 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000950 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000951 # Backslashes are only literal in the string and are never
952 # needed to make any special characters, so show a raw string.
953 return 'r' + testrepr[0] + test + testrepr[0]
954 return testrepr
955
Skip Montanarodf708782002-03-07 22:58:02 +0000956 repr_str = repr_string
957
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000958 def repr_instance(self, x, level):
959 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000960 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000961 except:
962 return '<%s instance>' % x.__class__.__name__
963
964class TextDoc(Doc):
965 """Formatter class for text documentation."""
966
967 # ------------------------------------------- text formatting utilities
968
969 _repr_instance = TextRepr()
970 repr = _repr_instance.repr
971
972 def bold(self, text):
973 """Format a string in bold by overstriking."""
974 return join(map(lambda ch: ch + '\b' + ch, text), '')
975
976 def indent(self, text, prefix=' '):
977 """Indent text by prepending a given prefix to each line."""
978 if not text: return ''
979 lines = split(text, '\n')
980 lines = map(lambda line, prefix=prefix: prefix + line, lines)
981 if lines: lines[-1] = rstrip(lines[-1])
982 return join(lines, '\n')
983
984 def section(self, title, contents):
985 """Format a section with a given heading."""
986 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
987
988 # ---------------------------------------------- type-specific routines
989
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000990 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000991 """Render in text a class tree as returned by inspect.getclasstree()."""
992 result = ''
993 for entry in tree:
994 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000995 c, bases = entry
996 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000997 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000998 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000999 result = result + '(%s)' % join(parents, ', ')
1000 result = result + '\n'
1001 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001002 result = result + self.formattree(
1003 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001004 return result
1005
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001006 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001007 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001008 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001009 synop, desc = splitdoc(getdoc(object))
1010 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001011
1012 try:
Skip Montanaroa5616d22004-06-11 04:46:12 +00001013 all = object.__all__
1014 except AttributeError:
1015 all = None
1016
1017 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001018 file = inspect.getabsfile(object)
1019 except TypeError:
1020 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001021 result = result + self.section('FILE', file)
Skip Montanaro4997a692003-09-10 16:47:51 +00001022
1023 docloc = self.getdocloc(object)
1024 if docloc is not None:
1025 result = result + self.section('MODULE DOCS', docloc)
1026
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001027 if desc:
1028 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001029
1030 classes = []
1031 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001032 # if __all__ exists, believe it. Otherwise use old heuristic.
1033 if (all is not None
1034 or (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001035 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001036 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001037 funcs = []
1038 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001039 # if __all__ exists, believe it. Otherwise use old heuristic.
1040 if (all is not None or
1041 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001042 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001043 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001044 data = []
1045 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001046 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001047 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001048
1049 if hasattr(object, '__path__'):
1050 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001051 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
1052 if ispkg:
1053 modpkgs.append(modname + ' (package)')
1054 else:
1055 modpkgs.append(modname)
1056
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001057 modpkgs.sort()
1058 result = result + self.section(
1059 'PACKAGE CONTENTS', join(modpkgs, '\n'))
1060
1061 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001062 classlist = map(lambda (key, value): value, classes)
1063 contents = [self.formattree(
1064 inspect.getclasstree(classlist, 1), name)]
1065 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001066 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001067 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001068
1069 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001070 contents = []
1071 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001072 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001073 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001074
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001075 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001076 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001077 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001078 contents.append(self.docother(value, key, name, maxlen=70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001079 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001080
1081 if hasattr(object, '__version__'):
1082 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001083 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1084 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001085 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001086 if hasattr(object, '__date__'):
1087 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001088 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001089 result = result + self.section('AUTHOR', str(object.__author__))
1090 if hasattr(object, '__credits__'):
1091 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001092 return result
1093
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001094 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001095 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001096 realname = object.__name__
1097 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001098 bases = object.__bases__
1099
Tim Petersc86f6ca2001-09-26 21:31:51 +00001100 def makename(c, m=object.__module__):
1101 return classname(c, m)
1102
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001103 if name == realname:
1104 title = 'class ' + self.bold(realname)
1105 else:
1106 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001107 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001108 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001109 title = title + '(%s)' % join(parents, ', ')
1110
1111 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001112 contents = doc and [doc + '\n'] or []
1113 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001114
Tim Petersc86f6ca2001-09-26 21:31:51 +00001115 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001116 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001117 if len(mro) > 2:
1118 push("Method resolution order:")
1119 for base in mro:
1120 push(' ' + makename(base))
1121 push('')
1122
Tim Petersf4aad8e2001-09-24 22:40:47 +00001123 # Cute little class to pump out a horizontal rule between sections.
1124 class HorizontalRule:
1125 def __init__(self):
1126 self.needone = 0
1127 def maybe(self):
1128 if self.needone:
1129 push('-' * 70)
1130 self.needone = 1
1131 hr = HorizontalRule()
1132
Tim Peters28355492001-09-23 21:29:55 +00001133 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001134 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001135 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001136 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001137 push(msg)
1138 for name, kind, homecls, value in ok:
1139 push(self.document(getattr(object, name),
1140 name, mod, object))
1141 return attrs
1142
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001143 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001144 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001145 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001146 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001147 push(msg)
1148 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001149 push(self._docdescriptor(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001150 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001151
Tim Petersfa26f7c2001-09-24 08:05:11 +00001152 def spilldata(msg, attrs, predicate):
1153 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001154 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001155 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001156 push(msg)
1157 for name, kind, homecls, value in ok:
Martin v. Löwise59e2ba2003-05-03 09:09:02 +00001158 if callable(value) or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001159 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001160 else:
1161 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001162 push(self.docother(getattr(object, name),
Georg Brandl8b813db2005-10-01 16:32:31 +00001163 name, mod, maxlen=70, doc=doc) + '\n')
Tim Peters28355492001-09-23 21:29:55 +00001164 return attrs
1165
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001166 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001167 classify_class_attrs(object))
Tim Petersfa26f7c2001-09-24 08:05:11 +00001168 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001169 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001170 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001171 else:
1172 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001173 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1174
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001175 if thisclass is __builtin__.object:
1176 attrs = inherited
1177 continue
1178 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001179 tag = "defined here"
1180 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001181 tag = "inherited from %s" % classname(thisclass,
1182 object.__module__)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001183 filter(lambda t: not t[0].startswith('_'), attrs)
Tim Peters28355492001-09-23 21:29:55 +00001184
1185 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001186 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001187
1188 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001189 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001190 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001191 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001192 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001193 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001194 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001195 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1196 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001197 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1198 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001199 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001200 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001201
1202 contents = '\n'.join(contents)
1203 if not contents:
1204 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001205 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1206
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001207 def formatvalue(self, object):
1208 """Format an argument default value as text."""
1209 return '=' + self.repr(object)
1210
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001211 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001212 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001213 realname = object.__name__
1214 name = name or realname
1215 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001216 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001217 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001218 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001219 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001220 if imclass is not cl:
1221 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001222 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001223 if object.im_self:
1224 note = ' method of %s instance' % classname(
1225 object.im_self.__class__, mod)
1226 else:
1227 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001228 object = object.im_func
1229
1230 if name == realname:
1231 title = self.bold(realname)
1232 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001233 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001234 cl.__dict__[realname] is object):
1235 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001236 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001237 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001238 args, varargs, varkw, defaults = inspect.getargspec(object)
1239 argspec = inspect.formatargspec(
1240 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001241 if realname == '<lambda>':
Georg Brandl501dd0d2006-02-17 09:45:40 +00001242 title = self.bold(name) + ' lambda '
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001243 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001244 else:
1245 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001246 decl = title + argspec + note
1247
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001248 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001249 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001250 else:
1251 doc = getdoc(object) or ''
1252 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001253
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001254 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001255 results = []
1256 push = results.append
1257
1258 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001259 push(self.bold(name))
1260 push('\n')
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001261 doc = getdoc(value) or ''
1262 if doc:
1263 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001264 push('\n')
1265 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001266
1267 def docproperty(self, object, name=None, mod=None, cl=None):
1268 """Produce text documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001269 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001270
Georg Brandl8b813db2005-10-01 16:32:31 +00001271 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001272 """Produce text documentation for a data object."""
1273 repr = self.repr(object)
1274 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001275 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001276 chop = maxlen - len(line)
1277 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001278 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001279 if doc is not None:
1280 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001281 return line
1282
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001283# --------------------------------------------------------- user interfaces
1284
1285def pager(text):
1286 """The first time this is called, determine what kind of pager to use."""
1287 global pager
1288 pager = getpager()
1289 pager(text)
1290
1291def getpager():
1292 """Decide what method to use for paging through text."""
1293 if type(sys.stdout) is not types.FileType:
1294 return plainpager
1295 if not sys.stdin.isatty() or not sys.stdout.isatty():
1296 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001297 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001298 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001299 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001300 elif os.environ.get('TERM') in ('dumb', 'emacs'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001301 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001302 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001303 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001304 if os.environ.get('TERM') in ('dumb', 'emacs'):
1305 return plainpager
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001306 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001307 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001308 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001309 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001310
1311 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001312 (fd, filename) = tempfile.mkstemp()
1313 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001314 try:
1315 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1316 return lambda text: pipepager(text, 'more')
1317 else:
1318 return ttypager
1319 finally:
1320 os.unlink(filename)
1321
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001322def plain(text):
1323 """Remove boldface formatting from text."""
1324 return re.sub('.\b', '', text)
1325
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001326def pipepager(text, cmd):
1327 """Page through text by feeding it to another program."""
1328 pipe = os.popen(cmd, 'w')
1329 try:
1330 pipe.write(text)
1331 pipe.close()
1332 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001333 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001334
1335def tempfilepager(text, cmd):
1336 """Page through text by invoking a program on a temporary file."""
1337 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001338 filename = tempfile.mktemp()
1339 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001340 file.write(text)
1341 file.close()
1342 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001343 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001344 finally:
1345 os.unlink(filename)
1346
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001347def ttypager(text):
1348 """Page through text on a text terminal."""
1349 lines = split(plain(text), '\n')
1350 try:
1351 import tty
1352 fd = sys.stdin.fileno()
1353 old = tty.tcgetattr(fd)
1354 tty.setcbreak(fd)
1355 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001356 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001357 tty = None
1358 getchar = lambda: sys.stdin.readline()[:-1][:1]
1359
1360 try:
1361 r = inc = os.environ.get('LINES', 25) - 1
1362 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1363 while lines[r:]:
1364 sys.stdout.write('-- more --')
1365 sys.stdout.flush()
1366 c = getchar()
1367
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001368 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001369 sys.stdout.write('\r \r')
1370 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001371 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001372 sys.stdout.write('\r \r' + lines[r] + '\n')
1373 r = r + 1
1374 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001375 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001376 r = r - inc - inc
1377 if r < 0: r = 0
1378 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1379 r = r + inc
1380
1381 finally:
1382 if tty:
1383 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1384
1385def plainpager(text):
1386 """Simply print unformatted text. This is the ultimate fallback."""
1387 sys.stdout.write(plain(text))
1388
1389def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001390 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001391 if inspect.ismodule(thing):
1392 if thing.__name__ in sys.builtin_module_names:
1393 return 'built-in module ' + thing.__name__
1394 if hasattr(thing, '__path__'):
1395 return 'package ' + thing.__name__
1396 else:
1397 return 'module ' + thing.__name__
1398 if inspect.isbuiltin(thing):
1399 return 'built-in function ' + thing.__name__
1400 if inspect.isclass(thing):
1401 return 'class ' + thing.__name__
1402 if inspect.isfunction(thing):
1403 return 'function ' + thing.__name__
1404 if inspect.ismethod(thing):
1405 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001406 if type(thing) is types.InstanceType:
1407 return 'instance of ' + thing.__class__.__name__
1408 return type(thing).__name__
1409
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001410def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001411 """Locate an object by name or dotted path, importing as necessary."""
Guido van Rossum97dede02003-02-16 01:12:32 +00001412 parts = [part for part in split(path, '.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001413 module, n = None, 0
1414 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001415 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001416 if nextmodule: module, n = nextmodule, n + 1
1417 else: break
1418 if module:
1419 object = module
1420 for part in parts[n:]:
1421 try: object = getattr(object, part)
1422 except AttributeError: return None
1423 return object
1424 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001425 if hasattr(__builtin__, path):
1426 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001427
1428# --------------------------------------- interactive interpreter interface
1429
1430text = TextDoc()
1431html = HTMLDoc()
1432
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001433def resolve(thing, forceload=0):
1434 """Given an object or a path to an object, get the object and its name."""
1435 if isinstance(thing, str):
1436 object = locate(thing, forceload)
1437 if not object:
1438 raise ImportError, 'no Python documentation found for %r' % thing
1439 return object, thing
1440 else:
1441 return thing, getattr(thing, '__name__', None)
1442
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001443def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001444 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001445 try:
1446 object, name = resolve(thing, forceload)
1447 desc = describe(object)
1448 module = inspect.getmodule(object)
1449 if name and '.' in name:
1450 desc += ' in ' + name[:name.rfind('.')]
1451 elif module and module is not object:
1452 desc += ' in module ' + module.__name__
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001453 if not (inspect.ismodule(object) or
1454 inspect.isclass(object) or
1455 inspect.isroutine(object) or
1456 isinstance(object, property)):
1457 # If the passed object is a piece of data or an instance,
1458 # document its available methods instead of its value.
1459 object = type(object)
1460 desc += ' object'
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001461 pager(title % desc + '\n\n' + text.document(object, name))
1462 except (ImportError, ErrorDuringImport), value:
1463 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001464
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001465def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001466 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001467 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001468 object, name = resolve(thing, forceload)
1469 page = html.page(describe(object), html.document(object, name))
1470 file = open(name + '.html', 'w')
1471 file.write(page)
1472 file.close()
1473 print 'wrote', name + '.html'
1474 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001475 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001476
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001477def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001478 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001479 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001480 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1481 writedoc(modname)
1482 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001483
Neal Norwitzce96f692006-03-17 06:49:51 +00001484def raw_input(prompt):
1485 sys.stdout.write(prompt)
1486 sys.stdout.flush()
1487 return sys.stdin.readline()
1488
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001489class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001490 keywords = {
1491 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001492 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001493 'break': ('ref/break', 'while for'),
1494 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1495 'continue': ('ref/continue', 'while for'),
1496 'def': ('ref/function', ''),
1497 'del': ('ref/del', 'BASICMETHODS'),
1498 'elif': 'if',
1499 'else': ('ref/if', 'while for'),
1500 'except': 'try',
1501 'exec': ('ref/exec', ''),
1502 'finally': 'try',
1503 'for': ('ref/for', 'break continue while'),
1504 'from': 'import',
1505 'global': ('ref/global', 'NAMESPACES'),
1506 'if': ('ref/if', 'TRUTHVALUE'),
1507 'import': ('ref/import', 'MODULES'),
1508 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1509 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001510 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001511 'not': 'BOOLEAN',
1512 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001513 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001514 'print': ('ref/print', ''),
1515 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001516 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001517 'try': ('ref/try', 'EXCEPTIONS'),
1518 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001519 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001520 }
1521
1522 topics = {
1523 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001524 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001525 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1526 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001527 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001528 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1529 'INTEGER': ('ref/integers', 'int range'),
1530 'FLOAT': ('ref/floating', 'float math'),
1531 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001532 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001533 'MAPPINGS': 'DICTIONARIES',
1534 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1535 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1536 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001537 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001538 'FRAMEOBJECTS': 'TYPES',
1539 'TRACEBACKS': 'TYPES',
1540 'NONE': ('lib/bltin-null-object', ''),
1541 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1542 'FILES': ('lib/bltin-file-objects', ''),
1543 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1544 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1545 'MODULES': ('lib/typesmodules', 'import'),
1546 'PACKAGES': 'import',
1547 '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'),
1548 'OPERATORS': 'EXPRESSIONS',
1549 'PRECEDENCE': 'EXPRESSIONS',
1550 'OBJECTS': ('ref/objects', 'TYPES'),
1551 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001552 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1553 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1554 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1555 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1556 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1557 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1558 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001559 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1560 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1561 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001562 'SCOPING': 'NAMESPACES',
1563 'FRAMES': 'NAMESPACES',
1564 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001565 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1566 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001567 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1568 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001569 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001570 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1571 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001572 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001573 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001574 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001575 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001576 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1577 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001578 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1579 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1580 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1581 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1582 'POWER': ('ref/power', 'EXPRESSIONS'),
1583 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1584 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1585 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1586 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1587 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001588 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001589 'ASSERTION': 'assert',
1590 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001591 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001592 'DELETION': 'del',
1593 'PRINTING': 'print',
1594 'RETURNING': 'return',
1595 'IMPORTING': 'import',
1596 'CONDITIONAL': 'if',
1597 'LOOPING': ('ref/compound', 'for while break continue'),
1598 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001599 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001600 }
1601
1602 def __init__(self, input, output):
1603 self.input = input
1604 self.output = output
1605 self.docdir = None
1606 execdir = os.path.dirname(sys.executable)
1607 homedir = os.environ.get('PYTHONHOME')
1608 for dir in [os.environ.get('PYTHONDOCS'),
1609 homedir and os.path.join(homedir, 'doc'),
1610 os.path.join(execdir, 'doc'),
1611 '/usr/doc/python-docs-' + split(sys.version)[0],
1612 '/usr/doc/python-' + split(sys.version)[0],
1613 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001614 '/usr/doc/python-' + sys.version[:3],
1615 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001616 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1617 self.docdir = dir
1618
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001619 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001620 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001621 self()
1622 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001623 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001624
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001625 def __call__(self, request=None):
1626 if request is not None:
1627 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001628 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001629 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001630 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001631 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001632You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001633If you want to ask for help on a particular object directly from the
1634interpreter, you can type "help(object)". Executing "help('string')"
1635has the same effect as typing a particular string at the help> prompt.
1636''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001637
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001638 def interact(self):
1639 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001640 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001641 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001642 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001643 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001644 except (KeyboardInterrupt, EOFError):
1645 break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001646 request = strip(replace(request, '"', '', "'", ''))
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001647 if lower(request) in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001648 self.help(request)
1649
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001650 def getline(self, prompt):
1651 """Read one line, using raw_input when available."""
1652 if self.input is sys.stdin:
1653 return raw_input(prompt)
1654 else:
1655 self.output.write(prompt)
1656 self.output.flush()
1657 return self.input.readline()
1658
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001659 def help(self, request):
1660 if type(request) is type(''):
1661 if request == 'help': self.intro()
1662 elif request == 'keywords': self.listkeywords()
1663 elif request == 'topics': self.listtopics()
1664 elif request == 'modules': self.listmodules()
1665 elif request[:8] == 'modules ':
1666 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001667 elif request in self.keywords: self.showtopic(request)
1668 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001669 elif request: doc(request, 'Help on %s:')
1670 elif isinstance(request, Helper): self()
1671 else: doc(request, 'Help on %s:')
1672 self.output.write('\n')
1673
1674 def intro(self):
1675 self.output.write('''
1676Welcome to Python %s! This is the online help utility.
1677
1678If this is your first time using Python, you should definitely check out
1679the tutorial on the Internet at http://www.python.org/doc/tut/.
1680
1681Enter the name of any module, keyword, or topic to get help on writing
1682Python programs and using Python modules. To quit this help utility and
1683return to the interpreter, just type "quit".
1684
1685To get a list of available modules, keywords, or topics, type "modules",
1686"keywords", or "topics". Each module also comes with a one-line summary
1687of what it does; to list the modules whose summaries contain a given word
1688such as "spam", type "modules spam".
1689''' % sys.version[:3])
1690
1691 def list(self, items, columns=4, width=80):
1692 items = items[:]
1693 items.sort()
1694 colw = width / columns
1695 rows = (len(items) + columns - 1) / columns
1696 for row in range(rows):
1697 for col in range(columns):
1698 i = col * rows + row
1699 if i < len(items):
1700 self.output.write(items[i])
1701 if col < columns - 1:
1702 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1703 self.output.write('\n')
1704
1705 def listkeywords(self):
1706 self.output.write('''
1707Here is a list of the Python keywords. Enter any keyword to get more help.
1708
1709''')
1710 self.list(self.keywords.keys())
1711
1712 def listtopics(self):
1713 self.output.write('''
1714Here is a list of available topics. Enter any topic name to get more help.
1715
1716''')
1717 self.list(self.topics.keys())
1718
1719 def showtopic(self, topic):
1720 if not self.docdir:
1721 self.output.write('''
1722Sorry, topic and keyword documentation is not available because the Python
1723HTML documentation files could not be found. If you have installed them,
1724please set the environment variable PYTHONDOCS to indicate their location.
1725''')
1726 return
1727 target = self.topics.get(topic, self.keywords.get(topic))
1728 if not target:
1729 self.output.write('no documentation found for %s\n' % repr(topic))
1730 return
1731 if type(target) is type(''):
1732 return self.showtopic(target)
1733
1734 filename, xrefs = target
1735 filename = self.docdir + '/' + filename + '.html'
1736 try:
1737 file = open(filename)
1738 except:
1739 self.output.write('could not read docs from %s\n' % filename)
1740 return
1741
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001742 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1743 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001744 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1745 file.close()
1746
1747 import htmllib, formatter, StringIO
1748 buffer = StringIO.StringIO()
1749 parser = htmllib.HTMLParser(
1750 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1751 parser.start_table = parser.do_p
1752 parser.end_table = lambda parser=parser: parser.do_p({})
1753 parser.start_tr = parser.do_br
1754 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1755 parser.feed(document)
1756 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1757 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001758 if xrefs:
1759 buffer = StringIO.StringIO()
1760 formatter.DumbWriter(buffer).send_flowing_data(
1761 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1762 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001763
1764 def listmodules(self, key=''):
1765 if key:
1766 self.output.write('''
1767Here is a list of matching modules. Enter any module name to get more help.
1768
1769''')
1770 apropos(key)
1771 else:
1772 self.output.write('''
1773Please wait a moment while I gather a list of all available modules...
1774
1775''')
1776 modules = {}
1777 def callback(path, modname, desc, modules=modules):
1778 if modname and modname[-9:] == '.__init__':
1779 modname = modname[:-9] + ' (package)'
1780 if find(modname, '.') < 0:
1781 modules[modname] = 1
1782 ModuleScanner().run(callback)
1783 self.list(modules.keys())
1784 self.output.write('''
1785Enter any module name to get more help. Or, type "modules spam" to search
1786for modules whose descriptions contain the word "spam".
1787''')
1788
1789help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001790
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001791class Scanner:
1792 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001793 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001794 self.roots = roots[:]
1795 self.state = []
1796 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001797 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001798
1799 def next(self):
1800 if not self.state:
1801 if not self.roots:
1802 return None
1803 root = self.roots.pop(0)
1804 self.state = [(root, self.children(root))]
1805 node, children = self.state[-1]
1806 if not children:
1807 self.state.pop()
1808 return self.next()
1809 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001810 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001811 self.state.append((child, self.children(child)))
1812 return child
1813
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001814
1815class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001816 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001817
Ka-Ping Yee66246962001-04-12 11:59:50 +00001818 def run(self, callback, key=None, completer=None):
1819 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001820 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001821 seen = {}
1822
1823 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001824 if modname != '__main__':
1825 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001826 if key is None:
1827 callback(None, modname, '')
1828 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001829 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001830 if find(lower(modname + ' - ' + desc), key) >= 0:
1831 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001832
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001833 for importer, modname, ispkg in pkgutil.walk_packages():
1834 if self.quit:
1835 break
1836 if key is None:
1837 callback(None, modname, '')
1838 else:
1839 loader = importer.find_module(modname)
1840 if hasattr(loader,'get_source'):
1841 import StringIO
1842 desc = source_synopsis(
1843 StringIO.StringIO(loader.get_source(modname))
1844 ) or ''
1845 if hasattr(loader,'get_filename'):
1846 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00001847 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001848 path = None
1849 else:
1850 module = loader.load_module(modname)
1851 desc = (module.__doc__ or '').splitlines()[0]
1852 path = getattr(module,'__file__',None)
1853 if find(lower(modname + ' - ' + desc), key) >= 0:
1854 callback(path, modname, desc)
1855
1856 if completer:
1857 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001858
1859def apropos(key):
1860 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001861 def callback(path, modname, desc):
1862 if modname[-9:] == '.__init__':
1863 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001864 print modname, desc and '- ' + desc
1865 try: import warnings
1866 except ImportError: pass
1867 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001868 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001869
1870# --------------------------------------------------- web browser interface
1871
Ka-Ping Yee66246962001-04-12 11:59:50 +00001872def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001873 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001874
1875 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1876 class Message(mimetools.Message):
1877 def __init__(self, fp, seekable=1):
1878 Message = self.__class__
1879 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1880 self.encodingheader = self.getheader('content-transfer-encoding')
1881 self.typeheader = self.getheader('content-type')
1882 self.parsetype()
1883 self.parseplist()
1884
1885 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1886 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001887 try:
1888 self.send_response(200)
1889 self.send_header('Content-Type', 'text/html')
1890 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001891 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001892 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001893
1894 def do_GET(self):
1895 path = self.path
1896 if path[-5:] == '.html': path = path[:-5]
1897 if path[:1] == '/': path = path[1:]
1898 if path and path != '.':
1899 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001900 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001901 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001902 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001903 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001904 if obj:
1905 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001906 else:
1907 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001908'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001909 else:
1910 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001911'<big><big><strong>Python: Index of Modules</strong></big></big>',
1912'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001913 def bltinlink(name):
1914 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001915 names = filter(lambda x: x != '__main__',
1916 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001917 contents = html.multicolumn(names, bltinlink)
1918 indices = ['<p>' + html.bigsection(
1919 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1920
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001921 seen = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001922 for dir in sys.path:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001923 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001924 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001925<font color="#909090" face="helvetica, arial"><strong>
1926pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001927 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001928
1929 def log_message(self, *args): pass
1930
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001931 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001932 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001933 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001934 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001935 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001936 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001937 self.base.__init__(self, self.address, self.handler)
1938
1939 def serve_until_quit(self):
1940 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001941 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001942 while not self.quit:
1943 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1944 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001945
1946 def server_activate(self):
1947 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001948 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001949
1950 DocServer.base = BaseHTTPServer.HTTPServer
1951 DocServer.handler = DocHandler
1952 DocHandler.MessageClass = Message
1953 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001954 try:
1955 DocServer(port, callback).serve_until_quit()
1956 except (KeyboardInterrupt, select.error):
1957 pass
1958 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001959 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001960
1961# ----------------------------------------------------- graphical interface
1962
1963def gui():
1964 """Graphical interface (starts web server and pops up a control window)."""
1965 class GUI:
1966 def __init__(self, window, port=7464):
1967 self.window = window
1968 self.server = None
1969 self.scanner = None
1970
1971 import Tkinter
1972 self.server_frm = Tkinter.Frame(window)
1973 self.title_lbl = Tkinter.Label(self.server_frm,
1974 text='Starting server...\n ')
1975 self.open_btn = Tkinter.Button(self.server_frm,
1976 text='open browser', command=self.open, state='disabled')
1977 self.quit_btn = Tkinter.Button(self.server_frm,
1978 text='quit serving', command=self.quit, state='disabled')
1979
1980 self.search_frm = Tkinter.Frame(window)
1981 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1982 self.search_ent = Tkinter.Entry(self.search_frm)
1983 self.search_ent.bind('<Return>', self.search)
1984 self.stop_btn = Tkinter.Button(self.search_frm,
1985 text='stop', pady=0, command=self.stop, state='disabled')
1986 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001987 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001988 self.stop_btn.pack(side='right')
1989
1990 self.window.title('pydoc')
1991 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1992 self.title_lbl.pack(side='top', fill='x')
1993 self.open_btn.pack(side='left', fill='x', expand=1)
1994 self.quit_btn.pack(side='right', fill='x', expand=1)
1995 self.server_frm.pack(side='top', fill='x')
1996
1997 self.search_lbl.pack(side='left')
1998 self.search_ent.pack(side='right', fill='x', expand=1)
1999 self.search_frm.pack(side='top', fill='x')
2000 self.search_ent.focus_set()
2001
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002002 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002003 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002004 self.result_lst.bind('<Button-1>', self.select)
2005 self.result_lst.bind('<Double-Button-1>', self.goto)
2006 self.result_scr = Tkinter.Scrollbar(window,
2007 orient='vertical', command=self.result_lst.yview)
2008 self.result_lst.config(yscrollcommand=self.result_scr.set)
2009
2010 self.result_frm = Tkinter.Frame(window)
2011 self.goto_btn = Tkinter.Button(self.result_frm,
2012 text='go to selected', command=self.goto)
2013 self.hide_btn = Tkinter.Button(self.result_frm,
2014 text='hide results', command=self.hide)
2015 self.goto_btn.pack(side='left', fill='x', expand=1)
2016 self.hide_btn.pack(side='right', fill='x', expand=1)
2017
2018 self.window.update()
2019 self.minwidth = self.window.winfo_width()
2020 self.minheight = self.window.winfo_height()
2021 self.bigminheight = (self.server_frm.winfo_reqheight() +
2022 self.search_frm.winfo_reqheight() +
2023 self.result_lst.winfo_reqheight() +
2024 self.result_frm.winfo_reqheight())
2025 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2026 self.expanded = 0
2027 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2028 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002029 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002030
2031 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002032 threading.Thread(
2033 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002034
2035 def ready(self, server):
2036 self.server = server
2037 self.title_lbl.config(
2038 text='Python documentation server at\n' + server.url)
2039 self.open_btn.config(state='normal')
2040 self.quit_btn.config(state='normal')
2041
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002042 def open(self, event=None, url=None):
2043 url = url or self.server.url
2044 try:
2045 import webbrowser
2046 webbrowser.open(url)
2047 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002048 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002049 os.system('start "%s"' % url)
2050 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002051 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002052 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002053 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002054 else:
2055 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2056 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002057
2058 def quit(self, event=None):
2059 if self.server:
2060 self.server.quit = 1
2061 self.window.quit()
2062
2063 def search(self, event=None):
2064 key = self.search_ent.get()
2065 self.stop_btn.pack(side='right')
2066 self.stop_btn.config(state='normal')
2067 self.search_lbl.config(text='Searching for "%s"...' % key)
2068 self.search_ent.forget()
2069 self.search_lbl.pack(side='left')
2070 self.result_lst.delete(0, 'end')
2071 self.goto_btn.config(state='disabled')
2072 self.expand()
2073
2074 import threading
2075 if self.scanner:
2076 self.scanner.quit = 1
2077 self.scanner = ModuleScanner()
2078 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002079 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002080
2081 def update(self, path, modname, desc):
2082 if modname[-9:] == '.__init__':
2083 modname = modname[:-9] + ' (package)'
2084 self.result_lst.insert('end',
2085 modname + ' - ' + (desc or '(no description)'))
2086
2087 def stop(self, event=None):
2088 if self.scanner:
2089 self.scanner.quit = 1
2090 self.scanner = None
2091
2092 def done(self):
2093 self.scanner = None
2094 self.search_lbl.config(text='Search for')
2095 self.search_lbl.pack(side='left')
2096 self.search_ent.pack(side='right', fill='x', expand=1)
2097 if sys.platform != 'win32': self.stop_btn.forget()
2098 self.stop_btn.config(state='disabled')
2099
2100 def select(self, event=None):
2101 self.goto_btn.config(state='normal')
2102
2103 def goto(self, event=None):
2104 selection = self.result_lst.curselection()
2105 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002106 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002107 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002108
2109 def collapse(self):
2110 if not self.expanded: return
2111 self.result_frm.forget()
2112 self.result_scr.forget()
2113 self.result_lst.forget()
2114 self.bigwidth = self.window.winfo_width()
2115 self.bigheight = self.window.winfo_height()
2116 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2117 self.window.wm_minsize(self.minwidth, self.minheight)
2118 self.expanded = 0
2119
2120 def expand(self):
2121 if self.expanded: return
2122 self.result_frm.pack(side='bottom', fill='x')
2123 self.result_scr.pack(side='right', fill='y')
2124 self.result_lst.pack(side='top', fill='both', expand=1)
2125 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2126 self.window.wm_minsize(self.minwidth, self.bigminheight)
2127 self.expanded = 1
2128
2129 def hide(self, event=None):
2130 self.stop()
2131 self.collapse()
2132
2133 import Tkinter
2134 try:
Martin v. Löwise09bd932004-08-22 16:13:26 +00002135 root = Tkinter.Tk()
2136 # Tk will crash if pythonw.exe has an XP .manifest
2137 # file and the root has is not destroyed explicitly.
2138 # If the problem is ever fixed in Tk, the explicit
2139 # destroy can go.
2140 try:
2141 gui = GUI(root)
2142 root.mainloop()
2143 finally:
2144 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002145 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002146 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002147
2148# -------------------------------------------------- command-line interface
2149
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002150def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002151 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002152
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002153def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002154 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002155 import getopt
2156 class BadUsage: pass
2157
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002158 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002159 scriptdir = os.path.dirname(sys.argv[0])
2160 if scriptdir in sys.path:
2161 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002162 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002163
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002164 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002165 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002166 writing = 0
2167
2168 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002169 if opt == '-g':
2170 gui()
2171 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002172 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002173 apropos(val)
2174 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002175 if opt == '-p':
2176 try:
2177 port = int(val)
2178 except ValueError:
2179 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002180 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002181 print 'pydoc server ready at %s' % server.url
2182 def stopped():
2183 print 'pydoc server stopped'
2184 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002185 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002186 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002187 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002188
2189 if not args: raise BadUsage
2190 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002191 if ispath(arg) and not os.path.exists(arg):
2192 print 'file %r does not exist' % arg
2193 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002194 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002195 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002196 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002197 if writing:
2198 if ispath(arg) and os.path.isdir(arg):
2199 writedocs(arg)
2200 else:
2201 writedoc(arg)
2202 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002203 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002204 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002205 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002206
2207 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002208 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002209 print """pydoc - the Python documentation tool
2210
2211%s <name> ...
2212 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002213 Python keyword, topic, function, module, or package, or a dotted
2214 reference to a class or function within a module or module in a
2215 package. If <name> contains a '%s', it is used as the path to a
2216 Python source file to document. If name is 'keywords', 'topics',
2217 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002218
2219%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002220 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002221
2222%s -p <port>
2223 Start an HTTP server on the given port on the local machine.
2224
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002225%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002226 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002227
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002228%s -w <name> ...
2229 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002230 directory. If <name> contains a '%s', it is treated as a filename; if
2231 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002232""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002233
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002234if __name__ == '__main__': cli()