blob: e6b53c19cd421645b40f21e3969cbddf65ff55d0 [file] [log] [blame]
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001#!/usr/bin/env python
Guido van Rossumfce538c2002-08-06 17:29:38 +00002# -*- coding: Latin-1 -*-
Ka-Ping Yee1d384632001-03-01 00:24:32 +00003"""Generate Python documentation in HTML or text for interactive use.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00004
Ka-Ping Yeedd175342001-02-27 14:43:46 +00005In the Python interpreter, do "from pydoc import help" to provide online
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00006help. Calling help(thing) on a Python object documents the object.
7
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00008Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00009
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000010Run "pydoc <name>" to show documentation on something. <name> may be
11the name of a function, module, package, or a dotted reference to a
12class or function within a module or module in a package. If the
13argument contains a path segment delimiter (e.g. slash on Unix,
14backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000015
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000016Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000018
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000019Run "pydoc -p <port>" to start an HTTP server on a given port on the
20local machine to generate documentation web pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000021
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000022For platforms without a command line, "pydoc -g" starts the HTTP server
23and also pops up a little window for controlling it.
24
25Run "pydoc -w <name>" to write out the HTML documentation for a module
26to a file named "<name>.html".
Skip Montanaro4997a692003-09-10 16:47:51 +000027
28Module docs for core modules are assumed to be in
29
30 http://www.python.org/doc/current/lib/
31
32This can be overridden by setting the PYTHONDOCS environment variable
33to a different URL or to a local directory containing the Library
34Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000035"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000036
37__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000038__date__ = "26 February 2001"
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000039__version__ = "$Revision$"
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000040__credits__ = """Guido van Rossum, for an excellent programming language.
41Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000042Paul Prescod, for all his work on onlinehelp.
43Richard Chamberlain, for the first implementation of textdoc.
44
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000045Mynd you, møøse bites Kan be pretty nasti..."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000046
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000047# Known bugs that can't be fixed here:
48# - imp.load_module() cannot be prevented from clobbering existing
49# loaded modules, so calling synopsis() on a binary module file
50# changes the contents of any existing module with the same name.
51# - If the __file__ attribute on a module is a relative path and
52# the current directory is changed with os.chdir(), an incorrect
53# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000054
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +000055import sys, imp, os, re, types, inspect, __builtin__
Ka-Ping Yeedd175342001-02-27 14:43:46 +000056from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000057from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
Raymond Hettinger756b3f32004-01-29 06:37:52 +000058from collections import deque
Ka-Ping Yeedd175342001-02-27 14:43:46 +000059
60# --------------------------------------------------------- common routines
61
Ka-Ping Yeedd175342001-02-27 14:43:46 +000062def pathdirs():
63 """Convert sys.path into a list of absolute, existing, unique paths."""
64 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000065 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000066 for dir in sys.path:
67 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000068 normdir = os.path.normcase(dir)
69 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000070 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000071 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000072 return dirs
73
74def getdoc(object):
75 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000076 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000077 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000078
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000079def splitdoc(doc):
80 """Split a doc string into a synopsis line (if any) and the rest."""
81 lines = split(strip(doc), '\n')
82 if len(lines) == 1:
83 return lines[0], ''
84 elif len(lines) >= 2 and not rstrip(lines[1]):
85 return lines[0], join(lines[2:], '\n')
86 return '', join(lines, '\n')
87
Ka-Ping Yeedd175342001-02-27 14:43:46 +000088def classname(object, modname):
89 """Get a class name and qualify it with a module name if necessary."""
90 name = object.__name__
91 if object.__module__ != modname:
92 name = object.__module__ + '.' + name
93 return name
94
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000095def isdata(object):
96 """Check if an object is of a type that probably means it's data."""
97 return not (inspect.ismodule(object) or inspect.isclass(object) or
98 inspect.isroutine(object) or inspect.isframe(object) or
99 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000100
101def replace(text, *pairs):
102 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000103 while pairs:
104 text = join(split(text, pairs[0]), pairs[1])
105 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000106 return text
107
108def cram(text, maxlen):
109 """Omit part of a string if needed to make it fit in a maximum length."""
110 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000111 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000112 post = max(0, maxlen-3-pre)
113 return text[:pre] + '...' + text[len(text)-post:]
114 return text
115
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000116def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000117 """Remove the hexadecimal id from a Python object representation."""
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000118 # The behaviour of %p is implementation-dependent; we check two cases.
Ka-Ping Yee45daeb02002-08-11 15:11:33 +0000119 for pattern in [' at 0x[0-9a-f]{6,}(>+)$', ' at [0-9A-F]{8,}(>+)$']:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000120 if re.search(pattern, repr(Exception)):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +0000121 return re.sub(pattern, '\\1', text)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000122 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000123
Tim Peters536d2262001-09-20 05:13:38 +0000124def _is_some_method(object):
125 return inspect.ismethod(object) or inspect.ismethoddescriptor(object)
126
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000127def allmethods(cl):
128 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000129 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000130 methods[key] = 1
131 for base in cl.__bases__:
132 methods.update(allmethods(base)) # all your base are belong to us
133 for key in methods.keys():
134 methods[key] = getattr(cl, key)
135 return methods
136
Tim Petersfa26f7c2001-09-24 08:05:11 +0000137def _split_list(s, predicate):
138 """Split sequence s via predicate, and return pair ([true], [false]).
139
140 The return value is a 2-tuple of lists,
141 ([x for x in s if predicate(x)],
142 [x for x in s if not predicate(x)])
143 """
144
Tim Peters28355492001-09-23 21:29:55 +0000145 yes = []
146 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000147 for x in s:
148 if predicate(x):
149 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000150 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000151 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000152 return yes, no
153
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000154def visiblename(name):
155 """Decide whether to show documentation on a variable."""
156 # Certain special names are redundant.
157 if name in ['__builtins__', '__doc__', '__file__', '__path__',
158 '__module__', '__name__']: return 0
159 # Private names are hidden, but special names are displayed.
160 if name.startswith('__') and name.endswith('__'): return 1
161 return not name.startswith('_')
162
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000163# ----------------------------------------------------- module manipulation
164
165def ispackage(path):
166 """Guess whether a path refers to a package directory."""
167 if os.path.isdir(path):
168 for ext in ['.py', '.pyc', '.pyo']:
169 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000170 return True
171 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000172
173def synopsis(filename, cache={}):
174 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000175 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000176 lastupdate, result = cache.get(filename, (0, None))
177 if lastupdate < mtime:
178 info = inspect.getmoduleinfo(filename)
179 file = open(filename)
180 if info and 'b' in info[2]: # binary modules have to be imported
181 try: module = imp.load_module('__temp__', file, filename, info[1:])
182 except: return None
183 result = split(module.__doc__ or '', '\n')[0]
184 del sys.modules['__temp__']
185 else: # text modules can be directly examined
186 line = file.readline()
187 while line[:1] == '#' or not strip(line):
188 line = file.readline()
189 if not line: break
190 line = strip(line)
191 if line[:4] == 'r"""': line = line[1:]
192 if line[:3] == '"""':
193 line = line[3:]
194 if line[-1:] == '\\': line = line[:-1]
195 while not strip(line):
196 line = file.readline()
197 if not line: break
198 result = strip(split(line, '"""')[0])
199 else: result = None
200 file.close()
201 cache[filename] = (mtime, result)
202 return result
203
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000204class ErrorDuringImport(Exception):
205 """Errors that occurred while trying to import something to document it."""
206 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000207 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000208 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000209 self.value = value
210 self.tb = tb
211
212 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000213 exc = self.exc
214 if type(exc) is types.ClassType:
215 exc = exc.__name__
216 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000217
218def importfile(path):
219 """Import a Python source file or compiled file given its path."""
220 magic = imp.get_magic()
221 file = open(path, 'r')
222 if file.read(len(magic)) == magic:
223 kind = imp.PY_COMPILED
224 else:
225 kind = imp.PY_SOURCE
226 file.close()
227 filename = os.path.basename(path)
228 name, ext = os.path.splitext(filename)
229 file = open(path, 'r')
230 try:
231 module = imp.load_module(name, file, path, (ext, 'r', kind))
232 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000233 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000234 file.close()
235 return module
236
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000237def safeimport(path, forceload=0, cache={}):
238 """Import a module; handle errors; return None if the module isn't found.
239
240 If the module *is* found but an exception occurs, it's wrapped in an
241 ErrorDuringImport exception and reraised. Unlike __import__, if a
242 package path is specified, the module at the end of the path is returned,
243 not the package at the beginning. If the optional 'forceload' argument
244 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000245 if forceload and path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000246 # This is the only way to be sure. Checking the mtime of the file
247 # isn't good enough (e.g. what if the module contains a class that
248 # inherits from another module that has changed?).
249 if path not in sys.builtin_module_names:
250 # Python never loads a dynamic extension a second time from the
251 # same path, even if the file is changed or missing. Deleting
252 # the entry in sys.modules doesn't help for dynamic extensions,
253 # so we're not even going to try to keep them up to date.
254 info = inspect.getmoduleinfo(sys.modules[path].__file__)
255 if info[3] != imp.C_EXTENSION:
256 cache[path] = sys.modules[path] # prevent module from clearing
257 del sys.modules[path]
258 try:
259 module = __import__(path)
260 except:
261 # Did the error occur before or after the module was found?
262 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000263 if path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000264 # An error occured while executing the imported module.
265 raise ErrorDuringImport(sys.modules[path].__file__, info)
266 elif exc is SyntaxError:
267 # A SyntaxError occurred before we could execute the module.
268 raise ErrorDuringImport(value.filename, info)
269 elif exc is ImportError and \
270 split(lower(str(value)))[:2] == ['no', 'module']:
271 # The module was not found.
272 return None
273 else:
274 # Some other error occurred during the importing process.
275 raise ErrorDuringImport(path, sys.exc_info())
276 for part in split(path, '.')[1:]:
277 try: module = getattr(module, part)
278 except AttributeError: return None
279 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000280
281# ---------------------------------------------------- formatter base class
282
283class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000284 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000285 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000286 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000287 # 'try' clause is to attempt to handle the possibility that inspect
288 # identifies something in a way that pydoc itself has issues handling;
289 # think 'super' and how it is a descriptor (which raises the exception
290 # by lacking a __name__ attribute) and an instance.
291 try:
292 if inspect.ismodule(object): return self.docmodule(*args)
293 if inspect.isclass(object): return self.docclass(*args)
294 if inspect.isroutine(object): return self.docroutine(*args)
295 except AttributeError:
296 pass
Guido van Rossum68468eb2003-02-27 20:14:51 +0000297 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000298
299 def fail(self, object, name=None, *args):
300 """Raise an exception for unimplemented types."""
301 message = "don't know how to document object%s of type %s" % (
302 name and ' ' + repr(name), type(object).__name__)
303 raise TypeError, message
304
305 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000306
Skip Montanaro4997a692003-09-10 16:47:51 +0000307 def getdocloc(self, object):
308 """Return the location of module docs or None"""
309
310 try:
311 file = inspect.getabsfile(object)
312 except TypeError:
313 file = '(built-in)'
314
315 docloc = os.environ.get("PYTHONDOCS",
316 "http://www.python.org/doc/current/lib")
317 basedir = os.path.join(sys.exec_prefix, "lib",
318 "python"+sys.version[0:3])
319 if (isinstance(object, type(os)) and
320 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
321 'marshal', 'posix', 'signal', 'sys',
322 'thread', 'zipimport') or
323 (file.startswith(basedir) and
324 not file.startswith(os.path.join(basedir, 'site-packages'))))):
325 if docloc.startswith("http://"):
326 docloc = (docloc.rstrip("/") +
327 "/module-%s.html" % object.__name__)
328 else:
329 docloc = os.path.join(docloc, "module-%s.html" % name)
330 else:
331 docloc = None
332 return docloc
333
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000334# -------------------------------------------- HTML documentation generator
335
336class HTMLRepr(Repr):
337 """Class for safely making an HTML representation of a Python object."""
338 def __init__(self):
339 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000340 self.maxlist = self.maxtuple = 20
341 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000342 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000343
344 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000345 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000346
347 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000348 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000349
350 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000351 if hasattr(type(x), '__name__'):
352 methodname = 'repr_' + join(split(type(x).__name__), '_')
353 if hasattr(self, methodname):
354 return getattr(self, methodname)(x, level)
355 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000356
357 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000358 test = cram(x, self.maxstring)
359 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000360 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000361 # Backslashes are only literal in the string and are never
362 # needed to make any special characters, so show a raw string.
363 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000364 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000365 r'<font color="#c040c0">\1</font>',
366 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000367
Skip Montanarodf708782002-03-07 22:58:02 +0000368 repr_str = repr_string
369
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000370 def repr_instance(self, x, level):
371 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000372 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000373 except:
374 return self.escape('<%s instance>' % x.__class__.__name__)
375
376 repr_unicode = repr_string
377
378class HTMLDoc(Doc):
379 """Formatter class for HTML documentation."""
380
381 # ------------------------------------------- HTML formatting utilities
382
383 _repr_instance = HTMLRepr()
384 repr = _repr_instance.repr
385 escape = _repr_instance.escape
386
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000387 def page(self, title, contents):
388 """Format an HTML page."""
389 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000390<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000391<html><head><title>Python: %s</title>
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000392</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000393%s
394</body></html>''' % (title, contents)
395
396 def heading(self, title, fgcol, bgcol, extras=''):
397 """Format a page heading."""
398 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000399<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000400<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000401<td valign=bottom>&nbsp;<br>
402<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000403><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000404><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000405 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
406
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000407 def section(self, title, fgcol, bgcol, contents, width=6,
408 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000409 """Format a section with a heading."""
410 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000411 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000412 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000413<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000414<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000415<td colspan=3 valign=bottom>&nbsp;<br>
416<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000417 ''' % (bgcol, fgcol, title)
418 if prelude:
419 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000420<tr bgcolor="%s"><td rowspan=2>%s</td>
421<td colspan=2>%s</td></tr>
422<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
423 else:
424 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000425<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000426
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000427 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000428
429 def bigsection(self, title, *args):
430 """Format a section with a big heading."""
431 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000432 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000433
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000434 def preformat(self, text):
435 """Format literal preformatted text."""
436 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000437 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
438 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000439
440 def multicolumn(self, list, format, cols=4):
441 """Format a list of items into a multi-column list."""
442 result = ''
443 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000444 for col in range(cols):
445 result = result + '<td width="%d%%" valign=top>' % (100/cols)
446 for i in range(rows*col, rows*col+rows):
447 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000448 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000449 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000450 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000451
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000452 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000453
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000454 def namelink(self, name, *dicts):
455 """Make a link for an identifier, given name-to-URL mappings."""
456 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000457 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000458 return '<a href="%s">%s</a>' % (dict[name], name)
459 return name
460
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000461 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000462 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000463 name, module = object.__name__, sys.modules.get(object.__module__)
464 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000465 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000466 module.__name__, name, classname(object, modname))
467 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000468
469 def modulelink(self, object):
470 """Make a link for a module."""
471 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
472
473 def modpkglink(self, (name, path, ispackage, shadowed)):
474 """Make a link for a module or package to display in an index."""
475 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000476 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000477 if path:
478 url = '%s.%s.html' % (path, name)
479 else:
480 url = '%s.html' % name
481 if ispackage:
482 text = '<strong>%s</strong>&nbsp;(package)' % name
483 else:
484 text = name
485 return '<a href="%s">%s</a>' % (url, text)
486
487 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
488 """Mark up some plain text, given a context of symbols to look for.
489 Each context dictionary maps object names to anchor names."""
490 escape = escape or self.escape
491 results = []
492 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000493 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
494 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000495 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000496 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000497 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000498 match = pattern.search(text, here)
499 if not match: break
500 start, end = match.span()
501 results.append(escape(text[here:start]))
502
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000503 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000504 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000505 url = escape(all).replace('"', '&quot;')
506 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000507 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000508 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
509 results.append('<a href="%s">%s</a>' % (url, escape(all)))
510 elif pep:
511 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000512 results.append('<a href="%s">%s</a>' % (url, escape(all)))
513 elif text[end:end+1] == '(':
514 results.append(self.namelink(name, methods, funcs, classes))
515 elif selfdot:
516 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000517 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000518 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000519 here = end
520 results.append(escape(text[here:]))
521 return join(results, '')
522
523 # ---------------------------------------------- type-specific routines
524
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000525 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000526 """Produce HTML for a class tree as given by inspect.getclasstree()."""
527 result = ''
528 for entry in tree:
529 if type(entry) is type(()):
530 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000531 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000532 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000533 if bases and bases != (parent,):
534 parents = []
535 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000536 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000537 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000538 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000539 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000540 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000541 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000542 return '<dl>\n%s</dl>\n' % result
543
Tim Peters8dd7ade2001-10-18 19:56:17 +0000544 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000545 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000546 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000547 parts = split(name, '.')
548 links = []
549 for i in range(len(parts)-1):
550 links.append(
551 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
552 (join(parts[:i+1], '.'), parts[i]))
553 linkedname = join(links + parts[-1:], '.')
554 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000555 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000556 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000557 url = path
558 if sys.platform == 'win32':
559 import nturl2path
560 url = nturl2path.pathname2url(path)
561 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000562 except TypeError:
563 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000564 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000565 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000566 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000567 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
568 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000569 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000570 if hasattr(object, '__date__'):
571 info.append(self.escape(str(object.__date__)))
572 if info:
573 head = head + ' (%s)' % join(info, ', ')
Skip Montanaro4997a692003-09-10 16:47:51 +0000574 docloc = self.getdocloc(object)
575 if docloc is not None:
576 docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
577 else:
578 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000579 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000580 head, '#ffffff', '#7799ee',
581 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000582
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000583 modules = inspect.getmembers(object, inspect.ismodule)
584
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000585 classes, cdict = [], {}
586 for key, value in inspect.getmembers(object, inspect.isclass):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000587 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000588 if visiblename(key):
589 classes.append((key, value))
590 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000591 for key, value in classes:
592 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000593 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000594 module = sys.modules.get(modname)
595 if modname != name and module and hasattr(module, key):
596 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000597 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000598 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000599 funcs, fdict = [], {}
600 for key, value in inspect.getmembers(object, inspect.isroutine):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000601 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000602 if visiblename(key):
603 funcs.append((key, value))
604 fdict[key] = '#-' + key
605 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000606 data = []
607 for key, value in inspect.getmembers(object, isdata):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000608 if visiblename(key):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000609 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000610
611 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
612 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000613 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000614
615 if hasattr(object, '__path__'):
616 modpkgs = []
617 modnames = []
618 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000619 path = os.path.join(object.__path__[0], file)
620 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000621 if modname != '__init__':
622 if modname and modname not in modnames:
623 modpkgs.append((modname, name, 0, 0))
624 modnames.append(modname)
625 elif ispackage(path):
626 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000627 modpkgs.sort()
628 contents = self.multicolumn(modpkgs, self.modpkglink)
629 result = result + self.bigsection(
630 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000631 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000632 contents = self.multicolumn(
633 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000634 result = result + self.bigsection(
635 'Modules', '#fffff', '#aa55cc', contents)
636
637 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000638 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000639 contents = [
640 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000641 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000642 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000643 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000644 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000645 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000646 contents = []
647 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000648 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000649 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000650 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000651 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000652 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000653 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000654 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000655 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000656 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000657 if hasattr(object, '__author__'):
658 contents = self.markup(str(object.__author__), self.preformat)
659 result = result + self.bigsection(
660 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000661 if hasattr(object, '__credits__'):
662 contents = self.markup(str(object.__credits__), self.preformat)
663 result = result + self.bigsection(
664 'Credits', '#ffffff', '#7799ee', contents)
665
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000666 return result
667
Tim Peters8dd7ade2001-10-18 19:56:17 +0000668 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
669 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000670 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000671 realname = object.__name__
672 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000673 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000674
Tim Petersb47879b2001-09-24 04:47:19 +0000675 contents = []
676 push = contents.append
677
Tim Petersfa26f7c2001-09-24 08:05:11 +0000678 # Cute little class to pump out a horizontal rule between sections.
679 class HorizontalRule:
680 def __init__(self):
681 self.needone = 0
682 def maybe(self):
683 if self.needone:
684 push('<hr>\n')
685 self.needone = 1
686 hr = HorizontalRule()
687
Tim Petersc86f6ca2001-09-26 21:31:51 +0000688 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000689 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000690 if len(mro) > 2:
691 hr.maybe()
692 push('<dl><dt>Method resolution order:</dt>\n')
693 for base in mro:
694 push('<dd>%s</dd>\n' % self.classlink(base,
695 object.__module__))
696 push('</dl>\n')
697
Tim Petersb47879b2001-09-24 04:47:19 +0000698 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000699 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000700 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000701 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000702 push(msg)
703 for name, kind, homecls, value in ok:
704 push(self.document(getattr(object, name), name, mod,
705 funcs, classes, mdict, object))
706 push('\n')
707 return attrs
708
Tim Petersfa26f7c2001-09-24 08:05:11 +0000709 def spillproperties(msg, attrs, predicate):
710 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000711 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000712 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000713 push(msg)
714 for name, kind, homecls, value in ok:
Tim Peters3e767d12001-09-25 00:01:06 +0000715 push('<dl><dt><strong>%s</strong></dt>\n' % name)
716 if value.__doc__ is not None:
717 doc = self.markup(value.__doc__, self.preformat,
718 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000719 push('<dd><tt>%s</tt></dd>\n' % doc)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000720 for attr, tag in [('fget', '<em>get</em>'),
721 ('fset', '<em>set</em>'),
722 ('fdel', '<em>delete</em>')]:
Tim Peters3e767d12001-09-25 00:01:06 +0000723 func = getattr(value, attr)
724 if func is not None:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000725 base = self.document(func, tag, mod,
Tim Peters3e767d12001-09-25 00:01:06 +0000726 funcs, classes, mdict, object)
727 push('<dd>%s</dd>\n' % base)
728 push('</dl>\n')
Tim Petersb47879b2001-09-24 04:47:19 +0000729 return attrs
730
Tim Petersfa26f7c2001-09-24 08:05:11 +0000731 def spilldata(msg, attrs, predicate):
732 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000733 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000734 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000735 push(msg)
736 for name, kind, homecls, value in ok:
737 base = self.docother(getattr(object, name), name, mod)
Martin v. Löwise59e2ba2003-05-03 09:09:02 +0000738 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000739 doc = getattr(value, "__doc__", None)
740 else:
741 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000742 if doc is None:
743 push('<dl><dt>%s</dl>\n' % base)
744 else:
745 doc = self.markup(getdoc(value), self.preformat,
746 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000747 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000748 push('<dl><dt>%s%s</dl>\n' % (base, doc))
749 push('\n')
750 return attrs
751
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000752 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
753 inspect.classify_class_attrs(object))
Tim Petersb47879b2001-09-24 04:47:19 +0000754 mdict = {}
755 for key, kind, homecls, value in attrs:
756 mdict[key] = anchor = '#' + name + '-' + key
757 value = getattr(object, key)
758 try:
759 # The value may not be hashable (e.g., a data attr with
760 # a dict or list value).
761 mdict[value] = anchor
762 except TypeError:
763 pass
764
Tim Petersfa26f7c2001-09-24 08:05:11 +0000765 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000766 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000767 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000768 else:
769 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000770 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
771
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000772 if thisclass is __builtin__.object:
773 attrs = inherited
774 continue
775 elif thisclass is object:
776 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000777 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000778 tag = 'inherited from %s' % self.classlink(thisclass,
779 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000780 tag += ':<br>\n'
781
782 # Sort attrs by name.
Raymond Hettinger6b59f5f2003-10-16 05:53:16 +0000783 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000784
785 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000786 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000787 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000788 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000789 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000790 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000791 lambda t: t[1] == 'static method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000792 attrs = spillproperties('Properties %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000793 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000794 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000795 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000796 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000797 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000798
799 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000800
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000801 if name == realname:
802 title = '<a name="%s">class <strong>%s</strong></a>' % (
803 name, realname)
804 else:
805 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
806 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000807 if bases:
808 parents = []
809 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000810 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000811 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000812 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000813 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000814
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000815 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000816
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000817 def formatvalue(self, object):
818 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000819 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000820
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000821 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000822 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000823 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000824 realname = object.__name__
825 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000826 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000827 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000828 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000829 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000830 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000831 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000832 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000833 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000834 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000835 if object.im_self:
836 note = ' method of %s instance' % self.classlink(
837 object.im_self.__class__, mod)
838 else:
839 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000840 object = object.im_func
841
842 if name == realname:
843 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
844 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000845 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000846 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000847 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000848 cl.__name__ + '-' + realname, realname)
849 skipdocs = 1
850 else:
851 reallink = realname
852 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
853 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000854 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000855 args, varargs, varkw, defaults = inspect.getargspec(object)
856 argspec = inspect.formatargspec(
857 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000858 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000859 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000860 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000861 else:
862 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000863
Tim Peters2306d242001-09-25 03:18:32 +0000864 decl = title + argspec + (note and self.grey(
865 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000866
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000867 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000868 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000869 else:
870 doc = self.markup(
871 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000872 doc = doc and '<dd><tt>%s</tt></dd>' % doc
873 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000874
Tim Peters8dd7ade2001-10-18 19:56:17 +0000875 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000876 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000877 lhs = name and '<strong>%s</strong> = ' % name or ''
878 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000879
880 def index(self, dir, shadowed=None):
881 """Generate an HTML index for a directory of modules."""
882 modpkgs = []
883 if shadowed is None: shadowed = {}
884 seen = {}
885 files = os.listdir(dir)
886
887 def found(name, ispackage,
888 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
Raymond Hettinger4f759d82002-11-02 02:02:46 +0000889 if name not in seen:
890 modpkgs.append((name, '', ispackage, name in shadowed))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000891 seen[name] = 1
892 shadowed[name] = 1
893
894 # Package spam/__init__.py takes precedence over module spam.py.
895 for file in files:
896 path = os.path.join(dir, file)
897 if ispackage(path): found(file, 1)
898 for file in files:
899 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000900 if os.path.isfile(path):
901 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000902 if modname: found(modname, 0)
903
904 modpkgs.sort()
905 contents = self.multicolumn(modpkgs, self.modpkglink)
906 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
907
908# -------------------------------------------- text documentation generator
909
910class TextRepr(Repr):
911 """Class for safely making a text representation of a Python object."""
912 def __init__(self):
913 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000914 self.maxlist = self.maxtuple = 20
915 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000916 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000917
918 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000919 if hasattr(type(x), '__name__'):
920 methodname = 'repr_' + join(split(type(x).__name__), '_')
921 if hasattr(self, methodname):
922 return getattr(self, methodname)(x, level)
923 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000924
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000925 def repr_string(self, x, level):
926 test = cram(x, self.maxstring)
927 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000928 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000929 # Backslashes are only literal in the string and are never
930 # needed to make any special characters, so show a raw string.
931 return 'r' + testrepr[0] + test + testrepr[0]
932 return testrepr
933
Skip Montanarodf708782002-03-07 22:58:02 +0000934 repr_str = repr_string
935
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000936 def repr_instance(self, x, level):
937 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000938 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000939 except:
940 return '<%s instance>' % x.__class__.__name__
941
942class TextDoc(Doc):
943 """Formatter class for text documentation."""
944
945 # ------------------------------------------- text formatting utilities
946
947 _repr_instance = TextRepr()
948 repr = _repr_instance.repr
949
950 def bold(self, text):
951 """Format a string in bold by overstriking."""
952 return join(map(lambda ch: ch + '\b' + ch, text), '')
953
954 def indent(self, text, prefix=' '):
955 """Indent text by prepending a given prefix to each line."""
956 if not text: return ''
957 lines = split(text, '\n')
958 lines = map(lambda line, prefix=prefix: prefix + line, lines)
959 if lines: lines[-1] = rstrip(lines[-1])
960 return join(lines, '\n')
961
962 def section(self, title, contents):
963 """Format a section with a given heading."""
964 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
965
966 # ---------------------------------------------- type-specific routines
967
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000968 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000969 """Render in text a class tree as returned by inspect.getclasstree()."""
970 result = ''
971 for entry in tree:
972 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000973 c, bases = entry
974 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000975 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000976 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000977 result = result + '(%s)' % join(parents, ', ')
978 result = result + '\n'
979 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000980 result = result + self.formattree(
981 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000982 return result
983
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000984 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000985 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000986 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000987 synop, desc = splitdoc(getdoc(object))
988 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000989
990 try:
991 file = inspect.getabsfile(object)
992 except TypeError:
993 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000994 result = result + self.section('FILE', file)
Skip Montanaro4997a692003-09-10 16:47:51 +0000995
996 docloc = self.getdocloc(object)
997 if docloc is not None:
998 result = result + self.section('MODULE DOCS', docloc)
999
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001000 if desc:
1001 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001002
1003 classes = []
1004 for key, value in inspect.getmembers(object, inspect.isclass):
1005 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001006 if visiblename(key):
1007 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001008 funcs = []
1009 for key, value in inspect.getmembers(object, inspect.isroutine):
1010 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001011 if visiblename(key):
1012 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001013 data = []
1014 for key, value in inspect.getmembers(object, isdata):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001015 if visiblename(key):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001016 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001017
1018 if hasattr(object, '__path__'):
1019 modpkgs = []
1020 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001021 path = os.path.join(object.__path__[0], file)
1022 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001023 if modname != '__init__':
1024 if modname and modname not in modpkgs:
1025 modpkgs.append(modname)
1026 elif ispackage(path):
1027 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001028 modpkgs.sort()
1029 result = result + self.section(
1030 'PACKAGE CONTENTS', join(modpkgs, '\n'))
1031
1032 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001033 classlist = map(lambda (key, value): value, classes)
1034 contents = [self.formattree(
1035 inspect.getclasstree(classlist, 1), name)]
1036 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001037 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001038 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001039
1040 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001041 contents = []
1042 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001043 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001044 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001045
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001046 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001047 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001048 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001049 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001050 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001051
1052 if hasattr(object, '__version__'):
1053 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001054 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1055 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001056 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001057 if hasattr(object, '__date__'):
1058 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001059 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001060 result = result + self.section('AUTHOR', str(object.__author__))
1061 if hasattr(object, '__credits__'):
1062 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001063 return result
1064
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001065 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001066 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001067 realname = object.__name__
1068 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001069 bases = object.__bases__
1070
Tim Petersc86f6ca2001-09-26 21:31:51 +00001071 def makename(c, m=object.__module__):
1072 return classname(c, m)
1073
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001074 if name == realname:
1075 title = 'class ' + self.bold(realname)
1076 else:
1077 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001078 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001079 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001080 title = title + '(%s)' % join(parents, ', ')
1081
1082 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001083 contents = doc and [doc + '\n'] or []
1084 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001085
Tim Petersc86f6ca2001-09-26 21:31:51 +00001086 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001087 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001088 if len(mro) > 2:
1089 push("Method resolution order:")
1090 for base in mro:
1091 push(' ' + makename(base))
1092 push('')
1093
Tim Petersf4aad8e2001-09-24 22:40:47 +00001094 # Cute little class to pump out a horizontal rule between sections.
1095 class HorizontalRule:
1096 def __init__(self):
1097 self.needone = 0
1098 def maybe(self):
1099 if self.needone:
1100 push('-' * 70)
1101 self.needone = 1
1102 hr = HorizontalRule()
1103
Tim Peters28355492001-09-23 21:29:55 +00001104 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001105 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001106 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001107 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001108 push(msg)
1109 for name, kind, homecls, value in ok:
1110 push(self.document(getattr(object, name),
1111 name, mod, object))
1112 return attrs
1113
Tim Petersfa26f7c2001-09-24 08:05:11 +00001114 def spillproperties(msg, attrs, predicate):
1115 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001116 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001117 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001118 push(msg)
1119 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001120 push(name)
1121 need_blank_after_doc = 0
1122 doc = getdoc(value) or ''
1123 if doc:
1124 push(self.indent(doc))
1125 need_blank_after_doc = 1
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001126 for attr, tag in [('fget', '<get>'),
1127 ('fset', '<set>'),
1128 ('fdel', '<delete>')]:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001129 func = getattr(value, attr)
1130 if func is not None:
1131 if need_blank_after_doc:
1132 push('')
1133 need_blank_after_doc = 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001134 base = self.document(func, tag, mod)
Tim Petersf4aad8e2001-09-24 22:40:47 +00001135 push(self.indent(base))
Tim Peters28355492001-09-23 21:29:55 +00001136 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001137
Tim Petersfa26f7c2001-09-24 08:05:11 +00001138 def spilldata(msg, attrs, predicate):
1139 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001140 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001141 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001142 push(msg)
1143 for name, kind, homecls, value in ok:
Martin v. Löwise59e2ba2003-05-03 09:09:02 +00001144 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +00001145 doc = getattr(value, "__doc__", None)
1146 else:
1147 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001148 push(self.docother(getattr(object, name),
1149 name, mod, 70, doc) + '\n')
1150 return attrs
1151
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001152 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
1153 inspect.classify_class_attrs(object))
Tim Petersfa26f7c2001-09-24 08:05:11 +00001154 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001155 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001156 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001157 else:
1158 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001159 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1160
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001161 if thisclass is __builtin__.object:
1162 attrs = inherited
1163 continue
1164 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001165 tag = "defined here"
1166 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001167 tag = "inherited from %s" % classname(thisclass,
1168 object.__module__)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001169 filter(lambda t: not t[0].startswith('_'), attrs)
Tim Peters28355492001-09-23 21:29:55 +00001170
1171 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001172 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001173
1174 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001175 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001176 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001177 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001178 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001179 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001180 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001181 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001182 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001183 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1184 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001185 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001186 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001187
1188 contents = '\n'.join(contents)
1189 if not contents:
1190 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001191 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1192
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001193 def formatvalue(self, object):
1194 """Format an argument default value as text."""
1195 return '=' + self.repr(object)
1196
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001197 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001198 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001199 realname = object.__name__
1200 name = name or realname
1201 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001202 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001203 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001204 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001205 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001206 if imclass is not cl:
1207 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001208 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001209 if object.im_self:
1210 note = ' method of %s instance' % classname(
1211 object.im_self.__class__, mod)
1212 else:
1213 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001214 object = object.im_func
1215
1216 if name == realname:
1217 title = self.bold(realname)
1218 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001219 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001220 cl.__dict__[realname] is object):
1221 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001222 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001223 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001224 args, varargs, varkw, defaults = inspect.getargspec(object)
1225 argspec = inspect.formatargspec(
1226 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001227 if realname == '<lambda>':
1228 title = 'lambda'
1229 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001230 else:
1231 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001232 decl = title + argspec + note
1233
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001234 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001235 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001236 else:
1237 doc = getdoc(object) or ''
1238 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001239
Tim Peters28355492001-09-23 21:29:55 +00001240 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001241 """Produce text documentation for a data object."""
1242 repr = self.repr(object)
1243 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001244 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001245 chop = maxlen - len(line)
1246 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001247 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001248 if doc is not None:
1249 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001250 return line
1251
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001252# --------------------------------------------------------- user interfaces
1253
1254def pager(text):
1255 """The first time this is called, determine what kind of pager to use."""
1256 global pager
1257 pager = getpager()
1258 pager(text)
1259
1260def getpager():
1261 """Decide what method to use for paging through text."""
1262 if type(sys.stdout) is not types.FileType:
1263 return plainpager
1264 if not sys.stdin.isatty() or not sys.stdout.isatty():
1265 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001266 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001267 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001268 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001269 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001270 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1271 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1272 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001273 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001274 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001275 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001276 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001277 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001278 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001279
1280 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001281 (fd, filename) = tempfile.mkstemp()
1282 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001283 try:
1284 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1285 return lambda text: pipepager(text, 'more')
1286 else:
1287 return ttypager
1288 finally:
1289 os.unlink(filename)
1290
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001291def plain(text):
1292 """Remove boldface formatting from text."""
1293 return re.sub('.\b', '', text)
1294
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001295def pipepager(text, cmd):
1296 """Page through text by feeding it to another program."""
1297 pipe = os.popen(cmd, 'w')
1298 try:
1299 pipe.write(text)
1300 pipe.close()
1301 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001302 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001303
1304def tempfilepager(text, cmd):
1305 """Page through text by invoking a program on a temporary file."""
1306 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001307 filename = tempfile.mktemp()
1308 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001309 file.write(text)
1310 file.close()
1311 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001312 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001313 finally:
1314 os.unlink(filename)
1315
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001316def ttypager(text):
1317 """Page through text on a text terminal."""
1318 lines = split(plain(text), '\n')
1319 try:
1320 import tty
1321 fd = sys.stdin.fileno()
1322 old = tty.tcgetattr(fd)
1323 tty.setcbreak(fd)
1324 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001325 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001326 tty = None
1327 getchar = lambda: sys.stdin.readline()[:-1][:1]
1328
1329 try:
1330 r = inc = os.environ.get('LINES', 25) - 1
1331 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1332 while lines[r:]:
1333 sys.stdout.write('-- more --')
1334 sys.stdout.flush()
1335 c = getchar()
1336
1337 if c in ['q', 'Q']:
1338 sys.stdout.write('\r \r')
1339 break
1340 elif c in ['\r', '\n']:
1341 sys.stdout.write('\r \r' + lines[r] + '\n')
1342 r = r + 1
1343 continue
1344 if c in ['b', 'B', '\x1b']:
1345 r = r - inc - inc
1346 if r < 0: r = 0
1347 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1348 r = r + inc
1349
1350 finally:
1351 if tty:
1352 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1353
1354def plainpager(text):
1355 """Simply print unformatted text. This is the ultimate fallback."""
1356 sys.stdout.write(plain(text))
1357
1358def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001359 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001360 if inspect.ismodule(thing):
1361 if thing.__name__ in sys.builtin_module_names:
1362 return 'built-in module ' + thing.__name__
1363 if hasattr(thing, '__path__'):
1364 return 'package ' + thing.__name__
1365 else:
1366 return 'module ' + thing.__name__
1367 if inspect.isbuiltin(thing):
1368 return 'built-in function ' + thing.__name__
1369 if inspect.isclass(thing):
1370 return 'class ' + thing.__name__
1371 if inspect.isfunction(thing):
1372 return 'function ' + thing.__name__
1373 if inspect.ismethod(thing):
1374 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001375 if type(thing) is types.InstanceType:
1376 return 'instance of ' + thing.__class__.__name__
1377 return type(thing).__name__
1378
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001379def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001380 """Locate an object by name or dotted path, importing as necessary."""
Guido van Rossum97dede02003-02-16 01:12:32 +00001381 parts = [part for part in split(path, '.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001382 module, n = None, 0
1383 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001384 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001385 if nextmodule: module, n = nextmodule, n + 1
1386 else: break
1387 if module:
1388 object = module
1389 for part in parts[n:]:
1390 try: object = getattr(object, part)
1391 except AttributeError: return None
1392 return object
1393 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001394 if hasattr(__builtin__, path):
1395 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001396
1397# --------------------------------------- interactive interpreter interface
1398
1399text = TextDoc()
1400html = HTMLDoc()
1401
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001402def resolve(thing, forceload=0):
1403 """Given an object or a path to an object, get the object and its name."""
1404 if isinstance(thing, str):
1405 object = locate(thing, forceload)
1406 if not object:
1407 raise ImportError, 'no Python documentation found for %r' % thing
1408 return object, thing
1409 else:
1410 return thing, getattr(thing, '__name__', None)
1411
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001412def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001413 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001414 try:
1415 object, name = resolve(thing, forceload)
1416 desc = describe(object)
1417 module = inspect.getmodule(object)
1418 if name and '.' in name:
1419 desc += ' in ' + name[:name.rfind('.')]
1420 elif module and module is not object:
1421 desc += ' in module ' + module.__name__
1422 pager(title % desc + '\n\n' + text.document(object, name))
1423 except (ImportError, ErrorDuringImport), value:
1424 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001425
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001426def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001427 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001428 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001429 object, name = resolve(thing, forceload)
1430 page = html.page(describe(object), html.document(object, name))
1431 file = open(name + '.html', 'w')
1432 file.write(page)
1433 file.close()
1434 print 'wrote', name + '.html'
1435 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001436 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001437
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001438def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001439 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001440 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001441 for file in os.listdir(dir):
1442 path = os.path.join(dir, file)
1443 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001444 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001445 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001446 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001447 if modname:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001448 if modname == '__init__':
1449 modname = pkgpath[:-1] # remove trailing period
1450 else:
1451 modname = pkgpath + modname
1452 if modname not in done:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001453 done[modname] = 1
1454 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001455
1456class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001457 keywords = {
1458 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001459 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001460 'break': ('ref/break', 'while for'),
1461 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1462 'continue': ('ref/continue', 'while for'),
1463 'def': ('ref/function', ''),
1464 'del': ('ref/del', 'BASICMETHODS'),
1465 'elif': 'if',
1466 'else': ('ref/if', 'while for'),
1467 'except': 'try',
1468 'exec': ('ref/exec', ''),
1469 'finally': 'try',
1470 'for': ('ref/for', 'break continue while'),
1471 'from': 'import',
1472 'global': ('ref/global', 'NAMESPACES'),
1473 'if': ('ref/if', 'TRUTHVALUE'),
1474 'import': ('ref/import', 'MODULES'),
1475 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1476 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001477 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001478 'not': 'BOOLEAN',
1479 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001480 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001481 'print': ('ref/print', ''),
1482 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001483 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001484 'try': ('ref/try', 'EXCEPTIONS'),
1485 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001486 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001487 }
1488
1489 topics = {
1490 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001491 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001492 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1493 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001494 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001495 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1496 'INTEGER': ('ref/integers', 'int range'),
1497 'FLOAT': ('ref/floating', 'float math'),
1498 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001499 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001500 'MAPPINGS': 'DICTIONARIES',
1501 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1502 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1503 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001504 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001505 'FRAMEOBJECTS': 'TYPES',
1506 'TRACEBACKS': 'TYPES',
1507 'NONE': ('lib/bltin-null-object', ''),
1508 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1509 'FILES': ('lib/bltin-file-objects', ''),
1510 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1511 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1512 'MODULES': ('lib/typesmodules', 'import'),
1513 'PACKAGES': 'import',
1514 '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'),
1515 'OPERATORS': 'EXPRESSIONS',
1516 'PRECEDENCE': 'EXPRESSIONS',
1517 'OBJECTS': ('ref/objects', 'TYPES'),
1518 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001519 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1520 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1521 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1522 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1523 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1524 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1525 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001526 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1527 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1528 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001529 'SCOPING': 'NAMESPACES',
1530 'FRAMES': 'NAMESPACES',
1531 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001532 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1533 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001534 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1535 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001536 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001537 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1538 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001539 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001540 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001541 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001542 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001543 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1544 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001545 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1546 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1547 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1548 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1549 'POWER': ('ref/power', 'EXPRESSIONS'),
1550 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1551 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1552 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1553 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1554 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001555 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001556 'ASSERTION': 'assert',
1557 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001558 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001559 'DELETION': 'del',
1560 'PRINTING': 'print',
1561 'RETURNING': 'return',
1562 'IMPORTING': 'import',
1563 'CONDITIONAL': 'if',
1564 'LOOPING': ('ref/compound', 'for while break continue'),
1565 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001566 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001567 }
1568
1569 def __init__(self, input, output):
1570 self.input = input
1571 self.output = output
1572 self.docdir = None
1573 execdir = os.path.dirname(sys.executable)
1574 homedir = os.environ.get('PYTHONHOME')
1575 for dir in [os.environ.get('PYTHONDOCS'),
1576 homedir and os.path.join(homedir, 'doc'),
1577 os.path.join(execdir, 'doc'),
1578 '/usr/doc/python-docs-' + split(sys.version)[0],
1579 '/usr/doc/python-' + split(sys.version)[0],
1580 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001581 '/usr/doc/python-' + sys.version[:3],
1582 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001583 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1584 self.docdir = dir
1585
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001586 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001587 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001588 self()
1589 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001590 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001591
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001592 def __call__(self, request=None):
1593 if request is not None:
1594 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001595 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001596 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001597 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001598 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001599You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001600If you want to ask for help on a particular object directly from the
1601interpreter, you can type "help(object)". Executing "help('string')"
1602has the same effect as typing a particular string at the help> prompt.
1603''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001604
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001605 def interact(self):
1606 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001607 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001608 self.output.write('help> ')
1609 self.output.flush()
1610 try:
1611 request = self.input.readline()
1612 if not request: break
1613 except KeyboardInterrupt: break
1614 request = strip(replace(request, '"', '', "'", ''))
1615 if lower(request) in ['q', 'quit']: break
1616 self.help(request)
1617
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001618 def help(self, request):
1619 if type(request) is type(''):
1620 if request == 'help': self.intro()
1621 elif request == 'keywords': self.listkeywords()
1622 elif request == 'topics': self.listtopics()
1623 elif request == 'modules': self.listmodules()
1624 elif request[:8] == 'modules ':
1625 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001626 elif request in self.keywords: self.showtopic(request)
1627 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001628 elif request: doc(request, 'Help on %s:')
1629 elif isinstance(request, Helper): self()
1630 else: doc(request, 'Help on %s:')
1631 self.output.write('\n')
1632
1633 def intro(self):
1634 self.output.write('''
1635Welcome to Python %s! This is the online help utility.
1636
1637If this is your first time using Python, you should definitely check out
1638the tutorial on the Internet at http://www.python.org/doc/tut/.
1639
1640Enter the name of any module, keyword, or topic to get help on writing
1641Python programs and using Python modules. To quit this help utility and
1642return to the interpreter, just type "quit".
1643
1644To get a list of available modules, keywords, or topics, type "modules",
1645"keywords", or "topics". Each module also comes with a one-line summary
1646of what it does; to list the modules whose summaries contain a given word
1647such as "spam", type "modules spam".
1648''' % sys.version[:3])
1649
1650 def list(self, items, columns=4, width=80):
1651 items = items[:]
1652 items.sort()
1653 colw = width / columns
1654 rows = (len(items) + columns - 1) / columns
1655 for row in range(rows):
1656 for col in range(columns):
1657 i = col * rows + row
1658 if i < len(items):
1659 self.output.write(items[i])
1660 if col < columns - 1:
1661 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1662 self.output.write('\n')
1663
1664 def listkeywords(self):
1665 self.output.write('''
1666Here is a list of the Python keywords. Enter any keyword to get more help.
1667
1668''')
1669 self.list(self.keywords.keys())
1670
1671 def listtopics(self):
1672 self.output.write('''
1673Here is a list of available topics. Enter any topic name to get more help.
1674
1675''')
1676 self.list(self.topics.keys())
1677
1678 def showtopic(self, topic):
1679 if not self.docdir:
1680 self.output.write('''
1681Sorry, topic and keyword documentation is not available because the Python
1682HTML documentation files could not be found. If you have installed them,
1683please set the environment variable PYTHONDOCS to indicate their location.
1684''')
1685 return
1686 target = self.topics.get(topic, self.keywords.get(topic))
1687 if not target:
1688 self.output.write('no documentation found for %s\n' % repr(topic))
1689 return
1690 if type(target) is type(''):
1691 return self.showtopic(target)
1692
1693 filename, xrefs = target
1694 filename = self.docdir + '/' + filename + '.html'
1695 try:
1696 file = open(filename)
1697 except:
1698 self.output.write('could not read docs from %s\n' % filename)
1699 return
1700
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001701 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1702 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001703 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1704 file.close()
1705
1706 import htmllib, formatter, StringIO
1707 buffer = StringIO.StringIO()
1708 parser = htmllib.HTMLParser(
1709 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1710 parser.start_table = parser.do_p
1711 parser.end_table = lambda parser=parser: parser.do_p({})
1712 parser.start_tr = parser.do_br
1713 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1714 parser.feed(document)
1715 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1716 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001717 if xrefs:
1718 buffer = StringIO.StringIO()
1719 formatter.DumbWriter(buffer).send_flowing_data(
1720 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1721 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001722
1723 def listmodules(self, key=''):
1724 if key:
1725 self.output.write('''
1726Here is a list of matching modules. Enter any module name to get more help.
1727
1728''')
1729 apropos(key)
1730 else:
1731 self.output.write('''
1732Please wait a moment while I gather a list of all available modules...
1733
1734''')
1735 modules = {}
1736 def callback(path, modname, desc, modules=modules):
1737 if modname and modname[-9:] == '.__init__':
1738 modname = modname[:-9] + ' (package)'
1739 if find(modname, '.') < 0:
1740 modules[modname] = 1
1741 ModuleScanner().run(callback)
1742 self.list(modules.keys())
1743 self.output.write('''
1744Enter any module name to get more help. Or, type "modules spam" to search
1745for modules whose descriptions contain the word "spam".
1746''')
1747
1748help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001749
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001750class Scanner:
1751 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001752 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001753 self.roots = roots[:]
1754 self.state = []
1755 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001756 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001757
1758 def next(self):
1759 if not self.state:
1760 if not self.roots:
1761 return None
1762 root = self.roots.pop(0)
1763 self.state = [(root, self.children(root))]
1764 node, children = self.state[-1]
1765 if not children:
1766 self.state.pop()
1767 return self.next()
1768 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001769 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001770 self.state.append((child, self.children(child)))
1771 return child
1772
1773class ModuleScanner(Scanner):
1774 """An interruptible scanner that searches module synopses."""
1775 def __init__(self):
1776 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001777 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001778 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001779
1780 def submodules(self, (dir, package)):
1781 children = []
1782 for file in os.listdir(dir):
1783 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001784 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001785 children.append((path, package + (package and '.') + file))
1786 else:
1787 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001788 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001789 return children
1790
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001791 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001792 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001793 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001794 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001795 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001796 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001797
Ka-Ping Yee66246962001-04-12 11:59:50 +00001798 def run(self, callback, key=None, completer=None):
1799 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001800 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001801 seen = {}
1802
1803 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001804 if modname != '__main__':
1805 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001806 if key is None:
1807 callback(None, modname, '')
1808 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001809 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001810 if find(lower(modname + ' - ' + desc), key) >= 0:
1811 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001812
1813 while not self.quit:
1814 node = self.next()
1815 if not node: break
1816 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001817 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001818 if os.path.isfile(path) and modname:
1819 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001820 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001821 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001822 if key is None:
1823 callback(path, modname, '')
1824 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001825 desc = synopsis(path) or ''
1826 if find(lower(modname + ' - ' + desc), key) >= 0:
1827 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001828 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001829
1830def apropos(key):
1831 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001832 def callback(path, modname, desc):
1833 if modname[-9:] == '.__init__':
1834 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001835 print modname, desc and '- ' + desc
1836 try: import warnings
1837 except ImportError: pass
1838 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001839 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001840
1841# --------------------------------------------------- web browser interface
1842
Ka-Ping Yee66246962001-04-12 11:59:50 +00001843def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001844 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001845
1846 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1847 class Message(mimetools.Message):
1848 def __init__(self, fp, seekable=1):
1849 Message = self.__class__
1850 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1851 self.encodingheader = self.getheader('content-transfer-encoding')
1852 self.typeheader = self.getheader('content-type')
1853 self.parsetype()
1854 self.parseplist()
1855
1856 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1857 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001858 try:
1859 self.send_response(200)
1860 self.send_header('Content-Type', 'text/html')
1861 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001862 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001863 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001864
1865 def do_GET(self):
1866 path = self.path
1867 if path[-5:] == '.html': path = path[:-5]
1868 if path[:1] == '/': path = path[1:]
1869 if path and path != '.':
1870 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001871 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001872 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001873 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001874 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001875 if obj:
1876 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001877 else:
1878 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001879'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001880 else:
1881 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001882'<big><big><strong>Python: Index of Modules</strong></big></big>',
1883'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001884 def bltinlink(name):
1885 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001886 names = filter(lambda x: x != '__main__',
1887 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001888 contents = html.multicolumn(names, bltinlink)
1889 indices = ['<p>' + html.bigsection(
1890 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1891
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001892 seen = {}
1893 for dir in pathdirs():
1894 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001895 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001896<font color="#909090" face="helvetica, arial"><strong>
1897pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001898 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001899
1900 def log_message(self, *args): pass
1901
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001902 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001903 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001904 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001905 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001906 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001907 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001908 self.base.__init__(self, self.address, self.handler)
1909
1910 def serve_until_quit(self):
1911 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001912 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001913 while not self.quit:
1914 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1915 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001916
1917 def server_activate(self):
1918 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001919 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001920
1921 DocServer.base = BaseHTTPServer.HTTPServer
1922 DocServer.handler = DocHandler
1923 DocHandler.MessageClass = Message
1924 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001925 try:
1926 DocServer(port, callback).serve_until_quit()
1927 except (KeyboardInterrupt, select.error):
1928 pass
1929 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001930 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001931
1932# ----------------------------------------------------- graphical interface
1933
1934def gui():
1935 """Graphical interface (starts web server and pops up a control window)."""
1936 class GUI:
1937 def __init__(self, window, port=7464):
1938 self.window = window
1939 self.server = None
1940 self.scanner = None
1941
1942 import Tkinter
1943 self.server_frm = Tkinter.Frame(window)
1944 self.title_lbl = Tkinter.Label(self.server_frm,
1945 text='Starting server...\n ')
1946 self.open_btn = Tkinter.Button(self.server_frm,
1947 text='open browser', command=self.open, state='disabled')
1948 self.quit_btn = Tkinter.Button(self.server_frm,
1949 text='quit serving', command=self.quit, state='disabled')
1950
1951 self.search_frm = Tkinter.Frame(window)
1952 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1953 self.search_ent = Tkinter.Entry(self.search_frm)
1954 self.search_ent.bind('<Return>', self.search)
1955 self.stop_btn = Tkinter.Button(self.search_frm,
1956 text='stop', pady=0, command=self.stop, state='disabled')
1957 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001958 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001959 self.stop_btn.pack(side='right')
1960
1961 self.window.title('pydoc')
1962 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1963 self.title_lbl.pack(side='top', fill='x')
1964 self.open_btn.pack(side='left', fill='x', expand=1)
1965 self.quit_btn.pack(side='right', fill='x', expand=1)
1966 self.server_frm.pack(side='top', fill='x')
1967
1968 self.search_lbl.pack(side='left')
1969 self.search_ent.pack(side='right', fill='x', expand=1)
1970 self.search_frm.pack(side='top', fill='x')
1971 self.search_ent.focus_set()
1972
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001973 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001974 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001975 self.result_lst.bind('<Button-1>', self.select)
1976 self.result_lst.bind('<Double-Button-1>', self.goto)
1977 self.result_scr = Tkinter.Scrollbar(window,
1978 orient='vertical', command=self.result_lst.yview)
1979 self.result_lst.config(yscrollcommand=self.result_scr.set)
1980
1981 self.result_frm = Tkinter.Frame(window)
1982 self.goto_btn = Tkinter.Button(self.result_frm,
1983 text='go to selected', command=self.goto)
1984 self.hide_btn = Tkinter.Button(self.result_frm,
1985 text='hide results', command=self.hide)
1986 self.goto_btn.pack(side='left', fill='x', expand=1)
1987 self.hide_btn.pack(side='right', fill='x', expand=1)
1988
1989 self.window.update()
1990 self.minwidth = self.window.winfo_width()
1991 self.minheight = self.window.winfo_height()
1992 self.bigminheight = (self.server_frm.winfo_reqheight() +
1993 self.search_frm.winfo_reqheight() +
1994 self.result_lst.winfo_reqheight() +
1995 self.result_frm.winfo_reqheight())
1996 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1997 self.expanded = 0
1998 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1999 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002000 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002001
2002 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002003 threading.Thread(
2004 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002005
2006 def ready(self, server):
2007 self.server = server
2008 self.title_lbl.config(
2009 text='Python documentation server at\n' + server.url)
2010 self.open_btn.config(state='normal')
2011 self.quit_btn.config(state='normal')
2012
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002013 def open(self, event=None, url=None):
2014 url = url or self.server.url
2015 try:
2016 import webbrowser
2017 webbrowser.open(url)
2018 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002019 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002020 os.system('start "%s"' % url)
2021 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002022 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002023 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002024 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002025 else:
2026 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2027 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002028
2029 def quit(self, event=None):
2030 if self.server:
2031 self.server.quit = 1
2032 self.window.quit()
2033
2034 def search(self, event=None):
2035 key = self.search_ent.get()
2036 self.stop_btn.pack(side='right')
2037 self.stop_btn.config(state='normal')
2038 self.search_lbl.config(text='Searching for "%s"...' % key)
2039 self.search_ent.forget()
2040 self.search_lbl.pack(side='left')
2041 self.result_lst.delete(0, 'end')
2042 self.goto_btn.config(state='disabled')
2043 self.expand()
2044
2045 import threading
2046 if self.scanner:
2047 self.scanner.quit = 1
2048 self.scanner = ModuleScanner()
2049 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002050 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002051
2052 def update(self, path, modname, desc):
2053 if modname[-9:] == '.__init__':
2054 modname = modname[:-9] + ' (package)'
2055 self.result_lst.insert('end',
2056 modname + ' - ' + (desc or '(no description)'))
2057
2058 def stop(self, event=None):
2059 if self.scanner:
2060 self.scanner.quit = 1
2061 self.scanner = None
2062
2063 def done(self):
2064 self.scanner = None
2065 self.search_lbl.config(text='Search for')
2066 self.search_lbl.pack(side='left')
2067 self.search_ent.pack(side='right', fill='x', expand=1)
2068 if sys.platform != 'win32': self.stop_btn.forget()
2069 self.stop_btn.config(state='disabled')
2070
2071 def select(self, event=None):
2072 self.goto_btn.config(state='normal')
2073
2074 def goto(self, event=None):
2075 selection = self.result_lst.curselection()
2076 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002077 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002078 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002079
2080 def collapse(self):
2081 if not self.expanded: return
2082 self.result_frm.forget()
2083 self.result_scr.forget()
2084 self.result_lst.forget()
2085 self.bigwidth = self.window.winfo_width()
2086 self.bigheight = self.window.winfo_height()
2087 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2088 self.window.wm_minsize(self.minwidth, self.minheight)
2089 self.expanded = 0
2090
2091 def expand(self):
2092 if self.expanded: return
2093 self.result_frm.pack(side='bottom', fill='x')
2094 self.result_scr.pack(side='right', fill='y')
2095 self.result_lst.pack(side='top', fill='both', expand=1)
2096 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2097 self.window.wm_minsize(self.minwidth, self.bigminheight)
2098 self.expanded = 1
2099
2100 def hide(self, event=None):
2101 self.stop()
2102 self.collapse()
2103
2104 import Tkinter
2105 try:
2106 gui = GUI(Tkinter.Tk())
2107 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002108 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002109 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002110
2111# -------------------------------------------------- command-line interface
2112
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002113def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002114 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002115
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002116def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002117 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002118 import getopt
2119 class BadUsage: pass
2120
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002121 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002122 scriptdir = os.path.dirname(sys.argv[0])
2123 if scriptdir in sys.path:
2124 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002125 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002126
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002127 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002128 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002129 writing = 0
2130
2131 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002132 if opt == '-g':
2133 gui()
2134 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002135 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002136 apropos(val)
2137 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002138 if opt == '-p':
2139 try:
2140 port = int(val)
2141 except ValueError:
2142 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002143 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002144 print 'pydoc server ready at %s' % server.url
2145 def stopped():
2146 print 'pydoc server stopped'
2147 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002148 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002149 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002150 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002151
2152 if not args: raise BadUsage
2153 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002154 if ispath(arg) and not os.path.exists(arg):
2155 print 'file %r does not exist' % arg
2156 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002157 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002158 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002159 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002160 if writing:
2161 if ispath(arg) and os.path.isdir(arg):
2162 writedocs(arg)
2163 else:
2164 writedoc(arg)
2165 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002166 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002167 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002168 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002169
2170 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002171 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002172 print """pydoc - the Python documentation tool
2173
2174%s <name> ...
2175 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002176 Python keyword, topic, function, module, or package, or a dotted
2177 reference to a class or function within a module or module in a
2178 package. If <name> contains a '%s', it is used as the path to a
2179 Python source file to document. If name is 'keywords', 'topics',
2180 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002181
2182%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002183 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002184
2185%s -p <port>
2186 Start an HTTP server on the given port on the local machine.
2187
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002188%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002189 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002190
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002191%s -w <name> ...
2192 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002193 directory. If <name> contains a '%s', it is treated as a filename; if
2194 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002195""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002196
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002197if __name__ == '__main__': cli()