blob: ff6e7ca21f84e0e118ca4fc5ac0c7ece08f29319 [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
Phillip J. Ebyceb30872006-04-18 00:59:55 +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
Phillip J. Ebyceb30872006-04-18 00:59:55 +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
Phillip J. Ebyceb30872006-04-18 00:59:55 +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
Phillip J. Ebyceb30872006-04-18 00:59:55 +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
Phillip J. Ebyceb30872006-04-18 00:59:55 +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 = []
Phillip J. Ebyceb30872006-04-18 00:59:55 +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.
Phillip J. Ebyceb30872006-04-18 00:59:55 +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 = {}
Phillip J. Ebyceb30872006-04-18 00:59:55 +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 = []
Phillip J. Ebyceb30872006-04-18 00:59:55 +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 = {}
Phillip J. Ebyceb30872006-04-18 00:59:55 +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
1484class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001485 keywords = {
1486 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001487 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001488 'break': ('ref/break', 'while for'),
1489 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1490 'continue': ('ref/continue', 'while for'),
1491 'def': ('ref/function', ''),
1492 'del': ('ref/del', 'BASICMETHODS'),
1493 'elif': 'if',
1494 'else': ('ref/if', 'while for'),
1495 'except': 'try',
1496 'exec': ('ref/exec', ''),
1497 'finally': 'try',
1498 'for': ('ref/for', 'break continue while'),
1499 'from': 'import',
1500 'global': ('ref/global', 'NAMESPACES'),
1501 'if': ('ref/if', 'TRUTHVALUE'),
1502 'import': ('ref/import', 'MODULES'),
1503 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1504 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001505 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001506 'not': 'BOOLEAN',
1507 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001508 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001509 'print': ('ref/print', ''),
1510 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001511 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001512 'try': ('ref/try', 'EXCEPTIONS'),
1513 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001514 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001515 }
1516
1517 topics = {
1518 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001519 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001520 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1521 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001522 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001523 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1524 'INTEGER': ('ref/integers', 'int range'),
1525 'FLOAT': ('ref/floating', 'float math'),
1526 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001527 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001528 'MAPPINGS': 'DICTIONARIES',
1529 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1530 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1531 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001532 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001533 'FRAMEOBJECTS': 'TYPES',
1534 'TRACEBACKS': 'TYPES',
1535 'NONE': ('lib/bltin-null-object', ''),
1536 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1537 'FILES': ('lib/bltin-file-objects', ''),
1538 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1539 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1540 'MODULES': ('lib/typesmodules', 'import'),
1541 'PACKAGES': 'import',
1542 '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'),
1543 'OPERATORS': 'EXPRESSIONS',
1544 'PRECEDENCE': 'EXPRESSIONS',
1545 'OBJECTS': ('ref/objects', 'TYPES'),
1546 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001547 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1548 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1549 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1550 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1551 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1552 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1553 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001554 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1555 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1556 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001557 'SCOPING': 'NAMESPACES',
1558 'FRAMES': 'NAMESPACES',
1559 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001560 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1561 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001562 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1563 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001564 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001565 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1566 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001567 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001568 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001569 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001570 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001571 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1572 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001573 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1574 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1575 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1576 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1577 'POWER': ('ref/power', 'EXPRESSIONS'),
1578 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1579 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1580 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1581 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1582 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001583 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001584 'ASSERTION': 'assert',
1585 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001586 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001587 'DELETION': 'del',
1588 'PRINTING': 'print',
1589 'RETURNING': 'return',
1590 'IMPORTING': 'import',
1591 'CONDITIONAL': 'if',
1592 'LOOPING': ('ref/compound', 'for while break continue'),
1593 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001594 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001595 }
1596
1597 def __init__(self, input, output):
1598 self.input = input
1599 self.output = output
1600 self.docdir = None
1601 execdir = os.path.dirname(sys.executable)
1602 homedir = os.environ.get('PYTHONHOME')
1603 for dir in [os.environ.get('PYTHONDOCS'),
1604 homedir and os.path.join(homedir, 'doc'),
1605 os.path.join(execdir, 'doc'),
1606 '/usr/doc/python-docs-' + split(sys.version)[0],
1607 '/usr/doc/python-' + split(sys.version)[0],
1608 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001609 '/usr/doc/python-' + sys.version[:3],
1610 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001611 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1612 self.docdir = dir
1613
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001614 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001615 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001616 self()
1617 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001618 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001619
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001620 def __call__(self, request=None):
1621 if request is not None:
1622 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001623 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001624 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001625 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001626 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001627You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001628If you want to ask for help on a particular object directly from the
1629interpreter, you can type "help(object)". Executing "help('string')"
1630has the same effect as typing a particular string at the help> prompt.
1631''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001632
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001633 def interact(self):
1634 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001635 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001636 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001637 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001638 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001639 except (KeyboardInterrupt, EOFError):
1640 break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001641 request = strip(replace(request, '"', '', "'", ''))
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001642 if lower(request) in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001643 self.help(request)
1644
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001645 def getline(self, prompt):
1646 """Read one line, using raw_input when available."""
1647 if self.input is sys.stdin:
1648 return raw_input(prompt)
1649 else:
1650 self.output.write(prompt)
1651 self.output.flush()
1652 return self.input.readline()
1653
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001654 def help(self, request):
1655 if type(request) is type(''):
1656 if request == 'help': self.intro()
1657 elif request == 'keywords': self.listkeywords()
1658 elif request == 'topics': self.listtopics()
1659 elif request == 'modules': self.listmodules()
1660 elif request[:8] == 'modules ':
1661 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001662 elif request in self.keywords: self.showtopic(request)
1663 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001664 elif request: doc(request, 'Help on %s:')
1665 elif isinstance(request, Helper): self()
1666 else: doc(request, 'Help on %s:')
1667 self.output.write('\n')
1668
1669 def intro(self):
1670 self.output.write('''
1671Welcome to Python %s! This is the online help utility.
1672
1673If this is your first time using Python, you should definitely check out
1674the tutorial on the Internet at http://www.python.org/doc/tut/.
1675
1676Enter the name of any module, keyword, or topic to get help on writing
1677Python programs and using Python modules. To quit this help utility and
1678return to the interpreter, just type "quit".
1679
1680To get a list of available modules, keywords, or topics, type "modules",
1681"keywords", or "topics". Each module also comes with a one-line summary
1682of what it does; to list the modules whose summaries contain a given word
1683such as "spam", type "modules spam".
1684''' % sys.version[:3])
1685
1686 def list(self, items, columns=4, width=80):
1687 items = items[:]
1688 items.sort()
1689 colw = width / columns
1690 rows = (len(items) + columns - 1) / columns
1691 for row in range(rows):
1692 for col in range(columns):
1693 i = col * rows + row
1694 if i < len(items):
1695 self.output.write(items[i])
1696 if col < columns - 1:
1697 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1698 self.output.write('\n')
1699
1700 def listkeywords(self):
1701 self.output.write('''
1702Here is a list of the Python keywords. Enter any keyword to get more help.
1703
1704''')
1705 self.list(self.keywords.keys())
1706
1707 def listtopics(self):
1708 self.output.write('''
1709Here is a list of available topics. Enter any topic name to get more help.
1710
1711''')
1712 self.list(self.topics.keys())
1713
1714 def showtopic(self, topic):
1715 if not self.docdir:
1716 self.output.write('''
1717Sorry, topic and keyword documentation is not available because the Python
1718HTML documentation files could not be found. If you have installed them,
1719please set the environment variable PYTHONDOCS to indicate their location.
1720''')
1721 return
1722 target = self.topics.get(topic, self.keywords.get(topic))
1723 if not target:
1724 self.output.write('no documentation found for %s\n' % repr(topic))
1725 return
1726 if type(target) is type(''):
1727 return self.showtopic(target)
1728
1729 filename, xrefs = target
1730 filename = self.docdir + '/' + filename + '.html'
1731 try:
1732 file = open(filename)
1733 except:
1734 self.output.write('could not read docs from %s\n' % filename)
1735 return
1736
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001737 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1738 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001739 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1740 file.close()
1741
1742 import htmllib, formatter, StringIO
1743 buffer = StringIO.StringIO()
1744 parser = htmllib.HTMLParser(
1745 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1746 parser.start_table = parser.do_p
1747 parser.end_table = lambda parser=parser: parser.do_p({})
1748 parser.start_tr = parser.do_br
1749 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1750 parser.feed(document)
1751 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1752 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001753 if xrefs:
1754 buffer = StringIO.StringIO()
1755 formatter.DumbWriter(buffer).send_flowing_data(
1756 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1757 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001758
1759 def listmodules(self, key=''):
1760 if key:
1761 self.output.write('''
1762Here is a list of matching modules. Enter any module name to get more help.
1763
1764''')
1765 apropos(key)
1766 else:
1767 self.output.write('''
1768Please wait a moment while I gather a list of all available modules...
1769
1770''')
1771 modules = {}
1772 def callback(path, modname, desc, modules=modules):
1773 if modname and modname[-9:] == '.__init__':
1774 modname = modname[:-9] + ' (package)'
1775 if find(modname, '.') < 0:
1776 modules[modname] = 1
1777 ModuleScanner().run(callback)
1778 self.list(modules.keys())
1779 self.output.write('''
1780Enter any module name to get more help. Or, type "modules spam" to search
1781for modules whose descriptions contain the word "spam".
1782''')
1783
1784help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001785
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001786class Scanner:
1787 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001788 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001789 self.roots = roots[:]
1790 self.state = []
1791 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001792 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001793
1794 def next(self):
1795 if not self.state:
1796 if not self.roots:
1797 return None
1798 root = self.roots.pop(0)
1799 self.state = [(root, self.children(root))]
1800 node, children = self.state[-1]
1801 if not children:
1802 self.state.pop()
1803 return self.next()
1804 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001805 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001806 self.state.append((child, self.children(child)))
1807 return child
1808
Phillip J. Ebyceb30872006-04-18 00:59:55 +00001809
1810class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001811 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001812
Ka-Ping Yee66246962001-04-12 11:59:50 +00001813 def run(self, callback, key=None, completer=None):
1814 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001815 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001816 seen = {}
1817
1818 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001819 if modname != '__main__':
1820 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001821 if key is None:
1822 callback(None, modname, '')
1823 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001824 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001825 if find(lower(modname + ' - ' + desc), key) >= 0:
1826 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001827
Phillip J. Ebyceb30872006-04-18 00:59:55 +00001828 for importer, modname, ispkg in pkgutil.walk_packages():
1829 if self.quit:
1830 break
1831 if key is None:
1832 callback(None, modname, '')
1833 else:
1834 loader = importer.find_module(modname)
1835 if hasattr(loader,'get_source'):
1836 import StringIO
1837 desc = source_synopsis(
1838 StringIO.StringIO(loader.get_source(modname))
1839 ) or ''
1840 if hasattr(loader,'get_filename'):
1841 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00001842 else:
Phillip J. Ebyceb30872006-04-18 00:59:55 +00001843 path = None
1844 else:
1845 module = loader.load_module(modname)
1846 desc = (module.__doc__ or '').splitlines()[0]
1847 path = getattr(module,'__file__',None)
1848 if find(lower(modname + ' - ' + desc), key) >= 0:
1849 callback(path, modname, desc)
1850
1851 if completer:
1852 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001853
1854def apropos(key):
1855 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001856 def callback(path, modname, desc):
1857 if modname[-9:] == '.__init__':
1858 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001859 print modname, desc and '- ' + desc
1860 try: import warnings
1861 except ImportError: pass
1862 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001863 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001864
1865# --------------------------------------------------- web browser interface
1866
Ka-Ping Yee66246962001-04-12 11:59:50 +00001867def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001868 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001869
1870 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1871 class Message(mimetools.Message):
1872 def __init__(self, fp, seekable=1):
1873 Message = self.__class__
1874 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1875 self.encodingheader = self.getheader('content-transfer-encoding')
1876 self.typeheader = self.getheader('content-type')
1877 self.parsetype()
1878 self.parseplist()
1879
1880 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1881 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001882 try:
1883 self.send_response(200)
1884 self.send_header('Content-Type', 'text/html')
1885 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001886 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001887 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001888
1889 def do_GET(self):
1890 path = self.path
1891 if path[-5:] == '.html': path = path[:-5]
1892 if path[:1] == '/': path = path[1:]
1893 if path and path != '.':
1894 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001895 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001896 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001897 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001898 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001899 if obj:
1900 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001901 else:
1902 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001903'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001904 else:
1905 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001906'<big><big><strong>Python: Index of Modules</strong></big></big>',
1907'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001908 def bltinlink(name):
1909 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001910 names = filter(lambda x: x != '__main__',
1911 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001912 contents = html.multicolumn(names, bltinlink)
1913 indices = ['<p>' + html.bigsection(
1914 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1915
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001916 seen = {}
Phillip J. Ebyceb30872006-04-18 00:59:55 +00001917 for dir in sys.path:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001918 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001919 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001920<font color="#909090" face="helvetica, arial"><strong>
1921pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001922 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001923
1924 def log_message(self, *args): pass
1925
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001926 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001927 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001928 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001929 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001930 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001931 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001932 self.base.__init__(self, self.address, self.handler)
1933
1934 def serve_until_quit(self):
1935 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001936 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001937 while not self.quit:
1938 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1939 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001940
1941 def server_activate(self):
1942 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001943 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001944
1945 DocServer.base = BaseHTTPServer.HTTPServer
1946 DocServer.handler = DocHandler
1947 DocHandler.MessageClass = Message
1948 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001949 try:
1950 DocServer(port, callback).serve_until_quit()
1951 except (KeyboardInterrupt, select.error):
1952 pass
1953 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001954 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001955
1956# ----------------------------------------------------- graphical interface
1957
1958def gui():
1959 """Graphical interface (starts web server and pops up a control window)."""
1960 class GUI:
1961 def __init__(self, window, port=7464):
1962 self.window = window
1963 self.server = None
1964 self.scanner = None
1965
1966 import Tkinter
1967 self.server_frm = Tkinter.Frame(window)
1968 self.title_lbl = Tkinter.Label(self.server_frm,
1969 text='Starting server...\n ')
1970 self.open_btn = Tkinter.Button(self.server_frm,
1971 text='open browser', command=self.open, state='disabled')
1972 self.quit_btn = Tkinter.Button(self.server_frm,
1973 text='quit serving', command=self.quit, state='disabled')
1974
1975 self.search_frm = Tkinter.Frame(window)
1976 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1977 self.search_ent = Tkinter.Entry(self.search_frm)
1978 self.search_ent.bind('<Return>', self.search)
1979 self.stop_btn = Tkinter.Button(self.search_frm,
1980 text='stop', pady=0, command=self.stop, state='disabled')
1981 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001982 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001983 self.stop_btn.pack(side='right')
1984
1985 self.window.title('pydoc')
1986 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1987 self.title_lbl.pack(side='top', fill='x')
1988 self.open_btn.pack(side='left', fill='x', expand=1)
1989 self.quit_btn.pack(side='right', fill='x', expand=1)
1990 self.server_frm.pack(side='top', fill='x')
1991
1992 self.search_lbl.pack(side='left')
1993 self.search_ent.pack(side='right', fill='x', expand=1)
1994 self.search_frm.pack(side='top', fill='x')
1995 self.search_ent.focus_set()
1996
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001997 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001998 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001999 self.result_lst.bind('<Button-1>', self.select)
2000 self.result_lst.bind('<Double-Button-1>', self.goto)
2001 self.result_scr = Tkinter.Scrollbar(window,
2002 orient='vertical', command=self.result_lst.yview)
2003 self.result_lst.config(yscrollcommand=self.result_scr.set)
2004
2005 self.result_frm = Tkinter.Frame(window)
2006 self.goto_btn = Tkinter.Button(self.result_frm,
2007 text='go to selected', command=self.goto)
2008 self.hide_btn = Tkinter.Button(self.result_frm,
2009 text='hide results', command=self.hide)
2010 self.goto_btn.pack(side='left', fill='x', expand=1)
2011 self.hide_btn.pack(side='right', fill='x', expand=1)
2012
2013 self.window.update()
2014 self.minwidth = self.window.winfo_width()
2015 self.minheight = self.window.winfo_height()
2016 self.bigminheight = (self.server_frm.winfo_reqheight() +
2017 self.search_frm.winfo_reqheight() +
2018 self.result_lst.winfo_reqheight() +
2019 self.result_frm.winfo_reqheight())
2020 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2021 self.expanded = 0
2022 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2023 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002024 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002025
2026 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002027 threading.Thread(
2028 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002029
2030 def ready(self, server):
2031 self.server = server
2032 self.title_lbl.config(
2033 text='Python documentation server at\n' + server.url)
2034 self.open_btn.config(state='normal')
2035 self.quit_btn.config(state='normal')
2036
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002037 def open(self, event=None, url=None):
2038 url = url or self.server.url
2039 try:
2040 import webbrowser
2041 webbrowser.open(url)
2042 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002043 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002044 os.system('start "%s"' % url)
2045 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002046 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002047 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002048 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002049 else:
2050 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2051 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002052
2053 def quit(self, event=None):
2054 if self.server:
2055 self.server.quit = 1
2056 self.window.quit()
2057
2058 def search(self, event=None):
2059 key = self.search_ent.get()
2060 self.stop_btn.pack(side='right')
2061 self.stop_btn.config(state='normal')
2062 self.search_lbl.config(text='Searching for "%s"...' % key)
2063 self.search_ent.forget()
2064 self.search_lbl.pack(side='left')
2065 self.result_lst.delete(0, 'end')
2066 self.goto_btn.config(state='disabled')
2067 self.expand()
2068
2069 import threading
2070 if self.scanner:
2071 self.scanner.quit = 1
2072 self.scanner = ModuleScanner()
2073 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002074 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002075
2076 def update(self, path, modname, desc):
2077 if modname[-9:] == '.__init__':
2078 modname = modname[:-9] + ' (package)'
2079 self.result_lst.insert('end',
2080 modname + ' - ' + (desc or '(no description)'))
2081
2082 def stop(self, event=None):
2083 if self.scanner:
2084 self.scanner.quit = 1
2085 self.scanner = None
2086
2087 def done(self):
2088 self.scanner = None
2089 self.search_lbl.config(text='Search for')
2090 self.search_lbl.pack(side='left')
2091 self.search_ent.pack(side='right', fill='x', expand=1)
2092 if sys.platform != 'win32': self.stop_btn.forget()
2093 self.stop_btn.config(state='disabled')
2094
2095 def select(self, event=None):
2096 self.goto_btn.config(state='normal')
2097
2098 def goto(self, event=None):
2099 selection = self.result_lst.curselection()
2100 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002101 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002102 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002103
2104 def collapse(self):
2105 if not self.expanded: return
2106 self.result_frm.forget()
2107 self.result_scr.forget()
2108 self.result_lst.forget()
2109 self.bigwidth = self.window.winfo_width()
2110 self.bigheight = self.window.winfo_height()
2111 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2112 self.window.wm_minsize(self.minwidth, self.minheight)
2113 self.expanded = 0
2114
2115 def expand(self):
2116 if self.expanded: return
2117 self.result_frm.pack(side='bottom', fill='x')
2118 self.result_scr.pack(side='right', fill='y')
2119 self.result_lst.pack(side='top', fill='both', expand=1)
2120 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2121 self.window.wm_minsize(self.minwidth, self.bigminheight)
2122 self.expanded = 1
2123
2124 def hide(self, event=None):
2125 self.stop()
2126 self.collapse()
2127
2128 import Tkinter
2129 try:
Martin v. Löwise09bd932004-08-22 16:13:26 +00002130 root = Tkinter.Tk()
2131 # Tk will crash if pythonw.exe has an XP .manifest
2132 # file and the root has is not destroyed explicitly.
2133 # If the problem is ever fixed in Tk, the explicit
2134 # destroy can go.
2135 try:
2136 gui = GUI(root)
2137 root.mainloop()
2138 finally:
2139 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002140 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002141 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002142
2143# -------------------------------------------------- command-line interface
2144
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002145def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002146 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002147
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002148def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002149 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002150 import getopt
2151 class BadUsage: pass
2152
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002153 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002154 scriptdir = os.path.dirname(sys.argv[0])
2155 if scriptdir in sys.path:
2156 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002157 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002158
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002159 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002160 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002161 writing = 0
2162
2163 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002164 if opt == '-g':
2165 gui()
2166 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002167 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002168 apropos(val)
2169 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002170 if opt == '-p':
2171 try:
2172 port = int(val)
2173 except ValueError:
2174 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002175 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002176 print 'pydoc server ready at %s' % server.url
2177 def stopped():
2178 print 'pydoc server stopped'
2179 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002180 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002181 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002182 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002183
2184 if not args: raise BadUsage
2185 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002186 if ispath(arg) and not os.path.exists(arg):
2187 print 'file %r does not exist' % arg
2188 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002189 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002190 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002191 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002192 if writing:
2193 if ispath(arg) and os.path.isdir(arg):
2194 writedocs(arg)
2195 else:
2196 writedoc(arg)
2197 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002198 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002199 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002200 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002201
2202 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002203 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002204 print """pydoc - the Python documentation tool
2205
2206%s <name> ...
2207 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002208 Python keyword, topic, function, module, or package, or a dotted
2209 reference to a class or function within a module or module in a
2210 package. If <name> contains a '%s', it is used as the path to a
2211 Python source file to document. If name is 'keywords', 'topics',
2212 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002213
2214%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002215 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002216
2217%s -p <port>
2218 Start an HTTP server on the given port on the local machine.
2219
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002220%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002221 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002222
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002223%s -w <name> ...
2224 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002225 directory. If <name> contains a '%s', it is treated as a filename; if
2226 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002227""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002228
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002229if __name__ == '__main__': cli()