blob: 50fe4a1527669803bf3ae9eb58bdef4823d731ae [file] [log] [blame]
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001#!/usr/bin/env python
Guido van Rossumfce538c2002-08-06 17:29:38 +00002# -*- coding: Latin-1 -*-
Ka-Ping Yee1d384632001-03-01 00:24:32 +00003"""Generate Python documentation in HTML or text for interactive use.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00004
Ka-Ping Yeedd175342001-02-27 14:43:46 +00005In the Python interpreter, do "from pydoc import help" to provide online
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00006help. Calling help(thing) on a Python object documents the object.
7
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00008Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00009
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000010Run "pydoc <name>" to show documentation on something. <name> may be
11the name of a function, module, package, or a dotted reference to a
12class or function within a module or module in a package. If the
13argument contains a path segment delimiter (e.g. slash on Unix,
14backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000015
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000016Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000018
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000019Run "pydoc -p <port>" to start an HTTP server on a given port on the
20local machine to generate documentation web pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000021
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000022For platforms without a command line, "pydoc -g" starts the HTTP server
23and also pops up a little window for controlling it.
24
25Run "pydoc -w <name>" to write out the HTML documentation for a module
26to a file named "<name>.html".
Skip Montanaro4997a692003-09-10 16:47:51 +000027
28Module docs for core modules are assumed to be in
29
30 http://www.python.org/doc/current/lib/
31
32This can be overridden by setting the PYTHONDOCS environment variable
33to a different URL or to a local directory containing the Library
34Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000035"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000036
37__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000038__date__ = "26 February 2001"
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000039__version__ = "$Revision$"
Martin v. Löwis6fe8f192004-11-14 10:21:04 +000040__credits__ = """Guido van Rossum, for an excellent programming language.
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000041Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000042Paul Prescod, for all his work on onlinehelp.
43Richard Chamberlain, for the first implementation of textdoc.
Raymond Hettingered2dbe32005-01-01 07:51:01 +000044"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000045
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000046# Known bugs that can't be fixed here:
47# - imp.load_module() cannot be prevented from clobbering existing
48# loaded modules, so calling synopsis() on a binary module file
49# changes the contents of any existing module with the same name.
50# - If the __file__ attribute on a module is a relative path and
51# the current directory is changed with os.chdir(), an incorrect
52# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000053
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +000054import sys, imp, os, re, types, inspect, __builtin__
Ka-Ping Yeedd175342001-02-27 14:43:46 +000055from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000056from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
Raymond Hettinger756b3f32004-01-29 06:37:52 +000057from collections import deque
Ka-Ping Yeedd175342001-02-27 14:43:46 +000058
59# --------------------------------------------------------- common routines
60
Ka-Ping Yeedd175342001-02-27 14:43:46 +000061def pathdirs():
62 """Convert sys.path into a list of absolute, existing, unique paths."""
63 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000064 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000065 for dir in sys.path:
66 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000067 normdir = os.path.normcase(dir)
68 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000069 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000070 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000071 return dirs
72
73def getdoc(object):
74 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000075 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000076 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000077
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000078def splitdoc(doc):
79 """Split a doc string into a synopsis line (if any) and the rest."""
80 lines = split(strip(doc), '\n')
81 if len(lines) == 1:
82 return lines[0], ''
83 elif len(lines) >= 2 and not rstrip(lines[1]):
84 return lines[0], join(lines[2:], '\n')
85 return '', join(lines, '\n')
86
Ka-Ping Yeedd175342001-02-27 14:43:46 +000087def classname(object, modname):
88 """Get a class name and qualify it with a module name if necessary."""
89 name = object.__name__
90 if object.__module__ != modname:
91 name = object.__module__ + '.' + name
92 return name
93
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000094def isdata(object):
Georg Brandl7eb4b7d2005-07-22 21:49:32 +000095 """Check if an object is of a type that probably means its data."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000096 return not (inspect.ismodule(object) or inspect.isclass(object) or
97 inspect.isroutine(object) or inspect.isframe(object) or
98 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +000099
100def replace(text, *pairs):
101 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000102 while pairs:
103 text = join(split(text, pairs[0]), pairs[1])
104 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000105 return text
106
107def cram(text, maxlen):
108 """Omit part of a string if needed to make it fit in a maximum length."""
109 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000110 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000111 post = max(0, maxlen-3-pre)
112 return text[:pre] + '...' + text[len(text)-post:]
113 return text
114
Brett Cannon84601f12004-06-19 01:22:48 +0000115_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000116def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000117 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000118 # The behaviour of %p is implementation-dependent in terms of case.
119 if _re_stripid.search(repr(Exception)):
120 return _re_stripid.sub(r'\1', text)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000121 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000122
Brett Cannonc6c1f472004-06-19 01:02:51 +0000123def _is_some_method(obj):
124 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000125
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000126def allmethods(cl):
127 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000128 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000129 methods[key] = 1
130 for base in cl.__bases__:
131 methods.update(allmethods(base)) # all your base are belong to us
132 for key in methods.keys():
133 methods[key] = getattr(cl, key)
134 return methods
135
Tim Petersfa26f7c2001-09-24 08:05:11 +0000136def _split_list(s, predicate):
137 """Split sequence s via predicate, and return pair ([true], [false]).
138
139 The return value is a 2-tuple of lists,
140 ([x for x in s if predicate(x)],
141 [x for x in s if not predicate(x)])
142 """
143
Tim Peters28355492001-09-23 21:29:55 +0000144 yes = []
145 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000146 for x in s:
147 if predicate(x):
148 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000149 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000150 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000151 return yes, no
152
Skip Montanaroa5616d22004-06-11 04:46:12 +0000153def visiblename(name, all=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000154 """Decide whether to show documentation on a variable."""
155 # Certain special names are redundant.
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000156 if name in ('__builtins__', '__doc__', '__file__', '__path__',
157 '__module__', '__name__', '__slots__'): return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000158 # Private names are hidden, but special names are displayed.
159 if name.startswith('__') and name.endswith('__'): return 1
Skip Montanaroa5616d22004-06-11 04:46:12 +0000160 if all is not None:
161 # only document that which the programmer exported in __all__
162 return name in all
163 else:
164 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000165
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000166def classify_class_attrs(object):
167 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
168 def fixup((name, kind, cls, value)):
169 if inspect.isdatadescriptor(value):
170 kind = 'data descriptor'
171 return name, kind, cls, value
172 return map(fixup, inspect.classify_class_attrs(object))
173
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000174# ----------------------------------------------------- module manipulation
175
176def ispackage(path):
177 """Guess whether a path refers to a package directory."""
178 if os.path.isdir(path):
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000179 for ext in ('.py', '.pyc', '.pyo'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000180 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000181 return True
182 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000183
184def synopsis(filename, cache={}):
185 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000186 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000187 lastupdate, result = cache.get(filename, (0, None))
188 if lastupdate < mtime:
189 info = inspect.getmoduleinfo(filename)
190 file = open(filename)
191 if info and 'b' in info[2]: # binary modules have to be imported
192 try: module = imp.load_module('__temp__', file, filename, info[1:])
193 except: return None
194 result = split(module.__doc__ or '', '\n')[0]
195 del sys.modules['__temp__']
196 else: # text modules can be directly examined
197 line = file.readline()
198 while line[:1] == '#' or not strip(line):
199 line = file.readline()
200 if not line: break
201 line = strip(line)
202 if line[:4] == 'r"""': line = line[1:]
203 if line[:3] == '"""':
204 line = line[3:]
205 if line[-1:] == '\\': line = line[:-1]
206 while not strip(line):
207 line = file.readline()
208 if not line: break
209 result = strip(split(line, '"""')[0])
210 else: result = None
211 file.close()
212 cache[filename] = (mtime, result)
213 return result
214
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000215class ErrorDuringImport(Exception):
216 """Errors that occurred while trying to import something to document it."""
217 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000218 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000219 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000220 self.value = value
221 self.tb = tb
222
223 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000224 exc = self.exc
225 if type(exc) is types.ClassType:
226 exc = exc.__name__
227 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000228
229def importfile(path):
230 """Import a Python source file or compiled file given its path."""
231 magic = imp.get_magic()
232 file = open(path, 'r')
233 if file.read(len(magic)) == magic:
234 kind = imp.PY_COMPILED
235 else:
236 kind = imp.PY_SOURCE
237 file.close()
238 filename = os.path.basename(path)
239 name, ext = os.path.splitext(filename)
240 file = open(path, 'r')
241 try:
242 module = imp.load_module(name, file, path, (ext, 'r', kind))
243 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000244 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000245 file.close()
246 return module
247
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000248def safeimport(path, forceload=0, cache={}):
249 """Import a module; handle errors; return None if the module isn't found.
250
251 If the module *is* found but an exception occurs, it's wrapped in an
252 ErrorDuringImport exception and reraised. Unlike __import__, if a
253 package path is specified, the module at the end of the path is returned,
254 not the package at the beginning. If the optional 'forceload' argument
255 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000256 if forceload and path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000257 # This is the only way to be sure. Checking the mtime of the file
258 # isn't good enough (e.g. what if the module contains a class that
259 # inherits from another module that has changed?).
260 if path not in sys.builtin_module_names:
261 # Python never loads a dynamic extension a second time from the
262 # same path, even if the file is changed or missing. Deleting
263 # the entry in sys.modules doesn't help for dynamic extensions,
264 # so we're not even going to try to keep them up to date.
265 info = inspect.getmoduleinfo(sys.modules[path].__file__)
266 if info[3] != imp.C_EXTENSION:
267 cache[path] = sys.modules[path] # prevent module from clearing
268 del sys.modules[path]
269 try:
270 module = __import__(path)
271 except:
272 # Did the error occur before or after the module was found?
273 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000274 if path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000275 # An error occured while executing the imported module.
276 raise ErrorDuringImport(sys.modules[path].__file__, info)
277 elif exc is SyntaxError:
278 # A SyntaxError occurred before we could execute the module.
279 raise ErrorDuringImport(value.filename, info)
280 elif exc is ImportError and \
281 split(lower(str(value)))[:2] == ['no', 'module']:
282 # The module was not found.
283 return None
284 else:
285 # Some other error occurred during the importing process.
286 raise ErrorDuringImport(path, sys.exc_info())
287 for part in split(path, '.')[1:]:
288 try: module = getattr(module, part)
289 except AttributeError: return None
290 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000291
292# ---------------------------------------------------- formatter base class
293
294class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000295 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000296 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000297 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000298 # 'try' clause is to attempt to handle the possibility that inspect
299 # identifies something in a way that pydoc itself has issues handling;
300 # think 'super' and how it is a descriptor (which raises the exception
301 # by lacking a __name__ attribute) and an instance.
302 try:
303 if inspect.ismodule(object): return self.docmodule(*args)
304 if inspect.isclass(object): return self.docclass(*args)
305 if inspect.isroutine(object): return self.docroutine(*args)
306 except AttributeError:
307 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000308 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000309 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000310
311 def fail(self, object, name=None, *args):
312 """Raise an exception for unimplemented types."""
313 message = "don't know how to document object%s of type %s" % (
314 name and ' ' + repr(name), type(object).__name__)
315 raise TypeError, message
316
317 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000318
Skip Montanaro4997a692003-09-10 16:47:51 +0000319 def getdocloc(self, object):
320 """Return the location of module docs or None"""
321
322 try:
323 file = inspect.getabsfile(object)
324 except TypeError:
325 file = '(built-in)'
326
327 docloc = os.environ.get("PYTHONDOCS",
328 "http://www.python.org/doc/current/lib")
329 basedir = os.path.join(sys.exec_prefix, "lib",
330 "python"+sys.version[0:3])
331 if (isinstance(object, type(os)) and
332 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
333 'marshal', 'posix', 'signal', 'sys',
334 'thread', 'zipimport') or
335 (file.startswith(basedir) and
336 not file.startswith(os.path.join(basedir, 'site-packages'))))):
Skip Montanarof2134842004-06-07 02:40:05 +0000337 htmlfile = "module-%s.html" % object.__name__
Skip Montanaro4997a692003-09-10 16:47:51 +0000338 if docloc.startswith("http://"):
Skip Montanarof2134842004-06-07 02:40:05 +0000339 docloc = "%s/%s" % (docloc.rstrip("/"), htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000340 else:
Skip Montanarof2134842004-06-07 02:40:05 +0000341 docloc = os.path.join(docloc, htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000342 else:
343 docloc = None
344 return docloc
345
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000346# -------------------------------------------- HTML documentation generator
347
348class HTMLRepr(Repr):
349 """Class for safely making an HTML representation of a Python object."""
350 def __init__(self):
351 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000352 self.maxlist = self.maxtuple = 20
353 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000354 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000355
356 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000357 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000358
359 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000360 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000361
362 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000363 if hasattr(type(x), '__name__'):
364 methodname = 'repr_' + join(split(type(x).__name__), '_')
365 if hasattr(self, methodname):
366 return getattr(self, methodname)(x, level)
367 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000368
369 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000370 test = cram(x, self.maxstring)
371 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000372 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000373 # Backslashes are only literal in the string and are never
374 # needed to make any special characters, so show a raw string.
375 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000376 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000377 r'<font color="#c040c0">\1</font>',
378 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000379
Skip Montanarodf708782002-03-07 22:58:02 +0000380 repr_str = repr_string
381
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000382 def repr_instance(self, x, level):
383 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000384 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000385 except:
386 return self.escape('<%s instance>' % x.__class__.__name__)
387
388 repr_unicode = repr_string
389
390class HTMLDoc(Doc):
391 """Formatter class for HTML documentation."""
392
393 # ------------------------------------------- HTML formatting utilities
394
395 _repr_instance = HTMLRepr()
396 repr = _repr_instance.repr
397 escape = _repr_instance.escape
398
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000399 def page(self, title, contents):
400 """Format an HTML page."""
401 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000402<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000403<html><head><title>Python: %s</title>
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000404</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000405%s
406</body></html>''' % (title, contents)
407
408 def heading(self, title, fgcol, bgcol, extras=''):
409 """Format a page heading."""
410 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000411<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000412<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000413<td valign=bottom>&nbsp;<br>
414<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000415><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000416><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000417 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
418
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000419 def section(self, title, fgcol, bgcol, contents, width=6,
420 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000421 """Format a section with a heading."""
422 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000423 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000424 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000425<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000426<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000427<td colspan=3 valign=bottom>&nbsp;<br>
428<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000429 ''' % (bgcol, fgcol, title)
430 if prelude:
431 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000432<tr bgcolor="%s"><td rowspan=2>%s</td>
433<td colspan=2>%s</td></tr>
434<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
435 else:
436 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000437<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000438
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000439 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000440
441 def bigsection(self, title, *args):
442 """Format a section with a big heading."""
443 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000444 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000445
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000446 def preformat(self, text):
447 """Format literal preformatted text."""
448 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000449 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
450 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000451
452 def multicolumn(self, list, format, cols=4):
453 """Format a list of items into a multi-column list."""
454 result = ''
455 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000456 for col in range(cols):
457 result = result + '<td width="%d%%" valign=top>' % (100/cols)
458 for i in range(rows*col, rows*col+rows):
459 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000460 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000461 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000462 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000463
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000464 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000465
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000466 def namelink(self, name, *dicts):
467 """Make a link for an identifier, given name-to-URL mappings."""
468 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000469 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000470 return '<a href="%s">%s</a>' % (dict[name], name)
471 return name
472
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000473 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000474 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000475 name, module = object.__name__, sys.modules.get(object.__module__)
476 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000477 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000478 module.__name__, name, classname(object, modname))
479 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000480
481 def modulelink(self, object):
482 """Make a link for a module."""
483 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
484
485 def modpkglink(self, (name, path, ispackage, shadowed)):
486 """Make a link for a module or package to display in an index."""
487 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000488 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000489 if path:
490 url = '%s.%s.html' % (path, name)
491 else:
492 url = '%s.html' % name
493 if ispackage:
494 text = '<strong>%s</strong>&nbsp;(package)' % name
495 else:
496 text = name
497 return '<a href="%s">%s</a>' % (url, text)
498
499 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
500 """Mark up some plain text, given a context of symbols to look for.
501 Each context dictionary maps object names to anchor names."""
502 escape = escape or self.escape
503 results = []
504 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000505 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
506 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000507 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000508 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000509 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000510 match = pattern.search(text, here)
511 if not match: break
512 start, end = match.span()
513 results.append(escape(text[here:start]))
514
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000515 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000516 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000517 url = escape(all).replace('"', '&quot;')
518 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000519 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000520 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
521 results.append('<a href="%s">%s</a>' % (url, escape(all)))
522 elif pep:
523 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000524 results.append('<a href="%s">%s</a>' % (url, escape(all)))
525 elif text[end:end+1] == '(':
526 results.append(self.namelink(name, methods, funcs, classes))
527 elif selfdot:
528 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000529 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000530 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000531 here = end
532 results.append(escape(text[here:]))
533 return join(results, '')
534
535 # ---------------------------------------------- type-specific routines
536
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000537 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000538 """Produce HTML for a class tree as given by inspect.getclasstree()."""
539 result = ''
540 for entry in tree:
541 if type(entry) is type(()):
542 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000543 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000544 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000545 if bases and bases != (parent,):
546 parents = []
547 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000548 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000549 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000550 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000551 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000552 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000553 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000554 return '<dl>\n%s</dl>\n' % result
555
Tim Peters8dd7ade2001-10-18 19:56:17 +0000556 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000557 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000558 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000559 try:
560 all = object.__all__
561 except AttributeError:
562 all = None
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000563 parts = split(name, '.')
564 links = []
565 for i in range(len(parts)-1):
566 links.append(
567 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
568 (join(parts[:i+1], '.'), parts[i]))
569 linkedname = join(links + parts[-1:], '.')
570 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000571 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000572 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000573 url = path
574 if sys.platform == 'win32':
575 import nturl2path
576 url = nturl2path.pathname2url(path)
577 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000578 except TypeError:
579 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000580 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000581 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000582 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000583 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
584 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000585 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000586 if hasattr(object, '__date__'):
587 info.append(self.escape(str(object.__date__)))
588 if info:
589 head = head + ' (%s)' % join(info, ', ')
Skip Montanaro4997a692003-09-10 16:47:51 +0000590 docloc = self.getdocloc(object)
591 if docloc is not None:
592 docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
593 else:
594 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000595 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000596 head, '#ffffff', '#7799ee',
597 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000598
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000599 modules = inspect.getmembers(object, inspect.ismodule)
600
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000601 classes, cdict = [], {}
602 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000603 # if __all__ exists, believe it. Otherwise use old heuristic.
604 if (all is not None or
605 (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000606 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000607 classes.append((key, value))
608 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000609 for key, value in classes:
610 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000611 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000612 module = sys.modules.get(modname)
613 if modname != name and module and hasattr(module, key):
614 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000615 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000616 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000617 funcs, fdict = [], {}
618 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000619 # if __all__ exists, believe it. Otherwise use old heuristic.
620 if (all is not None or
621 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000622 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000623 funcs.append((key, value))
624 fdict[key] = '#-' + key
625 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000626 data = []
627 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000628 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000629 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000630
631 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
632 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000633 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000634
635 if hasattr(object, '__path__'):
636 modpkgs = []
637 modnames = []
638 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000639 path = os.path.join(object.__path__[0], file)
640 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000641 if modname != '__init__':
642 if modname and modname not in modnames:
643 modpkgs.append((modname, name, 0, 0))
644 modnames.append(modname)
645 elif ispackage(path):
646 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000647 modpkgs.sort()
648 contents = self.multicolumn(modpkgs, self.modpkglink)
649 result = result + self.bigsection(
650 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000651 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000652 contents = self.multicolumn(
653 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000654 result = result + self.bigsection(
655 'Modules', '#fffff', '#aa55cc', contents)
656
657 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000658 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000659 contents = [
660 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000661 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000662 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000663 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000664 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000665 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000666 contents = []
667 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000668 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000669 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000670 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000671 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000672 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000673 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000674 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000675 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000676 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000677 if hasattr(object, '__author__'):
678 contents = self.markup(str(object.__author__), self.preformat)
679 result = result + self.bigsection(
680 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000681 if hasattr(object, '__credits__'):
682 contents = self.markup(str(object.__credits__), self.preformat)
683 result = result + self.bigsection(
684 'Credits', '#ffffff', '#7799ee', contents)
685
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000686 return result
687
Tim Peters8dd7ade2001-10-18 19:56:17 +0000688 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
689 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000690 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000691 realname = object.__name__
692 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000693 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000694
Tim Petersb47879b2001-09-24 04:47:19 +0000695 contents = []
696 push = contents.append
697
Tim Petersfa26f7c2001-09-24 08:05:11 +0000698 # Cute little class to pump out a horizontal rule between sections.
699 class HorizontalRule:
700 def __init__(self):
701 self.needone = 0
702 def maybe(self):
703 if self.needone:
704 push('<hr>\n')
705 self.needone = 1
706 hr = HorizontalRule()
707
Tim Petersc86f6ca2001-09-26 21:31:51 +0000708 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000709 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000710 if len(mro) > 2:
711 hr.maybe()
712 push('<dl><dt>Method resolution order:</dt>\n')
713 for base in mro:
714 push('<dd>%s</dd>\n' % self.classlink(base,
715 object.__module__))
716 push('</dl>\n')
717
Tim Petersb47879b2001-09-24 04:47:19 +0000718 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000719 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000720 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000721 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000722 push(msg)
723 for name, kind, homecls, value in ok:
724 push(self.document(getattr(object, name), name, mod,
725 funcs, classes, mdict, object))
726 push('\n')
727 return attrs
728
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000729 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000730 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000731 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000732 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000733 push(msg)
734 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000735 push(self._docdescriptor(name, value, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000736 return attrs
737
Tim Petersfa26f7c2001-09-24 08:05:11 +0000738 def spilldata(msg, attrs, predicate):
739 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:
744 base = self.docother(getattr(object, name), name, mod)
Martin v. Löwise59e2ba2003-05-03 09:09:02 +0000745 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000746 doc = getattr(value, "__doc__", None)
747 else:
748 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000749 if doc is None:
750 push('<dl><dt>%s</dl>\n' % base)
751 else:
752 doc = self.markup(getdoc(value), self.preformat,
753 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000754 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000755 push('<dl><dt>%s%s</dl>\n' % (base, doc))
756 push('\n')
757 return attrs
758
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000759 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000760 classify_class_attrs(object))
Tim Petersb47879b2001-09-24 04:47:19 +0000761 mdict = {}
762 for key, kind, homecls, value in attrs:
763 mdict[key] = anchor = '#' + name + '-' + key
764 value = getattr(object, key)
765 try:
766 # The value may not be hashable (e.g., a data attr with
767 # a dict or list value).
768 mdict[value] = anchor
769 except TypeError:
770 pass
771
Tim Petersfa26f7c2001-09-24 08:05:11 +0000772 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000773 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000774 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000775 else:
776 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000777 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
778
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000779 if thisclass is __builtin__.object:
780 attrs = inherited
781 continue
782 elif thisclass is object:
783 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000784 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000785 tag = 'inherited from %s' % self.classlink(thisclass,
786 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000787 tag += ':<br>\n'
788
789 # Sort attrs by name.
Raymond Hettinger6b59f5f2003-10-16 05:53:16 +0000790 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000791
792 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000793 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000794 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000795 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000796 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000797 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000798 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000799 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
800 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000801 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000802 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000803 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000804 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000805
806 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000807
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000808 if name == realname:
809 title = '<a name="%s">class <strong>%s</strong></a>' % (
810 name, realname)
811 else:
812 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
813 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000814 if bases:
815 parents = []
816 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000817 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000818 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000819 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000820 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000821
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000822 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000823
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000824 def formatvalue(self, object):
825 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000826 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000827
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000828 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000829 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000830 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000831 realname = object.__name__
832 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000833 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000834 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000835 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000836 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000837 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000838 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000839 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000840 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000841 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000842 if object.im_self:
843 note = ' method of %s instance' % self.classlink(
844 object.im_self.__class__, mod)
845 else:
846 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000847 object = object.im_func
848
849 if name == realname:
850 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
851 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000852 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000853 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000854 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000855 cl.__name__ + '-' + realname, realname)
856 skipdocs = 1
857 else:
858 reallink = realname
859 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
860 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000861 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000862 args, varargs, varkw, defaults = inspect.getargspec(object)
863 argspec = inspect.formatargspec(
864 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000865 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000866 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000867 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000868 else:
869 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000870
Tim Peters2306d242001-09-25 03:18:32 +0000871 decl = title + argspec + (note and self.grey(
872 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000873
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000874 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000875 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000876 else:
877 doc = self.markup(
878 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000879 doc = doc and '<dd><tt>%s</tt></dd>' % doc
880 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000881
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000882 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000883 results = []
884 push = results.append
885
886 if name:
887 push('<dl><dt><strong>%s</strong></dt>\n' % name)
888 if value.__doc__ is not None:
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +0000889 doc = self.markup(getdoc(value), self.preformat)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000890 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000891 push('</dl>\n')
892
893 return ''.join(results)
894
895 def docproperty(self, object, name=None, mod=None, cl=None):
896 """Produce html documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000897 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000898
Tim Peters8dd7ade2001-10-18 19:56:17 +0000899 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000900 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000901 lhs = name and '<strong>%s</strong> = ' % name or ''
902 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000903
904 def index(self, dir, shadowed=None):
905 """Generate an HTML index for a directory of modules."""
906 modpkgs = []
907 if shadowed is None: shadowed = {}
908 seen = {}
909 files = os.listdir(dir)
910
911 def found(name, ispackage,
912 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
Raymond Hettinger4f759d82002-11-02 02:02:46 +0000913 if name not in seen:
914 modpkgs.append((name, '', ispackage, name in shadowed))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000915 seen[name] = 1
916 shadowed[name] = 1
917
918 # Package spam/__init__.py takes precedence over module spam.py.
919 for file in files:
920 path = os.path.join(dir, file)
921 if ispackage(path): found(file, 1)
922 for file in files:
923 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000924 if os.path.isfile(path):
925 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000926 if modname: found(modname, 0)
927
928 modpkgs.sort()
929 contents = self.multicolumn(modpkgs, self.modpkglink)
930 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
931
932# -------------------------------------------- text documentation generator
933
934class TextRepr(Repr):
935 """Class for safely making a text representation of a Python object."""
936 def __init__(self):
937 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000938 self.maxlist = self.maxtuple = 20
939 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000940 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000941
942 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000943 if hasattr(type(x), '__name__'):
944 methodname = 'repr_' + join(split(type(x).__name__), '_')
945 if hasattr(self, methodname):
946 return getattr(self, methodname)(x, level)
947 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000948
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000949 def repr_string(self, x, level):
950 test = cram(x, self.maxstring)
951 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000952 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000953 # Backslashes are only literal in the string and are never
954 # needed to make any special characters, so show a raw string.
955 return 'r' + testrepr[0] + test + testrepr[0]
956 return testrepr
957
Skip Montanarodf708782002-03-07 22:58:02 +0000958 repr_str = repr_string
959
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000960 def repr_instance(self, x, level):
961 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000962 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000963 except:
964 return '<%s instance>' % x.__class__.__name__
965
966class TextDoc(Doc):
967 """Formatter class for text documentation."""
968
969 # ------------------------------------------- text formatting utilities
970
971 _repr_instance = TextRepr()
972 repr = _repr_instance.repr
973
974 def bold(self, text):
975 """Format a string in bold by overstriking."""
976 return join(map(lambda ch: ch + '\b' + ch, text), '')
977
978 def indent(self, text, prefix=' '):
979 """Indent text by prepending a given prefix to each line."""
980 if not text: return ''
981 lines = split(text, '\n')
982 lines = map(lambda line, prefix=prefix: prefix + line, lines)
983 if lines: lines[-1] = rstrip(lines[-1])
984 return join(lines, '\n')
985
986 def section(self, title, contents):
987 """Format a section with a given heading."""
988 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
989
990 # ---------------------------------------------- type-specific routines
991
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000992 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000993 """Render in text a class tree as returned by inspect.getclasstree()."""
994 result = ''
995 for entry in tree:
996 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000997 c, bases = entry
998 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000999 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001000 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001001 result = result + '(%s)' % join(parents, ', ')
1002 result = result + '\n'
1003 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001004 result = result + self.formattree(
1005 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001006 return result
1007
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001008 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001009 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001010 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001011 synop, desc = splitdoc(getdoc(object))
1012 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001013
1014 try:
Skip Montanaroa5616d22004-06-11 04:46:12 +00001015 all = object.__all__
1016 except AttributeError:
1017 all = None
1018
1019 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001020 file = inspect.getabsfile(object)
1021 except TypeError:
1022 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001023 result = result + self.section('FILE', file)
Skip Montanaro4997a692003-09-10 16:47:51 +00001024
1025 docloc = self.getdocloc(object)
1026 if docloc is not None:
1027 result = result + self.section('MODULE DOCS', docloc)
1028
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001029 if desc:
1030 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001031
1032 classes = []
1033 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001034 # if __all__ exists, believe it. Otherwise use old heuristic.
1035 if (all is not None
1036 or (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001037 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001038 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001039 funcs = []
1040 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001041 # if __all__ exists, believe it. Otherwise use old heuristic.
1042 if (all is not None or
1043 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001044 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001045 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001046 data = []
1047 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001048 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001049 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001050
1051 if hasattr(object, '__path__'):
1052 modpkgs = []
1053 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001054 path = os.path.join(object.__path__[0], file)
1055 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001056 if modname != '__init__':
1057 if modname and modname not in modpkgs:
1058 modpkgs.append(modname)
1059 elif ispackage(path):
1060 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001061 modpkgs.sort()
1062 result = result + self.section(
1063 'PACKAGE CONTENTS', join(modpkgs, '\n'))
1064
1065 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001066 classlist = map(lambda (key, value): value, classes)
1067 contents = [self.formattree(
1068 inspect.getclasstree(classlist, 1), name)]
1069 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001070 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001071 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001072
1073 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001074 contents = []
1075 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001076 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001077 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001078
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001079 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001080 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001081 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001082 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001083 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001084
1085 if hasattr(object, '__version__'):
1086 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001087 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1088 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001089 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001090 if hasattr(object, '__date__'):
1091 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001092 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001093 result = result + self.section('AUTHOR', str(object.__author__))
1094 if hasattr(object, '__credits__'):
1095 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001096 return result
1097
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001098 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001099 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001100 realname = object.__name__
1101 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001102 bases = object.__bases__
1103
Tim Petersc86f6ca2001-09-26 21:31:51 +00001104 def makename(c, m=object.__module__):
1105 return classname(c, m)
1106
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001107 if name == realname:
1108 title = 'class ' + self.bold(realname)
1109 else:
1110 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001111 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001112 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001113 title = title + '(%s)' % join(parents, ', ')
1114
1115 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001116 contents = doc and [doc + '\n'] or []
1117 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001118
Tim Petersc86f6ca2001-09-26 21:31:51 +00001119 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001120 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001121 if len(mro) > 2:
1122 push("Method resolution order:")
1123 for base in mro:
1124 push(' ' + makename(base))
1125 push('')
1126
Tim Petersf4aad8e2001-09-24 22:40:47 +00001127 # Cute little class to pump out a horizontal rule between sections.
1128 class HorizontalRule:
1129 def __init__(self):
1130 self.needone = 0
1131 def maybe(self):
1132 if self.needone:
1133 push('-' * 70)
1134 self.needone = 1
1135 hr = HorizontalRule()
1136
Tim Peters28355492001-09-23 21:29:55 +00001137 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001138 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001139 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001140 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001141 push(msg)
1142 for name, kind, homecls, value in ok:
1143 push(self.document(getattr(object, name),
1144 name, mod, object))
1145 return attrs
1146
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001147 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001148 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001149 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001150 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001151 push(msg)
1152 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001153 push(self._docdescriptor(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001154 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001155
Tim Petersfa26f7c2001-09-24 08:05:11 +00001156 def spilldata(msg, attrs, predicate):
1157 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001158 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001159 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001160 push(msg)
1161 for name, kind, homecls, value in ok:
Martin v. Löwise59e2ba2003-05-03 09:09:02 +00001162 if callable(value) or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001163 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001164 else:
1165 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001166 push(self.docother(getattr(object, name),
1167 name, mod, 70, doc) + '\n')
1168 return attrs
1169
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001170 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001171 classify_class_attrs(object))
Tim Petersfa26f7c2001-09-24 08:05:11 +00001172 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001173 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001174 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001175 else:
1176 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001177 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1178
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001179 if thisclass is __builtin__.object:
1180 attrs = inherited
1181 continue
1182 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001183 tag = "defined here"
1184 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001185 tag = "inherited from %s" % classname(thisclass,
1186 object.__module__)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001187 filter(lambda t: not t[0].startswith('_'), attrs)
Tim Peters28355492001-09-23 21:29:55 +00001188
1189 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001190 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001191
1192 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001193 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001194 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001195 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001196 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001197 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001198 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001199 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1200 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001201 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1202 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001203 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001204 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001205
1206 contents = '\n'.join(contents)
1207 if not contents:
1208 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001209 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1210
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001211 def formatvalue(self, object):
1212 """Format an argument default value as text."""
1213 return '=' + self.repr(object)
1214
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001215 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001216 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001217 realname = object.__name__
1218 name = name or realname
1219 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001220 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001221 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001222 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001223 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001224 if imclass is not cl:
1225 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001226 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001227 if object.im_self:
1228 note = ' method of %s instance' % classname(
1229 object.im_self.__class__, mod)
1230 else:
1231 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001232 object = object.im_func
1233
1234 if name == realname:
1235 title = self.bold(realname)
1236 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001237 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001238 cl.__dict__[realname] is object):
1239 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001240 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001241 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001242 args, varargs, varkw, defaults = inspect.getargspec(object)
1243 argspec = inspect.formatargspec(
1244 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001245 if realname == '<lambda>':
1246 title = 'lambda'
1247 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001248 else:
1249 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001250 decl = title + argspec + note
1251
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001252 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001253 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001254 else:
1255 doc = getdoc(object) or ''
1256 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001257
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001258 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001259 results = []
1260 push = results.append
1261
1262 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001263 push(self.bold(name))
1264 push('\n')
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001265 doc = getdoc(value) or ''
1266 if doc:
1267 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001268 push('\n')
1269 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001270
1271 def docproperty(self, object, name=None, mod=None, cl=None):
1272 """Produce text documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001273 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001274
Tim Peters28355492001-09-23 21:29:55 +00001275 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001276 """Produce text documentation for a data object."""
1277 repr = self.repr(object)
1278 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001279 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001280 chop = maxlen - len(line)
1281 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001282 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001283 if doc is not None:
1284 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001285 return line
1286
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001287# --------------------------------------------------------- user interfaces
1288
1289def pager(text):
1290 """The first time this is called, determine what kind of pager to use."""
1291 global pager
1292 pager = getpager()
1293 pager(text)
1294
1295def getpager():
1296 """Decide what method to use for paging through text."""
1297 if type(sys.stdout) is not types.FileType:
1298 return plainpager
1299 if not sys.stdin.isatty() or not sys.stdout.isatty():
1300 return plainpager
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001301 if os.environ.get('TERM') in ('dumb', 'emacs'):
Fred Drake5e9eb982001-07-23 19:48:10 +00001302 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001303 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001304 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001305 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001306 elif os.environ.get('TERM') in ('dumb', 'emacs'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001307 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001308 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001309 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001310 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001311 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001312 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001313 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001314
1315 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001316 (fd, filename) = tempfile.mkstemp()
1317 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001318 try:
1319 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1320 return lambda text: pipepager(text, 'more')
1321 else:
1322 return ttypager
1323 finally:
1324 os.unlink(filename)
1325
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001326def plain(text):
1327 """Remove boldface formatting from text."""
1328 return re.sub('.\b', '', text)
1329
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001330def pipepager(text, cmd):
1331 """Page through text by feeding it to another program."""
1332 pipe = os.popen(cmd, 'w')
1333 try:
1334 pipe.write(text)
1335 pipe.close()
1336 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001337 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001338
1339def tempfilepager(text, cmd):
1340 """Page through text by invoking a program on a temporary file."""
1341 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001342 filename = tempfile.mktemp()
1343 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001344 file.write(text)
1345 file.close()
1346 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001347 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001348 finally:
1349 os.unlink(filename)
1350
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001351def ttypager(text):
1352 """Page through text on a text terminal."""
1353 lines = split(plain(text), '\n')
1354 try:
1355 import tty
1356 fd = sys.stdin.fileno()
1357 old = tty.tcgetattr(fd)
1358 tty.setcbreak(fd)
1359 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001360 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001361 tty = None
1362 getchar = lambda: sys.stdin.readline()[:-1][:1]
1363
1364 try:
1365 r = inc = os.environ.get('LINES', 25) - 1
1366 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1367 while lines[r:]:
1368 sys.stdout.write('-- more --')
1369 sys.stdout.flush()
1370 c = getchar()
1371
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001372 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001373 sys.stdout.write('\r \r')
1374 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001375 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001376 sys.stdout.write('\r \r' + lines[r] + '\n')
1377 r = r + 1
1378 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001379 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001380 r = r - inc - inc
1381 if r < 0: r = 0
1382 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1383 r = r + inc
1384
1385 finally:
1386 if tty:
1387 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1388
1389def plainpager(text):
1390 """Simply print unformatted text. This is the ultimate fallback."""
1391 sys.stdout.write(plain(text))
1392
1393def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001394 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001395 if inspect.ismodule(thing):
1396 if thing.__name__ in sys.builtin_module_names:
1397 return 'built-in module ' + thing.__name__
1398 if hasattr(thing, '__path__'):
1399 return 'package ' + thing.__name__
1400 else:
1401 return 'module ' + thing.__name__
1402 if inspect.isbuiltin(thing):
1403 return 'built-in function ' + thing.__name__
1404 if inspect.isclass(thing):
1405 return 'class ' + thing.__name__
1406 if inspect.isfunction(thing):
1407 return 'function ' + thing.__name__
1408 if inspect.ismethod(thing):
1409 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001410 if type(thing) is types.InstanceType:
1411 return 'instance of ' + thing.__class__.__name__
1412 return type(thing).__name__
1413
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001414def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001415 """Locate an object by name or dotted path, importing as necessary."""
Guido van Rossum97dede02003-02-16 01:12:32 +00001416 parts = [part for part in split(path, '.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001417 module, n = None, 0
1418 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001419 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001420 if nextmodule: module, n = nextmodule, n + 1
1421 else: break
1422 if module:
1423 object = module
1424 for part in parts[n:]:
1425 try: object = getattr(object, part)
1426 except AttributeError: return None
1427 return object
1428 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001429 if hasattr(__builtin__, path):
1430 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001431
1432# --------------------------------------- interactive interpreter interface
1433
1434text = TextDoc()
1435html = HTMLDoc()
1436
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001437def resolve(thing, forceload=0):
1438 """Given an object or a path to an object, get the object and its name."""
1439 if isinstance(thing, str):
1440 object = locate(thing, forceload)
1441 if not object:
1442 raise ImportError, 'no Python documentation found for %r' % thing
1443 return object, thing
1444 else:
1445 return thing, getattr(thing, '__name__', None)
1446
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001447def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001448 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001449 try:
1450 object, name = resolve(thing, forceload)
1451 desc = describe(object)
1452 module = inspect.getmodule(object)
1453 if name and '.' in name:
1454 desc += ' in ' + name[:name.rfind('.')]
1455 elif module and module is not object:
1456 desc += ' in module ' + module.__name__
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001457 if not (inspect.ismodule(object) or
1458 inspect.isclass(object) or
1459 inspect.isroutine(object) or
1460 isinstance(object, property)):
1461 # If the passed object is a piece of data or an instance,
1462 # document its available methods instead of its value.
1463 object = type(object)
1464 desc += ' object'
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001465 pager(title % desc + '\n\n' + text.document(object, name))
1466 except (ImportError, ErrorDuringImport), value:
1467 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001468
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001469def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001470 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001471 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001472 object, name = resolve(thing, forceload)
1473 page = html.page(describe(object), html.document(object, name))
1474 file = open(name + '.html', 'w')
1475 file.write(page)
1476 file.close()
1477 print 'wrote', name + '.html'
1478 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001479 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001480
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001481def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001482 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001483 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001484 for file in os.listdir(dir):
1485 path = os.path.join(dir, file)
1486 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001487 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001488 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001489 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001490 if modname:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001491 if modname == '__init__':
1492 modname = pkgpath[:-1] # remove trailing period
1493 else:
1494 modname = pkgpath + modname
1495 if modname not in done:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001496 done[modname] = 1
1497 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001498
1499class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001500 keywords = {
1501 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001502 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001503 'break': ('ref/break', 'while for'),
1504 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1505 'continue': ('ref/continue', 'while for'),
1506 'def': ('ref/function', ''),
1507 'del': ('ref/del', 'BASICMETHODS'),
1508 'elif': 'if',
1509 'else': ('ref/if', 'while for'),
1510 'except': 'try',
1511 'exec': ('ref/exec', ''),
1512 'finally': 'try',
1513 'for': ('ref/for', 'break continue while'),
1514 'from': 'import',
1515 'global': ('ref/global', 'NAMESPACES'),
1516 'if': ('ref/if', 'TRUTHVALUE'),
1517 'import': ('ref/import', 'MODULES'),
1518 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1519 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001520 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001521 'not': 'BOOLEAN',
1522 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001523 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001524 'print': ('ref/print', ''),
1525 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001526 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001527 'try': ('ref/try', 'EXCEPTIONS'),
1528 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001529 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001530 }
1531
1532 topics = {
1533 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001534 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001535 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1536 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001537 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001538 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1539 'INTEGER': ('ref/integers', 'int range'),
1540 'FLOAT': ('ref/floating', 'float math'),
1541 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001542 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001543 'MAPPINGS': 'DICTIONARIES',
1544 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1545 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1546 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001547 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001548 'FRAMEOBJECTS': 'TYPES',
1549 'TRACEBACKS': 'TYPES',
1550 'NONE': ('lib/bltin-null-object', ''),
1551 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1552 'FILES': ('lib/bltin-file-objects', ''),
1553 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1554 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1555 'MODULES': ('lib/typesmodules', 'import'),
1556 'PACKAGES': 'import',
1557 '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'),
1558 'OPERATORS': 'EXPRESSIONS',
1559 'PRECEDENCE': 'EXPRESSIONS',
1560 'OBJECTS': ('ref/objects', 'TYPES'),
1561 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001562 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1563 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1564 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1565 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1566 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1567 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1568 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001569 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1570 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1571 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001572 'SCOPING': 'NAMESPACES',
1573 'FRAMES': 'NAMESPACES',
1574 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001575 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1576 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001577 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1578 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001579 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001580 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1581 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001582 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001583 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001584 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001585 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001586 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1587 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001588 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1589 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1590 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1591 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1592 'POWER': ('ref/power', 'EXPRESSIONS'),
1593 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1594 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1595 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1596 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1597 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001598 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001599 'ASSERTION': 'assert',
1600 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001601 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001602 'DELETION': 'del',
1603 'PRINTING': 'print',
1604 'RETURNING': 'return',
1605 'IMPORTING': 'import',
1606 'CONDITIONAL': 'if',
1607 'LOOPING': ('ref/compound', 'for while break continue'),
1608 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001609 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001610 }
1611
1612 def __init__(self, input, output):
1613 self.input = input
1614 self.output = output
1615 self.docdir = None
1616 execdir = os.path.dirname(sys.executable)
1617 homedir = os.environ.get('PYTHONHOME')
1618 for dir in [os.environ.get('PYTHONDOCS'),
1619 homedir and os.path.join(homedir, 'doc'),
1620 os.path.join(execdir, 'doc'),
1621 '/usr/doc/python-docs-' + split(sys.version)[0],
1622 '/usr/doc/python-' + split(sys.version)[0],
1623 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001624 '/usr/doc/python-' + sys.version[:3],
1625 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001626 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1627 self.docdir = dir
1628
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001629 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001630 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001631 self()
1632 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001633 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001634
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001635 def __call__(self, request=None):
1636 if request is not None:
1637 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001638 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001639 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001640 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001641 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001642You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001643If you want to ask for help on a particular object directly from the
1644interpreter, you can type "help(object)". Executing "help('string')"
1645has the same effect as typing a particular string at the help> prompt.
1646''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001647
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001648 def interact(self):
1649 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001650 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001651 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001652 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001653 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001654 except (KeyboardInterrupt, EOFError):
1655 break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001656 request = strip(replace(request, '"', '', "'", ''))
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001657 if lower(request) in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001658 self.help(request)
1659
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001660 def getline(self, prompt):
1661 """Read one line, using raw_input when available."""
1662 if self.input is sys.stdin:
1663 return raw_input(prompt)
1664 else:
1665 self.output.write(prompt)
1666 self.output.flush()
1667 return self.input.readline()
1668
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001669 def help(self, request):
1670 if type(request) is type(''):
1671 if request == 'help': self.intro()
1672 elif request == 'keywords': self.listkeywords()
1673 elif request == 'topics': self.listtopics()
1674 elif request == 'modules': self.listmodules()
1675 elif request[:8] == 'modules ':
1676 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001677 elif request in self.keywords: self.showtopic(request)
1678 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001679 elif request: doc(request, 'Help on %s:')
1680 elif isinstance(request, Helper): self()
1681 else: doc(request, 'Help on %s:')
1682 self.output.write('\n')
1683
1684 def intro(self):
1685 self.output.write('''
1686Welcome to Python %s! This is the online help utility.
1687
1688If this is your first time using Python, you should definitely check out
1689the tutorial on the Internet at http://www.python.org/doc/tut/.
1690
1691Enter the name of any module, keyword, or topic to get help on writing
1692Python programs and using Python modules. To quit this help utility and
1693return to the interpreter, just type "quit".
1694
1695To get a list of available modules, keywords, or topics, type "modules",
1696"keywords", or "topics". Each module also comes with a one-line summary
1697of what it does; to list the modules whose summaries contain a given word
1698such as "spam", type "modules spam".
1699''' % sys.version[:3])
1700
1701 def list(self, items, columns=4, width=80):
1702 items = items[:]
1703 items.sort()
1704 colw = width / columns
1705 rows = (len(items) + columns - 1) / columns
1706 for row in range(rows):
1707 for col in range(columns):
1708 i = col * rows + row
1709 if i < len(items):
1710 self.output.write(items[i])
1711 if col < columns - 1:
1712 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1713 self.output.write('\n')
1714
1715 def listkeywords(self):
1716 self.output.write('''
1717Here is a list of the Python keywords. Enter any keyword to get more help.
1718
1719''')
1720 self.list(self.keywords.keys())
1721
1722 def listtopics(self):
1723 self.output.write('''
1724Here is a list of available topics. Enter any topic name to get more help.
1725
1726''')
1727 self.list(self.topics.keys())
1728
1729 def showtopic(self, topic):
1730 if not self.docdir:
1731 self.output.write('''
1732Sorry, topic and keyword documentation is not available because the Python
1733HTML documentation files could not be found. If you have installed them,
1734please set the environment variable PYTHONDOCS to indicate their location.
1735''')
1736 return
1737 target = self.topics.get(topic, self.keywords.get(topic))
1738 if not target:
1739 self.output.write('no documentation found for %s\n' % repr(topic))
1740 return
1741 if type(target) is type(''):
1742 return self.showtopic(target)
1743
1744 filename, xrefs = target
1745 filename = self.docdir + '/' + filename + '.html'
1746 try:
1747 file = open(filename)
1748 except:
1749 self.output.write('could not read docs from %s\n' % filename)
1750 return
1751
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001752 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1753 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001754 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1755 file.close()
1756
1757 import htmllib, formatter, StringIO
1758 buffer = StringIO.StringIO()
1759 parser = htmllib.HTMLParser(
1760 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1761 parser.start_table = parser.do_p
1762 parser.end_table = lambda parser=parser: parser.do_p({})
1763 parser.start_tr = parser.do_br
1764 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1765 parser.feed(document)
1766 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1767 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001768 if xrefs:
1769 buffer = StringIO.StringIO()
1770 formatter.DumbWriter(buffer).send_flowing_data(
1771 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1772 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001773
1774 def listmodules(self, key=''):
1775 if key:
1776 self.output.write('''
1777Here is a list of matching modules. Enter any module name to get more help.
1778
1779''')
1780 apropos(key)
1781 else:
1782 self.output.write('''
1783Please wait a moment while I gather a list of all available modules...
1784
1785''')
1786 modules = {}
1787 def callback(path, modname, desc, modules=modules):
1788 if modname and modname[-9:] == '.__init__':
1789 modname = modname[:-9] + ' (package)'
1790 if find(modname, '.') < 0:
1791 modules[modname] = 1
1792 ModuleScanner().run(callback)
1793 self.list(modules.keys())
1794 self.output.write('''
1795Enter any module name to get more help. Or, type "modules spam" to search
1796for modules whose descriptions contain the word "spam".
1797''')
1798
1799help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001800
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001801class Scanner:
1802 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001803 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001804 self.roots = roots[:]
1805 self.state = []
1806 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001807 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001808
1809 def next(self):
1810 if not self.state:
1811 if not self.roots:
1812 return None
1813 root = self.roots.pop(0)
1814 self.state = [(root, self.children(root))]
1815 node, children = self.state[-1]
1816 if not children:
1817 self.state.pop()
1818 return self.next()
1819 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001820 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001821 self.state.append((child, self.children(child)))
1822 return child
1823
1824class ModuleScanner(Scanner):
1825 """An interruptible scanner that searches module synopses."""
1826 def __init__(self):
1827 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001828 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001829 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001830
1831 def submodules(self, (dir, package)):
1832 children = []
1833 for file in os.listdir(dir):
1834 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001835 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001836 children.append((path, package + (package and '.') + file))
1837 else:
1838 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001839 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001840 return children
1841
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001842 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001843 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001844 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001845 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001846 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001847 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001848
Ka-Ping Yee66246962001-04-12 11:59:50 +00001849 def run(self, callback, key=None, completer=None):
1850 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001851 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001852 seen = {}
1853
1854 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001855 if modname != '__main__':
1856 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001857 if key is None:
1858 callback(None, modname, '')
1859 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001860 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001861 if find(lower(modname + ' - ' + desc), key) >= 0:
1862 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001863
1864 while not self.quit:
1865 node = self.next()
1866 if not node: break
1867 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001868 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001869 if os.path.isfile(path) and modname:
1870 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001871 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001872 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001873 if key is None:
1874 callback(path, modname, '')
1875 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001876 desc = synopsis(path) or ''
1877 if find(lower(modname + ' - ' + desc), key) >= 0:
1878 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001879 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001880
1881def apropos(key):
1882 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001883 def callback(path, modname, desc):
1884 if modname[-9:] == '.__init__':
1885 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001886 print modname, desc and '- ' + desc
1887 try: import warnings
1888 except ImportError: pass
1889 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001890 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001891
1892# --------------------------------------------------- web browser interface
1893
Ka-Ping Yee66246962001-04-12 11:59:50 +00001894def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001895 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001896
1897 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1898 class Message(mimetools.Message):
1899 def __init__(self, fp, seekable=1):
1900 Message = self.__class__
1901 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1902 self.encodingheader = self.getheader('content-transfer-encoding')
1903 self.typeheader = self.getheader('content-type')
1904 self.parsetype()
1905 self.parseplist()
1906
1907 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1908 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001909 try:
1910 self.send_response(200)
1911 self.send_header('Content-Type', 'text/html')
1912 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001913 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001914 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001915
1916 def do_GET(self):
1917 path = self.path
1918 if path[-5:] == '.html': path = path[:-5]
1919 if path[:1] == '/': path = path[1:]
1920 if path and path != '.':
1921 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001922 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001923 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001924 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001925 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001926 if obj:
1927 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001928 else:
1929 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001930'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001931 else:
1932 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001933'<big><big><strong>Python: Index of Modules</strong></big></big>',
1934'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001935 def bltinlink(name):
1936 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001937 names = filter(lambda x: x != '__main__',
1938 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001939 contents = html.multicolumn(names, bltinlink)
1940 indices = ['<p>' + html.bigsection(
1941 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1942
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001943 seen = {}
1944 for dir in pathdirs():
1945 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001946 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001947<font color="#909090" face="helvetica, arial"><strong>
1948pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001949 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001950
1951 def log_message(self, *args): pass
1952
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001953 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001954 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001955 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001956 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001957 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001958 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001959 self.base.__init__(self, self.address, self.handler)
1960
1961 def serve_until_quit(self):
1962 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001963 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001964 while not self.quit:
1965 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1966 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001967
1968 def server_activate(self):
1969 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001970 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001971
1972 DocServer.base = BaseHTTPServer.HTTPServer
1973 DocServer.handler = DocHandler
1974 DocHandler.MessageClass = Message
1975 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001976 try:
1977 DocServer(port, callback).serve_until_quit()
1978 except (KeyboardInterrupt, select.error):
1979 pass
1980 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001981 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001982
1983# ----------------------------------------------------- graphical interface
1984
1985def gui():
1986 """Graphical interface (starts web server and pops up a control window)."""
1987 class GUI:
1988 def __init__(self, window, port=7464):
1989 self.window = window
1990 self.server = None
1991 self.scanner = None
1992
1993 import Tkinter
1994 self.server_frm = Tkinter.Frame(window)
1995 self.title_lbl = Tkinter.Label(self.server_frm,
1996 text='Starting server...\n ')
1997 self.open_btn = Tkinter.Button(self.server_frm,
1998 text='open browser', command=self.open, state='disabled')
1999 self.quit_btn = Tkinter.Button(self.server_frm,
2000 text='quit serving', command=self.quit, state='disabled')
2001
2002 self.search_frm = Tkinter.Frame(window)
2003 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
2004 self.search_ent = Tkinter.Entry(self.search_frm)
2005 self.search_ent.bind('<Return>', self.search)
2006 self.stop_btn = Tkinter.Button(self.search_frm,
2007 text='stop', pady=0, command=self.stop, state='disabled')
2008 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002009 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002010 self.stop_btn.pack(side='right')
2011
2012 self.window.title('pydoc')
2013 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2014 self.title_lbl.pack(side='top', fill='x')
2015 self.open_btn.pack(side='left', fill='x', expand=1)
2016 self.quit_btn.pack(side='right', fill='x', expand=1)
2017 self.server_frm.pack(side='top', fill='x')
2018
2019 self.search_lbl.pack(side='left')
2020 self.search_ent.pack(side='right', fill='x', expand=1)
2021 self.search_frm.pack(side='top', fill='x')
2022 self.search_ent.focus_set()
2023
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002024 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002025 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002026 self.result_lst.bind('<Button-1>', self.select)
2027 self.result_lst.bind('<Double-Button-1>', self.goto)
2028 self.result_scr = Tkinter.Scrollbar(window,
2029 orient='vertical', command=self.result_lst.yview)
2030 self.result_lst.config(yscrollcommand=self.result_scr.set)
2031
2032 self.result_frm = Tkinter.Frame(window)
2033 self.goto_btn = Tkinter.Button(self.result_frm,
2034 text='go to selected', command=self.goto)
2035 self.hide_btn = Tkinter.Button(self.result_frm,
2036 text='hide results', command=self.hide)
2037 self.goto_btn.pack(side='left', fill='x', expand=1)
2038 self.hide_btn.pack(side='right', fill='x', expand=1)
2039
2040 self.window.update()
2041 self.minwidth = self.window.winfo_width()
2042 self.minheight = self.window.winfo_height()
2043 self.bigminheight = (self.server_frm.winfo_reqheight() +
2044 self.search_frm.winfo_reqheight() +
2045 self.result_lst.winfo_reqheight() +
2046 self.result_frm.winfo_reqheight())
2047 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2048 self.expanded = 0
2049 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2050 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002051 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002052
2053 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002054 threading.Thread(
2055 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002056
2057 def ready(self, server):
2058 self.server = server
2059 self.title_lbl.config(
2060 text='Python documentation server at\n' + server.url)
2061 self.open_btn.config(state='normal')
2062 self.quit_btn.config(state='normal')
2063
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002064 def open(self, event=None, url=None):
2065 url = url or self.server.url
2066 try:
2067 import webbrowser
2068 webbrowser.open(url)
2069 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002070 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002071 os.system('start "%s"' % url)
2072 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002073 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002074 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002075 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002076 else:
2077 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2078 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002079
2080 def quit(self, event=None):
2081 if self.server:
2082 self.server.quit = 1
2083 self.window.quit()
2084
2085 def search(self, event=None):
2086 key = self.search_ent.get()
2087 self.stop_btn.pack(side='right')
2088 self.stop_btn.config(state='normal')
2089 self.search_lbl.config(text='Searching for "%s"...' % key)
2090 self.search_ent.forget()
2091 self.search_lbl.pack(side='left')
2092 self.result_lst.delete(0, 'end')
2093 self.goto_btn.config(state='disabled')
2094 self.expand()
2095
2096 import threading
2097 if self.scanner:
2098 self.scanner.quit = 1
2099 self.scanner = ModuleScanner()
2100 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002101 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002102
2103 def update(self, path, modname, desc):
2104 if modname[-9:] == '.__init__':
2105 modname = modname[:-9] + ' (package)'
2106 self.result_lst.insert('end',
2107 modname + ' - ' + (desc or '(no description)'))
2108
2109 def stop(self, event=None):
2110 if self.scanner:
2111 self.scanner.quit = 1
2112 self.scanner = None
2113
2114 def done(self):
2115 self.scanner = None
2116 self.search_lbl.config(text='Search for')
2117 self.search_lbl.pack(side='left')
2118 self.search_ent.pack(side='right', fill='x', expand=1)
2119 if sys.platform != 'win32': self.stop_btn.forget()
2120 self.stop_btn.config(state='disabled')
2121
2122 def select(self, event=None):
2123 self.goto_btn.config(state='normal')
2124
2125 def goto(self, event=None):
2126 selection = self.result_lst.curselection()
2127 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002128 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002129 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002130
2131 def collapse(self):
2132 if not self.expanded: return
2133 self.result_frm.forget()
2134 self.result_scr.forget()
2135 self.result_lst.forget()
2136 self.bigwidth = self.window.winfo_width()
2137 self.bigheight = self.window.winfo_height()
2138 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2139 self.window.wm_minsize(self.minwidth, self.minheight)
2140 self.expanded = 0
2141
2142 def expand(self):
2143 if self.expanded: return
2144 self.result_frm.pack(side='bottom', fill='x')
2145 self.result_scr.pack(side='right', fill='y')
2146 self.result_lst.pack(side='top', fill='both', expand=1)
2147 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2148 self.window.wm_minsize(self.minwidth, self.bigminheight)
2149 self.expanded = 1
2150
2151 def hide(self, event=None):
2152 self.stop()
2153 self.collapse()
2154
2155 import Tkinter
2156 try:
Martin v. Löwise09bd932004-08-22 16:13:26 +00002157 root = Tkinter.Tk()
2158 # Tk will crash if pythonw.exe has an XP .manifest
2159 # file and the root has is not destroyed explicitly.
2160 # If the problem is ever fixed in Tk, the explicit
2161 # destroy can go.
2162 try:
2163 gui = GUI(root)
2164 root.mainloop()
2165 finally:
2166 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002167 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002168 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002169
2170# -------------------------------------------------- command-line interface
2171
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002172def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002173 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002174
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002175def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002176 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002177 import getopt
2178 class BadUsage: pass
2179
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002180 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002181 scriptdir = os.path.dirname(sys.argv[0])
2182 if scriptdir in sys.path:
2183 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002184 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002185
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002186 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002187 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002188 writing = 0
2189
2190 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002191 if opt == '-g':
2192 gui()
2193 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002194 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002195 apropos(val)
2196 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002197 if opt == '-p':
2198 try:
2199 port = int(val)
2200 except ValueError:
2201 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002202 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002203 print 'pydoc server ready at %s' % server.url
2204 def stopped():
2205 print 'pydoc server stopped'
2206 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002207 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002208 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002209 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002210
2211 if not args: raise BadUsage
2212 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002213 if ispath(arg) and not os.path.exists(arg):
2214 print 'file %r does not exist' % arg
2215 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002216 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002217 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002218 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002219 if writing:
2220 if ispath(arg) and os.path.isdir(arg):
2221 writedocs(arg)
2222 else:
2223 writedoc(arg)
2224 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002225 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002226 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002227 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002228
2229 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002230 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002231 print """pydoc - the Python documentation tool
2232
2233%s <name> ...
2234 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002235 Python keyword, topic, function, module, or package, or a dotted
2236 reference to a class or function within a module or module in a
2237 package. If <name> contains a '%s', it is used as the path to a
2238 Python source file to document. If name is 'keywords', 'topics',
2239 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002240
2241%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002242 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002243
2244%s -p <port>
2245 Start an HTTP server on the given port on the local machine.
2246
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002247%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002248 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002249
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002250%s -w <name> ...
2251 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002252 directory. If <name> contains a '%s', it is treated as a filename; if
2253 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002254""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002255
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002256if __name__ == '__main__': cli()