blob: ee45643b43242bafc64c544a41ae3bbb4b85d65c [file] [log] [blame]
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001#!/usr/bin/env python
Guido van Rossumfce538c2002-08-06 17:29:38 +00002# -*- coding: Latin-1 -*-
Ka-Ping Yee1d384632001-03-01 00:24:32 +00003"""Generate Python documentation in HTML or text for interactive use.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00004
Ka-Ping Yeedd175342001-02-27 14:43:46 +00005In the Python interpreter, do "from pydoc import help" to provide online
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00006help. Calling help(thing) on a Python object documents the object.
7
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00008Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00009
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000010Run "pydoc <name>" to show documentation on something. <name> may be
11the name of a function, module, package, or a dotted reference to a
12class or function within a module or module in a package. If the
13argument contains a path segment delimiter (e.g. slash on Unix,
14backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000015
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000016Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000018
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000019Run "pydoc -p <port>" to start an HTTP server on a given port on the
20local machine to generate documentation web pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000021
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000022For platforms without a command line, "pydoc -g" starts the HTTP server
23and also pops up a little window for controlling it.
24
25Run "pydoc -w <name>" to write out the HTML documentation for a module
26to a file named "<name>.html".
Skip Montanaro4997a692003-09-10 16:47:51 +000027
28Module docs for core modules are assumed to be in
29
30 http://www.python.org/doc/current/lib/
31
32This can be overridden by setting the PYTHONDOCS environment variable
33to a different URL or to a local directory containing the Library
34Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000035"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000036
37__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000038__date__ = "26 February 2001"
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000039
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000040__version__ = "$Revision$"
Martin v. Löwis6fe8f192004-11-14 10:21:04 +000041__credits__ = """Guido van Rossum, for an excellent programming language.
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000042Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000043Paul Prescod, for all his work on onlinehelp.
44Richard Chamberlain, for the first implementation of textdoc.
Raymond Hettingered2dbe32005-01-01 07:51:01 +000045"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000046
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000047# Known bugs that can't be fixed here:
48# - imp.load_module() cannot be prevented from clobbering existing
49# loaded modules, so calling synopsis() on a binary module file
50# changes the contents of any existing module with the same name.
51# - If the __file__ attribute on a module is a relative path and
52# the current directory is changed with os.chdir(), an incorrect
53# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000054
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):
Georg Brandl94432422005-07-22 21:52:25 +000096 """Check if an object is of a type that probably means it's data."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000097 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.
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000157 if name in ('__builtins__', '__doc__', '__file__', '__path__',
158 '__module__', '__name__', '__slots__'): return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000159 # 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
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000167def classify_class_attrs(object):
168 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
169 def fixup((name, kind, cls, value)):
170 if inspect.isdatadescriptor(value):
171 kind = 'data descriptor'
172 return name, kind, cls, value
173 return map(fixup, inspect.classify_class_attrs(object))
174
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000175# ----------------------------------------------------- module manipulation
176
177def ispackage(path):
178 """Guess whether a path refers to a package directory."""
179 if os.path.isdir(path):
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000180 for ext in ('.py', '.pyc', '.pyo'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000181 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000182 return True
183 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000184
185def synopsis(filename, cache={}):
186 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000187 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000188 lastupdate, result = cache.get(filename, (0, None))
189 if lastupdate < mtime:
190 info = inspect.getmoduleinfo(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000191 try:
192 file = open(filename)
193 except IOError:
194 # module can't be opened, so skip it
195 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000196 if info and 'b' in info[2]: # binary modules have to be imported
197 try: module = imp.load_module('__temp__', file, filename, info[1:])
198 except: return None
199 result = split(module.__doc__ or '', '\n')[0]
200 del sys.modules['__temp__']
201 else: # text modules can be directly examined
202 line = file.readline()
203 while line[:1] == '#' or not strip(line):
204 line = file.readline()
205 if not line: break
206 line = strip(line)
207 if line[:4] == 'r"""': line = line[1:]
208 if line[:3] == '"""':
209 line = line[3:]
210 if line[-1:] == '\\': line = line[:-1]
211 while not strip(line):
212 line = file.readline()
213 if not line: break
214 result = strip(split(line, '"""')[0])
215 else: result = None
216 file.close()
217 cache[filename] = (mtime, result)
218 return result
219
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000220class ErrorDuringImport(Exception):
221 """Errors that occurred while trying to import something to document it."""
222 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000223 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000224 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000225 self.value = value
226 self.tb = tb
227
228 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000229 exc = self.exc
230 if type(exc) is types.ClassType:
231 exc = exc.__name__
232 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000233
234def importfile(path):
235 """Import a Python source file or compiled file given its path."""
236 magic = imp.get_magic()
237 file = open(path, 'r')
238 if file.read(len(magic)) == magic:
239 kind = imp.PY_COMPILED
240 else:
241 kind = imp.PY_SOURCE
242 file.close()
243 filename = os.path.basename(path)
244 name, ext = os.path.splitext(filename)
245 file = open(path, 'r')
246 try:
247 module = imp.load_module(name, file, path, (ext, 'r', kind))
248 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000249 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000250 file.close()
251 return module
252
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000253def safeimport(path, forceload=0, cache={}):
254 """Import a module; handle errors; return None if the module isn't found.
255
256 If the module *is* found but an exception occurs, it's wrapped in an
257 ErrorDuringImport exception and reraised. Unlike __import__, if a
258 package path is specified, the module at the end of the path is returned,
259 not the package at the beginning. If the optional 'forceload' argument
260 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000261 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000262 # If forceload is 1 and the module has been previously loaded from
263 # disk, we always have to reload the module. Checking the file's
264 # mtime isn't good enough (e.g. the module could contain a class
265 # that inherits from another module that has changed).
266 if forceload and path in sys.modules:
267 if path not in sys.builtin_module_names:
268 # Avoid simply calling reload() because it leaves names in
269 # the currently loaded module lying around if they're not
270 # defined in the new source file. Instead, remove the
271 # module from sys.modules and re-import. Also remove any
272 # submodules because they won't appear in the newly loaded
273 # module's namespace if they're already in sys.modules.
274 subs = [m for m in sys.modules if m.startswith(path + '.')]
275 for key in [path] + subs:
276 # Prevent garbage collection.
277 cache[key] = sys.modules[key]
278 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000279 module = __import__(path)
280 except:
281 # Did the error occur before or after the module was found?
282 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000283 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000284 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000285 raise ErrorDuringImport(sys.modules[path].__file__, info)
286 elif exc is SyntaxError:
287 # A SyntaxError occurred before we could execute the module.
288 raise ErrorDuringImport(value.filename, info)
289 elif exc is ImportError and \
290 split(lower(str(value)))[:2] == ['no', 'module']:
291 # The module was not found.
292 return None
293 else:
294 # Some other error occurred during the importing process.
295 raise ErrorDuringImport(path, sys.exc_info())
296 for part in split(path, '.')[1:]:
297 try: module = getattr(module, part)
298 except AttributeError: return None
299 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000300
301# ---------------------------------------------------- formatter base class
302
303class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000304 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000305 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000306 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000307 # 'try' clause is to attempt to handle the possibility that inspect
308 # identifies something in a way that pydoc itself has issues handling;
309 # think 'super' and how it is a descriptor (which raises the exception
310 # by lacking a __name__ attribute) and an instance.
311 try:
312 if inspect.ismodule(object): return self.docmodule(*args)
313 if inspect.isclass(object): return self.docclass(*args)
314 if inspect.isroutine(object): return self.docroutine(*args)
315 except AttributeError:
316 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000317 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000318 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000319
320 def fail(self, object, name=None, *args):
321 """Raise an exception for unimplemented types."""
322 message = "don't know how to document object%s of type %s" % (
323 name and ' ' + repr(name), type(object).__name__)
324 raise TypeError, message
325
326 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000327
Skip Montanaro4997a692003-09-10 16:47:51 +0000328 def getdocloc(self, object):
329 """Return the location of module docs or None"""
330
331 try:
332 file = inspect.getabsfile(object)
333 except TypeError:
334 file = '(built-in)'
335
336 docloc = os.environ.get("PYTHONDOCS",
337 "http://www.python.org/doc/current/lib")
338 basedir = os.path.join(sys.exec_prefix, "lib",
339 "python"+sys.version[0:3])
340 if (isinstance(object, type(os)) and
341 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
342 'marshal', 'posix', 'signal', 'sys',
343 'thread', 'zipimport') or
344 (file.startswith(basedir) and
345 not file.startswith(os.path.join(basedir, 'site-packages'))))):
Skip Montanarof2134842004-06-07 02:40:05 +0000346 htmlfile = "module-%s.html" % object.__name__
Skip Montanaro4997a692003-09-10 16:47:51 +0000347 if docloc.startswith("http://"):
Skip Montanarof2134842004-06-07 02:40:05 +0000348 docloc = "%s/%s" % (docloc.rstrip("/"), htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000349 else:
Skip Montanarof2134842004-06-07 02:40:05 +0000350 docloc = os.path.join(docloc, htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000351 else:
352 docloc = None
353 return docloc
354
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000355# -------------------------------------------- HTML documentation generator
356
357class HTMLRepr(Repr):
358 """Class for safely making an HTML representation of a Python object."""
359 def __init__(self):
360 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000361 self.maxlist = self.maxtuple = 20
362 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000363 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000364
365 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000366 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000367
368 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000369 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000370
371 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000372 if hasattr(type(x), '__name__'):
373 methodname = 'repr_' + join(split(type(x).__name__), '_')
374 if hasattr(self, methodname):
375 return getattr(self, methodname)(x, level)
376 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000377
378 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000379 test = cram(x, self.maxstring)
380 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000381 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000382 # Backslashes are only literal in the string and are never
383 # needed to make any special characters, so show a raw string.
384 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000385 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000386 r'<font color="#c040c0">\1</font>',
387 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000388
Skip Montanarodf708782002-03-07 22:58:02 +0000389 repr_str = repr_string
390
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000391 def repr_instance(self, x, level):
392 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000393 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000394 except:
395 return self.escape('<%s instance>' % x.__class__.__name__)
396
397 repr_unicode = repr_string
398
399class HTMLDoc(Doc):
400 """Formatter class for HTML documentation."""
401
402 # ------------------------------------------- HTML formatting utilities
403
404 _repr_instance = HTMLRepr()
405 repr = _repr_instance.repr
406 escape = _repr_instance.escape
407
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000408 def page(self, title, contents):
409 """Format an HTML page."""
410 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000411<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000412<html><head><title>Python: %s</title>
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000413</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000414%s
415</body></html>''' % (title, contents)
416
417 def heading(self, title, fgcol, bgcol, extras=''):
418 """Format a page heading."""
419 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000420<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000421<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000422<td valign=bottom>&nbsp;<br>
423<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000424><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000425><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000426 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
427
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000428 def section(self, title, fgcol, bgcol, contents, width=6,
429 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000430 """Format a section with a heading."""
431 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000432 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000433 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000434<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000435<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000436<td colspan=3 valign=bottom>&nbsp;<br>
437<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000438 ''' % (bgcol, fgcol, title)
439 if prelude:
440 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000441<tr bgcolor="%s"><td rowspan=2>%s</td>
442<td colspan=2>%s</td></tr>
443<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
444 else:
445 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000446<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000447
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000448 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000449
450 def bigsection(self, title, *args):
451 """Format a section with a big heading."""
452 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000453 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000454
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000455 def preformat(self, text):
456 """Format literal preformatted text."""
457 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000458 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
459 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000460
461 def multicolumn(self, list, format, cols=4):
462 """Format a list of items into a multi-column list."""
463 result = ''
464 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000465 for col in range(cols):
466 result = result + '<td width="%d%%" valign=top>' % (100/cols)
467 for i in range(rows*col, rows*col+rows):
468 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000469 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000470 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000471 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000472
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000473 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000474
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000475 def namelink(self, name, *dicts):
476 """Make a link for an identifier, given name-to-URL mappings."""
477 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000478 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000479 return '<a href="%s">%s</a>' % (dict[name], name)
480 return name
481
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000482 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000483 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000484 name, module = object.__name__, sys.modules.get(object.__module__)
485 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000486 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000487 module.__name__, name, classname(object, modname))
488 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000489
490 def modulelink(self, object):
491 """Make a link for a module."""
492 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
493
494 def modpkglink(self, (name, path, ispackage, shadowed)):
495 """Make a link for a module or package to display in an index."""
496 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000497 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000498 if path:
499 url = '%s.%s.html' % (path, name)
500 else:
501 url = '%s.html' % name
502 if ispackage:
503 text = '<strong>%s</strong>&nbsp;(package)' % name
504 else:
505 text = name
506 return '<a href="%s">%s</a>' % (url, text)
507
508 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
509 """Mark up some plain text, given a context of symbols to look for.
510 Each context dictionary maps object names to anchor names."""
511 escape = escape or self.escape
512 results = []
513 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000514 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
515 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000516 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000517 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000518 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000519 match = pattern.search(text, here)
520 if not match: break
521 start, end = match.span()
522 results.append(escape(text[here:start]))
523
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000524 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000525 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000526 url = escape(all).replace('"', '&quot;')
527 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000528 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000529 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
530 results.append('<a href="%s">%s</a>' % (url, escape(all)))
531 elif pep:
532 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000533 results.append('<a href="%s">%s</a>' % (url, escape(all)))
534 elif text[end:end+1] == '(':
535 results.append(self.namelink(name, methods, funcs, classes))
536 elif selfdot:
537 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000538 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000539 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000540 here = end
541 results.append(escape(text[here:]))
542 return join(results, '')
543
544 # ---------------------------------------------- type-specific routines
545
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000546 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000547 """Produce HTML for a class tree as given by inspect.getclasstree()."""
548 result = ''
549 for entry in tree:
550 if type(entry) is type(()):
551 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000552 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000553 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000554 if bases and bases != (parent,):
555 parents = []
556 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000557 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000558 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000559 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000560 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000561 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000562 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000563 return '<dl>\n%s</dl>\n' % result
564
Tim Peters8dd7ade2001-10-18 19:56:17 +0000565 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000566 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000567 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000568 try:
569 all = object.__all__
570 except AttributeError:
571 all = None
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000572 parts = split(name, '.')
573 links = []
574 for i in range(len(parts)-1):
575 links.append(
576 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
577 (join(parts[:i+1], '.'), parts[i]))
578 linkedname = join(links + parts[-1:], '.')
579 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000580 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000581 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000582 url = path
583 if sys.platform == 'win32':
584 import nturl2path
585 url = nturl2path.pathname2url(path)
586 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000587 except TypeError:
588 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000589 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000590 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000591 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000592 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
593 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000594 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000595 if hasattr(object, '__date__'):
596 info.append(self.escape(str(object.__date__)))
597 if info:
598 head = head + ' (%s)' % join(info, ', ')
Skip Montanaro4997a692003-09-10 16:47:51 +0000599 docloc = self.getdocloc(object)
600 if docloc is not None:
601 docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
602 else:
603 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000604 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000605 head, '#ffffff', '#7799ee',
606 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000607
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000608 modules = inspect.getmembers(object, inspect.ismodule)
609
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000610 classes, cdict = [], {}
611 for key, value in inspect.getmembers(object, inspect.isclass):
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.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000615 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000616 classes.append((key, value))
617 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000618 for key, value in classes:
619 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000620 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000621 module = sys.modules.get(modname)
622 if modname != name and module and hasattr(module, key):
623 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000624 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000625 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000626 funcs, fdict = [], {}
627 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000628 # if __all__ exists, believe it. Otherwise use old heuristic.
629 if (all is not None or
630 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000631 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000632 funcs.append((key, value))
633 fdict[key] = '#-' + key
634 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000635 data = []
636 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000637 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000638 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000639
640 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
641 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000642 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000643
644 if hasattr(object, '__path__'):
645 modpkgs = []
646 modnames = []
647 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000648 path = os.path.join(object.__path__[0], file)
649 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000650 if modname != '__init__':
651 if modname and modname not in modnames:
652 modpkgs.append((modname, name, 0, 0))
653 modnames.append(modname)
654 elif ispackage(path):
655 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000656 modpkgs.sort()
657 contents = self.multicolumn(modpkgs, self.modpkglink)
658 result = result + self.bigsection(
659 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000660 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000661 contents = self.multicolumn(
662 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000663 result = result + self.bigsection(
664 'Modules', '#fffff', '#aa55cc', contents)
665
666 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000667 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000668 contents = [
669 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000670 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000671 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000672 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000673 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000674 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000675 contents = []
676 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000677 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000678 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000679 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000680 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000681 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000682 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000683 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000684 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000685 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000686 if hasattr(object, '__author__'):
687 contents = self.markup(str(object.__author__), self.preformat)
688 result = result + self.bigsection(
689 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000690 if hasattr(object, '__credits__'):
691 contents = self.markup(str(object.__credits__), self.preformat)
692 result = result + self.bigsection(
693 'Credits', '#ffffff', '#7799ee', contents)
694
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000695 return result
696
Tim Peters8dd7ade2001-10-18 19:56:17 +0000697 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
698 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000699 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000700 realname = object.__name__
701 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000702 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000703
Tim Petersb47879b2001-09-24 04:47:19 +0000704 contents = []
705 push = contents.append
706
Tim Petersfa26f7c2001-09-24 08:05:11 +0000707 # Cute little class to pump out a horizontal rule between sections.
708 class HorizontalRule:
709 def __init__(self):
710 self.needone = 0
711 def maybe(self):
712 if self.needone:
713 push('<hr>\n')
714 self.needone = 1
715 hr = HorizontalRule()
716
Tim Petersc86f6ca2001-09-26 21:31:51 +0000717 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000718 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000719 if len(mro) > 2:
720 hr.maybe()
721 push('<dl><dt>Method resolution order:</dt>\n')
722 for base in mro:
723 push('<dd>%s</dd>\n' % self.classlink(base,
724 object.__module__))
725 push('</dl>\n')
726
Tim Petersb47879b2001-09-24 04:47:19 +0000727 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000728 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000729 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000730 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000731 push(msg)
732 for name, kind, homecls, value in ok:
733 push(self.document(getattr(object, name), name, mod,
734 funcs, classes, mdict, object))
735 push('\n')
736 return attrs
737
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000738 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000739 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000740 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000741 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000742 push(msg)
743 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000744 push(self._docdescriptor(name, value, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000745 return attrs
746
Tim Petersfa26f7c2001-09-24 08:05:11 +0000747 def spilldata(msg, attrs, predicate):
748 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000749 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000750 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000751 push(msg)
752 for name, kind, homecls, value in ok:
753 base = self.docother(getattr(object, name), name, mod)
Martin v. Löwise59e2ba2003-05-03 09:09:02 +0000754 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000755 doc = getattr(value, "__doc__", None)
756 else:
757 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000758 if doc is None:
759 push('<dl><dt>%s</dl>\n' % base)
760 else:
761 doc = self.markup(getdoc(value), self.preformat,
762 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000763 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000764 push('<dl><dt>%s%s</dl>\n' % (base, doc))
765 push('\n')
766 return attrs
767
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000768 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000769 classify_class_attrs(object))
Tim Petersb47879b2001-09-24 04:47:19 +0000770 mdict = {}
771 for key, kind, homecls, value in attrs:
772 mdict[key] = anchor = '#' + name + '-' + key
773 value = getattr(object, key)
774 try:
775 # The value may not be hashable (e.g., a data attr with
776 # a dict or list value).
777 mdict[value] = anchor
778 except TypeError:
779 pass
780
Tim Petersfa26f7c2001-09-24 08:05:11 +0000781 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000782 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000783 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000784 else:
785 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000786 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
787
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000788 if thisclass is __builtin__.object:
789 attrs = inherited
790 continue
791 elif thisclass is object:
792 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000793 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000794 tag = 'inherited from %s' % self.classlink(thisclass,
795 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000796 tag += ':<br>\n'
797
798 # Sort attrs by name.
Raymond Hettinger6b59f5f2003-10-16 05:53:16 +0000799 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000800
801 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000802 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000803 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000804 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000805 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000806 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000807 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000808 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
809 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000810 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000811 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000812 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000813 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000814
815 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000816
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000817 if name == realname:
818 title = '<a name="%s">class <strong>%s</strong></a>' % (
819 name, realname)
820 else:
821 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
822 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000823 if bases:
824 parents = []
825 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000826 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000827 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000828 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000829 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000830
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000831 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000832
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000833 def formatvalue(self, object):
834 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000835 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000836
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000837 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000838 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000839 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000840 realname = object.__name__
841 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000842 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000843 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000844 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000845 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000846 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000847 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000848 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000849 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000850 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000851 if object.im_self:
852 note = ' method of %s instance' % self.classlink(
853 object.im_self.__class__, mod)
854 else:
855 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000856 object = object.im_func
857
858 if name == realname:
859 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
860 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000861 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000862 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000863 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000864 cl.__name__ + '-' + realname, realname)
865 skipdocs = 1
866 else:
867 reallink = realname
868 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
869 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000870 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000871 args, varargs, varkw, defaults = inspect.getargspec(object)
872 argspec = inspect.formatargspec(
873 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000874 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000875 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000876 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000877 else:
878 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000879
Tim Peters2306d242001-09-25 03:18:32 +0000880 decl = title + argspec + (note and self.grey(
881 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000882
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000883 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000884 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000885 else:
886 doc = self.markup(
887 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000888 doc = doc and '<dd><tt>%s</tt></dd>' % doc
889 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000890
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000891 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000892 results = []
893 push = results.append
894
895 if name:
896 push('<dl><dt><strong>%s</strong></dt>\n' % name)
897 if value.__doc__ is not None:
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +0000898 doc = self.markup(getdoc(value), self.preformat)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000899 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000900 push('</dl>\n')
901
902 return ''.join(results)
903
904 def docproperty(self, object, name=None, mod=None, cl=None):
905 """Produce html documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000906 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000907
Tim Peters8dd7ade2001-10-18 19:56:17 +0000908 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000909 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000910 lhs = name and '<strong>%s</strong> = ' % name or ''
911 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000912
913 def index(self, dir, shadowed=None):
914 """Generate an HTML index for a directory of modules."""
915 modpkgs = []
916 if shadowed is None: shadowed = {}
917 seen = {}
918 files = os.listdir(dir)
919
920 def found(name, ispackage,
921 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
Raymond Hettinger4f759d82002-11-02 02:02:46 +0000922 if name not in seen:
923 modpkgs.append((name, '', ispackage, name in shadowed))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000924 seen[name] = 1
925 shadowed[name] = 1
926
927 # Package spam/__init__.py takes precedence over module spam.py.
928 for file in files:
929 path = os.path.join(dir, file)
930 if ispackage(path): found(file, 1)
931 for file in files:
932 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000933 if os.path.isfile(path):
934 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000935 if modname: found(modname, 0)
936
937 modpkgs.sort()
938 contents = self.multicolumn(modpkgs, self.modpkglink)
939 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
940
941# -------------------------------------------- text documentation generator
942
943class TextRepr(Repr):
944 """Class for safely making a text representation of a Python object."""
945 def __init__(self):
946 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000947 self.maxlist = self.maxtuple = 20
948 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000949 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000950
951 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000952 if hasattr(type(x), '__name__'):
953 methodname = 'repr_' + join(split(type(x).__name__), '_')
954 if hasattr(self, methodname):
955 return getattr(self, methodname)(x, level)
956 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000957
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000958 def repr_string(self, x, level):
959 test = cram(x, self.maxstring)
960 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000961 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000962 # Backslashes are only literal in the string and are never
963 # needed to make any special characters, so show a raw string.
964 return 'r' + testrepr[0] + test + testrepr[0]
965 return testrepr
966
Skip Montanarodf708782002-03-07 22:58:02 +0000967 repr_str = repr_string
968
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000969 def repr_instance(self, x, level):
970 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000971 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000972 except:
973 return '<%s instance>' % x.__class__.__name__
974
975class TextDoc(Doc):
976 """Formatter class for text documentation."""
977
978 # ------------------------------------------- text formatting utilities
979
980 _repr_instance = TextRepr()
981 repr = _repr_instance.repr
982
983 def bold(self, text):
984 """Format a string in bold by overstriking."""
985 return join(map(lambda ch: ch + '\b' + ch, text), '')
986
987 def indent(self, text, prefix=' '):
988 """Indent text by prepending a given prefix to each line."""
989 if not text: return ''
990 lines = split(text, '\n')
991 lines = map(lambda line, prefix=prefix: prefix + line, lines)
992 if lines: lines[-1] = rstrip(lines[-1])
993 return join(lines, '\n')
994
995 def section(self, title, contents):
996 """Format a section with a given heading."""
997 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
998
999 # ---------------------------------------------- type-specific routines
1000
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001001 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001002 """Render in text a class tree as returned by inspect.getclasstree()."""
1003 result = ''
1004 for entry in tree:
1005 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001006 c, bases = entry
1007 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001008 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001009 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001010 result = result + '(%s)' % join(parents, ', ')
1011 result = result + '\n'
1012 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001013 result = result + self.formattree(
1014 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001015 return result
1016
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001017 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001018 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001019 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001020 synop, desc = splitdoc(getdoc(object))
1021 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001022
1023 try:
Skip Montanaroa5616d22004-06-11 04:46:12 +00001024 all = object.__all__
1025 except AttributeError:
1026 all = None
1027
1028 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001029 file = inspect.getabsfile(object)
1030 except TypeError:
1031 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001032 result = result + self.section('FILE', file)
Skip Montanaro4997a692003-09-10 16:47:51 +00001033
1034 docloc = self.getdocloc(object)
1035 if docloc is not None:
1036 result = result + self.section('MODULE DOCS', docloc)
1037
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001038 if desc:
1039 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001040
1041 classes = []
1042 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001043 # if __all__ exists, believe it. Otherwise use old heuristic.
1044 if (all is not None
1045 or (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001046 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001047 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001048 funcs = []
1049 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001050 # if __all__ exists, believe it. Otherwise use old heuristic.
1051 if (all is not None or
1052 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001053 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001054 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001055 data = []
1056 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001057 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001058 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001059
1060 if hasattr(object, '__path__'):
1061 modpkgs = []
1062 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001063 path = os.path.join(object.__path__[0], file)
1064 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001065 if modname != '__init__':
1066 if modname and modname not in modpkgs:
1067 modpkgs.append(modname)
1068 elif ispackage(path):
1069 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001070 modpkgs.sort()
1071 result = result + self.section(
1072 'PACKAGE CONTENTS', join(modpkgs, '\n'))
1073
1074 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001075 classlist = map(lambda (key, value): value, classes)
1076 contents = [self.formattree(
1077 inspect.getclasstree(classlist, 1), name)]
1078 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001079 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001080 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001081
1082 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001083 contents = []
1084 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001085 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001086 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001087
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001088 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001089 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001090 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001091 contents.append(self.docother(value, key, name, maxlen=70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001092 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001093
1094 if hasattr(object, '__version__'):
1095 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001096 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1097 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001098 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001099 if hasattr(object, '__date__'):
1100 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001101 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001102 result = result + self.section('AUTHOR', str(object.__author__))
1103 if hasattr(object, '__credits__'):
1104 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001105 return result
1106
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001107 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001108 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001109 realname = object.__name__
1110 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001111 bases = object.__bases__
1112
Tim Petersc86f6ca2001-09-26 21:31:51 +00001113 def makename(c, m=object.__module__):
1114 return classname(c, m)
1115
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001116 if name == realname:
1117 title = 'class ' + self.bold(realname)
1118 else:
1119 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001120 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001121 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001122 title = title + '(%s)' % join(parents, ', ')
1123
1124 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001125 contents = doc and [doc + '\n'] or []
1126 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001127
Tim Petersc86f6ca2001-09-26 21:31:51 +00001128 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001129 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001130 if len(mro) > 2:
1131 push("Method resolution order:")
1132 for base in mro:
1133 push(' ' + makename(base))
1134 push('')
1135
Tim Petersf4aad8e2001-09-24 22:40:47 +00001136 # Cute little class to pump out a horizontal rule between sections.
1137 class HorizontalRule:
1138 def __init__(self):
1139 self.needone = 0
1140 def maybe(self):
1141 if self.needone:
1142 push('-' * 70)
1143 self.needone = 1
1144 hr = HorizontalRule()
1145
Tim Peters28355492001-09-23 21:29:55 +00001146 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001147 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001148 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001149 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001150 push(msg)
1151 for name, kind, homecls, value in ok:
1152 push(self.document(getattr(object, name),
1153 name, mod, object))
1154 return attrs
1155
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001156 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001157 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:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001162 push(self._docdescriptor(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001163 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001164
Tim Petersfa26f7c2001-09-24 08:05:11 +00001165 def spilldata(msg, attrs, predicate):
1166 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001167 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001168 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001169 push(msg)
1170 for name, kind, homecls, value in ok:
Martin v. Löwise59e2ba2003-05-03 09:09:02 +00001171 if callable(value) or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001172 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001173 else:
1174 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001175 push(self.docother(getattr(object, name),
Georg Brandl8b813db2005-10-01 16:32:31 +00001176 name, mod, maxlen=70, doc=doc) + '\n')
Tim Peters28355492001-09-23 21:29:55 +00001177 return attrs
1178
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001179 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001180 classify_class_attrs(object))
Tim Petersfa26f7c2001-09-24 08:05:11 +00001181 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001182 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001183 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001184 else:
1185 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001186 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1187
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001188 if thisclass is __builtin__.object:
1189 attrs = inherited
1190 continue
1191 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001192 tag = "defined here"
1193 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001194 tag = "inherited from %s" % classname(thisclass,
1195 object.__module__)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001196 filter(lambda t: not t[0].startswith('_'), attrs)
Tim Peters28355492001-09-23 21:29:55 +00001197
1198 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001199 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001200
1201 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001202 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001203 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001204 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001205 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001206 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001207 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001208 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1209 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001210 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1211 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001212 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001213 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001214
1215 contents = '\n'.join(contents)
1216 if not contents:
1217 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001218 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1219
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001220 def formatvalue(self, object):
1221 """Format an argument default value as text."""
1222 return '=' + self.repr(object)
1223
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001224 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001225 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001226 realname = object.__name__
1227 name = name or realname
1228 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001229 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001230 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001231 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001232 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001233 if imclass is not cl:
1234 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001235 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001236 if object.im_self:
1237 note = ' method of %s instance' % classname(
1238 object.im_self.__class__, mod)
1239 else:
1240 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001241 object = object.im_func
1242
1243 if name == realname:
1244 title = self.bold(realname)
1245 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001246 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001247 cl.__dict__[realname] is object):
1248 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001249 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001250 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001251 args, varargs, varkw, defaults = inspect.getargspec(object)
1252 argspec = inspect.formatargspec(
1253 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001254 if realname == '<lambda>':
Georg Brandl501dd0d2006-02-17 09:45:40 +00001255 title = self.bold(name) + ' lambda '
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001256 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001257 else:
1258 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001259 decl = title + argspec + note
1260
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001261 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001262 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001263 else:
1264 doc = getdoc(object) or ''
1265 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001266
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001267 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001268 results = []
1269 push = results.append
1270
1271 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001272 push(self.bold(name))
1273 push('\n')
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001274 doc = getdoc(value) or ''
1275 if doc:
1276 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001277 push('\n')
1278 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001279
1280 def docproperty(self, object, name=None, mod=None, cl=None):
1281 """Produce text documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001282 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001283
Georg Brandl8b813db2005-10-01 16:32:31 +00001284 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001285 """Produce text documentation for a data object."""
1286 repr = self.repr(object)
1287 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001288 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001289 chop = maxlen - len(line)
1290 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001291 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001292 if doc is not None:
1293 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001294 return line
1295
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001296# --------------------------------------------------------- user interfaces
1297
1298def pager(text):
1299 """The first time this is called, determine what kind of pager to use."""
1300 global pager
1301 pager = getpager()
1302 pager(text)
1303
1304def getpager():
1305 """Decide what method to use for paging through text."""
1306 if type(sys.stdout) is not types.FileType:
1307 return plainpager
1308 if not sys.stdin.isatty() or not sys.stdout.isatty():
1309 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001310 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001311 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001312 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001313 elif os.environ.get('TERM') in ('dumb', 'emacs'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001314 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001315 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001316 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001317 if os.environ.get('TERM') in ('dumb', 'emacs'):
1318 return plainpager
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001319 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001320 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001321 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001322 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001323
1324 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001325 (fd, filename) = tempfile.mkstemp()
1326 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001327 try:
1328 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1329 return lambda text: pipepager(text, 'more')
1330 else:
1331 return ttypager
1332 finally:
1333 os.unlink(filename)
1334
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001335def plain(text):
1336 """Remove boldface formatting from text."""
1337 return re.sub('.\b', '', text)
1338
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001339def pipepager(text, cmd):
1340 """Page through text by feeding it to another program."""
1341 pipe = os.popen(cmd, 'w')
1342 try:
1343 pipe.write(text)
1344 pipe.close()
1345 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001346 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001347
1348def tempfilepager(text, cmd):
1349 """Page through text by invoking a program on a temporary file."""
1350 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001351 filename = tempfile.mktemp()
1352 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001353 file.write(text)
1354 file.close()
1355 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001356 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001357 finally:
1358 os.unlink(filename)
1359
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001360def ttypager(text):
1361 """Page through text on a text terminal."""
1362 lines = split(plain(text), '\n')
1363 try:
1364 import tty
1365 fd = sys.stdin.fileno()
1366 old = tty.tcgetattr(fd)
1367 tty.setcbreak(fd)
1368 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001369 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001370 tty = None
1371 getchar = lambda: sys.stdin.readline()[:-1][:1]
1372
1373 try:
1374 r = inc = os.environ.get('LINES', 25) - 1
1375 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1376 while lines[r:]:
1377 sys.stdout.write('-- more --')
1378 sys.stdout.flush()
1379 c = getchar()
1380
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001381 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001382 sys.stdout.write('\r \r')
1383 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001384 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001385 sys.stdout.write('\r \r' + lines[r] + '\n')
1386 r = r + 1
1387 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001388 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001389 r = r - inc - inc
1390 if r < 0: r = 0
1391 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1392 r = r + inc
1393
1394 finally:
1395 if tty:
1396 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1397
1398def plainpager(text):
1399 """Simply print unformatted text. This is the ultimate fallback."""
1400 sys.stdout.write(plain(text))
1401
1402def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001403 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001404 if inspect.ismodule(thing):
1405 if thing.__name__ in sys.builtin_module_names:
1406 return 'built-in module ' + thing.__name__
1407 if hasattr(thing, '__path__'):
1408 return 'package ' + thing.__name__
1409 else:
1410 return 'module ' + thing.__name__
1411 if inspect.isbuiltin(thing):
1412 return 'built-in function ' + thing.__name__
1413 if inspect.isclass(thing):
1414 return 'class ' + thing.__name__
1415 if inspect.isfunction(thing):
1416 return 'function ' + thing.__name__
1417 if inspect.ismethod(thing):
1418 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001419 if type(thing) is types.InstanceType:
1420 return 'instance of ' + thing.__class__.__name__
1421 return type(thing).__name__
1422
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001423def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001424 """Locate an object by name or dotted path, importing as necessary."""
Guido van Rossum97dede02003-02-16 01:12:32 +00001425 parts = [part for part in split(path, '.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001426 module, n = None, 0
1427 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001428 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001429 if nextmodule: module, n = nextmodule, n + 1
1430 else: break
1431 if module:
1432 object = module
1433 for part in parts[n:]:
1434 try: object = getattr(object, part)
1435 except AttributeError: return None
1436 return object
1437 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001438 if hasattr(__builtin__, path):
1439 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001440
1441# --------------------------------------- interactive interpreter interface
1442
1443text = TextDoc()
1444html = HTMLDoc()
1445
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001446def resolve(thing, forceload=0):
1447 """Given an object or a path to an object, get the object and its name."""
1448 if isinstance(thing, str):
1449 object = locate(thing, forceload)
1450 if not object:
1451 raise ImportError, 'no Python documentation found for %r' % thing
1452 return object, thing
1453 else:
1454 return thing, getattr(thing, '__name__', None)
1455
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001456def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001457 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001458 try:
1459 object, name = resolve(thing, forceload)
1460 desc = describe(object)
1461 module = inspect.getmodule(object)
1462 if name and '.' in name:
1463 desc += ' in ' + name[:name.rfind('.')]
1464 elif module and module is not object:
1465 desc += ' in module ' + module.__name__
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001466 if not (inspect.ismodule(object) or
1467 inspect.isclass(object) or
1468 inspect.isroutine(object) or
1469 isinstance(object, property)):
1470 # If the passed object is a piece of data or an instance,
1471 # document its available methods instead of its value.
1472 object = type(object)
1473 desc += ' object'
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001474 pager(title % desc + '\n\n' + text.document(object, name))
1475 except (ImportError, ErrorDuringImport), value:
1476 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001477
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001478def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001479 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001480 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001481 object, name = resolve(thing, forceload)
1482 page = html.page(describe(object), html.document(object, name))
1483 file = open(name + '.html', 'w')
1484 file.write(page)
1485 file.close()
1486 print 'wrote', name + '.html'
1487 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001488 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001489
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001490def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001491 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001492 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001493 for file in os.listdir(dir):
1494 path = os.path.join(dir, file)
1495 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001496 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001497 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001498 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001499 if modname:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001500 if modname == '__init__':
1501 modname = pkgpath[:-1] # remove trailing period
1502 else:
1503 modname = pkgpath + modname
1504 if modname not in done:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001505 done[modname] = 1
1506 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001507
1508class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001509 keywords = {
1510 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001511 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001512 'break': ('ref/break', 'while for'),
1513 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1514 'continue': ('ref/continue', 'while for'),
1515 'def': ('ref/function', ''),
1516 'del': ('ref/del', 'BASICMETHODS'),
1517 'elif': 'if',
1518 'else': ('ref/if', 'while for'),
1519 'except': 'try',
1520 'exec': ('ref/exec', ''),
1521 'finally': 'try',
1522 'for': ('ref/for', 'break continue while'),
1523 'from': 'import',
1524 'global': ('ref/global', 'NAMESPACES'),
1525 'if': ('ref/if', 'TRUTHVALUE'),
1526 'import': ('ref/import', 'MODULES'),
1527 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1528 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001529 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001530 'not': 'BOOLEAN',
1531 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001532 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001533 'print': ('ref/print', ''),
1534 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001535 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001536 'try': ('ref/try', 'EXCEPTIONS'),
1537 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001538 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001539 }
1540
1541 topics = {
1542 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001543 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001544 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1545 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001546 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001547 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1548 'INTEGER': ('ref/integers', 'int range'),
1549 'FLOAT': ('ref/floating', 'float math'),
1550 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001551 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001552 'MAPPINGS': 'DICTIONARIES',
1553 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1554 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1555 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001556 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001557 'FRAMEOBJECTS': 'TYPES',
1558 'TRACEBACKS': 'TYPES',
1559 'NONE': ('lib/bltin-null-object', ''),
1560 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1561 'FILES': ('lib/bltin-file-objects', ''),
1562 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1563 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1564 'MODULES': ('lib/typesmodules', 'import'),
1565 'PACKAGES': 'import',
1566 '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'),
1567 'OPERATORS': 'EXPRESSIONS',
1568 'PRECEDENCE': 'EXPRESSIONS',
1569 'OBJECTS': ('ref/objects', 'TYPES'),
1570 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001571 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1572 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1573 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1574 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1575 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1576 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1577 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001578 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1579 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1580 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001581 'SCOPING': 'NAMESPACES',
1582 'FRAMES': 'NAMESPACES',
1583 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001584 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1585 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001586 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1587 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001588 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001589 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1590 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001591 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001592 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001593 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001594 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001595 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1596 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001597 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1598 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1599 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1600 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1601 'POWER': ('ref/power', 'EXPRESSIONS'),
1602 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1603 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1604 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1605 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1606 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001607 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001608 'ASSERTION': 'assert',
1609 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001610 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001611 'DELETION': 'del',
1612 'PRINTING': 'print',
1613 'RETURNING': 'return',
1614 'IMPORTING': 'import',
1615 'CONDITIONAL': 'if',
1616 'LOOPING': ('ref/compound', 'for while break continue'),
1617 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001618 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001619 }
1620
1621 def __init__(self, input, output):
1622 self.input = input
1623 self.output = output
1624 self.docdir = None
1625 execdir = os.path.dirname(sys.executable)
1626 homedir = os.environ.get('PYTHONHOME')
1627 for dir in [os.environ.get('PYTHONDOCS'),
1628 homedir and os.path.join(homedir, 'doc'),
1629 os.path.join(execdir, 'doc'),
1630 '/usr/doc/python-docs-' + split(sys.version)[0],
1631 '/usr/doc/python-' + split(sys.version)[0],
1632 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001633 '/usr/doc/python-' + sys.version[:3],
1634 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001635 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1636 self.docdir = dir
1637
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001638 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001639 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001640 self()
1641 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001642 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001643
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001644 def __call__(self, request=None):
1645 if request is not None:
1646 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001647 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001648 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001649 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001650 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001651You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001652If you want to ask for help on a particular object directly from the
1653interpreter, you can type "help(object)". Executing "help('string')"
1654has the same effect as typing a particular string at the help> prompt.
1655''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001656
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001657 def interact(self):
1658 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001659 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001660 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001661 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001662 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001663 except (KeyboardInterrupt, EOFError):
1664 break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001665 request = strip(replace(request, '"', '', "'", ''))
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001666 if lower(request) in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001667 self.help(request)
1668
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001669 def getline(self, prompt):
1670 """Read one line, using raw_input when available."""
1671 if self.input is sys.stdin:
1672 return raw_input(prompt)
1673 else:
1674 self.output.write(prompt)
1675 self.output.flush()
1676 return self.input.readline()
1677
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001678 def help(self, request):
1679 if type(request) is type(''):
1680 if request == 'help': self.intro()
1681 elif request == 'keywords': self.listkeywords()
1682 elif request == 'topics': self.listtopics()
1683 elif request == 'modules': self.listmodules()
1684 elif request[:8] == 'modules ':
1685 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001686 elif request in self.keywords: self.showtopic(request)
1687 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001688 elif request: doc(request, 'Help on %s:')
1689 elif isinstance(request, Helper): self()
1690 else: doc(request, 'Help on %s:')
1691 self.output.write('\n')
1692
1693 def intro(self):
1694 self.output.write('''
1695Welcome to Python %s! This is the online help utility.
1696
1697If this is your first time using Python, you should definitely check out
1698the tutorial on the Internet at http://www.python.org/doc/tut/.
1699
1700Enter the name of any module, keyword, or topic to get help on writing
1701Python programs and using Python modules. To quit this help utility and
1702return to the interpreter, just type "quit".
1703
1704To get a list of available modules, keywords, or topics, type "modules",
1705"keywords", or "topics". Each module also comes with a one-line summary
1706of what it does; to list the modules whose summaries contain a given word
1707such as "spam", type "modules spam".
1708''' % sys.version[:3])
1709
1710 def list(self, items, columns=4, width=80):
1711 items = items[:]
1712 items.sort()
1713 colw = width / columns
1714 rows = (len(items) + columns - 1) / columns
1715 for row in range(rows):
1716 for col in range(columns):
1717 i = col * rows + row
1718 if i < len(items):
1719 self.output.write(items[i])
1720 if col < columns - 1:
1721 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1722 self.output.write('\n')
1723
1724 def listkeywords(self):
1725 self.output.write('''
1726Here is a list of the Python keywords. Enter any keyword to get more help.
1727
1728''')
1729 self.list(self.keywords.keys())
1730
1731 def listtopics(self):
1732 self.output.write('''
1733Here is a list of available topics. Enter any topic name to get more help.
1734
1735''')
1736 self.list(self.topics.keys())
1737
1738 def showtopic(self, topic):
1739 if not self.docdir:
1740 self.output.write('''
1741Sorry, topic and keyword documentation is not available because the Python
1742HTML documentation files could not be found. If you have installed them,
1743please set the environment variable PYTHONDOCS to indicate their location.
1744''')
1745 return
1746 target = self.topics.get(topic, self.keywords.get(topic))
1747 if not target:
1748 self.output.write('no documentation found for %s\n' % repr(topic))
1749 return
1750 if type(target) is type(''):
1751 return self.showtopic(target)
1752
1753 filename, xrefs = target
1754 filename = self.docdir + '/' + filename + '.html'
1755 try:
1756 file = open(filename)
1757 except:
1758 self.output.write('could not read docs from %s\n' % filename)
1759 return
1760
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001761 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1762 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001763 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1764 file.close()
1765
1766 import htmllib, formatter, StringIO
1767 buffer = StringIO.StringIO()
1768 parser = htmllib.HTMLParser(
1769 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1770 parser.start_table = parser.do_p
1771 parser.end_table = lambda parser=parser: parser.do_p({})
1772 parser.start_tr = parser.do_br
1773 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1774 parser.feed(document)
1775 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1776 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001777 if xrefs:
1778 buffer = StringIO.StringIO()
1779 formatter.DumbWriter(buffer).send_flowing_data(
1780 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1781 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001782
1783 def listmodules(self, key=''):
1784 if key:
1785 self.output.write('''
1786Here is a list of matching modules. Enter any module name to get more help.
1787
1788''')
1789 apropos(key)
1790 else:
1791 self.output.write('''
1792Please wait a moment while I gather a list of all available modules...
1793
1794''')
1795 modules = {}
1796 def callback(path, modname, desc, modules=modules):
1797 if modname and modname[-9:] == '.__init__':
1798 modname = modname[:-9] + ' (package)'
1799 if find(modname, '.') < 0:
1800 modules[modname] = 1
1801 ModuleScanner().run(callback)
1802 self.list(modules.keys())
1803 self.output.write('''
1804Enter any module name to get more help. Or, type "modules spam" to search
1805for modules whose descriptions contain the word "spam".
1806''')
1807
1808help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001809
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001810class Scanner:
1811 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001812 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001813 self.roots = roots[:]
1814 self.state = []
1815 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001816 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001817
1818 def next(self):
1819 if not self.state:
1820 if not self.roots:
1821 return None
1822 root = self.roots.pop(0)
1823 self.state = [(root, self.children(root))]
1824 node, children = self.state[-1]
1825 if not children:
1826 self.state.pop()
1827 return self.next()
1828 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001829 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001830 self.state.append((child, self.children(child)))
1831 return child
1832
1833class ModuleScanner(Scanner):
1834 """An interruptible scanner that searches module synopses."""
1835 def __init__(self):
1836 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001837 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001838 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001839
1840 def submodules(self, (dir, package)):
1841 children = []
1842 for file in os.listdir(dir):
1843 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001844 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001845 children.append((path, package + (package and '.') + file))
1846 else:
1847 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001848 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001849 return children
1850
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001851 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001852 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001853 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001854 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001855 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001856 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001857
Ka-Ping Yee66246962001-04-12 11:59:50 +00001858 def run(self, callback, key=None, completer=None):
1859 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001860 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001861 seen = {}
1862
1863 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001864 if modname != '__main__':
1865 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001866 if key is None:
1867 callback(None, modname, '')
1868 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001869 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001870 if find(lower(modname + ' - ' + desc), key) >= 0:
1871 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001872
1873 while not self.quit:
1874 node = self.next()
1875 if not node: break
1876 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001877 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001878 if os.path.isfile(path) and modname:
1879 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001880 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001881 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001882 if key is None:
1883 callback(path, modname, '')
1884 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001885 desc = synopsis(path) or ''
1886 if find(lower(modname + ' - ' + desc), key) >= 0:
1887 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001888 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001889
1890def apropos(key):
1891 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001892 def callback(path, modname, desc):
1893 if modname[-9:] == '.__init__':
1894 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001895 print modname, desc and '- ' + desc
1896 try: import warnings
1897 except ImportError: pass
1898 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001899 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001900
1901# --------------------------------------------------- web browser interface
1902
Ka-Ping Yee66246962001-04-12 11:59:50 +00001903def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001904 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001905
1906 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1907 class Message(mimetools.Message):
1908 def __init__(self, fp, seekable=1):
1909 Message = self.__class__
1910 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1911 self.encodingheader = self.getheader('content-transfer-encoding')
1912 self.typeheader = self.getheader('content-type')
1913 self.parsetype()
1914 self.parseplist()
1915
1916 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1917 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001918 try:
1919 self.send_response(200)
1920 self.send_header('Content-Type', 'text/html')
1921 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001922 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001923 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001924
1925 def do_GET(self):
1926 path = self.path
1927 if path[-5:] == '.html': path = path[:-5]
1928 if path[:1] == '/': path = path[1:]
1929 if path and path != '.':
1930 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001931 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001932 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001933 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001934 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001935 if obj:
1936 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001937 else:
1938 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001939'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001940 else:
1941 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001942'<big><big><strong>Python: Index of Modules</strong></big></big>',
1943'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001944 def bltinlink(name):
1945 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001946 names = filter(lambda x: x != '__main__',
1947 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001948 contents = html.multicolumn(names, bltinlink)
1949 indices = ['<p>' + html.bigsection(
1950 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1951
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001952 seen = {}
1953 for dir in pathdirs():
1954 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001955 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001956<font color="#909090" face="helvetica, arial"><strong>
1957pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001958 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001959
1960 def log_message(self, *args): pass
1961
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001962 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001963 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001964 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001965 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001966 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001967 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001968 self.base.__init__(self, self.address, self.handler)
1969
1970 def serve_until_quit(self):
1971 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001972 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001973 while not self.quit:
1974 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1975 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001976
1977 def server_activate(self):
1978 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001979 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001980
1981 DocServer.base = BaseHTTPServer.HTTPServer
1982 DocServer.handler = DocHandler
1983 DocHandler.MessageClass = Message
1984 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001985 try:
1986 DocServer(port, callback).serve_until_quit()
1987 except (KeyboardInterrupt, select.error):
1988 pass
1989 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001990 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001991
1992# ----------------------------------------------------- graphical interface
1993
1994def gui():
1995 """Graphical interface (starts web server and pops up a control window)."""
1996 class GUI:
1997 def __init__(self, window, port=7464):
1998 self.window = window
1999 self.server = None
2000 self.scanner = None
2001
2002 import Tkinter
2003 self.server_frm = Tkinter.Frame(window)
2004 self.title_lbl = Tkinter.Label(self.server_frm,
2005 text='Starting server...\n ')
2006 self.open_btn = Tkinter.Button(self.server_frm,
2007 text='open browser', command=self.open, state='disabled')
2008 self.quit_btn = Tkinter.Button(self.server_frm,
2009 text='quit serving', command=self.quit, state='disabled')
2010
2011 self.search_frm = Tkinter.Frame(window)
2012 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
2013 self.search_ent = Tkinter.Entry(self.search_frm)
2014 self.search_ent.bind('<Return>', self.search)
2015 self.stop_btn = Tkinter.Button(self.search_frm,
2016 text='stop', pady=0, command=self.stop, state='disabled')
2017 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002018 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002019 self.stop_btn.pack(side='right')
2020
2021 self.window.title('pydoc')
2022 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2023 self.title_lbl.pack(side='top', fill='x')
2024 self.open_btn.pack(side='left', fill='x', expand=1)
2025 self.quit_btn.pack(side='right', fill='x', expand=1)
2026 self.server_frm.pack(side='top', fill='x')
2027
2028 self.search_lbl.pack(side='left')
2029 self.search_ent.pack(side='right', fill='x', expand=1)
2030 self.search_frm.pack(side='top', fill='x')
2031 self.search_ent.focus_set()
2032
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002033 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002034 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002035 self.result_lst.bind('<Button-1>', self.select)
2036 self.result_lst.bind('<Double-Button-1>', self.goto)
2037 self.result_scr = Tkinter.Scrollbar(window,
2038 orient='vertical', command=self.result_lst.yview)
2039 self.result_lst.config(yscrollcommand=self.result_scr.set)
2040
2041 self.result_frm = Tkinter.Frame(window)
2042 self.goto_btn = Tkinter.Button(self.result_frm,
2043 text='go to selected', command=self.goto)
2044 self.hide_btn = Tkinter.Button(self.result_frm,
2045 text='hide results', command=self.hide)
2046 self.goto_btn.pack(side='left', fill='x', expand=1)
2047 self.hide_btn.pack(side='right', fill='x', expand=1)
2048
2049 self.window.update()
2050 self.minwidth = self.window.winfo_width()
2051 self.minheight = self.window.winfo_height()
2052 self.bigminheight = (self.server_frm.winfo_reqheight() +
2053 self.search_frm.winfo_reqheight() +
2054 self.result_lst.winfo_reqheight() +
2055 self.result_frm.winfo_reqheight())
2056 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2057 self.expanded = 0
2058 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2059 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002060 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002061
2062 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002063 threading.Thread(
2064 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002065
2066 def ready(self, server):
2067 self.server = server
2068 self.title_lbl.config(
2069 text='Python documentation server at\n' + server.url)
2070 self.open_btn.config(state='normal')
2071 self.quit_btn.config(state='normal')
2072
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002073 def open(self, event=None, url=None):
2074 url = url or self.server.url
2075 try:
2076 import webbrowser
2077 webbrowser.open(url)
2078 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002079 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002080 os.system('start "%s"' % url)
2081 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002082 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002083 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002084 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002085 else:
2086 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2087 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002088
2089 def quit(self, event=None):
2090 if self.server:
2091 self.server.quit = 1
2092 self.window.quit()
2093
2094 def search(self, event=None):
2095 key = self.search_ent.get()
2096 self.stop_btn.pack(side='right')
2097 self.stop_btn.config(state='normal')
2098 self.search_lbl.config(text='Searching for "%s"...' % key)
2099 self.search_ent.forget()
2100 self.search_lbl.pack(side='left')
2101 self.result_lst.delete(0, 'end')
2102 self.goto_btn.config(state='disabled')
2103 self.expand()
2104
2105 import threading
2106 if self.scanner:
2107 self.scanner.quit = 1
2108 self.scanner = ModuleScanner()
2109 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002110 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002111
2112 def update(self, path, modname, desc):
2113 if modname[-9:] == '.__init__':
2114 modname = modname[:-9] + ' (package)'
2115 self.result_lst.insert('end',
2116 modname + ' - ' + (desc or '(no description)'))
2117
2118 def stop(self, event=None):
2119 if self.scanner:
2120 self.scanner.quit = 1
2121 self.scanner = None
2122
2123 def done(self):
2124 self.scanner = None
2125 self.search_lbl.config(text='Search for')
2126 self.search_lbl.pack(side='left')
2127 self.search_ent.pack(side='right', fill='x', expand=1)
2128 if sys.platform != 'win32': self.stop_btn.forget()
2129 self.stop_btn.config(state='disabled')
2130
2131 def select(self, event=None):
2132 self.goto_btn.config(state='normal')
2133
2134 def goto(self, event=None):
2135 selection = self.result_lst.curselection()
2136 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002137 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002138 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002139
2140 def collapse(self):
2141 if not self.expanded: return
2142 self.result_frm.forget()
2143 self.result_scr.forget()
2144 self.result_lst.forget()
2145 self.bigwidth = self.window.winfo_width()
2146 self.bigheight = self.window.winfo_height()
2147 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2148 self.window.wm_minsize(self.minwidth, self.minheight)
2149 self.expanded = 0
2150
2151 def expand(self):
2152 if self.expanded: return
2153 self.result_frm.pack(side='bottom', fill='x')
2154 self.result_scr.pack(side='right', fill='y')
2155 self.result_lst.pack(side='top', fill='both', expand=1)
2156 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2157 self.window.wm_minsize(self.minwidth, self.bigminheight)
2158 self.expanded = 1
2159
2160 def hide(self, event=None):
2161 self.stop()
2162 self.collapse()
2163
2164 import Tkinter
2165 try:
Martin v. Löwise09bd932004-08-22 16:13:26 +00002166 root = Tkinter.Tk()
2167 # Tk will crash if pythonw.exe has an XP .manifest
2168 # file and the root has is not destroyed explicitly.
2169 # If the problem is ever fixed in Tk, the explicit
2170 # destroy can go.
2171 try:
2172 gui = GUI(root)
2173 root.mainloop()
2174 finally:
2175 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002176 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002177 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002178
2179# -------------------------------------------------- command-line interface
2180
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002181def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002182 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002183
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002184def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002185 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002186 import getopt
2187 class BadUsage: pass
2188
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002189 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002190 scriptdir = os.path.dirname(sys.argv[0])
2191 if scriptdir in sys.path:
2192 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002193 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002194
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002195 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002196 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002197 writing = 0
2198
2199 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002200 if opt == '-g':
2201 gui()
2202 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002203 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002204 apropos(val)
2205 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002206 if opt == '-p':
2207 try:
2208 port = int(val)
2209 except ValueError:
2210 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002211 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002212 print 'pydoc server ready at %s' % server.url
2213 def stopped():
2214 print 'pydoc server stopped'
2215 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002216 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002217 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002218 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002219
2220 if not args: raise BadUsage
2221 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002222 if ispath(arg) and not os.path.exists(arg):
2223 print 'file %r does not exist' % arg
2224 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002225 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002226 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002227 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002228 if writing:
2229 if ispath(arg) and os.path.isdir(arg):
2230 writedocs(arg)
2231 else:
2232 writedoc(arg)
2233 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002234 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002235 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002236 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002237
2238 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002239 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002240 print """pydoc - the Python documentation tool
2241
2242%s <name> ...
2243 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002244 Python keyword, topic, function, module, or package, or a dotted
2245 reference to a class or function within a module or module in a
2246 package. If <name> contains a '%s', it is used as the path to a
2247 Python source file to document. If name is 'keywords', 'topics',
2248 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002249
2250%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002251 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002252
2253%s -p <port>
2254 Start an HTTP server on the given port on the local machine.
2255
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002256%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002257 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002258
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002259%s -w <name> ...
2260 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002261 directory. If <name> contains a '%s', it is treated as a filename; if
2262 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002263""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002264
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002265if __name__ == '__main__': cli()