blob: b6afc7f9ad52715098110636593337a4b61bffd4 [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
Neal Norwitzce96f692006-03-17 06:49:51 +00001508def raw_input(prompt):
1509 sys.stdout.write(prompt)
1510 sys.stdout.flush()
1511 return sys.stdin.readline()
1512
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001513class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001514 keywords = {
1515 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001516 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001517 'break': ('ref/break', 'while for'),
1518 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1519 'continue': ('ref/continue', 'while for'),
1520 'def': ('ref/function', ''),
1521 'del': ('ref/del', 'BASICMETHODS'),
1522 'elif': 'if',
1523 'else': ('ref/if', 'while for'),
1524 'except': 'try',
1525 'exec': ('ref/exec', ''),
1526 'finally': 'try',
1527 'for': ('ref/for', 'break continue while'),
1528 'from': 'import',
1529 'global': ('ref/global', 'NAMESPACES'),
1530 'if': ('ref/if', 'TRUTHVALUE'),
1531 'import': ('ref/import', 'MODULES'),
1532 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1533 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001534 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001535 'not': 'BOOLEAN',
1536 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001537 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001538 'print': ('ref/print', ''),
1539 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001540 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001541 'try': ('ref/try', 'EXCEPTIONS'),
1542 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001543 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001544 }
1545
1546 topics = {
1547 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001548 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001549 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1550 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001551 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001552 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1553 'INTEGER': ('ref/integers', 'int range'),
1554 'FLOAT': ('ref/floating', 'float math'),
1555 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001556 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001557 'MAPPINGS': 'DICTIONARIES',
1558 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1559 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1560 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001561 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001562 'FRAMEOBJECTS': 'TYPES',
1563 'TRACEBACKS': 'TYPES',
1564 'NONE': ('lib/bltin-null-object', ''),
1565 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1566 'FILES': ('lib/bltin-file-objects', ''),
1567 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1568 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1569 'MODULES': ('lib/typesmodules', 'import'),
1570 'PACKAGES': 'import',
1571 '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'),
1572 'OPERATORS': 'EXPRESSIONS',
1573 'PRECEDENCE': 'EXPRESSIONS',
1574 'OBJECTS': ('ref/objects', 'TYPES'),
1575 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001576 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1577 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1578 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1579 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1580 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1581 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1582 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001583 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1584 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1585 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001586 'SCOPING': 'NAMESPACES',
1587 'FRAMES': 'NAMESPACES',
1588 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001589 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1590 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001591 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1592 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001593 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001594 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1595 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001596 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001597 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001598 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001599 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001600 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1601 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001602 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1603 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1604 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1605 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1606 'POWER': ('ref/power', 'EXPRESSIONS'),
1607 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1608 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1609 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1610 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1611 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001612 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001613 'ASSERTION': 'assert',
1614 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001615 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001616 'DELETION': 'del',
1617 'PRINTING': 'print',
1618 'RETURNING': 'return',
1619 'IMPORTING': 'import',
1620 'CONDITIONAL': 'if',
1621 'LOOPING': ('ref/compound', 'for while break continue'),
1622 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001623 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001624 }
1625
1626 def __init__(self, input, output):
1627 self.input = input
1628 self.output = output
1629 self.docdir = None
1630 execdir = os.path.dirname(sys.executable)
1631 homedir = os.environ.get('PYTHONHOME')
1632 for dir in [os.environ.get('PYTHONDOCS'),
1633 homedir and os.path.join(homedir, 'doc'),
1634 os.path.join(execdir, 'doc'),
1635 '/usr/doc/python-docs-' + split(sys.version)[0],
1636 '/usr/doc/python-' + split(sys.version)[0],
1637 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001638 '/usr/doc/python-' + sys.version[:3],
1639 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001640 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1641 self.docdir = dir
1642
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001643 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001644 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001645 self()
1646 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001647 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001648
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001649 def __call__(self, request=None):
1650 if request is not None:
1651 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001652 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001653 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001654 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001655 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001656You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001657If you want to ask for help on a particular object directly from the
1658interpreter, you can type "help(object)". Executing "help('string')"
1659has the same effect as typing a particular string at the help> prompt.
1660''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001661
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001662 def interact(self):
1663 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001664 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001665 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001666 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001667 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001668 except (KeyboardInterrupt, EOFError):
1669 break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001670 request = strip(replace(request, '"', '', "'", ''))
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001671 if lower(request) in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001672 self.help(request)
1673
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001674 def getline(self, prompt):
1675 """Read one line, using raw_input when available."""
1676 if self.input is sys.stdin:
1677 return raw_input(prompt)
1678 else:
1679 self.output.write(prompt)
1680 self.output.flush()
1681 return self.input.readline()
1682
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001683 def help(self, request):
1684 if type(request) is type(''):
1685 if request == 'help': self.intro()
1686 elif request == 'keywords': self.listkeywords()
1687 elif request == 'topics': self.listtopics()
1688 elif request == 'modules': self.listmodules()
1689 elif request[:8] == 'modules ':
1690 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001691 elif request in self.keywords: self.showtopic(request)
1692 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001693 elif request: doc(request, 'Help on %s:')
1694 elif isinstance(request, Helper): self()
1695 else: doc(request, 'Help on %s:')
1696 self.output.write('\n')
1697
1698 def intro(self):
1699 self.output.write('''
1700Welcome to Python %s! This is the online help utility.
1701
1702If this is your first time using Python, you should definitely check out
1703the tutorial on the Internet at http://www.python.org/doc/tut/.
1704
1705Enter the name of any module, keyword, or topic to get help on writing
1706Python programs and using Python modules. To quit this help utility and
1707return to the interpreter, just type "quit".
1708
1709To get a list of available modules, keywords, or topics, type "modules",
1710"keywords", or "topics". Each module also comes with a one-line summary
1711of what it does; to list the modules whose summaries contain a given word
1712such as "spam", type "modules spam".
1713''' % sys.version[:3])
1714
1715 def list(self, items, columns=4, width=80):
1716 items = items[:]
1717 items.sort()
1718 colw = width / columns
1719 rows = (len(items) + columns - 1) / columns
1720 for row in range(rows):
1721 for col in range(columns):
1722 i = col * rows + row
1723 if i < len(items):
1724 self.output.write(items[i])
1725 if col < columns - 1:
1726 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1727 self.output.write('\n')
1728
1729 def listkeywords(self):
1730 self.output.write('''
1731Here is a list of the Python keywords. Enter any keyword to get more help.
1732
1733''')
1734 self.list(self.keywords.keys())
1735
1736 def listtopics(self):
1737 self.output.write('''
1738Here is a list of available topics. Enter any topic name to get more help.
1739
1740''')
1741 self.list(self.topics.keys())
1742
1743 def showtopic(self, topic):
1744 if not self.docdir:
1745 self.output.write('''
1746Sorry, topic and keyword documentation is not available because the Python
1747HTML documentation files could not be found. If you have installed them,
1748please set the environment variable PYTHONDOCS to indicate their location.
1749''')
1750 return
1751 target = self.topics.get(topic, self.keywords.get(topic))
1752 if not target:
1753 self.output.write('no documentation found for %s\n' % repr(topic))
1754 return
1755 if type(target) is type(''):
1756 return self.showtopic(target)
1757
1758 filename, xrefs = target
1759 filename = self.docdir + '/' + filename + '.html'
1760 try:
1761 file = open(filename)
1762 except:
1763 self.output.write('could not read docs from %s\n' % filename)
1764 return
1765
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001766 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1767 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001768 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1769 file.close()
1770
1771 import htmllib, formatter, StringIO
1772 buffer = StringIO.StringIO()
1773 parser = htmllib.HTMLParser(
1774 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1775 parser.start_table = parser.do_p
1776 parser.end_table = lambda parser=parser: parser.do_p({})
1777 parser.start_tr = parser.do_br
1778 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1779 parser.feed(document)
1780 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1781 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001782 if xrefs:
1783 buffer = StringIO.StringIO()
1784 formatter.DumbWriter(buffer).send_flowing_data(
1785 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1786 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001787
1788 def listmodules(self, key=''):
1789 if key:
1790 self.output.write('''
1791Here is a list of matching modules. Enter any module name to get more help.
1792
1793''')
1794 apropos(key)
1795 else:
1796 self.output.write('''
1797Please wait a moment while I gather a list of all available modules...
1798
1799''')
1800 modules = {}
1801 def callback(path, modname, desc, modules=modules):
1802 if modname and modname[-9:] == '.__init__':
1803 modname = modname[:-9] + ' (package)'
1804 if find(modname, '.') < 0:
1805 modules[modname] = 1
1806 ModuleScanner().run(callback)
1807 self.list(modules.keys())
1808 self.output.write('''
1809Enter any module name to get more help. Or, type "modules spam" to search
1810for modules whose descriptions contain the word "spam".
1811''')
1812
1813help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001814
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001815class Scanner:
1816 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001817 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001818 self.roots = roots[:]
1819 self.state = []
1820 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001821 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001822
1823 def next(self):
1824 if not self.state:
1825 if not self.roots:
1826 return None
1827 root = self.roots.pop(0)
1828 self.state = [(root, self.children(root))]
1829 node, children = self.state[-1]
1830 if not children:
1831 self.state.pop()
1832 return self.next()
1833 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001834 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001835 self.state.append((child, self.children(child)))
1836 return child
1837
1838class ModuleScanner(Scanner):
1839 """An interruptible scanner that searches module synopses."""
1840 def __init__(self):
1841 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001842 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001843 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001844
1845 def submodules(self, (dir, package)):
1846 children = []
1847 for file in os.listdir(dir):
1848 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001849 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001850 children.append((path, package + (package and '.') + file))
1851 else:
1852 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001853 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001854 return children
1855
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001856 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001857 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001858 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001859 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001860 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001861 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001862
Ka-Ping Yee66246962001-04-12 11:59:50 +00001863 def run(self, callback, key=None, completer=None):
1864 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001865 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001866 seen = {}
1867
1868 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001869 if modname != '__main__':
1870 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001871 if key is None:
1872 callback(None, modname, '')
1873 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001874 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001875 if find(lower(modname + ' - ' + desc), key) >= 0:
1876 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001877
1878 while not self.quit:
1879 node = self.next()
1880 if not node: break
1881 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001882 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001883 if os.path.isfile(path) and modname:
1884 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001885 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001886 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001887 if key is None:
1888 callback(path, modname, '')
1889 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001890 desc = synopsis(path) or ''
1891 if find(lower(modname + ' - ' + desc), key) >= 0:
1892 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001893 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001894
1895def apropos(key):
1896 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001897 def callback(path, modname, desc):
1898 if modname[-9:] == '.__init__':
1899 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001900 print modname, desc and '- ' + desc
1901 try: import warnings
1902 except ImportError: pass
1903 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001904 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001905
1906# --------------------------------------------------- web browser interface
1907
Ka-Ping Yee66246962001-04-12 11:59:50 +00001908def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001909 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001910
1911 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1912 class Message(mimetools.Message):
1913 def __init__(self, fp, seekable=1):
1914 Message = self.__class__
1915 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1916 self.encodingheader = self.getheader('content-transfer-encoding')
1917 self.typeheader = self.getheader('content-type')
1918 self.parsetype()
1919 self.parseplist()
1920
1921 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1922 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001923 try:
1924 self.send_response(200)
1925 self.send_header('Content-Type', 'text/html')
1926 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001927 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001928 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001929
1930 def do_GET(self):
1931 path = self.path
1932 if path[-5:] == '.html': path = path[:-5]
1933 if path[:1] == '/': path = path[1:]
1934 if path and path != '.':
1935 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001936 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001937 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001938 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001939 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001940 if obj:
1941 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001942 else:
1943 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001944'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001945 else:
1946 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001947'<big><big><strong>Python: Index of Modules</strong></big></big>',
1948'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001949 def bltinlink(name):
1950 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001951 names = filter(lambda x: x != '__main__',
1952 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001953 contents = html.multicolumn(names, bltinlink)
1954 indices = ['<p>' + html.bigsection(
1955 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1956
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001957 seen = {}
1958 for dir in pathdirs():
1959 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001960 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001961<font color="#909090" face="helvetica, arial"><strong>
1962pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001963 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001964
1965 def log_message(self, *args): pass
1966
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001967 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001968 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001969 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001970 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001971 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001972 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001973 self.base.__init__(self, self.address, self.handler)
1974
1975 def serve_until_quit(self):
1976 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001977 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001978 while not self.quit:
1979 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1980 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001981
1982 def server_activate(self):
1983 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001984 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001985
1986 DocServer.base = BaseHTTPServer.HTTPServer
1987 DocServer.handler = DocHandler
1988 DocHandler.MessageClass = Message
1989 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001990 try:
1991 DocServer(port, callback).serve_until_quit()
1992 except (KeyboardInterrupt, select.error):
1993 pass
1994 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001995 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001996
1997# ----------------------------------------------------- graphical interface
1998
1999def gui():
2000 """Graphical interface (starts web server and pops up a control window)."""
2001 class GUI:
2002 def __init__(self, window, port=7464):
2003 self.window = window
2004 self.server = None
2005 self.scanner = None
2006
2007 import Tkinter
2008 self.server_frm = Tkinter.Frame(window)
2009 self.title_lbl = Tkinter.Label(self.server_frm,
2010 text='Starting server...\n ')
2011 self.open_btn = Tkinter.Button(self.server_frm,
2012 text='open browser', command=self.open, state='disabled')
2013 self.quit_btn = Tkinter.Button(self.server_frm,
2014 text='quit serving', command=self.quit, state='disabled')
2015
2016 self.search_frm = Tkinter.Frame(window)
2017 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
2018 self.search_ent = Tkinter.Entry(self.search_frm)
2019 self.search_ent.bind('<Return>', self.search)
2020 self.stop_btn = Tkinter.Button(self.search_frm,
2021 text='stop', pady=0, command=self.stop, state='disabled')
2022 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002023 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002024 self.stop_btn.pack(side='right')
2025
2026 self.window.title('pydoc')
2027 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2028 self.title_lbl.pack(side='top', fill='x')
2029 self.open_btn.pack(side='left', fill='x', expand=1)
2030 self.quit_btn.pack(side='right', fill='x', expand=1)
2031 self.server_frm.pack(side='top', fill='x')
2032
2033 self.search_lbl.pack(side='left')
2034 self.search_ent.pack(side='right', fill='x', expand=1)
2035 self.search_frm.pack(side='top', fill='x')
2036 self.search_ent.focus_set()
2037
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002038 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002039 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002040 self.result_lst.bind('<Button-1>', self.select)
2041 self.result_lst.bind('<Double-Button-1>', self.goto)
2042 self.result_scr = Tkinter.Scrollbar(window,
2043 orient='vertical', command=self.result_lst.yview)
2044 self.result_lst.config(yscrollcommand=self.result_scr.set)
2045
2046 self.result_frm = Tkinter.Frame(window)
2047 self.goto_btn = Tkinter.Button(self.result_frm,
2048 text='go to selected', command=self.goto)
2049 self.hide_btn = Tkinter.Button(self.result_frm,
2050 text='hide results', command=self.hide)
2051 self.goto_btn.pack(side='left', fill='x', expand=1)
2052 self.hide_btn.pack(side='right', fill='x', expand=1)
2053
2054 self.window.update()
2055 self.minwidth = self.window.winfo_width()
2056 self.minheight = self.window.winfo_height()
2057 self.bigminheight = (self.server_frm.winfo_reqheight() +
2058 self.search_frm.winfo_reqheight() +
2059 self.result_lst.winfo_reqheight() +
2060 self.result_frm.winfo_reqheight())
2061 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2062 self.expanded = 0
2063 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2064 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002065 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002066
2067 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002068 threading.Thread(
2069 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002070
2071 def ready(self, server):
2072 self.server = server
2073 self.title_lbl.config(
2074 text='Python documentation server at\n' + server.url)
2075 self.open_btn.config(state='normal')
2076 self.quit_btn.config(state='normal')
2077
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002078 def open(self, event=None, url=None):
2079 url = url or self.server.url
2080 try:
2081 import webbrowser
2082 webbrowser.open(url)
2083 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002084 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002085 os.system('start "%s"' % url)
2086 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002087 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002088 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002089 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002090 else:
2091 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2092 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002093
2094 def quit(self, event=None):
2095 if self.server:
2096 self.server.quit = 1
2097 self.window.quit()
2098
2099 def search(self, event=None):
2100 key = self.search_ent.get()
2101 self.stop_btn.pack(side='right')
2102 self.stop_btn.config(state='normal')
2103 self.search_lbl.config(text='Searching for "%s"...' % key)
2104 self.search_ent.forget()
2105 self.search_lbl.pack(side='left')
2106 self.result_lst.delete(0, 'end')
2107 self.goto_btn.config(state='disabled')
2108 self.expand()
2109
2110 import threading
2111 if self.scanner:
2112 self.scanner.quit = 1
2113 self.scanner = ModuleScanner()
2114 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002115 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002116
2117 def update(self, path, modname, desc):
2118 if modname[-9:] == '.__init__':
2119 modname = modname[:-9] + ' (package)'
2120 self.result_lst.insert('end',
2121 modname + ' - ' + (desc or '(no description)'))
2122
2123 def stop(self, event=None):
2124 if self.scanner:
2125 self.scanner.quit = 1
2126 self.scanner = None
2127
2128 def done(self):
2129 self.scanner = None
2130 self.search_lbl.config(text='Search for')
2131 self.search_lbl.pack(side='left')
2132 self.search_ent.pack(side='right', fill='x', expand=1)
2133 if sys.platform != 'win32': self.stop_btn.forget()
2134 self.stop_btn.config(state='disabled')
2135
2136 def select(self, event=None):
2137 self.goto_btn.config(state='normal')
2138
2139 def goto(self, event=None):
2140 selection = self.result_lst.curselection()
2141 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002142 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002143 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002144
2145 def collapse(self):
2146 if not self.expanded: return
2147 self.result_frm.forget()
2148 self.result_scr.forget()
2149 self.result_lst.forget()
2150 self.bigwidth = self.window.winfo_width()
2151 self.bigheight = self.window.winfo_height()
2152 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2153 self.window.wm_minsize(self.minwidth, self.minheight)
2154 self.expanded = 0
2155
2156 def expand(self):
2157 if self.expanded: return
2158 self.result_frm.pack(side='bottom', fill='x')
2159 self.result_scr.pack(side='right', fill='y')
2160 self.result_lst.pack(side='top', fill='both', expand=1)
2161 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2162 self.window.wm_minsize(self.minwidth, self.bigminheight)
2163 self.expanded = 1
2164
2165 def hide(self, event=None):
2166 self.stop()
2167 self.collapse()
2168
2169 import Tkinter
2170 try:
Martin v. Löwise09bd932004-08-22 16:13:26 +00002171 root = Tkinter.Tk()
2172 # Tk will crash if pythonw.exe has an XP .manifest
2173 # file and the root has is not destroyed explicitly.
2174 # If the problem is ever fixed in Tk, the explicit
2175 # destroy can go.
2176 try:
2177 gui = GUI(root)
2178 root.mainloop()
2179 finally:
2180 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002181 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002182 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002183
2184# -------------------------------------------------- command-line interface
2185
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002186def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002187 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002188
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002189def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002190 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002191 import getopt
2192 class BadUsage: pass
2193
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002194 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002195 scriptdir = os.path.dirname(sys.argv[0])
2196 if scriptdir in sys.path:
2197 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002198 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002199
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002200 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002201 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002202 writing = 0
2203
2204 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002205 if opt == '-g':
2206 gui()
2207 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002208 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002209 apropos(val)
2210 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002211 if opt == '-p':
2212 try:
2213 port = int(val)
2214 except ValueError:
2215 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002216 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002217 print 'pydoc server ready at %s' % server.url
2218 def stopped():
2219 print 'pydoc server stopped'
2220 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002221 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002222 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002223 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002224
2225 if not args: raise BadUsage
2226 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002227 if ispath(arg) and not os.path.exists(arg):
2228 print 'file %r does not exist' % arg
2229 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002230 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002231 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002232 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002233 if writing:
2234 if ispath(arg) and os.path.isdir(arg):
2235 writedocs(arg)
2236 else:
2237 writedoc(arg)
2238 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002239 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002240 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002241 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002242
2243 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002244 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002245 print """pydoc - the Python documentation tool
2246
2247%s <name> ...
2248 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002249 Python keyword, topic, function, module, or package, or a dotted
2250 reference to a class or function within a module or module in a
2251 package. If <name> contains a '%s', it is used as the path to a
2252 Python source file to document. If name is 'keywords', 'topics',
2253 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002254
2255%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002256 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002257
2258%s -p <port>
2259 Start an HTTP server on the given port on the local machine.
2260
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002261%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002262 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002263
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002264%s -w <name> ...
2265 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002266 directory. If <name> contains a '%s', it is treated as a filename; if
2267 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002268""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002269
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002270if __name__ == '__main__': cli()