blob: e53aa1611c3a434e68221a6383985bf62166eade [file] [log] [blame]
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001#!/usr/bin/env python
Guido van Rossumfce538c2002-08-06 17:29:38 +00002# -*- coding: Latin-1 -*-
Ka-Ping Yee1d384632001-03-01 00:24:32 +00003"""Generate Python documentation in HTML or text for interactive use.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00004
Ka-Ping Yeedd175342001-02-27 14:43:46 +00005In the Python interpreter, do "from pydoc import help" to provide online
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00006help. Calling help(thing) on a Python object documents the object.
7
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00008Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00009
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000010Run "pydoc <name>" to show documentation on something. <name> may be
11the name of a function, module, package, or a dotted reference to a
12class or function within a module or module in a package. If the
13argument contains a path segment delimiter (e.g. slash on Unix,
14backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000015
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000016Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000018
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000019Run "pydoc -p <port>" to start an HTTP server on a given port on the
20local machine to generate documentation web pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000021
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000022For platforms without a command line, "pydoc -g" starts the HTTP server
23and also pops up a little window for controlling it.
24
25Run "pydoc -w <name>" to write out the HTML documentation for a module
26to a file named "<name>.html".
Skip Montanaro4997a692003-09-10 16:47:51 +000027
28Module docs for core modules are assumed to be in
29
30 http://www.python.org/doc/current/lib/
31
32This can be overridden by setting the PYTHONDOCS environment variable
33to a different URL or to a local directory containing the Library
34Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000035"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000036
37__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000038__date__ = "26 February 2001"
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000039__version__ = "$Revision$"
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000040__credits__ = """Guido van Rossum, for an excellent programming language.
41Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000042Paul Prescod, for all his work on onlinehelp.
43Richard Chamberlain, for the first implementation of textdoc.
44
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000045Mynd you, møøse bites Kan be pretty nasti..."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000046
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000047# Known bugs that can't be fixed here:
48# - imp.load_module() cannot be prevented from clobbering existing
49# loaded modules, so calling synopsis() on a binary module file
50# changes the contents of any existing module with the same name.
51# - If the __file__ attribute on a module is a relative path and
52# the current directory is changed with os.chdir(), an incorrect
53# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000054
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +000055import sys, imp, os, re, types, inspect, __builtin__
Ka-Ping Yeedd175342001-02-27 14:43:46 +000056from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000057from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
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):
95 """Check if an object is of a type that probably means it's data."""
96 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
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000115def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000116 """Remove the hexadecimal id from a Python object representation."""
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000117 # The behaviour of %p is implementation-dependent; we check two cases.
Ka-Ping Yee45daeb02002-08-11 15:11:33 +0000118 for pattern in [' at 0x[0-9a-f]{6,}(>+)$', ' at [0-9A-F]{8,}(>+)$']:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000119 if re.search(pattern, repr(Exception)):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +0000120 return re.sub(pattern, '\\1', text)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000121 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000122
Tim Peters536d2262001-09-20 05:13:38 +0000123def _is_some_method(object):
124 return inspect.ismethod(object) or inspect.ismethoddescriptor(object)
125
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
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000153def visiblename(name):
154 """Decide whether to show documentation on a variable."""
155 # Certain special names are redundant.
156 if name in ['__builtins__', '__doc__', '__file__', '__path__',
157 '__module__', '__name__']: return 0
158 # Private names are hidden, but special names are displayed.
159 if name.startswith('__') and name.endswith('__'): return 1
160 return not name.startswith('_')
161
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000162# ----------------------------------------------------- module manipulation
163
164def ispackage(path):
165 """Guess whether a path refers to a package directory."""
166 if os.path.isdir(path):
167 for ext in ['.py', '.pyc', '.pyo']:
168 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000169 return True
170 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000171
172def synopsis(filename, cache={}):
173 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000174 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000175 lastupdate, result = cache.get(filename, (0, None))
176 if lastupdate < mtime:
177 info = inspect.getmoduleinfo(filename)
178 file = open(filename)
179 if info and 'b' in info[2]: # binary modules have to be imported
180 try: module = imp.load_module('__temp__', file, filename, info[1:])
181 except: return None
182 result = split(module.__doc__ or '', '\n')[0]
183 del sys.modules['__temp__']
184 else: # text modules can be directly examined
185 line = file.readline()
186 while line[:1] == '#' or not strip(line):
187 line = file.readline()
188 if not line: break
189 line = strip(line)
190 if line[:4] == 'r"""': line = line[1:]
191 if line[:3] == '"""':
192 line = line[3:]
193 if line[-1:] == '\\': line = line[:-1]
194 while not strip(line):
195 line = file.readline()
196 if not line: break
197 result = strip(split(line, '"""')[0])
198 else: result = None
199 file.close()
200 cache[filename] = (mtime, result)
201 return result
202
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000203class ErrorDuringImport(Exception):
204 """Errors that occurred while trying to import something to document it."""
205 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000206 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000207 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000208 self.value = value
209 self.tb = tb
210
211 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000212 exc = self.exc
213 if type(exc) is types.ClassType:
214 exc = exc.__name__
215 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000216
217def importfile(path):
218 """Import a Python source file or compiled file given its path."""
219 magic = imp.get_magic()
220 file = open(path, 'r')
221 if file.read(len(magic)) == magic:
222 kind = imp.PY_COMPILED
223 else:
224 kind = imp.PY_SOURCE
225 file.close()
226 filename = os.path.basename(path)
227 name, ext = os.path.splitext(filename)
228 file = open(path, 'r')
229 try:
230 module = imp.load_module(name, file, path, (ext, 'r', kind))
231 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000232 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000233 file.close()
234 return module
235
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000236def safeimport(path, forceload=0, cache={}):
237 """Import a module; handle errors; return None if the module isn't found.
238
239 If the module *is* found but an exception occurs, it's wrapped in an
240 ErrorDuringImport exception and reraised. Unlike __import__, if a
241 package path is specified, the module at the end of the path is returned,
242 not the package at the beginning. If the optional 'forceload' argument
243 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000244 if forceload and path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000245 # This is the only way to be sure. Checking the mtime of the file
246 # isn't good enough (e.g. what if the module contains a class that
247 # inherits from another module that has changed?).
248 if path not in sys.builtin_module_names:
249 # Python never loads a dynamic extension a second time from the
250 # same path, even if the file is changed or missing. Deleting
251 # the entry in sys.modules doesn't help for dynamic extensions,
252 # so we're not even going to try to keep them up to date.
253 info = inspect.getmoduleinfo(sys.modules[path].__file__)
254 if info[3] != imp.C_EXTENSION:
255 cache[path] = sys.modules[path] # prevent module from clearing
256 del sys.modules[path]
257 try:
258 module = __import__(path)
259 except:
260 # Did the error occur before or after the module was found?
261 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000262 if path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000263 # An error occured while executing the imported module.
264 raise ErrorDuringImport(sys.modules[path].__file__, info)
265 elif exc is SyntaxError:
266 # A SyntaxError occurred before we could execute the module.
267 raise ErrorDuringImport(value.filename, info)
268 elif exc is ImportError and \
269 split(lower(str(value)))[:2] == ['no', 'module']:
270 # The module was not found.
271 return None
272 else:
273 # Some other error occurred during the importing process.
274 raise ErrorDuringImport(path, sys.exc_info())
275 for part in split(path, '.')[1:]:
276 try: module = getattr(module, part)
277 except AttributeError: return None
278 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000279
280# ---------------------------------------------------- formatter base class
281
282class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000283 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000284 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000285 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000286 # 'try' clause is to attempt to handle the possibility that inspect
287 # identifies something in a way that pydoc itself has issues handling;
288 # think 'super' and how it is a descriptor (which raises the exception
289 # by lacking a __name__ attribute) and an instance.
290 try:
291 if inspect.ismodule(object): return self.docmodule(*args)
292 if inspect.isclass(object): return self.docclass(*args)
293 if inspect.isroutine(object): return self.docroutine(*args)
294 except AttributeError:
295 pass
Guido van Rossum68468eb2003-02-27 20:14:51 +0000296 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000297
298 def fail(self, object, name=None, *args):
299 """Raise an exception for unimplemented types."""
300 message = "don't know how to document object%s of type %s" % (
301 name and ' ' + repr(name), type(object).__name__)
302 raise TypeError, message
303
304 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000305
Skip Montanaro4997a692003-09-10 16:47:51 +0000306 def getdocloc(self, object):
307 """Return the location of module docs or None"""
308
309 try:
310 file = inspect.getabsfile(object)
311 except TypeError:
312 file = '(built-in)'
313
314 docloc = os.environ.get("PYTHONDOCS",
315 "http://www.python.org/doc/current/lib")
316 basedir = os.path.join(sys.exec_prefix, "lib",
317 "python"+sys.version[0:3])
318 if (isinstance(object, type(os)) and
319 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
320 'marshal', 'posix', 'signal', 'sys',
321 'thread', 'zipimport') or
322 (file.startswith(basedir) and
323 not file.startswith(os.path.join(basedir, 'site-packages'))))):
324 if docloc.startswith("http://"):
325 docloc = (docloc.rstrip("/") +
326 "/module-%s.html" % object.__name__)
327 else:
328 docloc = os.path.join(docloc, "module-%s.html" % name)
329 else:
330 docloc = None
331 return docloc
332
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000333# -------------------------------------------- HTML documentation generator
334
335class HTMLRepr(Repr):
336 """Class for safely making an HTML representation of a Python object."""
337 def __init__(self):
338 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000339 self.maxlist = self.maxtuple = 20
340 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000341 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000342
343 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000344 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000345
346 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000347 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000348
349 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000350 if hasattr(type(x), '__name__'):
351 methodname = 'repr_' + join(split(type(x).__name__), '_')
352 if hasattr(self, methodname):
353 return getattr(self, methodname)(x, level)
354 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000355
356 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000357 test = cram(x, self.maxstring)
358 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000359 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000360 # Backslashes are only literal in the string and are never
361 # needed to make any special characters, so show a raw string.
362 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000363 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000364 r'<font color="#c040c0">\1</font>',
365 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000366
Skip Montanarodf708782002-03-07 22:58:02 +0000367 repr_str = repr_string
368
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000369 def repr_instance(self, x, level):
370 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000371 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000372 except:
373 return self.escape('<%s instance>' % x.__class__.__name__)
374
375 repr_unicode = repr_string
376
377class HTMLDoc(Doc):
378 """Formatter class for HTML documentation."""
379
380 # ------------------------------------------- HTML formatting utilities
381
382 _repr_instance = HTMLRepr()
383 repr = _repr_instance.repr
384 escape = _repr_instance.escape
385
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000386 def page(self, title, contents):
387 """Format an HTML page."""
388 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000389<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000390<html><head><title>Python: %s</title>
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000391</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000392%s
393</body></html>''' % (title, contents)
394
395 def heading(self, title, fgcol, bgcol, extras=''):
396 """Format a page heading."""
397 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000398<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000399<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000400<td valign=bottom>&nbsp;<br>
401<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000402><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000403><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000404 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
405
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000406 def section(self, title, fgcol, bgcol, contents, width=6,
407 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000408 """Format a section with a heading."""
409 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000410 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000411 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000412<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000413<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000414<td colspan=3 valign=bottom>&nbsp;<br>
415<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000416 ''' % (bgcol, fgcol, title)
417 if prelude:
418 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000419<tr bgcolor="%s"><td rowspan=2>%s</td>
420<td colspan=2>%s</td></tr>
421<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
422 else:
423 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000424<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000425
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000426 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000427
428 def bigsection(self, title, *args):
429 """Format a section with a big heading."""
430 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000431 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000432
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000433 def preformat(self, text):
434 """Format literal preformatted text."""
435 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000436 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
437 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000438
439 def multicolumn(self, list, format, cols=4):
440 """Format a list of items into a multi-column list."""
441 result = ''
442 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000443 for col in range(cols):
444 result = result + '<td width="%d%%" valign=top>' % (100/cols)
445 for i in range(rows*col, rows*col+rows):
446 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000447 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000448 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000449 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000450
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000451 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000452
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000453 def namelink(self, name, *dicts):
454 """Make a link for an identifier, given name-to-URL mappings."""
455 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000456 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000457 return '<a href="%s">%s</a>' % (dict[name], name)
458 return name
459
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000460 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000461 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000462 name, module = object.__name__, sys.modules.get(object.__module__)
463 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000464 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000465 module.__name__, name, classname(object, modname))
466 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000467
468 def modulelink(self, object):
469 """Make a link for a module."""
470 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
471
472 def modpkglink(self, (name, path, ispackage, shadowed)):
473 """Make a link for a module or package to display in an index."""
474 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000475 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000476 if path:
477 url = '%s.%s.html' % (path, name)
478 else:
479 url = '%s.html' % name
480 if ispackage:
481 text = '<strong>%s</strong>&nbsp;(package)' % name
482 else:
483 text = name
484 return '<a href="%s">%s</a>' % (url, text)
485
486 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
487 """Mark up some plain text, given a context of symbols to look for.
488 Each context dictionary maps object names to anchor names."""
489 escape = escape or self.escape
490 results = []
491 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000492 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
493 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000494 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000495 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000496 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000497 match = pattern.search(text, here)
498 if not match: break
499 start, end = match.span()
500 results.append(escape(text[here:start]))
501
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000502 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000503 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000504 url = escape(all).replace('"', '&quot;')
505 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000506 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000507 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
508 results.append('<a href="%s">%s</a>' % (url, escape(all)))
509 elif pep:
510 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000511 results.append('<a href="%s">%s</a>' % (url, escape(all)))
512 elif text[end:end+1] == '(':
513 results.append(self.namelink(name, methods, funcs, classes))
514 elif selfdot:
515 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000516 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000517 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000518 here = end
519 results.append(escape(text[here:]))
520 return join(results, '')
521
522 # ---------------------------------------------- type-specific routines
523
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000524 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000525 """Produce HTML for a class tree as given by inspect.getclasstree()."""
526 result = ''
527 for entry in tree:
528 if type(entry) is type(()):
529 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000530 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000531 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000532 if bases and bases != (parent,):
533 parents = []
534 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000535 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000536 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000537 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000538 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000539 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000540 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000541 return '<dl>\n%s</dl>\n' % result
542
Tim Peters8dd7ade2001-10-18 19:56:17 +0000543 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000544 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000545 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000546 parts = split(name, '.')
547 links = []
548 for i in range(len(parts)-1):
549 links.append(
550 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
551 (join(parts[:i+1], '.'), parts[i]))
552 linkedname = join(links + parts[-1:], '.')
553 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000554 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000555 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000556 url = path
557 if sys.platform == 'win32':
558 import nturl2path
559 url = nturl2path.pathname2url(path)
560 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000561 except TypeError:
562 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000563 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000564 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000565 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000566 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
567 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000568 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000569 if hasattr(object, '__date__'):
570 info.append(self.escape(str(object.__date__)))
571 if info:
572 head = head + ' (%s)' % join(info, ', ')
Skip Montanaro4997a692003-09-10 16:47:51 +0000573 docloc = self.getdocloc(object)
574 if docloc is not None:
575 docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
576 else:
577 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000578 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000579 head, '#ffffff', '#7799ee',
580 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000581
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000582 modules = inspect.getmembers(object, inspect.ismodule)
583
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000584 classes, cdict = [], {}
585 for key, value in inspect.getmembers(object, inspect.isclass):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000586 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000587 if visiblename(key):
588 classes.append((key, value))
589 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000590 for key, value in classes:
591 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000592 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000593 module = sys.modules.get(modname)
594 if modname != name and module and hasattr(module, key):
595 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000596 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000597 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000598 funcs, fdict = [], {}
599 for key, value in inspect.getmembers(object, inspect.isroutine):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000600 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000601 if visiblename(key):
602 funcs.append((key, value))
603 fdict[key] = '#-' + key
604 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000605 data = []
606 for key, value in inspect.getmembers(object, isdata):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000607 if visiblename(key):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000608 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000609
610 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
611 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000612 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000613
614 if hasattr(object, '__path__'):
615 modpkgs = []
616 modnames = []
617 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000618 path = os.path.join(object.__path__[0], file)
619 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000620 if modname != '__init__':
621 if modname and modname not in modnames:
622 modpkgs.append((modname, name, 0, 0))
623 modnames.append(modname)
624 elif ispackage(path):
625 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000626 modpkgs.sort()
627 contents = self.multicolumn(modpkgs, self.modpkglink)
628 result = result + self.bigsection(
629 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000630 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000631 contents = self.multicolumn(
632 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000633 result = result + self.bigsection(
634 'Modules', '#fffff', '#aa55cc', contents)
635
636 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000637 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000638 contents = [
639 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000640 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000641 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000642 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000643 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000644 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000645 contents = []
646 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000647 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000648 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000649 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000650 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000651 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000652 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000653 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000654 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000655 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000656 if hasattr(object, '__author__'):
657 contents = self.markup(str(object.__author__), self.preformat)
658 result = result + self.bigsection(
659 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000660 if hasattr(object, '__credits__'):
661 contents = self.markup(str(object.__credits__), self.preformat)
662 result = result + self.bigsection(
663 'Credits', '#ffffff', '#7799ee', contents)
664
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000665 return result
666
Tim Peters8dd7ade2001-10-18 19:56:17 +0000667 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
668 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000669 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000670 realname = object.__name__
671 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000672 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000673
Tim Petersb47879b2001-09-24 04:47:19 +0000674 contents = []
675 push = contents.append
676
Tim Petersfa26f7c2001-09-24 08:05:11 +0000677 # Cute little class to pump out a horizontal rule between sections.
678 class HorizontalRule:
679 def __init__(self):
680 self.needone = 0
681 def maybe(self):
682 if self.needone:
683 push('<hr>\n')
684 self.needone = 1
685 hr = HorizontalRule()
686
Tim Petersc86f6ca2001-09-26 21:31:51 +0000687 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +0000688 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000689 if len(mro) > 2:
690 hr.maybe()
691 push('<dl><dt>Method resolution order:</dt>\n')
692 for base in mro:
693 push('<dd>%s</dd>\n' % self.classlink(base,
694 object.__module__))
695 push('</dl>\n')
696
Tim Petersb47879b2001-09-24 04:47:19 +0000697 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000698 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000699 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000700 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000701 push(msg)
702 for name, kind, homecls, value in ok:
703 push(self.document(getattr(object, name), name, mod,
704 funcs, classes, mdict, object))
705 push('\n')
706 return attrs
707
Tim Petersfa26f7c2001-09-24 08:05:11 +0000708 def spillproperties(msg, attrs, predicate):
709 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000710 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000711 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000712 push(msg)
713 for name, kind, homecls, value in ok:
Tim Peters3e767d12001-09-25 00:01:06 +0000714 push('<dl><dt><strong>%s</strong></dt>\n' % name)
715 if value.__doc__ is not None:
716 doc = self.markup(value.__doc__, self.preformat,
717 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000718 push('<dd><tt>%s</tt></dd>\n' % doc)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000719 for attr, tag in [('fget', '<em>get</em>'),
720 ('fset', '<em>set</em>'),
721 ('fdel', '<em>delete</em>')]:
Tim Peters3e767d12001-09-25 00:01:06 +0000722 func = getattr(value, attr)
723 if func is not None:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000724 base = self.document(func, tag, mod,
Tim Peters3e767d12001-09-25 00:01:06 +0000725 funcs, classes, mdict, object)
726 push('<dd>%s</dd>\n' % base)
727 push('</dl>\n')
Tim Petersb47879b2001-09-24 04:47:19 +0000728 return attrs
729
Tim Petersfa26f7c2001-09-24 08:05:11 +0000730 def spilldata(msg, attrs, predicate):
731 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000732 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000733 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000734 push(msg)
735 for name, kind, homecls, value in ok:
736 base = self.docother(getattr(object, name), name, mod)
Martin v. Löwise59e2ba2003-05-03 09:09:02 +0000737 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000738 doc = getattr(value, "__doc__", None)
739 else:
740 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000741 if doc is None:
742 push('<dl><dt>%s</dl>\n' % base)
743 else:
744 doc = self.markup(getdoc(value), self.preformat,
745 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000746 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000747 push('<dl><dt>%s%s</dl>\n' % (base, doc))
748 push('\n')
749 return attrs
750
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000751 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
752 inspect.classify_class_attrs(object))
Tim Petersb47879b2001-09-24 04:47:19 +0000753 mdict = {}
754 for key, kind, homecls, value in attrs:
755 mdict[key] = anchor = '#' + name + '-' + key
756 value = getattr(object, key)
757 try:
758 # The value may not be hashable (e.g., a data attr with
759 # a dict or list value).
760 mdict[value] = anchor
761 except TypeError:
762 pass
763
Tim Petersfa26f7c2001-09-24 08:05:11 +0000764 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000765 if mro:
766 thisclass = mro.pop(0)
767 else:
768 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000769 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
770
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000771 if thisclass is __builtin__.object:
772 attrs = inherited
773 continue
774 elif thisclass is object:
775 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000776 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000777 tag = 'inherited from %s' % self.classlink(thisclass,
778 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000779 tag += ':<br>\n'
780
781 # Sort attrs by name.
Raymond Hettinger6b59f5f2003-10-16 05:53:16 +0000782 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000783
784 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000785 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000786 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000787 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000788 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000789 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000790 lambda t: t[1] == 'static method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000791 attrs = spillproperties('Properties %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000792 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000793 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000794 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000795 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000796 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000797
798 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000799
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000800 if name == realname:
801 title = '<a name="%s">class <strong>%s</strong></a>' % (
802 name, realname)
803 else:
804 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
805 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000806 if bases:
807 parents = []
808 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000809 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000810 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000811 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000812 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000813
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000814 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000815
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000816 def formatvalue(self, object):
817 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000818 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000819
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000820 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000821 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000822 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000823 realname = object.__name__
824 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000825 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000826 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000827 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000828 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000829 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000830 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000831 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000832 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000833 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000834 if object.im_self:
835 note = ' method of %s instance' % self.classlink(
836 object.im_self.__class__, mod)
837 else:
838 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000839 object = object.im_func
840
841 if name == realname:
842 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
843 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000844 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000845 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000846 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000847 cl.__name__ + '-' + realname, realname)
848 skipdocs = 1
849 else:
850 reallink = realname
851 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
852 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000853 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000854 args, varargs, varkw, defaults = inspect.getargspec(object)
855 argspec = inspect.formatargspec(
856 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000857 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000858 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000859 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000860 else:
861 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000862
Tim Peters2306d242001-09-25 03:18:32 +0000863 decl = title + argspec + (note and self.grey(
864 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000865
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000866 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000867 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000868 else:
869 doc = self.markup(
870 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000871 doc = doc and '<dd><tt>%s</tt></dd>' % doc
872 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000873
Tim Peters8dd7ade2001-10-18 19:56:17 +0000874 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000875 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000876 lhs = name and '<strong>%s</strong> = ' % name or ''
877 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000878
879 def index(self, dir, shadowed=None):
880 """Generate an HTML index for a directory of modules."""
881 modpkgs = []
882 if shadowed is None: shadowed = {}
883 seen = {}
884 files = os.listdir(dir)
885
886 def found(name, ispackage,
887 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
Raymond Hettinger4f759d82002-11-02 02:02:46 +0000888 if name not in seen:
889 modpkgs.append((name, '', ispackage, name in shadowed))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000890 seen[name] = 1
891 shadowed[name] = 1
892
893 # Package spam/__init__.py takes precedence over module spam.py.
894 for file in files:
895 path = os.path.join(dir, file)
896 if ispackage(path): found(file, 1)
897 for file in files:
898 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000899 if os.path.isfile(path):
900 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000901 if modname: found(modname, 0)
902
903 modpkgs.sort()
904 contents = self.multicolumn(modpkgs, self.modpkglink)
905 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
906
907# -------------------------------------------- text documentation generator
908
909class TextRepr(Repr):
910 """Class for safely making a text representation of a Python object."""
911 def __init__(self):
912 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000913 self.maxlist = self.maxtuple = 20
914 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000915 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000916
917 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000918 if hasattr(type(x), '__name__'):
919 methodname = 'repr_' + join(split(type(x).__name__), '_')
920 if hasattr(self, methodname):
921 return getattr(self, methodname)(x, level)
922 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000923
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000924 def repr_string(self, x, level):
925 test = cram(x, self.maxstring)
926 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000927 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000928 # Backslashes are only literal in the string and are never
929 # needed to make any special characters, so show a raw string.
930 return 'r' + testrepr[0] + test + testrepr[0]
931 return testrepr
932
Skip Montanarodf708782002-03-07 22:58:02 +0000933 repr_str = repr_string
934
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000935 def repr_instance(self, x, level):
936 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000937 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000938 except:
939 return '<%s instance>' % x.__class__.__name__
940
941class TextDoc(Doc):
942 """Formatter class for text documentation."""
943
944 # ------------------------------------------- text formatting utilities
945
946 _repr_instance = TextRepr()
947 repr = _repr_instance.repr
948
949 def bold(self, text):
950 """Format a string in bold by overstriking."""
951 return join(map(lambda ch: ch + '\b' + ch, text), '')
952
953 def indent(self, text, prefix=' '):
954 """Indent text by prepending a given prefix to each line."""
955 if not text: return ''
956 lines = split(text, '\n')
957 lines = map(lambda line, prefix=prefix: prefix + line, lines)
958 if lines: lines[-1] = rstrip(lines[-1])
959 return join(lines, '\n')
960
961 def section(self, title, contents):
962 """Format a section with a given heading."""
963 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
964
965 # ---------------------------------------------- type-specific routines
966
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000967 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000968 """Render in text a class tree as returned by inspect.getclasstree()."""
969 result = ''
970 for entry in tree:
971 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000972 c, bases = entry
973 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000974 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000975 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000976 result = result + '(%s)' % join(parents, ', ')
977 result = result + '\n'
978 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000979 result = result + self.formattree(
980 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000981 return result
982
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000983 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000984 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000985 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000986 synop, desc = splitdoc(getdoc(object))
987 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000988
989 try:
990 file = inspect.getabsfile(object)
991 except TypeError:
992 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000993 result = result + self.section('FILE', file)
Skip Montanaro4997a692003-09-10 16:47:51 +0000994
995 docloc = self.getdocloc(object)
996 if docloc is not None:
997 result = result + self.section('MODULE DOCS', docloc)
998
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000999 if desc:
1000 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001001
1002 classes = []
1003 for key, value in inspect.getmembers(object, inspect.isclass):
1004 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001005 if visiblename(key):
1006 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001007 funcs = []
1008 for key, value in inspect.getmembers(object, inspect.isroutine):
1009 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001010 if visiblename(key):
1011 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001012 data = []
1013 for key, value in inspect.getmembers(object, isdata):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001014 if visiblename(key):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001015 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001016
1017 if hasattr(object, '__path__'):
1018 modpkgs = []
1019 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001020 path = os.path.join(object.__path__[0], file)
1021 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001022 if modname != '__init__':
1023 if modname and modname not in modpkgs:
1024 modpkgs.append(modname)
1025 elif ispackage(path):
1026 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001027 modpkgs.sort()
1028 result = result + self.section(
1029 'PACKAGE CONTENTS', join(modpkgs, '\n'))
1030
1031 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001032 classlist = map(lambda (key, value): value, classes)
1033 contents = [self.formattree(
1034 inspect.getclasstree(classlist, 1), name)]
1035 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001036 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001037 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001038
1039 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001040 contents = []
1041 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001042 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001043 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001044
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001045 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001046 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001047 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001048 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001049 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001050
1051 if hasattr(object, '__version__'):
1052 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001053 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1054 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001055 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001056 if hasattr(object, '__date__'):
1057 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001058 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001059 result = result + self.section('AUTHOR', str(object.__author__))
1060 if hasattr(object, '__credits__'):
1061 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001062 return result
1063
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001064 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001065 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001066 realname = object.__name__
1067 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001068 bases = object.__bases__
1069
Tim Petersc86f6ca2001-09-26 21:31:51 +00001070 def makename(c, m=object.__module__):
1071 return classname(c, m)
1072
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001073 if name == realname:
1074 title = 'class ' + self.bold(realname)
1075 else:
1076 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001077 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001078 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001079 title = title + '(%s)' % join(parents, ', ')
1080
1081 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001082 contents = doc and [doc + '\n'] or []
1083 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001084
Tim Petersc86f6ca2001-09-26 21:31:51 +00001085 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +00001086 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001087 if len(mro) > 2:
1088 push("Method resolution order:")
1089 for base in mro:
1090 push(' ' + makename(base))
1091 push('')
1092
Tim Petersf4aad8e2001-09-24 22:40:47 +00001093 # Cute little class to pump out a horizontal rule between sections.
1094 class HorizontalRule:
1095 def __init__(self):
1096 self.needone = 0
1097 def maybe(self):
1098 if self.needone:
1099 push('-' * 70)
1100 self.needone = 1
1101 hr = HorizontalRule()
1102
Tim Peters28355492001-09-23 21:29:55 +00001103 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001104 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001105 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001106 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001107 push(msg)
1108 for name, kind, homecls, value in ok:
1109 push(self.document(getattr(object, name),
1110 name, mod, object))
1111 return attrs
1112
Tim Petersfa26f7c2001-09-24 08:05:11 +00001113 def spillproperties(msg, attrs, predicate):
1114 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001115 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001116 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001117 push(msg)
1118 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001119 push(name)
1120 need_blank_after_doc = 0
1121 doc = getdoc(value) or ''
1122 if doc:
1123 push(self.indent(doc))
1124 need_blank_after_doc = 1
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001125 for attr, tag in [('fget', '<get>'),
1126 ('fset', '<set>'),
1127 ('fdel', '<delete>')]:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001128 func = getattr(value, attr)
1129 if func is not None:
1130 if need_blank_after_doc:
1131 push('')
1132 need_blank_after_doc = 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001133 base = self.document(func, tag, mod)
Tim Petersf4aad8e2001-09-24 22:40:47 +00001134 push(self.indent(base))
Tim Peters28355492001-09-23 21:29:55 +00001135 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001136
Tim Petersfa26f7c2001-09-24 08:05:11 +00001137 def spilldata(msg, attrs, predicate):
1138 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:
Martin v. Löwise59e2ba2003-05-03 09:09:02 +00001143 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +00001144 doc = getattr(value, "__doc__", None)
1145 else:
1146 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001147 push(self.docother(getattr(object, name),
1148 name, mod, 70, doc) + '\n')
1149 return attrs
1150
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001151 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
1152 inspect.classify_class_attrs(object))
Tim Petersfa26f7c2001-09-24 08:05:11 +00001153 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001154 if mro:
1155 thisclass = mro.pop(0)
1156 else:
1157 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001158 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1159
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001160 if thisclass is __builtin__.object:
1161 attrs = inherited
1162 continue
1163 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001164 tag = "defined here"
1165 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001166 tag = "inherited from %s" % classname(thisclass,
1167 object.__module__)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001168 filter(lambda t: not t[0].startswith('_'), attrs)
Tim Peters28355492001-09-23 21:29:55 +00001169
1170 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001171 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001172
1173 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001174 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001175 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001176 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001177 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001178 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001179 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001180 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001181 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001182 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1183 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001184 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001185 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001186
1187 contents = '\n'.join(contents)
1188 if not contents:
1189 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001190 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1191
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001192 def formatvalue(self, object):
1193 """Format an argument default value as text."""
1194 return '=' + self.repr(object)
1195
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001196 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001197 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001198 realname = object.__name__
1199 name = name or realname
1200 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001201 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001202 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001203 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001204 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001205 if imclass is not cl:
1206 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001207 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001208 if object.im_self:
1209 note = ' method of %s instance' % classname(
1210 object.im_self.__class__, mod)
1211 else:
1212 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001213 object = object.im_func
1214
1215 if name == realname:
1216 title = self.bold(realname)
1217 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001218 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001219 cl.__dict__[realname] is object):
1220 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001221 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001222 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001223 args, varargs, varkw, defaults = inspect.getargspec(object)
1224 argspec = inspect.formatargspec(
1225 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001226 if realname == '<lambda>':
1227 title = 'lambda'
1228 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001229 else:
1230 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001231 decl = title + argspec + note
1232
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001233 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001234 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001235 else:
1236 doc = getdoc(object) or ''
1237 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001238
Tim Peters28355492001-09-23 21:29:55 +00001239 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001240 """Produce text documentation for a data object."""
1241 repr = self.repr(object)
1242 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001243 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001244 chop = maxlen - len(line)
1245 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001246 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001247 if doc is not None:
1248 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001249 return line
1250
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001251# --------------------------------------------------------- user interfaces
1252
1253def pager(text):
1254 """The first time this is called, determine what kind of pager to use."""
1255 global pager
1256 pager = getpager()
1257 pager(text)
1258
1259def getpager():
1260 """Decide what method to use for paging through text."""
1261 if type(sys.stdout) is not types.FileType:
1262 return plainpager
1263 if not sys.stdin.isatty() or not sys.stdout.isatty():
1264 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001265 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001266 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001267 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001268 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001269 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1270 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1271 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001272 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001273 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001274 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001275 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001276 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001277 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001278
1279 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001280 (fd, filename) = tempfile.mkstemp()
1281 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001282 try:
1283 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1284 return lambda text: pipepager(text, 'more')
1285 else:
1286 return ttypager
1287 finally:
1288 os.unlink(filename)
1289
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001290def plain(text):
1291 """Remove boldface formatting from text."""
1292 return re.sub('.\b', '', text)
1293
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001294def pipepager(text, cmd):
1295 """Page through text by feeding it to another program."""
1296 pipe = os.popen(cmd, 'w')
1297 try:
1298 pipe.write(text)
1299 pipe.close()
1300 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001301 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001302
1303def tempfilepager(text, cmd):
1304 """Page through text by invoking a program on a temporary file."""
1305 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001306 filename = tempfile.mktemp()
1307 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001308 file.write(text)
1309 file.close()
1310 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001311 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001312 finally:
1313 os.unlink(filename)
1314
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001315def ttypager(text):
1316 """Page through text on a text terminal."""
1317 lines = split(plain(text), '\n')
1318 try:
1319 import tty
1320 fd = sys.stdin.fileno()
1321 old = tty.tcgetattr(fd)
1322 tty.setcbreak(fd)
1323 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001324 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001325 tty = None
1326 getchar = lambda: sys.stdin.readline()[:-1][:1]
1327
1328 try:
1329 r = inc = os.environ.get('LINES', 25) - 1
1330 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1331 while lines[r:]:
1332 sys.stdout.write('-- more --')
1333 sys.stdout.flush()
1334 c = getchar()
1335
1336 if c in ['q', 'Q']:
1337 sys.stdout.write('\r \r')
1338 break
1339 elif c in ['\r', '\n']:
1340 sys.stdout.write('\r \r' + lines[r] + '\n')
1341 r = r + 1
1342 continue
1343 if c in ['b', 'B', '\x1b']:
1344 r = r - inc - inc
1345 if r < 0: r = 0
1346 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1347 r = r + inc
1348
1349 finally:
1350 if tty:
1351 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1352
1353def plainpager(text):
1354 """Simply print unformatted text. This is the ultimate fallback."""
1355 sys.stdout.write(plain(text))
1356
1357def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001358 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001359 if inspect.ismodule(thing):
1360 if thing.__name__ in sys.builtin_module_names:
1361 return 'built-in module ' + thing.__name__
1362 if hasattr(thing, '__path__'):
1363 return 'package ' + thing.__name__
1364 else:
1365 return 'module ' + thing.__name__
1366 if inspect.isbuiltin(thing):
1367 return 'built-in function ' + thing.__name__
1368 if inspect.isclass(thing):
1369 return 'class ' + thing.__name__
1370 if inspect.isfunction(thing):
1371 return 'function ' + thing.__name__
1372 if inspect.ismethod(thing):
1373 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001374 if type(thing) is types.InstanceType:
1375 return 'instance of ' + thing.__class__.__name__
1376 return type(thing).__name__
1377
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001378def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001379 """Locate an object by name or dotted path, importing as necessary."""
Guido van Rossum97dede02003-02-16 01:12:32 +00001380 parts = [part for part in split(path, '.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001381 module, n = None, 0
1382 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001383 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001384 if nextmodule: module, n = nextmodule, n + 1
1385 else: break
1386 if module:
1387 object = module
1388 for part in parts[n:]:
1389 try: object = getattr(object, part)
1390 except AttributeError: return None
1391 return object
1392 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001393 if hasattr(__builtin__, path):
1394 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001395
1396# --------------------------------------- interactive interpreter interface
1397
1398text = TextDoc()
1399html = HTMLDoc()
1400
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001401def resolve(thing, forceload=0):
1402 """Given an object or a path to an object, get the object and its name."""
1403 if isinstance(thing, str):
1404 object = locate(thing, forceload)
1405 if not object:
1406 raise ImportError, 'no Python documentation found for %r' % thing
1407 return object, thing
1408 else:
1409 return thing, getattr(thing, '__name__', None)
1410
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001411def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001412 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001413 try:
1414 object, name = resolve(thing, forceload)
1415 desc = describe(object)
1416 module = inspect.getmodule(object)
1417 if name and '.' in name:
1418 desc += ' in ' + name[:name.rfind('.')]
1419 elif module and module is not object:
1420 desc += ' in module ' + module.__name__
1421 pager(title % desc + '\n\n' + text.document(object, name))
1422 except (ImportError, ErrorDuringImport), value:
1423 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001424
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001425def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001426 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001427 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001428 object, name = resolve(thing, forceload)
1429 page = html.page(describe(object), html.document(object, name))
1430 file = open(name + '.html', 'w')
1431 file.write(page)
1432 file.close()
1433 print 'wrote', name + '.html'
1434 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001435 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001436
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001437def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001438 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001439 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001440 for file in os.listdir(dir):
1441 path = os.path.join(dir, file)
1442 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001443 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001444 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001445 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001446 if modname:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001447 if modname == '__init__':
1448 modname = pkgpath[:-1] # remove trailing period
1449 else:
1450 modname = pkgpath + modname
1451 if modname not in done:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001452 done[modname] = 1
1453 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001454
1455class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001456 keywords = {
1457 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001458 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001459 'break': ('ref/break', 'while for'),
1460 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1461 'continue': ('ref/continue', 'while for'),
1462 'def': ('ref/function', ''),
1463 'del': ('ref/del', 'BASICMETHODS'),
1464 'elif': 'if',
1465 'else': ('ref/if', 'while for'),
1466 'except': 'try',
1467 'exec': ('ref/exec', ''),
1468 'finally': 'try',
1469 'for': ('ref/for', 'break continue while'),
1470 'from': 'import',
1471 'global': ('ref/global', 'NAMESPACES'),
1472 'if': ('ref/if', 'TRUTHVALUE'),
1473 'import': ('ref/import', 'MODULES'),
1474 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1475 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001476 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001477 'not': 'BOOLEAN',
1478 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001479 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001480 'print': ('ref/print', ''),
1481 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001482 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001483 'try': ('ref/try', 'EXCEPTIONS'),
1484 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001485 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001486 }
1487
1488 topics = {
1489 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001490 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001491 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1492 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001493 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001494 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1495 'INTEGER': ('ref/integers', 'int range'),
1496 'FLOAT': ('ref/floating', 'float math'),
1497 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001498 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001499 'MAPPINGS': 'DICTIONARIES',
1500 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1501 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1502 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001503 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001504 'FRAMEOBJECTS': 'TYPES',
1505 'TRACEBACKS': 'TYPES',
1506 'NONE': ('lib/bltin-null-object', ''),
1507 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1508 'FILES': ('lib/bltin-file-objects', ''),
1509 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1510 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1511 'MODULES': ('lib/typesmodules', 'import'),
1512 'PACKAGES': 'import',
1513 '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'),
1514 'OPERATORS': 'EXPRESSIONS',
1515 'PRECEDENCE': 'EXPRESSIONS',
1516 'OBJECTS': ('ref/objects', 'TYPES'),
1517 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001518 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1519 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1520 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1521 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1522 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1523 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1524 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001525 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1526 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1527 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001528 'SCOPING': 'NAMESPACES',
1529 'FRAMES': 'NAMESPACES',
1530 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001531 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1532 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001533 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1534 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001535 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001536 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1537 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001538 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001539 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001540 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001541 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001542 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1543 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001544 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1545 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1546 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1547 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1548 'POWER': ('ref/power', 'EXPRESSIONS'),
1549 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1550 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1551 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1552 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1553 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001554 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001555 'ASSERTION': 'assert',
1556 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001557 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001558 'DELETION': 'del',
1559 'PRINTING': 'print',
1560 'RETURNING': 'return',
1561 'IMPORTING': 'import',
1562 'CONDITIONAL': 'if',
1563 'LOOPING': ('ref/compound', 'for while break continue'),
1564 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001565 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001566 }
1567
1568 def __init__(self, input, output):
1569 self.input = input
1570 self.output = output
1571 self.docdir = None
1572 execdir = os.path.dirname(sys.executable)
1573 homedir = os.environ.get('PYTHONHOME')
1574 for dir in [os.environ.get('PYTHONDOCS'),
1575 homedir and os.path.join(homedir, 'doc'),
1576 os.path.join(execdir, 'doc'),
1577 '/usr/doc/python-docs-' + split(sys.version)[0],
1578 '/usr/doc/python-' + split(sys.version)[0],
1579 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001580 '/usr/doc/python-' + sys.version[:3],
1581 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001582 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1583 self.docdir = dir
1584
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001585 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001586 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001587 self()
1588 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001589 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001590
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001591 def __call__(self, request=None):
1592 if request is not None:
1593 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001594 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001595 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001596 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001597 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001598You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001599If you want to ask for help on a particular object directly from the
1600interpreter, you can type "help(object)". Executing "help('string')"
1601has the same effect as typing a particular string at the help> prompt.
1602''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001603
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001604 def interact(self):
1605 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001606 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001607 self.output.write('help> ')
1608 self.output.flush()
1609 try:
1610 request = self.input.readline()
1611 if not request: break
1612 except KeyboardInterrupt: break
1613 request = strip(replace(request, '"', '', "'", ''))
1614 if lower(request) in ['q', 'quit']: break
1615 self.help(request)
1616
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001617 def help(self, request):
1618 if type(request) is type(''):
1619 if request == 'help': self.intro()
1620 elif request == 'keywords': self.listkeywords()
1621 elif request == 'topics': self.listtopics()
1622 elif request == 'modules': self.listmodules()
1623 elif request[:8] == 'modules ':
1624 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001625 elif request in self.keywords: self.showtopic(request)
1626 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001627 elif request: doc(request, 'Help on %s:')
1628 elif isinstance(request, Helper): self()
1629 else: doc(request, 'Help on %s:')
1630 self.output.write('\n')
1631
1632 def intro(self):
1633 self.output.write('''
1634Welcome to Python %s! This is the online help utility.
1635
1636If this is your first time using Python, you should definitely check out
1637the tutorial on the Internet at http://www.python.org/doc/tut/.
1638
1639Enter the name of any module, keyword, or topic to get help on writing
1640Python programs and using Python modules. To quit this help utility and
1641return to the interpreter, just type "quit".
1642
1643To get a list of available modules, keywords, or topics, type "modules",
1644"keywords", or "topics". Each module also comes with a one-line summary
1645of what it does; to list the modules whose summaries contain a given word
1646such as "spam", type "modules spam".
1647''' % sys.version[:3])
1648
1649 def list(self, items, columns=4, width=80):
1650 items = items[:]
1651 items.sort()
1652 colw = width / columns
1653 rows = (len(items) + columns - 1) / columns
1654 for row in range(rows):
1655 for col in range(columns):
1656 i = col * rows + row
1657 if i < len(items):
1658 self.output.write(items[i])
1659 if col < columns - 1:
1660 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1661 self.output.write('\n')
1662
1663 def listkeywords(self):
1664 self.output.write('''
1665Here is a list of the Python keywords. Enter any keyword to get more help.
1666
1667''')
1668 self.list(self.keywords.keys())
1669
1670 def listtopics(self):
1671 self.output.write('''
1672Here is a list of available topics. Enter any topic name to get more help.
1673
1674''')
1675 self.list(self.topics.keys())
1676
1677 def showtopic(self, topic):
1678 if not self.docdir:
1679 self.output.write('''
1680Sorry, topic and keyword documentation is not available because the Python
1681HTML documentation files could not be found. If you have installed them,
1682please set the environment variable PYTHONDOCS to indicate their location.
1683''')
1684 return
1685 target = self.topics.get(topic, self.keywords.get(topic))
1686 if not target:
1687 self.output.write('no documentation found for %s\n' % repr(topic))
1688 return
1689 if type(target) is type(''):
1690 return self.showtopic(target)
1691
1692 filename, xrefs = target
1693 filename = self.docdir + '/' + filename + '.html'
1694 try:
1695 file = open(filename)
1696 except:
1697 self.output.write('could not read docs from %s\n' % filename)
1698 return
1699
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001700 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1701 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001702 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1703 file.close()
1704
1705 import htmllib, formatter, StringIO
1706 buffer = StringIO.StringIO()
1707 parser = htmllib.HTMLParser(
1708 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1709 parser.start_table = parser.do_p
1710 parser.end_table = lambda parser=parser: parser.do_p({})
1711 parser.start_tr = parser.do_br
1712 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1713 parser.feed(document)
1714 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1715 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001716 if xrefs:
1717 buffer = StringIO.StringIO()
1718 formatter.DumbWriter(buffer).send_flowing_data(
1719 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1720 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001721
1722 def listmodules(self, key=''):
1723 if key:
1724 self.output.write('''
1725Here is a list of matching modules. Enter any module name to get more help.
1726
1727''')
1728 apropos(key)
1729 else:
1730 self.output.write('''
1731Please wait a moment while I gather a list of all available modules...
1732
1733''')
1734 modules = {}
1735 def callback(path, modname, desc, modules=modules):
1736 if modname and modname[-9:] == '.__init__':
1737 modname = modname[:-9] + ' (package)'
1738 if find(modname, '.') < 0:
1739 modules[modname] = 1
1740 ModuleScanner().run(callback)
1741 self.list(modules.keys())
1742 self.output.write('''
1743Enter any module name to get more help. Or, type "modules spam" to search
1744for modules whose descriptions contain the word "spam".
1745''')
1746
1747help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001748
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001749class Scanner:
1750 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001751 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001752 self.roots = roots[:]
1753 self.state = []
1754 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001755 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001756
1757 def next(self):
1758 if not self.state:
1759 if not self.roots:
1760 return None
1761 root = self.roots.pop(0)
1762 self.state = [(root, self.children(root))]
1763 node, children = self.state[-1]
1764 if not children:
1765 self.state.pop()
1766 return self.next()
1767 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001768 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001769 self.state.append((child, self.children(child)))
1770 return child
1771
1772class ModuleScanner(Scanner):
1773 """An interruptible scanner that searches module synopses."""
1774 def __init__(self):
1775 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001776 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001777 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001778
1779 def submodules(self, (dir, package)):
1780 children = []
1781 for file in os.listdir(dir):
1782 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001783 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001784 children.append((path, package + (package and '.') + file))
1785 else:
1786 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001787 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001788 return children
1789
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001790 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001791 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001792 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001793 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001794 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001795 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001796
Ka-Ping Yee66246962001-04-12 11:59:50 +00001797 def run(self, callback, key=None, completer=None):
1798 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001799 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001800 seen = {}
1801
1802 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001803 if modname != '__main__':
1804 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001805 if key is None:
1806 callback(None, modname, '')
1807 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001808 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001809 if find(lower(modname + ' - ' + desc), key) >= 0:
1810 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001811
1812 while not self.quit:
1813 node = self.next()
1814 if not node: break
1815 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001816 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001817 if os.path.isfile(path) and modname:
1818 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001819 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001820 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001821 if key is None:
1822 callback(path, modname, '')
1823 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001824 desc = synopsis(path) or ''
1825 if find(lower(modname + ' - ' + desc), key) >= 0:
1826 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001827 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001828
1829def apropos(key):
1830 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001831 def callback(path, modname, desc):
1832 if modname[-9:] == '.__init__':
1833 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001834 print modname, desc and '- ' + desc
1835 try: import warnings
1836 except ImportError: pass
1837 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001838 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001839
1840# --------------------------------------------------- web browser interface
1841
Ka-Ping Yee66246962001-04-12 11:59:50 +00001842def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001843 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001844
1845 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1846 class Message(mimetools.Message):
1847 def __init__(self, fp, seekable=1):
1848 Message = self.__class__
1849 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1850 self.encodingheader = self.getheader('content-transfer-encoding')
1851 self.typeheader = self.getheader('content-type')
1852 self.parsetype()
1853 self.parseplist()
1854
1855 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1856 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001857 try:
1858 self.send_response(200)
1859 self.send_header('Content-Type', 'text/html')
1860 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001861 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001862 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001863
1864 def do_GET(self):
1865 path = self.path
1866 if path[-5:] == '.html': path = path[:-5]
1867 if path[:1] == '/': path = path[1:]
1868 if path and path != '.':
1869 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001870 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001871 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001872 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001873 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001874 if obj:
1875 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001876 else:
1877 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001878'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001879 else:
1880 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001881'<big><big><strong>Python: Index of Modules</strong></big></big>',
1882'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001883 def bltinlink(name):
1884 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001885 names = filter(lambda x: x != '__main__',
1886 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001887 contents = html.multicolumn(names, bltinlink)
1888 indices = ['<p>' + html.bigsection(
1889 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1890
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001891 seen = {}
1892 for dir in pathdirs():
1893 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001894 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001895<font color="#909090" face="helvetica, arial"><strong>
1896pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001897 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001898
1899 def log_message(self, *args): pass
1900
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001901 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001902 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001903 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001904 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001905 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001906 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001907 self.base.__init__(self, self.address, self.handler)
1908
1909 def serve_until_quit(self):
1910 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001911 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001912 while not self.quit:
1913 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1914 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001915
1916 def server_activate(self):
1917 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001918 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001919
1920 DocServer.base = BaseHTTPServer.HTTPServer
1921 DocServer.handler = DocHandler
1922 DocHandler.MessageClass = Message
1923 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001924 try:
1925 DocServer(port, callback).serve_until_quit()
1926 except (KeyboardInterrupt, select.error):
1927 pass
1928 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001929 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001930
1931# ----------------------------------------------------- graphical interface
1932
1933def gui():
1934 """Graphical interface (starts web server and pops up a control window)."""
1935 class GUI:
1936 def __init__(self, window, port=7464):
1937 self.window = window
1938 self.server = None
1939 self.scanner = None
1940
1941 import Tkinter
1942 self.server_frm = Tkinter.Frame(window)
1943 self.title_lbl = Tkinter.Label(self.server_frm,
1944 text='Starting server...\n ')
1945 self.open_btn = Tkinter.Button(self.server_frm,
1946 text='open browser', command=self.open, state='disabled')
1947 self.quit_btn = Tkinter.Button(self.server_frm,
1948 text='quit serving', command=self.quit, state='disabled')
1949
1950 self.search_frm = Tkinter.Frame(window)
1951 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1952 self.search_ent = Tkinter.Entry(self.search_frm)
1953 self.search_ent.bind('<Return>', self.search)
1954 self.stop_btn = Tkinter.Button(self.search_frm,
1955 text='stop', pady=0, command=self.stop, state='disabled')
1956 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001957 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001958 self.stop_btn.pack(side='right')
1959
1960 self.window.title('pydoc')
1961 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1962 self.title_lbl.pack(side='top', fill='x')
1963 self.open_btn.pack(side='left', fill='x', expand=1)
1964 self.quit_btn.pack(side='right', fill='x', expand=1)
1965 self.server_frm.pack(side='top', fill='x')
1966
1967 self.search_lbl.pack(side='left')
1968 self.search_ent.pack(side='right', fill='x', expand=1)
1969 self.search_frm.pack(side='top', fill='x')
1970 self.search_ent.focus_set()
1971
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001972 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001973 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001974 self.result_lst.bind('<Button-1>', self.select)
1975 self.result_lst.bind('<Double-Button-1>', self.goto)
1976 self.result_scr = Tkinter.Scrollbar(window,
1977 orient='vertical', command=self.result_lst.yview)
1978 self.result_lst.config(yscrollcommand=self.result_scr.set)
1979
1980 self.result_frm = Tkinter.Frame(window)
1981 self.goto_btn = Tkinter.Button(self.result_frm,
1982 text='go to selected', command=self.goto)
1983 self.hide_btn = Tkinter.Button(self.result_frm,
1984 text='hide results', command=self.hide)
1985 self.goto_btn.pack(side='left', fill='x', expand=1)
1986 self.hide_btn.pack(side='right', fill='x', expand=1)
1987
1988 self.window.update()
1989 self.minwidth = self.window.winfo_width()
1990 self.minheight = self.window.winfo_height()
1991 self.bigminheight = (self.server_frm.winfo_reqheight() +
1992 self.search_frm.winfo_reqheight() +
1993 self.result_lst.winfo_reqheight() +
1994 self.result_frm.winfo_reqheight())
1995 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1996 self.expanded = 0
1997 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1998 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00001999 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002000
2001 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002002 threading.Thread(
2003 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002004
2005 def ready(self, server):
2006 self.server = server
2007 self.title_lbl.config(
2008 text='Python documentation server at\n' + server.url)
2009 self.open_btn.config(state='normal')
2010 self.quit_btn.config(state='normal')
2011
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002012 def open(self, event=None, url=None):
2013 url = url or self.server.url
2014 try:
2015 import webbrowser
2016 webbrowser.open(url)
2017 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002018 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002019 os.system('start "%s"' % url)
2020 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002021 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002022 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002023 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002024 else:
2025 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2026 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002027
2028 def quit(self, event=None):
2029 if self.server:
2030 self.server.quit = 1
2031 self.window.quit()
2032
2033 def search(self, event=None):
2034 key = self.search_ent.get()
2035 self.stop_btn.pack(side='right')
2036 self.stop_btn.config(state='normal')
2037 self.search_lbl.config(text='Searching for "%s"...' % key)
2038 self.search_ent.forget()
2039 self.search_lbl.pack(side='left')
2040 self.result_lst.delete(0, 'end')
2041 self.goto_btn.config(state='disabled')
2042 self.expand()
2043
2044 import threading
2045 if self.scanner:
2046 self.scanner.quit = 1
2047 self.scanner = ModuleScanner()
2048 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002049 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002050
2051 def update(self, path, modname, desc):
2052 if modname[-9:] == '.__init__':
2053 modname = modname[:-9] + ' (package)'
2054 self.result_lst.insert('end',
2055 modname + ' - ' + (desc or '(no description)'))
2056
2057 def stop(self, event=None):
2058 if self.scanner:
2059 self.scanner.quit = 1
2060 self.scanner = None
2061
2062 def done(self):
2063 self.scanner = None
2064 self.search_lbl.config(text='Search for')
2065 self.search_lbl.pack(side='left')
2066 self.search_ent.pack(side='right', fill='x', expand=1)
2067 if sys.platform != 'win32': self.stop_btn.forget()
2068 self.stop_btn.config(state='disabled')
2069
2070 def select(self, event=None):
2071 self.goto_btn.config(state='normal')
2072
2073 def goto(self, event=None):
2074 selection = self.result_lst.curselection()
2075 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002076 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002077 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002078
2079 def collapse(self):
2080 if not self.expanded: return
2081 self.result_frm.forget()
2082 self.result_scr.forget()
2083 self.result_lst.forget()
2084 self.bigwidth = self.window.winfo_width()
2085 self.bigheight = self.window.winfo_height()
2086 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2087 self.window.wm_minsize(self.minwidth, self.minheight)
2088 self.expanded = 0
2089
2090 def expand(self):
2091 if self.expanded: return
2092 self.result_frm.pack(side='bottom', fill='x')
2093 self.result_scr.pack(side='right', fill='y')
2094 self.result_lst.pack(side='top', fill='both', expand=1)
2095 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2096 self.window.wm_minsize(self.minwidth, self.bigminheight)
2097 self.expanded = 1
2098
2099 def hide(self, event=None):
2100 self.stop()
2101 self.collapse()
2102
2103 import Tkinter
2104 try:
2105 gui = GUI(Tkinter.Tk())
2106 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002107 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002108 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002109
2110# -------------------------------------------------- command-line interface
2111
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002112def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002113 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002114
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002115def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002116 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002117 import getopt
2118 class BadUsage: pass
2119
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002120 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002121 scriptdir = os.path.dirname(sys.argv[0])
2122 if scriptdir in sys.path:
2123 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002124 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002125
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002126 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002127 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002128 writing = 0
2129
2130 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002131 if opt == '-g':
2132 gui()
2133 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002134 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002135 apropos(val)
2136 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002137 if opt == '-p':
2138 try:
2139 port = int(val)
2140 except ValueError:
2141 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002142 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002143 print 'pydoc server ready at %s' % server.url
2144 def stopped():
2145 print 'pydoc server stopped'
2146 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002147 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002148 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002149 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002150
2151 if not args: raise BadUsage
2152 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002153 if ispath(arg) and not os.path.exists(arg):
2154 print 'file %r does not exist' % arg
2155 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002156 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002157 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002158 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002159 if writing:
2160 if ispath(arg) and os.path.isdir(arg):
2161 writedocs(arg)
2162 else:
2163 writedoc(arg)
2164 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002165 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002166 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002167 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002168
2169 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002170 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002171 print """pydoc - the Python documentation tool
2172
2173%s <name> ...
2174 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002175 Python keyword, topic, function, module, or package, or a dotted
2176 reference to a class or function within a module or module in a
2177 package. If <name> contains a '%s', it is used as the path to a
2178 Python source file to document. If name is 'keywords', 'topics',
2179 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002180
2181%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002182 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002183
2184%s -p <port>
2185 Start an HTTP server on the given port on the local machine.
2186
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002187%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002188 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002189
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002190%s -w <name> ...
2191 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002192 directory. If <name> contains a '%s', it is treated as a filename; if
2193 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002194""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002195
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002196if __name__ == '__main__': cli()