blob: 40a4e16075e223abebd94277d5a1ff66e25e2d46 [file] [log] [blame]
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001#!/usr/bin/env python
Guido van Rossumfce538c2002-08-06 17:29:38 +00002# -*- coding: Latin-1 -*-
Ka-Ping Yee1d384632001-03-01 00:24:32 +00003"""Generate Python documentation in HTML or text for interactive use.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00004
Ka-Ping Yeedd175342001-02-27 14:43:46 +00005In the Python interpreter, do "from pydoc import help" to provide online
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00006help. Calling help(thing) on a Python object documents the object.
7
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00008Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00009
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000010Run "pydoc <name>" to show documentation on something. <name> may be
11the name of a function, module, package, or a dotted reference to a
12class or function within a module or module in a package. If the
13argument contains a path segment delimiter (e.g. slash on Unix,
14backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000015
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000016Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000018
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000019Run "pydoc -p <port>" to start an HTTP server on a given port on the
20local machine to generate documentation web pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000021
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000022For platforms without a command line, "pydoc -g" starts the HTTP server
23and also pops up a little window for controlling it.
24
25Run "pydoc -w <name>" to write out the HTML documentation for a module
26to a file named "<name>.html".
Skip Montanaro4997a692003-09-10 16:47:51 +000027
28Module docs for core modules are assumed to be in
29
30 http://www.python.org/doc/current/lib/
31
32This can be overridden by setting the PYTHONDOCS environment variable
33to a different URL or to a local directory containing the Library
34Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000035"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000036
37__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000038__date__ = "26 February 2001"
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000039__version__ = "$Revision$"
Martin v. Löwis6fe8f192004-11-14 10:21:04 +000040__credits__ = """Guido van Rossum, for an excellent programming language.
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000041Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000042Paul Prescod, for all his work on onlinehelp.
43Richard Chamberlain, for the first implementation of textdoc.
44
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000045Mynd you, møøse bites Kan be pretty nasti..."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000046
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000047# Known bugs that can't be fixed here:
48# - imp.load_module() cannot be prevented from clobbering existing
49# loaded modules, so calling synopsis() on a binary module file
50# changes the contents of any existing module with the same name.
51# - If the __file__ attribute on a module is a relative path and
52# the current directory is changed with os.chdir(), an incorrect
53# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000054
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +000055import sys, imp, os, re, types, inspect, __builtin__
Ka-Ping Yeedd175342001-02-27 14:43:46 +000056from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000057from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
Raymond Hettinger756b3f32004-01-29 06:37:52 +000058from collections import deque
Ka-Ping Yeedd175342001-02-27 14:43:46 +000059
60# --------------------------------------------------------- common routines
61
Ka-Ping Yeedd175342001-02-27 14:43:46 +000062def pathdirs():
63 """Convert sys.path into a list of absolute, existing, unique paths."""
64 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000065 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000066 for dir in sys.path:
67 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000068 normdir = os.path.normcase(dir)
69 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000070 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000071 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000072 return dirs
73
74def getdoc(object):
75 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000076 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000077 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000078
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000079def splitdoc(doc):
80 """Split a doc string into a synopsis line (if any) and the rest."""
81 lines = split(strip(doc), '\n')
82 if len(lines) == 1:
83 return lines[0], ''
84 elif len(lines) >= 2 and not rstrip(lines[1]):
85 return lines[0], join(lines[2:], '\n')
86 return '', join(lines, '\n')
87
Ka-Ping Yeedd175342001-02-27 14:43:46 +000088def classname(object, modname):
89 """Get a class name and qualify it with a module name if necessary."""
90 name = object.__name__
91 if object.__module__ != modname:
92 name = object.__module__ + '.' + name
93 return name
94
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000095def isdata(object):
96 """Check if an object is of a type that probably means it's data."""
97 return not (inspect.ismodule(object) or inspect.isclass(object) or
98 inspect.isroutine(object) or inspect.isframe(object) or
99 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000100
101def replace(text, *pairs):
102 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000103 while pairs:
104 text = join(split(text, pairs[0]), pairs[1])
105 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000106 return text
107
108def cram(text, maxlen):
109 """Omit part of a string if needed to make it fit in a maximum length."""
110 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000111 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000112 post = max(0, maxlen-3-pre)
113 return text[:pre] + '...' + text[len(text)-post:]
114 return text
115
Brett Cannon84601f12004-06-19 01:22:48 +0000116_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000117def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000118 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000119 # The behaviour of %p is implementation-dependent in terms of case.
120 if _re_stripid.search(repr(Exception)):
121 return _re_stripid.sub(r'\1', text)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000122 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000123
Brett Cannonc6c1f472004-06-19 01:02:51 +0000124def _is_some_method(obj):
125 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000126
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000127def allmethods(cl):
128 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000129 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000130 methods[key] = 1
131 for base in cl.__bases__:
132 methods.update(allmethods(base)) # all your base are belong to us
133 for key in methods.keys():
134 methods[key] = getattr(cl, key)
135 return methods
136
Tim Petersfa26f7c2001-09-24 08:05:11 +0000137def _split_list(s, predicate):
138 """Split sequence s via predicate, and return pair ([true], [false]).
139
140 The return value is a 2-tuple of lists,
141 ([x for x in s if predicate(x)],
142 [x for x in s if not predicate(x)])
143 """
144
Tim Peters28355492001-09-23 21:29:55 +0000145 yes = []
146 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000147 for x in s:
148 if predicate(x):
149 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000150 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000151 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000152 return yes, no
153
Skip Montanaroa5616d22004-06-11 04:46:12 +0000154def visiblename(name, all=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000155 """Decide whether to show documentation on a variable."""
156 # Certain special names are redundant.
157 if name in ['__builtins__', '__doc__', '__file__', '__path__',
158 '__module__', '__name__']: return 0
159 # Private names are hidden, but special names are displayed.
160 if name.startswith('__') and name.endswith('__'): return 1
Skip Montanaroa5616d22004-06-11 04:46:12 +0000161 if all is not None:
162 # only document that which the programmer exported in __all__
163 return name in all
164 else:
165 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000166
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000167# ----------------------------------------------------- module manipulation
168
169def ispackage(path):
170 """Guess whether a path refers to a package directory."""
171 if os.path.isdir(path):
172 for ext in ['.py', '.pyc', '.pyo']:
173 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000174 return True
175 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000176
177def synopsis(filename, cache={}):
178 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000179 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000180 lastupdate, result = cache.get(filename, (0, None))
181 if lastupdate < mtime:
182 info = inspect.getmoduleinfo(filename)
183 file = open(filename)
184 if info and 'b' in info[2]: # binary modules have to be imported
185 try: module = imp.load_module('__temp__', file, filename, info[1:])
186 except: return None
187 result = split(module.__doc__ or '', '\n')[0]
188 del sys.modules['__temp__']
189 else: # text modules can be directly examined
190 line = file.readline()
191 while line[:1] == '#' or not strip(line):
192 line = file.readline()
193 if not line: break
194 line = strip(line)
195 if line[:4] == 'r"""': line = line[1:]
196 if line[:3] == '"""':
197 line = line[3:]
198 if line[-1:] == '\\': line = line[:-1]
199 while not strip(line):
200 line = file.readline()
201 if not line: break
202 result = strip(split(line, '"""')[0])
203 else: result = None
204 file.close()
205 cache[filename] = (mtime, result)
206 return result
207
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000208class ErrorDuringImport(Exception):
209 """Errors that occurred while trying to import something to document it."""
210 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000211 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000212 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000213 self.value = value
214 self.tb = tb
215
216 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000217 exc = self.exc
218 if type(exc) is types.ClassType:
219 exc = exc.__name__
220 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000221
222def importfile(path):
223 """Import a Python source file or compiled file given its path."""
224 magic = imp.get_magic()
225 file = open(path, 'r')
226 if file.read(len(magic)) == magic:
227 kind = imp.PY_COMPILED
228 else:
229 kind = imp.PY_SOURCE
230 file.close()
231 filename = os.path.basename(path)
232 name, ext = os.path.splitext(filename)
233 file = open(path, 'r')
234 try:
235 module = imp.load_module(name, file, path, (ext, 'r', kind))
236 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000237 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000238 file.close()
239 return module
240
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000241def safeimport(path, forceload=0, cache={}):
242 """Import a module; handle errors; return None if the module isn't found.
243
244 If the module *is* found but an exception occurs, it's wrapped in an
245 ErrorDuringImport exception and reraised. Unlike __import__, if a
246 package path is specified, the module at the end of the path is returned,
247 not the package at the beginning. If the optional 'forceload' argument
248 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000249 if forceload and path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000250 # This is the only way to be sure. Checking the mtime of the file
251 # isn't good enough (e.g. what if the module contains a class that
252 # inherits from another module that has changed?).
253 if path not in sys.builtin_module_names:
254 # Python never loads a dynamic extension a second time from the
255 # same path, even if the file is changed or missing. Deleting
256 # the entry in sys.modules doesn't help for dynamic extensions,
257 # so we're not even going to try to keep them up to date.
258 info = inspect.getmoduleinfo(sys.modules[path].__file__)
259 if info[3] != imp.C_EXTENSION:
260 cache[path] = sys.modules[path] # prevent module from clearing
261 del sys.modules[path]
262 try:
263 module = __import__(path)
264 except:
265 # Did the error occur before or after the module was found?
266 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000267 if path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000268 # An error occured while executing the imported module.
269 raise ErrorDuringImport(sys.modules[path].__file__, info)
270 elif exc is SyntaxError:
271 # A SyntaxError occurred before we could execute the module.
272 raise ErrorDuringImport(value.filename, info)
273 elif exc is ImportError and \
274 split(lower(str(value)))[:2] == ['no', 'module']:
275 # The module was not found.
276 return None
277 else:
278 # Some other error occurred during the importing process.
279 raise ErrorDuringImport(path, sys.exc_info())
280 for part in split(path, '.')[1:]:
281 try: module = getattr(module, part)
282 except AttributeError: return None
283 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000284
285# ---------------------------------------------------- formatter base class
286
287class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000288 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000289 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000290 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000291 # 'try' clause is to attempt to handle the possibility that inspect
292 # identifies something in a way that pydoc itself has issues handling;
293 # think 'super' and how it is a descriptor (which raises the exception
294 # by lacking a __name__ attribute) and an instance.
295 try:
296 if inspect.ismodule(object): return self.docmodule(*args)
297 if inspect.isclass(object): return self.docclass(*args)
298 if inspect.isroutine(object): return self.docroutine(*args)
299 except AttributeError:
300 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000301 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000302 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000303
304 def fail(self, object, name=None, *args):
305 """Raise an exception for unimplemented types."""
306 message = "don't know how to document object%s of type %s" % (
307 name and ' ' + repr(name), type(object).__name__)
308 raise TypeError, message
309
310 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000311
Skip Montanaro4997a692003-09-10 16:47:51 +0000312 def getdocloc(self, object):
313 """Return the location of module docs or None"""
314
315 try:
316 file = inspect.getabsfile(object)
317 except TypeError:
318 file = '(built-in)'
319
320 docloc = os.environ.get("PYTHONDOCS",
321 "http://www.python.org/doc/current/lib")
322 basedir = os.path.join(sys.exec_prefix, "lib",
323 "python"+sys.version[0:3])
324 if (isinstance(object, type(os)) and
325 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
326 'marshal', 'posix', 'signal', 'sys',
327 'thread', 'zipimport') or
328 (file.startswith(basedir) and
329 not file.startswith(os.path.join(basedir, 'site-packages'))))):
Skip Montanarof2134842004-06-07 02:40:05 +0000330 htmlfile = "module-%s.html" % object.__name__
Skip Montanaro4997a692003-09-10 16:47:51 +0000331 if docloc.startswith("http://"):
Skip Montanarof2134842004-06-07 02:40:05 +0000332 docloc = "%s/%s" % (docloc.rstrip("/"), htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000333 else:
Skip Montanarof2134842004-06-07 02:40:05 +0000334 docloc = os.path.join(docloc, htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000335 else:
336 docloc = None
337 return docloc
338
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000339# -------------------------------------------- HTML documentation generator
340
341class HTMLRepr(Repr):
342 """Class for safely making an HTML representation of a Python object."""
343 def __init__(self):
344 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000345 self.maxlist = self.maxtuple = 20
346 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000347 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000348
349 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000350 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000351
352 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000353 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000354
355 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000356 if hasattr(type(x), '__name__'):
357 methodname = 'repr_' + join(split(type(x).__name__), '_')
358 if hasattr(self, methodname):
359 return getattr(self, methodname)(x, level)
360 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000361
362 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000363 test = cram(x, self.maxstring)
364 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000365 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000366 # Backslashes are only literal in the string and are never
367 # needed to make any special characters, so show a raw string.
368 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000369 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000370 r'<font color="#c040c0">\1</font>',
371 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000372
Skip Montanarodf708782002-03-07 22:58:02 +0000373 repr_str = repr_string
374
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000375 def repr_instance(self, x, level):
376 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000377 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000378 except:
379 return self.escape('<%s instance>' % x.__class__.__name__)
380
381 repr_unicode = repr_string
382
383class HTMLDoc(Doc):
384 """Formatter class for HTML documentation."""
385
386 # ------------------------------------------- HTML formatting utilities
387
388 _repr_instance = HTMLRepr()
389 repr = _repr_instance.repr
390 escape = _repr_instance.escape
391
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000392 def page(self, title, contents):
393 """Format an HTML page."""
394 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000395<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000396<html><head><title>Python: %s</title>
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000397</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000398%s
399</body></html>''' % (title, contents)
400
401 def heading(self, title, fgcol, bgcol, extras=''):
402 """Format a page heading."""
403 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000404<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000405<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000406<td valign=bottom>&nbsp;<br>
407<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000408><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000409><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000410 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
411
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000412 def section(self, title, fgcol, bgcol, contents, width=6,
413 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000414 """Format a section with a heading."""
415 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000416 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000417 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000418<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000419<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000420<td colspan=3 valign=bottom>&nbsp;<br>
421<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000422 ''' % (bgcol, fgcol, title)
423 if prelude:
424 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000425<tr bgcolor="%s"><td rowspan=2>%s</td>
426<td colspan=2>%s</td></tr>
427<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
428 else:
429 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000430<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000431
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000432 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000433
434 def bigsection(self, title, *args):
435 """Format a section with a big heading."""
436 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000437 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000438
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000439 def preformat(self, text):
440 """Format literal preformatted text."""
441 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000442 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
443 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000444
445 def multicolumn(self, list, format, cols=4):
446 """Format a list of items into a multi-column list."""
447 result = ''
448 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000449 for col in range(cols):
450 result = result + '<td width="%d%%" valign=top>' % (100/cols)
451 for i in range(rows*col, rows*col+rows):
452 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000453 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000454 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000455 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000456
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000457 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000458
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000459 def namelink(self, name, *dicts):
460 """Make a link for an identifier, given name-to-URL mappings."""
461 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000462 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000463 return '<a href="%s">%s</a>' % (dict[name], name)
464 return name
465
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000466 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000467 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000468 name, module = object.__name__, sys.modules.get(object.__module__)
469 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000470 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000471 module.__name__, name, classname(object, modname))
472 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000473
474 def modulelink(self, object):
475 """Make a link for a module."""
476 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
477
478 def modpkglink(self, (name, path, ispackage, shadowed)):
479 """Make a link for a module or package to display in an index."""
480 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000481 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000482 if path:
483 url = '%s.%s.html' % (path, name)
484 else:
485 url = '%s.html' % name
486 if ispackage:
487 text = '<strong>%s</strong>&nbsp;(package)' % name
488 else:
489 text = name
490 return '<a href="%s">%s</a>' % (url, text)
491
492 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
493 """Mark up some plain text, given a context of symbols to look for.
494 Each context dictionary maps object names to anchor names."""
495 escape = escape or self.escape
496 results = []
497 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000498 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
499 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000500 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000501 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000502 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000503 match = pattern.search(text, here)
504 if not match: break
505 start, end = match.span()
506 results.append(escape(text[here:start]))
507
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000508 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000509 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000510 url = escape(all).replace('"', '&quot;')
511 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000512 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000513 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
514 results.append('<a href="%s">%s</a>' % (url, escape(all)))
515 elif pep:
516 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000517 results.append('<a href="%s">%s</a>' % (url, escape(all)))
518 elif text[end:end+1] == '(':
519 results.append(self.namelink(name, methods, funcs, classes))
520 elif selfdot:
521 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000522 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000523 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000524 here = end
525 results.append(escape(text[here:]))
526 return join(results, '')
527
528 # ---------------------------------------------- type-specific routines
529
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000530 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000531 """Produce HTML for a class tree as given by inspect.getclasstree()."""
532 result = ''
533 for entry in tree:
534 if type(entry) is type(()):
535 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000536 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000537 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000538 if bases and bases != (parent,):
539 parents = []
540 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000541 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000542 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000543 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000544 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000545 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000546 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000547 return '<dl>\n%s</dl>\n' % result
548
Tim Peters8dd7ade2001-10-18 19:56:17 +0000549 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000550 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000551 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000552 try:
553 all = object.__all__
554 except AttributeError:
555 all = None
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000556 parts = split(name, '.')
557 links = []
558 for i in range(len(parts)-1):
559 links.append(
560 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
561 (join(parts[:i+1], '.'), parts[i]))
562 linkedname = join(links + parts[-1:], '.')
563 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000564 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000565 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000566 url = path
567 if sys.platform == 'win32':
568 import nturl2path
569 url = nturl2path.pathname2url(path)
570 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000571 except TypeError:
572 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000573 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000574 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000575 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000576 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
577 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000578 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000579 if hasattr(object, '__date__'):
580 info.append(self.escape(str(object.__date__)))
581 if info:
582 head = head + ' (%s)' % join(info, ', ')
Skip Montanaro4997a692003-09-10 16:47:51 +0000583 docloc = self.getdocloc(object)
584 if docloc is not None:
585 docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
586 else:
587 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000588 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000589 head, '#ffffff', '#7799ee',
590 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000591
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000592 modules = inspect.getmembers(object, inspect.ismodule)
593
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000594 classes, cdict = [], {}
595 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000596 # if __all__ exists, believe it. Otherwise use old heuristic.
597 if (all is not None or
598 (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000599 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000600 classes.append((key, value))
601 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000602 for key, value in classes:
603 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000604 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000605 module = sys.modules.get(modname)
606 if modname != name and module and hasattr(module, key):
607 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000608 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000609 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000610 funcs, fdict = [], {}
611 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000612 # if __all__ exists, believe it. Otherwise use old heuristic.
613 if (all is not None or
614 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000615 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000616 funcs.append((key, value))
617 fdict[key] = '#-' + key
618 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000619 data = []
620 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000621 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000622 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000623
624 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
625 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000626 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000627
628 if hasattr(object, '__path__'):
629 modpkgs = []
630 modnames = []
631 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000632 path = os.path.join(object.__path__[0], file)
633 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000634 if modname != '__init__':
635 if modname and modname not in modnames:
636 modpkgs.append((modname, name, 0, 0))
637 modnames.append(modname)
638 elif ispackage(path):
639 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000640 modpkgs.sort()
641 contents = self.multicolumn(modpkgs, self.modpkglink)
642 result = result + self.bigsection(
643 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000644 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000645 contents = self.multicolumn(
646 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000647 result = result + self.bigsection(
648 'Modules', '#fffff', '#aa55cc', contents)
649
650 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000651 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000652 contents = [
653 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000654 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000655 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000656 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000657 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000658 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000659 contents = []
660 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000661 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000662 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000663 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000664 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000665 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000666 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000667 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000668 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000669 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000670 if hasattr(object, '__author__'):
671 contents = self.markup(str(object.__author__), self.preformat)
672 result = result + self.bigsection(
673 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000674 if hasattr(object, '__credits__'):
675 contents = self.markup(str(object.__credits__), self.preformat)
676 result = result + self.bigsection(
677 'Credits', '#ffffff', '#7799ee', contents)
678
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000679 return result
680
Tim Peters8dd7ade2001-10-18 19:56:17 +0000681 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
682 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000683 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000684 realname = object.__name__
685 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000686 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000687
Tim Petersb47879b2001-09-24 04:47:19 +0000688 contents = []
689 push = contents.append
690
Tim Petersfa26f7c2001-09-24 08:05:11 +0000691 # Cute little class to pump out a horizontal rule between sections.
692 class HorizontalRule:
693 def __init__(self):
694 self.needone = 0
695 def maybe(self):
696 if self.needone:
697 push('<hr>\n')
698 self.needone = 1
699 hr = HorizontalRule()
700
Tim Petersc86f6ca2001-09-26 21:31:51 +0000701 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000702 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000703 if len(mro) > 2:
704 hr.maybe()
705 push('<dl><dt>Method resolution order:</dt>\n')
706 for base in mro:
707 push('<dd>%s</dd>\n' % self.classlink(base,
708 object.__module__))
709 push('</dl>\n')
710
Tim Petersb47879b2001-09-24 04:47:19 +0000711 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000712 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000713 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000714 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000715 push(msg)
716 for name, kind, homecls, value in ok:
717 push(self.document(getattr(object, name), name, mod,
718 funcs, classes, mdict, object))
719 push('\n')
720 return attrs
721
Tim Petersfa26f7c2001-09-24 08:05:11 +0000722 def spillproperties(msg, attrs, predicate):
723 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000724 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000725 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000726 push(msg)
727 for name, kind, homecls, value in ok:
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000728 push(self._docproperty(name, value, mod))
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
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000875 def _docproperty(self, name, value, mod):
876 results = []
877 push = results.append
878
879 if name:
880 push('<dl><dt><strong>%s</strong></dt>\n' % name)
881 if value.__doc__ is not None:
882 doc = self.markup(value.__doc__, self.preformat)
883 push('<dd><tt>%s</tt></dd>\n' % doc)
884 for attr, tag in [('fget', '<em>get</em>'),
885 ('fset', '<em>set</em>'),
886 ('fdel', '<em>delete</em>')]:
887 func = getattr(value, attr)
888 if func is not None:
889 base = self.document(func, tag, mod)
890 push('<dd>%s</dd>\n' % base)
891 push('</dl>\n')
892
893 return ''.join(results)
894
895 def docproperty(self, object, name=None, mod=None, cl=None):
896 """Produce html documentation for a property."""
897 return self._docproperty(name, object, mod)
898
Tim Peters8dd7ade2001-10-18 19:56:17 +0000899 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000900 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000901 lhs = name and '<strong>%s</strong> = ' % name or ''
902 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000903
904 def index(self, dir, shadowed=None):
905 """Generate an HTML index for a directory of modules."""
906 modpkgs = []
907 if shadowed is None: shadowed = {}
908 seen = {}
909 files = os.listdir(dir)
910
911 def found(name, ispackage,
912 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
Raymond Hettinger4f759d82002-11-02 02:02:46 +0000913 if name not in seen:
914 modpkgs.append((name, '', ispackage, name in shadowed))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000915 seen[name] = 1
916 shadowed[name] = 1
917
918 # Package spam/__init__.py takes precedence over module spam.py.
919 for file in files:
920 path = os.path.join(dir, file)
921 if ispackage(path): found(file, 1)
922 for file in files:
923 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000924 if os.path.isfile(path):
925 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000926 if modname: found(modname, 0)
927
928 modpkgs.sort()
929 contents = self.multicolumn(modpkgs, self.modpkglink)
930 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
931
932# -------------------------------------------- text documentation generator
933
934class TextRepr(Repr):
935 """Class for safely making a text representation of a Python object."""
936 def __init__(self):
937 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000938 self.maxlist = self.maxtuple = 20
939 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000940 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000941
942 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000943 if hasattr(type(x), '__name__'):
944 methodname = 'repr_' + join(split(type(x).__name__), '_')
945 if hasattr(self, methodname):
946 return getattr(self, methodname)(x, level)
947 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000948
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000949 def repr_string(self, x, level):
950 test = cram(x, self.maxstring)
951 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000952 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000953 # Backslashes are only literal in the string and are never
954 # needed to make any special characters, so show a raw string.
955 return 'r' + testrepr[0] + test + testrepr[0]
956 return testrepr
957
Skip Montanarodf708782002-03-07 22:58:02 +0000958 repr_str = repr_string
959
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000960 def repr_instance(self, x, level):
961 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000962 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000963 except:
964 return '<%s instance>' % x.__class__.__name__
965
966class TextDoc(Doc):
967 """Formatter class for text documentation."""
968
969 # ------------------------------------------- text formatting utilities
970
971 _repr_instance = TextRepr()
972 repr = _repr_instance.repr
973
974 def bold(self, text):
975 """Format a string in bold by overstriking."""
976 return join(map(lambda ch: ch + '\b' + ch, text), '')
977
978 def indent(self, text, prefix=' '):
979 """Indent text by prepending a given prefix to each line."""
980 if not text: return ''
981 lines = split(text, '\n')
982 lines = map(lambda line, prefix=prefix: prefix + line, lines)
983 if lines: lines[-1] = rstrip(lines[-1])
984 return join(lines, '\n')
985
986 def section(self, title, contents):
987 """Format a section with a given heading."""
988 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
989
990 # ---------------------------------------------- type-specific routines
991
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000992 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000993 """Render in text a class tree as returned by inspect.getclasstree()."""
994 result = ''
995 for entry in tree:
996 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000997 c, bases = entry
998 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000999 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001000 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001001 result = result + '(%s)' % join(parents, ', ')
1002 result = result + '\n'
1003 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001004 result = result + self.formattree(
1005 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001006 return result
1007
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001008 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001009 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001010 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001011 synop, desc = splitdoc(getdoc(object))
1012 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001013
1014 try:
Skip Montanaroa5616d22004-06-11 04:46:12 +00001015 all = object.__all__
1016 except AttributeError:
1017 all = None
1018
1019 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001020 file = inspect.getabsfile(object)
1021 except TypeError:
1022 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001023 result = result + self.section('FILE', file)
Skip Montanaro4997a692003-09-10 16:47:51 +00001024
1025 docloc = self.getdocloc(object)
1026 if docloc is not None:
1027 result = result + self.section('MODULE DOCS', docloc)
1028
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001029 if desc:
1030 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001031
1032 classes = []
1033 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001034 # if __all__ exists, believe it. Otherwise use old heuristic.
1035 if (all is not None
1036 or (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001037 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001038 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001039 funcs = []
1040 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001041 # if __all__ exists, believe it. Otherwise use old heuristic.
1042 if (all is not None or
1043 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001044 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001045 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001046 data = []
1047 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001048 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001049 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001050
1051 if hasattr(object, '__path__'):
1052 modpkgs = []
1053 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001054 path = os.path.join(object.__path__[0], file)
1055 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001056 if modname != '__init__':
1057 if modname and modname not in modpkgs:
1058 modpkgs.append(modname)
1059 elif ispackage(path):
1060 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001061 modpkgs.sort()
1062 result = result + self.section(
1063 'PACKAGE CONTENTS', join(modpkgs, '\n'))
1064
1065 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001066 classlist = map(lambda (key, value): value, classes)
1067 contents = [self.formattree(
1068 inspect.getclasstree(classlist, 1), name)]
1069 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001070 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001071 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001072
1073 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001074 contents = []
1075 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001076 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001077 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001078
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001079 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001080 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001081 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001082 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001083 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001084
1085 if hasattr(object, '__version__'):
1086 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001087 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1088 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001089 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001090 if hasattr(object, '__date__'):
1091 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001092 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001093 result = result + self.section('AUTHOR', str(object.__author__))
1094 if hasattr(object, '__credits__'):
1095 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001096 return result
1097
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001098 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001099 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001100 realname = object.__name__
1101 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001102 bases = object.__bases__
1103
Tim Petersc86f6ca2001-09-26 21:31:51 +00001104 def makename(c, m=object.__module__):
1105 return classname(c, m)
1106
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001107 if name == realname:
1108 title = 'class ' + self.bold(realname)
1109 else:
1110 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001111 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001112 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001113 title = title + '(%s)' % join(parents, ', ')
1114
1115 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001116 contents = doc and [doc + '\n'] or []
1117 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001118
Tim Petersc86f6ca2001-09-26 21:31:51 +00001119 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001120 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001121 if len(mro) > 2:
1122 push("Method resolution order:")
1123 for base in mro:
1124 push(' ' + makename(base))
1125 push('')
1126
Tim Petersf4aad8e2001-09-24 22:40:47 +00001127 # Cute little class to pump out a horizontal rule between sections.
1128 class HorizontalRule:
1129 def __init__(self):
1130 self.needone = 0
1131 def maybe(self):
1132 if self.needone:
1133 push('-' * 70)
1134 self.needone = 1
1135 hr = HorizontalRule()
1136
Tim Peters28355492001-09-23 21:29:55 +00001137 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001138 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001139 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001140 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001141 push(msg)
1142 for name, kind, homecls, value in ok:
1143 push(self.document(getattr(object, name),
1144 name, mod, object))
1145 return attrs
1146
Tim Petersfa26f7c2001-09-24 08:05:11 +00001147 def spillproperties(msg, attrs, predicate):
1148 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001149 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001150 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001151 push(msg)
1152 for name, kind, homecls, value in ok:
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001153 push(self._docproperty(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001154 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001155
Tim Petersfa26f7c2001-09-24 08:05:11 +00001156 def spilldata(msg, attrs, predicate):
1157 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001158 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001159 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001160 push(msg)
1161 for name, kind, homecls, value in ok:
Martin v. Löwise59e2ba2003-05-03 09:09:02 +00001162 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +00001163 doc = getattr(value, "__doc__", None)
1164 else:
1165 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001166 push(self.docother(getattr(object, name),
1167 name, mod, 70, doc) + '\n')
1168 return attrs
1169
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001170 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
1171 inspect.classify_class_attrs(object))
Tim Petersfa26f7c2001-09-24 08:05:11 +00001172 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001173 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001174 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001175 else:
1176 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001177 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1178
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001179 if thisclass is __builtin__.object:
1180 attrs = inherited
1181 continue
1182 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001183 tag = "defined here"
1184 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001185 tag = "inherited from %s" % classname(thisclass,
1186 object.__module__)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001187 filter(lambda t: not t[0].startswith('_'), attrs)
Tim Peters28355492001-09-23 21:29:55 +00001188
1189 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001190 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001191
1192 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001193 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001194 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001195 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001196 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001197 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001198 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001199 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001200 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001201 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1202 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001203 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001204 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001205
1206 contents = '\n'.join(contents)
1207 if not contents:
1208 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001209 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1210
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001211 def formatvalue(self, object):
1212 """Format an argument default value as text."""
1213 return '=' + self.repr(object)
1214
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001215 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001216 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001217 realname = object.__name__
1218 name = name or realname
1219 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001220 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001221 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001222 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001223 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001224 if imclass is not cl:
1225 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001226 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001227 if object.im_self:
1228 note = ' method of %s instance' % classname(
1229 object.im_self.__class__, mod)
1230 else:
1231 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001232 object = object.im_func
1233
1234 if name == realname:
1235 title = self.bold(realname)
1236 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001237 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001238 cl.__dict__[realname] is object):
1239 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001240 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001241 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001242 args, varargs, varkw, defaults = inspect.getargspec(object)
1243 argspec = inspect.formatargspec(
1244 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001245 if realname == '<lambda>':
1246 title = 'lambda'
1247 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001248 else:
1249 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001250 decl = title + argspec + note
1251
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001252 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001253 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001254 else:
1255 doc = getdoc(object) or ''
1256 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001257
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001258 def _docproperty(self, name, value, mod):
1259 results = []
1260 push = results.append
1261
1262 if name:
1263 push(name)
1264 need_blank_after_doc = 0
1265 doc = getdoc(value) or ''
1266 if doc:
1267 push(self.indent(doc))
1268 need_blank_after_doc = 1
1269 for attr, tag in [('fget', '<get>'),
1270 ('fset', '<set>'),
1271 ('fdel', '<delete>')]:
1272 func = getattr(value, attr)
1273 if func is not None:
1274 if need_blank_after_doc:
1275 push('')
1276 need_blank_after_doc = 0
1277 base = self.document(func, tag, mod)
1278 push(self.indent(base))
1279
1280 return '\n'.join(results)
1281
1282 def docproperty(self, object, name=None, mod=None, cl=None):
1283 """Produce text documentation for a property."""
1284 return self._docproperty(name, object, mod)
1285
Tim Peters28355492001-09-23 21:29:55 +00001286 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001287 """Produce text documentation for a data object."""
1288 repr = self.repr(object)
1289 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001290 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001291 chop = maxlen - len(line)
1292 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001293 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001294 if doc is not None:
1295 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001296 return line
1297
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001298# --------------------------------------------------------- user interfaces
1299
1300def pager(text):
1301 """The first time this is called, determine what kind of pager to use."""
1302 global pager
1303 pager = getpager()
1304 pager(text)
1305
1306def getpager():
1307 """Decide what method to use for paging through text."""
1308 if type(sys.stdout) is not types.FileType:
1309 return plainpager
1310 if not sys.stdin.isatty() or not sys.stdout.isatty():
1311 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001312 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001313 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001314 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001315 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001316 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1317 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1318 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001319 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001320 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001321 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001322 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001323 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001324 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001325
1326 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001327 (fd, filename) = tempfile.mkstemp()
1328 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001329 try:
1330 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1331 return lambda text: pipepager(text, 'more')
1332 else:
1333 return ttypager
1334 finally:
1335 os.unlink(filename)
1336
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001337def plain(text):
1338 """Remove boldface formatting from text."""
1339 return re.sub('.\b', '', text)
1340
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001341def pipepager(text, cmd):
1342 """Page through text by feeding it to another program."""
1343 pipe = os.popen(cmd, 'w')
1344 try:
1345 pipe.write(text)
1346 pipe.close()
1347 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001348 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001349
1350def tempfilepager(text, cmd):
1351 """Page through text by invoking a program on a temporary file."""
1352 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001353 filename = tempfile.mktemp()
1354 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001355 file.write(text)
1356 file.close()
1357 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001358 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001359 finally:
1360 os.unlink(filename)
1361
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001362def ttypager(text):
1363 """Page through text on a text terminal."""
1364 lines = split(plain(text), '\n')
1365 try:
1366 import tty
1367 fd = sys.stdin.fileno()
1368 old = tty.tcgetattr(fd)
1369 tty.setcbreak(fd)
1370 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001371 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001372 tty = None
1373 getchar = lambda: sys.stdin.readline()[:-1][:1]
1374
1375 try:
1376 r = inc = os.environ.get('LINES', 25) - 1
1377 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1378 while lines[r:]:
1379 sys.stdout.write('-- more --')
1380 sys.stdout.flush()
1381 c = getchar()
1382
1383 if c in ['q', 'Q']:
1384 sys.stdout.write('\r \r')
1385 break
1386 elif c in ['\r', '\n']:
1387 sys.stdout.write('\r \r' + lines[r] + '\n')
1388 r = r + 1
1389 continue
1390 if c in ['b', 'B', '\x1b']:
1391 r = r - inc - inc
1392 if r < 0: r = 0
1393 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1394 r = r + inc
1395
1396 finally:
1397 if tty:
1398 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1399
1400def plainpager(text):
1401 """Simply print unformatted text. This is the ultimate fallback."""
1402 sys.stdout.write(plain(text))
1403
1404def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001405 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001406 if inspect.ismodule(thing):
1407 if thing.__name__ in sys.builtin_module_names:
1408 return 'built-in module ' + thing.__name__
1409 if hasattr(thing, '__path__'):
1410 return 'package ' + thing.__name__
1411 else:
1412 return 'module ' + thing.__name__
1413 if inspect.isbuiltin(thing):
1414 return 'built-in function ' + thing.__name__
1415 if inspect.isclass(thing):
1416 return 'class ' + thing.__name__
1417 if inspect.isfunction(thing):
1418 return 'function ' + thing.__name__
1419 if inspect.ismethod(thing):
1420 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001421 if type(thing) is types.InstanceType:
1422 return 'instance of ' + thing.__class__.__name__
1423 return type(thing).__name__
1424
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001425def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001426 """Locate an object by name or dotted path, importing as necessary."""
Guido van Rossum97dede02003-02-16 01:12:32 +00001427 parts = [part for part in split(path, '.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001428 module, n = None, 0
1429 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001430 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001431 if nextmodule: module, n = nextmodule, n + 1
1432 else: break
1433 if module:
1434 object = module
1435 for part in parts[n:]:
1436 try: object = getattr(object, part)
1437 except AttributeError: return None
1438 return object
1439 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001440 if hasattr(__builtin__, path):
1441 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001442
1443# --------------------------------------- interactive interpreter interface
1444
1445text = TextDoc()
1446html = HTMLDoc()
1447
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001448def resolve(thing, forceload=0):
1449 """Given an object or a path to an object, get the object and its name."""
1450 if isinstance(thing, str):
1451 object = locate(thing, forceload)
1452 if not object:
1453 raise ImportError, 'no Python documentation found for %r' % thing
1454 return object, thing
1455 else:
1456 return thing, getattr(thing, '__name__', None)
1457
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001458def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001459 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001460 try:
1461 object, name = resolve(thing, forceload)
1462 desc = describe(object)
1463 module = inspect.getmodule(object)
1464 if name and '.' in name:
1465 desc += ' in ' + name[:name.rfind('.')]
1466 elif module and module is not object:
1467 desc += ' in module ' + module.__name__
1468 pager(title % desc + '\n\n' + text.document(object, name))
1469 except (ImportError, ErrorDuringImport), value:
1470 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001471
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001472def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001473 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001474 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001475 object, name = resolve(thing, forceload)
1476 page = html.page(describe(object), html.document(object, name))
1477 file = open(name + '.html', 'w')
1478 file.write(page)
1479 file.close()
1480 print 'wrote', name + '.html'
1481 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001482 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001483
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001484def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001485 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001486 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001487 for file in os.listdir(dir):
1488 path = os.path.join(dir, file)
1489 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001490 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001491 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001492 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001493 if modname:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001494 if modname == '__init__':
1495 modname = pkgpath[:-1] # remove trailing period
1496 else:
1497 modname = pkgpath + modname
1498 if modname not in done:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001499 done[modname] = 1
1500 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001501
1502class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001503 keywords = {
1504 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001505 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001506 'break': ('ref/break', 'while for'),
1507 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1508 'continue': ('ref/continue', 'while for'),
1509 'def': ('ref/function', ''),
1510 'del': ('ref/del', 'BASICMETHODS'),
1511 'elif': 'if',
1512 'else': ('ref/if', 'while for'),
1513 'except': 'try',
1514 'exec': ('ref/exec', ''),
1515 'finally': 'try',
1516 'for': ('ref/for', 'break continue while'),
1517 'from': 'import',
1518 'global': ('ref/global', 'NAMESPACES'),
1519 'if': ('ref/if', 'TRUTHVALUE'),
1520 'import': ('ref/import', 'MODULES'),
1521 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1522 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001523 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001524 'not': 'BOOLEAN',
1525 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001526 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001527 'print': ('ref/print', ''),
1528 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001529 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001530 'try': ('ref/try', 'EXCEPTIONS'),
1531 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001532 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001533 }
1534
1535 topics = {
1536 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001537 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001538 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1539 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001540 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001541 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1542 'INTEGER': ('ref/integers', 'int range'),
1543 'FLOAT': ('ref/floating', 'float math'),
1544 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001545 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001546 'MAPPINGS': 'DICTIONARIES',
1547 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1548 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1549 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001550 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001551 'FRAMEOBJECTS': 'TYPES',
1552 'TRACEBACKS': 'TYPES',
1553 'NONE': ('lib/bltin-null-object', ''),
1554 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1555 'FILES': ('lib/bltin-file-objects', ''),
1556 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1557 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1558 'MODULES': ('lib/typesmodules', 'import'),
1559 'PACKAGES': 'import',
1560 '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'),
1561 'OPERATORS': 'EXPRESSIONS',
1562 'PRECEDENCE': 'EXPRESSIONS',
1563 'OBJECTS': ('ref/objects', 'TYPES'),
1564 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001565 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1566 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1567 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1568 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1569 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1570 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1571 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001572 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1573 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1574 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001575 'SCOPING': 'NAMESPACES',
1576 'FRAMES': 'NAMESPACES',
1577 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001578 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1579 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001580 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1581 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001582 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001583 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1584 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001585 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001586 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001587 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001588 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001589 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1590 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001591 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1592 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1593 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1594 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1595 'POWER': ('ref/power', 'EXPRESSIONS'),
1596 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1597 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1598 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1599 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1600 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001601 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001602 'ASSERTION': 'assert',
1603 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001604 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001605 'DELETION': 'del',
1606 'PRINTING': 'print',
1607 'RETURNING': 'return',
1608 'IMPORTING': 'import',
1609 'CONDITIONAL': 'if',
1610 'LOOPING': ('ref/compound', 'for while break continue'),
1611 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001612 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001613 }
1614
1615 def __init__(self, input, output):
1616 self.input = input
1617 self.output = output
1618 self.docdir = None
1619 execdir = os.path.dirname(sys.executable)
1620 homedir = os.environ.get('PYTHONHOME')
1621 for dir in [os.environ.get('PYTHONDOCS'),
1622 homedir and os.path.join(homedir, 'doc'),
1623 os.path.join(execdir, 'doc'),
1624 '/usr/doc/python-docs-' + split(sys.version)[0],
1625 '/usr/doc/python-' + split(sys.version)[0],
1626 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001627 '/usr/doc/python-' + sys.version[:3],
1628 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001629 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1630 self.docdir = dir
1631
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001632 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001633 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001634 self()
1635 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001636 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001637
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001638 def __call__(self, request=None):
1639 if request is not None:
1640 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001641 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001642 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001643 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001644 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001645You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001646If you want to ask for help on a particular object directly from the
1647interpreter, you can type "help(object)". Executing "help('string')"
1648has the same effect as typing a particular string at the help> prompt.
1649''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001650
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001651 def interact(self):
1652 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001653 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001654 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001655 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001656 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001657 except (KeyboardInterrupt, EOFError):
1658 break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001659 request = strip(replace(request, '"', '', "'", ''))
1660 if lower(request) in ['q', 'quit']: break
1661 self.help(request)
1662
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001663 def getline(self, prompt):
1664 """Read one line, using raw_input when available."""
1665 if self.input is sys.stdin:
1666 return raw_input(prompt)
1667 else:
1668 self.output.write(prompt)
1669 self.output.flush()
1670 return self.input.readline()
1671
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001672 def help(self, request):
1673 if type(request) is type(''):
1674 if request == 'help': self.intro()
1675 elif request == 'keywords': self.listkeywords()
1676 elif request == 'topics': self.listtopics()
1677 elif request == 'modules': self.listmodules()
1678 elif request[:8] == 'modules ':
1679 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001680 elif request in self.keywords: self.showtopic(request)
1681 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001682 elif request: doc(request, 'Help on %s:')
1683 elif isinstance(request, Helper): self()
1684 else: doc(request, 'Help on %s:')
1685 self.output.write('\n')
1686
1687 def intro(self):
1688 self.output.write('''
1689Welcome to Python %s! This is the online help utility.
1690
1691If this is your first time using Python, you should definitely check out
1692the tutorial on the Internet at http://www.python.org/doc/tut/.
1693
1694Enter the name of any module, keyword, or topic to get help on writing
1695Python programs and using Python modules. To quit this help utility and
1696return to the interpreter, just type "quit".
1697
1698To get a list of available modules, keywords, or topics, type "modules",
1699"keywords", or "topics". Each module also comes with a one-line summary
1700of what it does; to list the modules whose summaries contain a given word
1701such as "spam", type "modules spam".
1702''' % sys.version[:3])
1703
1704 def list(self, items, columns=4, width=80):
1705 items = items[:]
1706 items.sort()
1707 colw = width / columns
1708 rows = (len(items) + columns - 1) / columns
1709 for row in range(rows):
1710 for col in range(columns):
1711 i = col * rows + row
1712 if i < len(items):
1713 self.output.write(items[i])
1714 if col < columns - 1:
1715 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1716 self.output.write('\n')
1717
1718 def listkeywords(self):
1719 self.output.write('''
1720Here is a list of the Python keywords. Enter any keyword to get more help.
1721
1722''')
1723 self.list(self.keywords.keys())
1724
1725 def listtopics(self):
1726 self.output.write('''
1727Here is a list of available topics. Enter any topic name to get more help.
1728
1729''')
1730 self.list(self.topics.keys())
1731
1732 def showtopic(self, topic):
1733 if not self.docdir:
1734 self.output.write('''
1735Sorry, topic and keyword documentation is not available because the Python
1736HTML documentation files could not be found. If you have installed them,
1737please set the environment variable PYTHONDOCS to indicate their location.
1738''')
1739 return
1740 target = self.topics.get(topic, self.keywords.get(topic))
1741 if not target:
1742 self.output.write('no documentation found for %s\n' % repr(topic))
1743 return
1744 if type(target) is type(''):
1745 return self.showtopic(target)
1746
1747 filename, xrefs = target
1748 filename = self.docdir + '/' + filename + '.html'
1749 try:
1750 file = open(filename)
1751 except:
1752 self.output.write('could not read docs from %s\n' % filename)
1753 return
1754
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001755 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1756 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001757 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1758 file.close()
1759
1760 import htmllib, formatter, StringIO
1761 buffer = StringIO.StringIO()
1762 parser = htmllib.HTMLParser(
1763 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1764 parser.start_table = parser.do_p
1765 parser.end_table = lambda parser=parser: parser.do_p({})
1766 parser.start_tr = parser.do_br
1767 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1768 parser.feed(document)
1769 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1770 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001771 if xrefs:
1772 buffer = StringIO.StringIO()
1773 formatter.DumbWriter(buffer).send_flowing_data(
1774 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1775 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001776
1777 def listmodules(self, key=''):
1778 if key:
1779 self.output.write('''
1780Here is a list of matching modules. Enter any module name to get more help.
1781
1782''')
1783 apropos(key)
1784 else:
1785 self.output.write('''
1786Please wait a moment while I gather a list of all available modules...
1787
1788''')
1789 modules = {}
1790 def callback(path, modname, desc, modules=modules):
1791 if modname and modname[-9:] == '.__init__':
1792 modname = modname[:-9] + ' (package)'
1793 if find(modname, '.') < 0:
1794 modules[modname] = 1
1795 ModuleScanner().run(callback)
1796 self.list(modules.keys())
1797 self.output.write('''
1798Enter any module name to get more help. Or, type "modules spam" to search
1799for modules whose descriptions contain the word "spam".
1800''')
1801
1802help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001803
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001804class Scanner:
1805 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001806 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001807 self.roots = roots[:]
1808 self.state = []
1809 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001810 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001811
1812 def next(self):
1813 if not self.state:
1814 if not self.roots:
1815 return None
1816 root = self.roots.pop(0)
1817 self.state = [(root, self.children(root))]
1818 node, children = self.state[-1]
1819 if not children:
1820 self.state.pop()
1821 return self.next()
1822 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001823 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001824 self.state.append((child, self.children(child)))
1825 return child
1826
1827class ModuleScanner(Scanner):
1828 """An interruptible scanner that searches module synopses."""
1829 def __init__(self):
1830 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001831 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001832 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001833
1834 def submodules(self, (dir, package)):
1835 children = []
1836 for file in os.listdir(dir):
1837 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001838 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001839 children.append((path, package + (package and '.') + file))
1840 else:
1841 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001842 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001843 return children
1844
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001845 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001846 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001847 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001848 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001849 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001850 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001851
Ka-Ping Yee66246962001-04-12 11:59:50 +00001852 def run(self, callback, key=None, completer=None):
1853 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001854 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001855 seen = {}
1856
1857 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001858 if modname != '__main__':
1859 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001860 if key is None:
1861 callback(None, modname, '')
1862 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001863 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001864 if find(lower(modname + ' - ' + desc), key) >= 0:
1865 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001866
1867 while not self.quit:
1868 node = self.next()
1869 if not node: break
1870 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001871 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001872 if os.path.isfile(path) and modname:
1873 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001874 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001875 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001876 if key is None:
1877 callback(path, modname, '')
1878 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001879 desc = synopsis(path) or ''
1880 if find(lower(modname + ' - ' + desc), key) >= 0:
1881 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001882 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001883
1884def apropos(key):
1885 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001886 def callback(path, modname, desc):
1887 if modname[-9:] == '.__init__':
1888 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001889 print modname, desc and '- ' + desc
1890 try: import warnings
1891 except ImportError: pass
1892 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001893 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001894
1895# --------------------------------------------------- web browser interface
1896
Ka-Ping Yee66246962001-04-12 11:59:50 +00001897def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001898 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001899
1900 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1901 class Message(mimetools.Message):
1902 def __init__(self, fp, seekable=1):
1903 Message = self.__class__
1904 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1905 self.encodingheader = self.getheader('content-transfer-encoding')
1906 self.typeheader = self.getheader('content-type')
1907 self.parsetype()
1908 self.parseplist()
1909
1910 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1911 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001912 try:
1913 self.send_response(200)
1914 self.send_header('Content-Type', 'text/html')
1915 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001916 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001917 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001918
1919 def do_GET(self):
1920 path = self.path
1921 if path[-5:] == '.html': path = path[:-5]
1922 if path[:1] == '/': path = path[1:]
1923 if path and path != '.':
1924 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001925 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001926 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001927 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001928 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001929 if obj:
1930 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001931 else:
1932 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001933'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001934 else:
1935 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001936'<big><big><strong>Python: Index of Modules</strong></big></big>',
1937'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001938 def bltinlink(name):
1939 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001940 names = filter(lambda x: x != '__main__',
1941 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001942 contents = html.multicolumn(names, bltinlink)
1943 indices = ['<p>' + html.bigsection(
1944 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1945
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001946 seen = {}
1947 for dir in pathdirs():
1948 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001949 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001950<font color="#909090" face="helvetica, arial"><strong>
1951pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001952 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001953
1954 def log_message(self, *args): pass
1955
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001956 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001957 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001958 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001959 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001960 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001961 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001962 self.base.__init__(self, self.address, self.handler)
1963
1964 def serve_until_quit(self):
1965 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001966 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001967 while not self.quit:
1968 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1969 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001970
1971 def server_activate(self):
1972 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001973 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001974
1975 DocServer.base = BaseHTTPServer.HTTPServer
1976 DocServer.handler = DocHandler
1977 DocHandler.MessageClass = Message
1978 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001979 try:
1980 DocServer(port, callback).serve_until_quit()
1981 except (KeyboardInterrupt, select.error):
1982 pass
1983 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001984 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001985
1986# ----------------------------------------------------- graphical interface
1987
1988def gui():
1989 """Graphical interface (starts web server and pops up a control window)."""
1990 class GUI:
1991 def __init__(self, window, port=7464):
1992 self.window = window
1993 self.server = None
1994 self.scanner = None
1995
1996 import Tkinter
1997 self.server_frm = Tkinter.Frame(window)
1998 self.title_lbl = Tkinter.Label(self.server_frm,
1999 text='Starting server...\n ')
2000 self.open_btn = Tkinter.Button(self.server_frm,
2001 text='open browser', command=self.open, state='disabled')
2002 self.quit_btn = Tkinter.Button(self.server_frm,
2003 text='quit serving', command=self.quit, state='disabled')
2004
2005 self.search_frm = Tkinter.Frame(window)
2006 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
2007 self.search_ent = Tkinter.Entry(self.search_frm)
2008 self.search_ent.bind('<Return>', self.search)
2009 self.stop_btn = Tkinter.Button(self.search_frm,
2010 text='stop', pady=0, command=self.stop, state='disabled')
2011 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002012 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002013 self.stop_btn.pack(side='right')
2014
2015 self.window.title('pydoc')
2016 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2017 self.title_lbl.pack(side='top', fill='x')
2018 self.open_btn.pack(side='left', fill='x', expand=1)
2019 self.quit_btn.pack(side='right', fill='x', expand=1)
2020 self.server_frm.pack(side='top', fill='x')
2021
2022 self.search_lbl.pack(side='left')
2023 self.search_ent.pack(side='right', fill='x', expand=1)
2024 self.search_frm.pack(side='top', fill='x')
2025 self.search_ent.focus_set()
2026
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002027 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002028 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002029 self.result_lst.bind('<Button-1>', self.select)
2030 self.result_lst.bind('<Double-Button-1>', self.goto)
2031 self.result_scr = Tkinter.Scrollbar(window,
2032 orient='vertical', command=self.result_lst.yview)
2033 self.result_lst.config(yscrollcommand=self.result_scr.set)
2034
2035 self.result_frm = Tkinter.Frame(window)
2036 self.goto_btn = Tkinter.Button(self.result_frm,
2037 text='go to selected', command=self.goto)
2038 self.hide_btn = Tkinter.Button(self.result_frm,
2039 text='hide results', command=self.hide)
2040 self.goto_btn.pack(side='left', fill='x', expand=1)
2041 self.hide_btn.pack(side='right', fill='x', expand=1)
2042
2043 self.window.update()
2044 self.minwidth = self.window.winfo_width()
2045 self.minheight = self.window.winfo_height()
2046 self.bigminheight = (self.server_frm.winfo_reqheight() +
2047 self.search_frm.winfo_reqheight() +
2048 self.result_lst.winfo_reqheight() +
2049 self.result_frm.winfo_reqheight())
2050 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2051 self.expanded = 0
2052 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2053 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002054 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002055
2056 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002057 threading.Thread(
2058 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002059
2060 def ready(self, server):
2061 self.server = server
2062 self.title_lbl.config(
2063 text='Python documentation server at\n' + server.url)
2064 self.open_btn.config(state='normal')
2065 self.quit_btn.config(state='normal')
2066
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002067 def open(self, event=None, url=None):
2068 url = url or self.server.url
2069 try:
2070 import webbrowser
2071 webbrowser.open(url)
2072 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002073 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002074 os.system('start "%s"' % url)
2075 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002076 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002077 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002078 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002079 else:
2080 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2081 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002082
2083 def quit(self, event=None):
2084 if self.server:
2085 self.server.quit = 1
2086 self.window.quit()
2087
2088 def search(self, event=None):
2089 key = self.search_ent.get()
2090 self.stop_btn.pack(side='right')
2091 self.stop_btn.config(state='normal')
2092 self.search_lbl.config(text='Searching for "%s"...' % key)
2093 self.search_ent.forget()
2094 self.search_lbl.pack(side='left')
2095 self.result_lst.delete(0, 'end')
2096 self.goto_btn.config(state='disabled')
2097 self.expand()
2098
2099 import threading
2100 if self.scanner:
2101 self.scanner.quit = 1
2102 self.scanner = ModuleScanner()
2103 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002104 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002105
2106 def update(self, path, modname, desc):
2107 if modname[-9:] == '.__init__':
2108 modname = modname[:-9] + ' (package)'
2109 self.result_lst.insert('end',
2110 modname + ' - ' + (desc or '(no description)'))
2111
2112 def stop(self, event=None):
2113 if self.scanner:
2114 self.scanner.quit = 1
2115 self.scanner = None
2116
2117 def done(self):
2118 self.scanner = None
2119 self.search_lbl.config(text='Search for')
2120 self.search_lbl.pack(side='left')
2121 self.search_ent.pack(side='right', fill='x', expand=1)
2122 if sys.platform != 'win32': self.stop_btn.forget()
2123 self.stop_btn.config(state='disabled')
2124
2125 def select(self, event=None):
2126 self.goto_btn.config(state='normal')
2127
2128 def goto(self, event=None):
2129 selection = self.result_lst.curselection()
2130 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002131 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002132 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002133
2134 def collapse(self):
2135 if not self.expanded: return
2136 self.result_frm.forget()
2137 self.result_scr.forget()
2138 self.result_lst.forget()
2139 self.bigwidth = self.window.winfo_width()
2140 self.bigheight = self.window.winfo_height()
2141 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2142 self.window.wm_minsize(self.minwidth, self.minheight)
2143 self.expanded = 0
2144
2145 def expand(self):
2146 if self.expanded: return
2147 self.result_frm.pack(side='bottom', fill='x')
2148 self.result_scr.pack(side='right', fill='y')
2149 self.result_lst.pack(side='top', fill='both', expand=1)
2150 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2151 self.window.wm_minsize(self.minwidth, self.bigminheight)
2152 self.expanded = 1
2153
2154 def hide(self, event=None):
2155 self.stop()
2156 self.collapse()
2157
2158 import Tkinter
2159 try:
Martin v. Löwise09bd932004-08-22 16:13:26 +00002160 root = Tkinter.Tk()
2161 # Tk will crash if pythonw.exe has an XP .manifest
2162 # file and the root has is not destroyed explicitly.
2163 # If the problem is ever fixed in Tk, the explicit
2164 # destroy can go.
2165 try:
2166 gui = GUI(root)
2167 root.mainloop()
2168 finally:
2169 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002170 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002171 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002172
2173# -------------------------------------------------- command-line interface
2174
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002175def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002176 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002177
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002178def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002179 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002180 import getopt
2181 class BadUsage: pass
2182
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002183 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002184 scriptdir = os.path.dirname(sys.argv[0])
2185 if scriptdir in sys.path:
2186 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002187 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002188
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002189 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002190 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002191 writing = 0
2192
2193 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002194 if opt == '-g':
2195 gui()
2196 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002197 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002198 apropos(val)
2199 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002200 if opt == '-p':
2201 try:
2202 port = int(val)
2203 except ValueError:
2204 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002205 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002206 print 'pydoc server ready at %s' % server.url
2207 def stopped():
2208 print 'pydoc server stopped'
2209 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002210 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002211 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002212 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002213
2214 if not args: raise BadUsage
2215 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002216 if ispath(arg) and not os.path.exists(arg):
2217 print 'file %r does not exist' % arg
2218 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002219 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002220 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002221 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002222 if writing:
2223 if ispath(arg) and os.path.isdir(arg):
2224 writedocs(arg)
2225 else:
2226 writedoc(arg)
2227 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002228 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002229 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002230 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002231
2232 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002233 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002234 print """pydoc - the Python documentation tool
2235
2236%s <name> ...
2237 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002238 Python keyword, topic, function, module, or package, or a dotted
2239 reference to a class or function within a module or module in a
2240 package. If <name> contains a '%s', it is used as the path to a
2241 Python source file to document. If name is 'keywords', 'topics',
2242 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002243
2244%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002245 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002246
2247%s -p <port>
2248 Start an HTTP server on the given port on the local machine.
2249
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002250%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002251 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002252
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002253%s -w <name> ...
2254 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002255 directory. If <name> contains a '%s', it is treated as a filename; if
2256 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002257""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002258
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002259if __name__ == '__main__': cli()