blob: de6fc63835ca4560e0b84275fc7e4d5a981dcfa2 [file] [log] [blame]
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001#!/usr/bin/env python
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002"""Generate Python documentation in HTML or text for interactive use.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00003
Ka-Ping Yeedd175342001-02-27 14:43:46 +00004In the Python interpreter, do "from pydoc import help" to provide online
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00005help. Calling help(thing) on a Python object documents the object.
6
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00007Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00008
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00009Run "pydoc <name>" to show documentation on something. <name> may be
10the name of a function, module, package, or a dotted reference to a
11class or function within a module or module in a package. If the
12argument contains a path segment delimiter (e.g. slash on Unix,
13backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000014
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000015Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
16of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000017
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000018Run "pydoc -p <port>" to start an HTTP server on a given port on the
19local machine to generate documentation web pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000020
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000021For platforms without a command line, "pydoc -g" starts the HTTP server
22and also pops up a little window for controlling it.
23
24Run "pydoc -w <name>" to write out the HTML documentation for a module
25to a file named "<name>.html".
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000026"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000027
28__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000029__date__ = "26 February 2001"
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000030__version__ = "$Revision$"
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000031__credits__ = """Guido van Rossum, for an excellent programming language.
32Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000033Paul Prescod, for all his work on onlinehelp.
34Richard Chamberlain, for the first implementation of textdoc.
35
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000036Mynd you, møøse bites Kan be pretty nasti..."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000037
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000038# Known bugs that can't be fixed here:
39# - imp.load_module() cannot be prevented from clobbering existing
40# loaded modules, so calling synopsis() on a binary module file
41# changes the contents of any existing module with the same name.
42# - If the __file__ attribute on a module is a relative path and
43# the current directory is changed with os.chdir(), an incorrect
44# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000045
Ka-Ping Yeedd175342001-02-27 14:43:46 +000046import sys, imp, os, stat, re, types, inspect
47from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000048from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
Ka-Ping Yeedd175342001-02-27 14:43:46 +000049
50# --------------------------------------------------------- common routines
51
Ka-Ping Yeedd175342001-02-27 14:43:46 +000052def pathdirs():
53 """Convert sys.path into a list of absolute, existing, unique paths."""
54 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000055 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000056 for dir in sys.path:
57 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000058 normdir = os.path.normcase(dir)
59 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000060 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000061 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000062 return dirs
63
64def getdoc(object):
65 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000066 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000067 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000068
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000069def splitdoc(doc):
70 """Split a doc string into a synopsis line (if any) and the rest."""
71 lines = split(strip(doc), '\n')
72 if len(lines) == 1:
73 return lines[0], ''
74 elif len(lines) >= 2 and not rstrip(lines[1]):
75 return lines[0], join(lines[2:], '\n')
76 return '', join(lines, '\n')
77
Ka-Ping Yeedd175342001-02-27 14:43:46 +000078def classname(object, modname):
79 """Get a class name and qualify it with a module name if necessary."""
80 name = object.__name__
81 if object.__module__ != modname:
82 name = object.__module__ + '.' + name
83 return name
84
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000085def isdata(object):
86 """Check if an object is of a type that probably means it's data."""
87 return not (inspect.ismodule(object) or inspect.isclass(object) or
88 inspect.isroutine(object) or inspect.isframe(object) or
89 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +000090
91def replace(text, *pairs):
92 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +000093 while pairs:
94 text = join(split(text, pairs[0]), pairs[1])
95 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +000096 return text
97
98def cram(text, maxlen):
99 """Omit part of a string if needed to make it fit in a maximum length."""
100 if len(text) > maxlen:
101 pre = max(0, (maxlen-3)/2)
102 post = max(0, maxlen-3-pre)
103 return text[:pre] + '...' + text[len(text)-post:]
104 return text
105
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000106def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000107 """Remove the hexadecimal id from a Python object representation."""
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000108 # The behaviour of %p is implementation-dependent; we check two cases.
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000109 for pattern in [' at 0x[0-9a-f]{6,}>$', ' at [0-9A-F]{8,}>$']:
110 if re.search(pattern, repr(Exception)):
111 return re.sub(pattern, '>', text)
112 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000113
Tim Peters536d2262001-09-20 05:13:38 +0000114def _is_some_method(object):
115 return inspect.ismethod(object) or inspect.ismethoddescriptor(object)
116
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000117def allmethods(cl):
118 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000119 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000120 methods[key] = 1
121 for base in cl.__bases__:
122 methods.update(allmethods(base)) # all your base are belong to us
123 for key in methods.keys():
124 methods[key] = getattr(cl, key)
125 return methods
126
Tim Petersfa26f7c2001-09-24 08:05:11 +0000127def _split_list(s, predicate):
128 """Split sequence s via predicate, and return pair ([true], [false]).
129
130 The return value is a 2-tuple of lists,
131 ([x for x in s if predicate(x)],
132 [x for x in s if not predicate(x)])
133 """
134
Tim Peters28355492001-09-23 21:29:55 +0000135 yes = []
136 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000137 for x in s:
138 if predicate(x):
139 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000140 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000141 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000142 return yes, no
143
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000144# ----------------------------------------------------- module manipulation
145
146def ispackage(path):
147 """Guess whether a path refers to a package directory."""
148 if os.path.isdir(path):
149 for ext in ['.py', '.pyc', '.pyo']:
150 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000151 return True
152 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000153
154def synopsis(filename, cache={}):
155 """Get the one-line summary out of a module file."""
156 mtime = os.stat(filename)[stat.ST_MTIME]
157 lastupdate, result = cache.get(filename, (0, None))
158 if lastupdate < mtime:
159 info = inspect.getmoduleinfo(filename)
160 file = open(filename)
161 if info and 'b' in info[2]: # binary modules have to be imported
162 try: module = imp.load_module('__temp__', file, filename, info[1:])
163 except: return None
164 result = split(module.__doc__ or '', '\n')[0]
165 del sys.modules['__temp__']
166 else: # text modules can be directly examined
167 line = file.readline()
168 while line[:1] == '#' or not strip(line):
169 line = file.readline()
170 if not line: break
171 line = strip(line)
172 if line[:4] == 'r"""': line = line[1:]
173 if line[:3] == '"""':
174 line = line[3:]
175 if line[-1:] == '\\': line = line[:-1]
176 while not strip(line):
177 line = file.readline()
178 if not line: break
179 result = strip(split(line, '"""')[0])
180 else: result = None
181 file.close()
182 cache[filename] = (mtime, result)
183 return result
184
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000185class ErrorDuringImport(Exception):
186 """Errors that occurred while trying to import something to document it."""
187 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000188 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000189 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000190 self.value = value
191 self.tb = tb
192
193 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000194 exc = self.exc
195 if type(exc) is types.ClassType:
196 exc = exc.__name__
197 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000198
199def importfile(path):
200 """Import a Python source file or compiled file given its path."""
201 magic = imp.get_magic()
202 file = open(path, 'r')
203 if file.read(len(magic)) == magic:
204 kind = imp.PY_COMPILED
205 else:
206 kind = imp.PY_SOURCE
207 file.close()
208 filename = os.path.basename(path)
209 name, ext = os.path.splitext(filename)
210 file = open(path, 'r')
211 try:
212 module = imp.load_module(name, file, path, (ext, 'r', kind))
213 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000214 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000215 file.close()
216 return module
217
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000218def safeimport(path, forceload=0, cache={}):
219 """Import a module; handle errors; return None if the module isn't found.
220
221 If the module *is* found but an exception occurs, it's wrapped in an
222 ErrorDuringImport exception and reraised. Unlike __import__, if a
223 package path is specified, the module at the end of the path is returned,
224 not the package at the beginning. If the optional 'forceload' argument
225 is 1, we reload the module from disk (unless it's a dynamic extension)."""
226 if forceload and sys.modules.has_key(path):
227 # This is the only way to be sure. Checking the mtime of the file
228 # isn't good enough (e.g. what if the module contains a class that
229 # inherits from another module that has changed?).
230 if path not in sys.builtin_module_names:
231 # Python never loads a dynamic extension a second time from the
232 # same path, even if the file is changed or missing. Deleting
233 # the entry in sys.modules doesn't help for dynamic extensions,
234 # so we're not even going to try to keep them up to date.
235 info = inspect.getmoduleinfo(sys.modules[path].__file__)
236 if info[3] != imp.C_EXTENSION:
237 cache[path] = sys.modules[path] # prevent module from clearing
238 del sys.modules[path]
239 try:
240 module = __import__(path)
241 except:
242 # Did the error occur before or after the module was found?
243 (exc, value, tb) = info = sys.exc_info()
244 if sys.modules.has_key(path):
245 # An error occured while executing the imported module.
246 raise ErrorDuringImport(sys.modules[path].__file__, info)
247 elif exc is SyntaxError:
248 # A SyntaxError occurred before we could execute the module.
249 raise ErrorDuringImport(value.filename, info)
250 elif exc is ImportError and \
251 split(lower(str(value)))[:2] == ['no', 'module']:
252 # The module was not found.
253 return None
254 else:
255 # Some other error occurred during the importing process.
256 raise ErrorDuringImport(path, sys.exc_info())
257 for part in split(path, '.')[1:]:
258 try: module = getattr(module, part)
259 except AttributeError: return None
260 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000261
262# ---------------------------------------------------- formatter base class
263
264class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000265 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000266 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000267 args = (object, name) + args
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000268 if inspect.ismodule(object): return apply(self.docmodule, args)
269 if inspect.isclass(object): return apply(self.docclass, args)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000270 if inspect.isroutine(object): return apply(self.docroutine, args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000271 return apply(self.docother, args)
272
273 def fail(self, object, name=None, *args):
274 """Raise an exception for unimplemented types."""
275 message = "don't know how to document object%s of type %s" % (
276 name and ' ' + repr(name), type(object).__name__)
277 raise TypeError, message
278
279 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000280
281# -------------------------------------------- HTML documentation generator
282
283class HTMLRepr(Repr):
284 """Class for safely making an HTML representation of a Python object."""
285 def __init__(self):
286 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000287 self.maxlist = self.maxtuple = 20
288 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000289 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000290
291 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000292 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000293
294 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000295 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000296
297 def repr1(self, x, level):
298 methodname = 'repr_' + join(split(type(x).__name__), '_')
299 if hasattr(self, methodname):
300 return getattr(self, methodname)(x, level)
301 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000302 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000303
304 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000305 test = cram(x, self.maxstring)
306 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000307 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000308 # Backslashes are only literal in the string and are never
309 # needed to make any special characters, so show a raw string.
310 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000311 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000312 r'<font color="#c040c0">\1</font>',
313 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000314
Skip Montanarodf708782002-03-07 22:58:02 +0000315 repr_str = repr_string
316
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000317 def repr_instance(self, x, level):
318 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000319 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000320 except:
321 return self.escape('<%s instance>' % x.__class__.__name__)
322
323 repr_unicode = repr_string
324
325class HTMLDoc(Doc):
326 """Formatter class for HTML documentation."""
327
328 # ------------------------------------------- HTML formatting utilities
329
330 _repr_instance = HTMLRepr()
331 repr = _repr_instance.repr
332 escape = _repr_instance.escape
333
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000334 def page(self, title, contents):
335 """Format an HTML page."""
336 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000337<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000338<html><head><title>Python: %s</title>
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000339<style type="text/css"><!--
Ka-Ping Yeed03f8fe2001-04-13 15:04:32 +0000340TT { font-family: lucidatypewriter, lucida console, courier }
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000341--></style></head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000342%s
343</body></html>''' % (title, contents)
344
345 def heading(self, title, fgcol, bgcol, extras=''):
346 """Format a page heading."""
347 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000348<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000349<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000350<td valign=bottom>&nbsp;<br>
351<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000352><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000353><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000354 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
355
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000356 def section(self, title, fgcol, bgcol, contents, width=10,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000357 prelude='', marginalia=None, gap='&nbsp;&nbsp;'):
358 """Format a section with a heading."""
359 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000360 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000361 result = '''
Tim Peters59ed4482001-10-31 04:20:26 +0000362<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000363<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000364<td colspan=3 valign=bottom>&nbsp;<br>
365<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000366 ''' % (bgcol, fgcol, title)
367 if prelude:
368 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000369<tr bgcolor="%s"><td rowspan=2>%s</td>
370<td colspan=2>%s</td></tr>
371<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
372 else:
373 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000374<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000375
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000376 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000377
378 def bigsection(self, title, *args):
379 """Format a section with a big heading."""
380 title = '<big><strong>%s</strong></big>' % title
381 return apply(self.section, (title,) + args)
382
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000383 def preformat(self, text):
384 """Format literal preformatted text."""
385 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000386 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
387 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000388
389 def multicolumn(self, list, format, cols=4):
390 """Format a list of items into a multi-column list."""
391 result = ''
392 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000393 for col in range(cols):
394 result = result + '<td width="%d%%" valign=top>' % (100/cols)
395 for i in range(rows*col, rows*col+rows):
396 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000397 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000398 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000399 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000400
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000401 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000402
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000403 def namelink(self, name, *dicts):
404 """Make a link for an identifier, given name-to-URL mappings."""
405 for dict in dicts:
406 if dict.has_key(name):
407 return '<a href="%s">%s</a>' % (dict[name], name)
408 return name
409
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000410 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000411 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000412 name, module = object.__name__, sys.modules.get(object.__module__)
413 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000414 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000415 module.__name__, name, classname(object, modname))
416 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000417
418 def modulelink(self, object):
419 """Make a link for a module."""
420 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
421
422 def modpkglink(self, (name, path, ispackage, shadowed)):
423 """Make a link for a module or package to display in an index."""
424 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000425 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000426 if path:
427 url = '%s.%s.html' % (path, name)
428 else:
429 url = '%s.html' % name
430 if ispackage:
431 text = '<strong>%s</strong>&nbsp;(package)' % name
432 else:
433 text = name
434 return '<a href="%s">%s</a>' % (url, text)
435
436 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
437 """Mark up some plain text, given a context of symbols to look for.
438 Each context dictionary maps object names to anchor names."""
439 escape = escape or self.escape
440 results = []
441 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000442 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
443 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000444 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000445 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000446 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000447 match = pattern.search(text, here)
448 if not match: break
449 start, end = match.span()
450 results.append(escape(text[here:start]))
451
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000452 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000453 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000454 url = escape(all).replace('"', '&quot;')
455 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000456 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000457 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
458 results.append('<a href="%s">%s</a>' % (url, escape(all)))
459 elif pep:
460 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000461 results.append('<a href="%s">%s</a>' % (url, escape(all)))
462 elif text[end:end+1] == '(':
463 results.append(self.namelink(name, methods, funcs, classes))
464 elif selfdot:
465 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000466 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000467 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000468 here = end
469 results.append(escape(text[here:]))
470 return join(results, '')
471
472 # ---------------------------------------------- type-specific routines
473
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000474 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000475 """Produce HTML for a class tree as given by inspect.getclasstree()."""
476 result = ''
477 for entry in tree:
478 if type(entry) is type(()):
479 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000480 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000481 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000482 if bases and bases != (parent,):
483 parents = []
484 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000485 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000486 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000487 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000488 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000489 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000490 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000491 return '<dl>\n%s</dl>\n' % result
492
Tim Peters8dd7ade2001-10-18 19:56:17 +0000493 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000494 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000495 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000496 parts = split(name, '.')
497 links = []
498 for i in range(len(parts)-1):
499 links.append(
500 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
501 (join(parts[:i+1], '.'), parts[i]))
502 linkedname = join(links + parts[-1:], '.')
503 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000504 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000505 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000506 url = path
507 if sys.platform == 'win32':
508 import nturl2path
509 url = nturl2path.pathname2url(path)
510 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000511 except TypeError:
512 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000513 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000514 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000515 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000516 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
517 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000518 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000519 if hasattr(object, '__date__'):
520 info.append(self.escape(str(object.__date__)))
521 if info:
522 head = head + ' (%s)' % join(info, ', ')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000523 result = self.heading(
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000524 head, '#ffffff', '#7799ee', '<a href=".">index</a><br>' + filelink)
525
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000526 modules = inspect.getmembers(object, inspect.ismodule)
527
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000528 classes, cdict = [], {}
529 for key, value in inspect.getmembers(object, inspect.isclass):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000530 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000531 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000532 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000533 for key, value in classes:
534 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000535 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000536 module = sys.modules.get(modname)
537 if modname != name and module and hasattr(module, key):
538 if getattr(module, key) is base:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000539 if not cdict.has_key(key):
540 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000541 funcs, fdict = [], {}
542 for key, value in inspect.getmembers(object, inspect.isroutine):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000543 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000544 funcs.append((key, value))
545 fdict[key] = '#-' + key
546 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000547 data = []
548 for key, value in inspect.getmembers(object, isdata):
549 if key not in ['__builtins__', '__doc__']:
550 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000551
552 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
553 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000554 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000555
556 if hasattr(object, '__path__'):
557 modpkgs = []
558 modnames = []
559 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000560 path = os.path.join(object.__path__[0], file)
561 modname = inspect.getmodulename(file)
562 if modname and modname not in modnames:
563 modpkgs.append((modname, name, 0, 0))
564 modnames.append(modname)
565 elif ispackage(path):
566 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000567 modpkgs.sort()
568 contents = self.multicolumn(modpkgs, self.modpkglink)
569 result = result + self.bigsection(
570 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000571 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000572 contents = self.multicolumn(
573 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000574 result = result + self.bigsection(
575 'Modules', '#fffff', '#aa55cc', contents)
576
577 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000578 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000579 contents = [
580 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000581 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000582 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000583 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000584 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000585 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000586 contents = []
587 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000588 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000589 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000590 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000591 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000592 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000593 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000594 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000595 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000596 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000597 if hasattr(object, '__author__'):
598 contents = self.markup(str(object.__author__), self.preformat)
599 result = result + self.bigsection(
600 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000601 if hasattr(object, '__credits__'):
602 contents = self.markup(str(object.__credits__), self.preformat)
603 result = result + self.bigsection(
604 'Credits', '#ffffff', '#7799ee', contents)
605
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000606 return result
607
Tim Peters8dd7ade2001-10-18 19:56:17 +0000608 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
609 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000610 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000611 realname = object.__name__
612 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000613 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000614
Tim Petersb47879b2001-09-24 04:47:19 +0000615 contents = []
616 push = contents.append
617
Tim Petersfa26f7c2001-09-24 08:05:11 +0000618 # Cute little class to pump out a horizontal rule between sections.
619 class HorizontalRule:
620 def __init__(self):
621 self.needone = 0
622 def maybe(self):
623 if self.needone:
624 push('<hr>\n')
625 self.needone = 1
626 hr = HorizontalRule()
627
Tim Petersc86f6ca2001-09-26 21:31:51 +0000628 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +0000629 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000630 if len(mro) > 2:
631 hr.maybe()
632 push('<dl><dt>Method resolution order:</dt>\n')
633 for base in mro:
634 push('<dd>%s</dd>\n' % self.classlink(base,
635 object.__module__))
636 push('</dl>\n')
637
Tim Petersb47879b2001-09-24 04:47:19 +0000638 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000639 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000640 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000641 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000642 push(msg)
643 for name, kind, homecls, value in ok:
644 push(self.document(getattr(object, name), name, mod,
645 funcs, classes, mdict, object))
646 push('\n')
647 return attrs
648
Tim Petersfa26f7c2001-09-24 08:05:11 +0000649 def spillproperties(msg, attrs, predicate):
650 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000651 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000652 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000653 push(msg)
654 for name, kind, homecls, value in ok:
Tim Peters3e767d12001-09-25 00:01:06 +0000655 push('<dl><dt><strong>%s</strong></dt>\n' % name)
656 if value.__doc__ is not None:
657 doc = self.markup(value.__doc__, self.preformat,
658 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000659 push('<dd><tt>%s</tt></dd>\n' % doc)
Tim Petersf33532c2001-09-25 06:30:51 +0000660 for attr, tag in [("fget", " getter"),
661 ("fset", " setter"),
Tim Peters3e767d12001-09-25 00:01:06 +0000662 ("fdel", " deleter")]:
663 func = getattr(value, attr)
664 if func is not None:
665 base = self.document(func, name + tag, mod,
666 funcs, classes, mdict, object)
667 push('<dd>%s</dd>\n' % base)
668 push('</dl>\n')
Tim Petersb47879b2001-09-24 04:47:19 +0000669 return attrs
670
Tim Petersfa26f7c2001-09-24 08:05:11 +0000671 def spilldata(msg, attrs, predicate):
672 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000673 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000674 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000675 push(msg)
676 for name, kind, homecls, value in ok:
677 base = self.docother(getattr(object, name), name, mod)
678 doc = getattr(value, "__doc__", None)
679 if doc is None:
680 push('<dl><dt>%s</dl>\n' % base)
681 else:
682 doc = self.markup(getdoc(value), self.preformat,
683 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000684 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000685 push('<dl><dt>%s%s</dl>\n' % (base, doc))
686 push('\n')
687 return attrs
688
689 attrs = inspect.classify_class_attrs(object)
690 mdict = {}
691 for key, kind, homecls, value in attrs:
692 mdict[key] = anchor = '#' + name + '-' + key
693 value = getattr(object, key)
694 try:
695 # The value may not be hashable (e.g., a data attr with
696 # a dict or list value).
697 mdict[value] = anchor
698 except TypeError:
699 pass
700
Tim Petersfa26f7c2001-09-24 08:05:11 +0000701 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000702 if mro:
703 thisclass = mro.pop(0)
704 else:
705 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000706 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
707
Tim Petersb47879b2001-09-24 04:47:19 +0000708 if thisclass is object:
709 tag = "defined here"
710 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000711 tag = "inherited from %s" % self.classlink(thisclass,
Tim Petersb47879b2001-09-24 04:47:19 +0000712 object.__module__)
713 tag += ':<br>\n'
714
715 # Sort attrs by name.
716 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
717
718 # Pump out the attrs, segregated by kind.
719 attrs = spill("Methods %s" % tag, attrs,
720 lambda t: t[1] == 'method')
721 attrs = spill("Class methods %s" % tag, attrs,
722 lambda t: t[1] == 'class method')
723 attrs = spill("Static methods %s" % tag, attrs,
724 lambda t: t[1] == 'static method')
Tim Petersfa26f7c2001-09-24 08:05:11 +0000725 attrs = spillproperties("Properties %s" % tag, attrs,
726 lambda t: t[1] == 'property')
Tim Petersf33532c2001-09-25 06:30:51 +0000727 attrs = spilldata("Data and non-method functions %s" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000728 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000729 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000730 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000731
732 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000733
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000734 if name == realname:
735 title = '<a name="%s">class <strong>%s</strong></a>' % (
736 name, realname)
737 else:
738 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
739 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000740 if bases:
741 parents = []
742 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000743 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000744 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000745 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
746 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc or '&nbsp;'
Tim Petersc86f6ca2001-09-26 21:31:51 +0000747
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000748 return self.section(title, '#000000', '#ffc8d8', contents, 5, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000749
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000750 def formatvalue(self, object):
751 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000752 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000753
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000754 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000755 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000756 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000757 realname = object.__name__
758 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000759 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000760 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000761 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000762 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000763 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000764 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000765 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000766 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000767 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000768 if object.im_self:
769 note = ' method of %s instance' % self.classlink(
770 object.im_self.__class__, mod)
771 else:
772 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000773 object = object.im_func
774
775 if name == realname:
776 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
777 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000778 if (cl and cl.__dict__.has_key(realname) and
779 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000780 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000781 cl.__name__ + '-' + realname, realname)
782 skipdocs = 1
783 else:
784 reallink = realname
785 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
786 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000787 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000788 args, varargs, varkw, defaults = inspect.getargspec(object)
789 argspec = inspect.formatargspec(
790 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000791 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000792 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000793 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000794 else:
795 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000796
Tim Peters2306d242001-09-25 03:18:32 +0000797 decl = title + argspec + (note and self.grey(
798 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000799
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000800 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000801 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000802 else:
803 doc = self.markup(
804 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000805 doc = doc and '<dd><tt>%s</tt></dd>' % doc
806 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000807
Tim Peters8dd7ade2001-10-18 19:56:17 +0000808 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000809 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000810 lhs = name and '<strong>%s</strong> = ' % name or ''
811 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000812
813 def index(self, dir, shadowed=None):
814 """Generate an HTML index for a directory of modules."""
815 modpkgs = []
816 if shadowed is None: shadowed = {}
817 seen = {}
818 files = os.listdir(dir)
819
820 def found(name, ispackage,
821 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
822 if not seen.has_key(name):
823 modpkgs.append((name, '', ispackage, shadowed.has_key(name)))
824 seen[name] = 1
825 shadowed[name] = 1
826
827 # Package spam/__init__.py takes precedence over module spam.py.
828 for file in files:
829 path = os.path.join(dir, file)
830 if ispackage(path): found(file, 1)
831 for file in files:
832 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000833 if os.path.isfile(path):
834 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000835 if modname: found(modname, 0)
836
837 modpkgs.sort()
838 contents = self.multicolumn(modpkgs, self.modpkglink)
839 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
840
841# -------------------------------------------- text documentation generator
842
843class TextRepr(Repr):
844 """Class for safely making a text representation of a Python object."""
845 def __init__(self):
846 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000847 self.maxlist = self.maxtuple = 20
848 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000849 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000850
851 def repr1(self, x, level):
852 methodname = 'repr_' + join(split(type(x).__name__), '_')
853 if hasattr(self, methodname):
854 return getattr(self, methodname)(x, level)
855 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000856 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000857
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000858 def repr_string(self, x, level):
859 test = cram(x, self.maxstring)
860 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000861 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000862 # Backslashes are only literal in the string and are never
863 # needed to make any special characters, so show a raw string.
864 return 'r' + testrepr[0] + test + testrepr[0]
865 return testrepr
866
Skip Montanarodf708782002-03-07 22:58:02 +0000867 repr_str = repr_string
868
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000869 def repr_instance(self, x, level):
870 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000871 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000872 except:
873 return '<%s instance>' % x.__class__.__name__
874
875class TextDoc(Doc):
876 """Formatter class for text documentation."""
877
878 # ------------------------------------------- text formatting utilities
879
880 _repr_instance = TextRepr()
881 repr = _repr_instance.repr
882
883 def bold(self, text):
884 """Format a string in bold by overstriking."""
885 return join(map(lambda ch: ch + '\b' + ch, text), '')
886
887 def indent(self, text, prefix=' '):
888 """Indent text by prepending a given prefix to each line."""
889 if not text: return ''
890 lines = split(text, '\n')
891 lines = map(lambda line, prefix=prefix: prefix + line, lines)
892 if lines: lines[-1] = rstrip(lines[-1])
893 return join(lines, '\n')
894
895 def section(self, title, contents):
896 """Format a section with a given heading."""
897 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
898
899 # ---------------------------------------------- type-specific routines
900
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000901 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000902 """Render in text a class tree as returned by inspect.getclasstree()."""
903 result = ''
904 for entry in tree:
905 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000906 c, bases = entry
907 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000908 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000909 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000910 result = result + '(%s)' % join(parents, ', ')
911 result = result + '\n'
912 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000913 result = result + self.formattree(
914 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000915 return result
916
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000917 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000918 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000919 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000920 synop, desc = splitdoc(getdoc(object))
921 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000922
923 try:
924 file = inspect.getabsfile(object)
925 except TypeError:
926 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000927 result = result + self.section('FILE', file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000928 if desc:
929 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000930
931 classes = []
932 for key, value in inspect.getmembers(object, inspect.isclass):
933 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000934 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000935 funcs = []
936 for key, value in inspect.getmembers(object, inspect.isroutine):
937 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000938 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000939 data = []
940 for key, value in inspect.getmembers(object, isdata):
941 if key not in ['__builtins__', '__doc__']:
942 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000943
944 if hasattr(object, '__path__'):
945 modpkgs = []
946 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000947 path = os.path.join(object.__path__[0], file)
948 modname = inspect.getmodulename(file)
949 if modname and modname not in modpkgs:
950 modpkgs.append(modname)
951 elif ispackage(path):
952 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000953 modpkgs.sort()
954 result = result + self.section(
955 'PACKAGE CONTENTS', join(modpkgs, '\n'))
956
957 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000958 classlist = map(lambda (key, value): value, classes)
959 contents = [self.formattree(
960 inspect.getclasstree(classlist, 1), name)]
961 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000962 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000963 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000964
965 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000966 contents = []
967 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000968 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000969 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000970
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000971 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000972 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000973 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000974 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000975 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000976
977 if hasattr(object, '__version__'):
978 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000979 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
980 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000981 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000982 if hasattr(object, '__date__'):
983 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000984 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000985 result = result + self.section('AUTHOR', str(object.__author__))
986 if hasattr(object, '__credits__'):
987 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000988 return result
989
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000990 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000991 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000992 realname = object.__name__
993 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000994 bases = object.__bases__
995
Tim Petersc86f6ca2001-09-26 21:31:51 +0000996 def makename(c, m=object.__module__):
997 return classname(c, m)
998
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000999 if name == realname:
1000 title = 'class ' + self.bold(realname)
1001 else:
1002 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001003 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001004 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001005 title = title + '(%s)' % join(parents, ', ')
1006
1007 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001008 contents = doc and [doc + '\n'] or []
1009 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001010
Tim Petersc86f6ca2001-09-26 21:31:51 +00001011 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +00001012 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001013 if len(mro) > 2:
1014 push("Method resolution order:")
1015 for base in mro:
1016 push(' ' + makename(base))
1017 push('')
1018
Tim Petersf4aad8e2001-09-24 22:40:47 +00001019 # Cute little class to pump out a horizontal rule between sections.
1020 class HorizontalRule:
1021 def __init__(self):
1022 self.needone = 0
1023 def maybe(self):
1024 if self.needone:
1025 push('-' * 70)
1026 self.needone = 1
1027 hr = HorizontalRule()
1028
Tim Peters28355492001-09-23 21:29:55 +00001029 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001030 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001031 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001032 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001033 push(msg)
1034 for name, kind, homecls, value in ok:
1035 push(self.document(getattr(object, name),
1036 name, mod, object))
1037 return attrs
1038
Tim Petersfa26f7c2001-09-24 08:05:11 +00001039 def spillproperties(msg, attrs, predicate):
1040 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001041 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001042 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001043 push(msg)
1044 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001045 push(name)
1046 need_blank_after_doc = 0
1047 doc = getdoc(value) or ''
1048 if doc:
1049 push(self.indent(doc))
1050 need_blank_after_doc = 1
Tim Petersf33532c2001-09-25 06:30:51 +00001051 for attr, tag in [("fget", " getter"),
1052 ("fset", " setter"),
Tim Petersf4aad8e2001-09-24 22:40:47 +00001053 ("fdel", " deleter")]:
1054 func = getattr(value, attr)
1055 if func is not None:
1056 if need_blank_after_doc:
1057 push('')
1058 need_blank_after_doc = 0
1059 base = self.docother(func, name + tag, mod, 70)
1060 push(self.indent(base))
1061 push('')
Tim Peters28355492001-09-23 21:29:55 +00001062 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001063
Tim Petersfa26f7c2001-09-24 08:05:11 +00001064 def spilldata(msg, attrs, predicate):
1065 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001066 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001067 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001068 push(msg)
1069 for name, kind, homecls, value in ok:
1070 doc = getattr(value, "__doc__", None)
1071 push(self.docother(getattr(object, name),
1072 name, mod, 70, doc) + '\n')
1073 return attrs
1074
1075 attrs = inspect.classify_class_attrs(object)
Tim Petersfa26f7c2001-09-24 08:05:11 +00001076 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001077 if mro:
1078 thisclass = mro.pop(0)
1079 else:
1080 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001081 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1082
Tim Peters28355492001-09-23 21:29:55 +00001083 if thisclass is object:
1084 tag = "defined here"
1085 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001086 tag = "inherited from %s" % classname(thisclass,
1087 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001088
1089 # Sort attrs by name.
1090 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
1091
1092 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001093 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001094 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001095 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001096 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001097 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001098 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001099 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001100 lambda t: t[1] == 'property')
Tim Petersf33532c2001-09-25 06:30:51 +00001101 attrs = spilldata("Data and non-method functions %s:\n" % tag,
1102 attrs, lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001103 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001104 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001105
1106 contents = '\n'.join(contents)
1107 if not contents:
1108 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001109 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1110
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001111 def formatvalue(self, object):
1112 """Format an argument default value as text."""
1113 return '=' + self.repr(object)
1114
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001115 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001116 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001117 realname = object.__name__
1118 name = name or realname
1119 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001120 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001121 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001122 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001123 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001124 if imclass is not cl:
1125 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001126 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001127 if object.im_self:
1128 note = ' method of %s instance' % classname(
1129 object.im_self.__class__, mod)
1130 else:
1131 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001132 object = object.im_func
1133
1134 if name == realname:
1135 title = self.bold(realname)
1136 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001137 if (cl and cl.__dict__.has_key(realname) and
1138 cl.__dict__[realname] is object):
1139 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001140 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001141 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001142 args, varargs, varkw, defaults = inspect.getargspec(object)
1143 argspec = inspect.formatargspec(
1144 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001145 if realname == '<lambda>':
1146 title = 'lambda'
1147 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001148 else:
1149 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001150 decl = title + argspec + note
1151
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001152 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001153 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001154 else:
1155 doc = getdoc(object) or ''
1156 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001157
Tim Peters28355492001-09-23 21:29:55 +00001158 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001159 """Produce text documentation for a data object."""
1160 repr = self.repr(object)
1161 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001162 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001163 chop = maxlen - len(line)
1164 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001165 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001166 if doc is not None:
1167 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001168 return line
1169
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001170# --------------------------------------------------------- user interfaces
1171
1172def pager(text):
1173 """The first time this is called, determine what kind of pager to use."""
1174 global pager
1175 pager = getpager()
1176 pager(text)
1177
1178def getpager():
1179 """Decide what method to use for paging through text."""
1180 if type(sys.stdout) is not types.FileType:
1181 return plainpager
1182 if not sys.stdin.isatty() or not sys.stdout.isatty():
1183 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001184 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001185 return plainpager
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001186 if os.environ.has_key('PAGER'):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001187 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001188 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1189 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1190 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001191 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001192 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001193 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001194 return lambda text: tempfilepager(plain(text), 'more <')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001195 if hasattr(os, 'system') and os.system('less 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001196 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001197
1198 import tempfile
1199 filename = tempfile.mktemp()
1200 open(filename, 'w').close()
1201 try:
1202 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1203 return lambda text: pipepager(text, 'more')
1204 else:
1205 return ttypager
1206 finally:
1207 os.unlink(filename)
1208
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001209def plain(text):
1210 """Remove boldface formatting from text."""
1211 return re.sub('.\b', '', text)
1212
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001213def pipepager(text, cmd):
1214 """Page through text by feeding it to another program."""
1215 pipe = os.popen(cmd, 'w')
1216 try:
1217 pipe.write(text)
1218 pipe.close()
1219 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001220 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001221
1222def tempfilepager(text, cmd):
1223 """Page through text by invoking a program on a temporary file."""
1224 import tempfile
1225 filename = tempfile.mktemp()
1226 file = open(filename, 'w')
1227 file.write(text)
1228 file.close()
1229 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001230 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001231 finally:
1232 os.unlink(filename)
1233
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001234def ttypager(text):
1235 """Page through text on a text terminal."""
1236 lines = split(plain(text), '\n')
1237 try:
1238 import tty
1239 fd = sys.stdin.fileno()
1240 old = tty.tcgetattr(fd)
1241 tty.setcbreak(fd)
1242 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001243 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001244 tty = None
1245 getchar = lambda: sys.stdin.readline()[:-1][:1]
1246
1247 try:
1248 r = inc = os.environ.get('LINES', 25) - 1
1249 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1250 while lines[r:]:
1251 sys.stdout.write('-- more --')
1252 sys.stdout.flush()
1253 c = getchar()
1254
1255 if c in ['q', 'Q']:
1256 sys.stdout.write('\r \r')
1257 break
1258 elif c in ['\r', '\n']:
1259 sys.stdout.write('\r \r' + lines[r] + '\n')
1260 r = r + 1
1261 continue
1262 if c in ['b', 'B', '\x1b']:
1263 r = r - inc - inc
1264 if r < 0: r = 0
1265 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1266 r = r + inc
1267
1268 finally:
1269 if tty:
1270 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1271
1272def plainpager(text):
1273 """Simply print unformatted text. This is the ultimate fallback."""
1274 sys.stdout.write(plain(text))
1275
1276def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001277 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001278 if inspect.ismodule(thing):
1279 if thing.__name__ in sys.builtin_module_names:
1280 return 'built-in module ' + thing.__name__
1281 if hasattr(thing, '__path__'):
1282 return 'package ' + thing.__name__
1283 else:
1284 return 'module ' + thing.__name__
1285 if inspect.isbuiltin(thing):
1286 return 'built-in function ' + thing.__name__
1287 if inspect.isclass(thing):
1288 return 'class ' + thing.__name__
1289 if inspect.isfunction(thing):
1290 return 'function ' + thing.__name__
1291 if inspect.ismethod(thing):
1292 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001293 if type(thing) is types.InstanceType:
1294 return 'instance of ' + thing.__class__.__name__
1295 return type(thing).__name__
1296
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001297def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001298 """Locate an object by name or dotted path, importing as necessary."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001299 parts = split(path, '.')
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001300 module, n = None, 0
1301 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001302 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001303 if nextmodule: module, n = nextmodule, n + 1
1304 else: break
1305 if module:
1306 object = module
1307 for part in parts[n:]:
1308 try: object = getattr(object, part)
1309 except AttributeError: return None
1310 return object
1311 else:
1312 import __builtin__
1313 if hasattr(__builtin__, path):
1314 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001315
1316# --------------------------------------- interactive interpreter interface
1317
1318text = TextDoc()
1319html = HTMLDoc()
1320
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001321def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001322 """Display text documentation, given an object or a path to an object."""
1323 suffix, name = '', None
1324 if type(thing) is type(''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001325 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001326 object = locate(thing, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001327 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001328 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001329 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001330 if not object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001331 print 'no Python documentation found for %s' % repr(thing)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001332 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001333 parts = split(thing, '.')
1334 if len(parts) > 1: suffix = ' in ' + join(parts[:-1], '.')
1335 name = parts[-1]
1336 thing = object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001337
1338 desc = describe(thing)
1339 module = inspect.getmodule(thing)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001340 if not suffix and module and module is not thing:
1341 suffix = ' in module ' + module.__name__
Ka-Ping Yee66246962001-04-12 11:59:50 +00001342 pager(title % (desc + suffix) + '\n\n' + text.document(thing, name))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001343
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001344def writedoc(key, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001345 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001346 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001347 object = locate(key, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001348 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001349 print value
1350 else:
1351 if object:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001352 page = html.page(describe(object),
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001353 html.document(object, object.__name__))
1354 file = open(key + '.html', 'w')
1355 file.write(page)
1356 file.close()
1357 print 'wrote', key + '.html'
1358 else:
1359 print 'no Python documentation found for %s' % repr(key)
1360
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001361def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001362 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001363 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001364 for file in os.listdir(dir):
1365 path = os.path.join(dir, file)
1366 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001367 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001368 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001369 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001370 if modname:
1371 modname = pkgpath + modname
1372 if not done.has_key(modname):
1373 done[modname] = 1
1374 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001375
1376class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001377 keywords = {
1378 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001379 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001380 'break': ('ref/break', 'while for'),
1381 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1382 'continue': ('ref/continue', 'while for'),
1383 'def': ('ref/function', ''),
1384 'del': ('ref/del', 'BASICMETHODS'),
1385 'elif': 'if',
1386 'else': ('ref/if', 'while for'),
1387 'except': 'try',
1388 'exec': ('ref/exec', ''),
1389 'finally': 'try',
1390 'for': ('ref/for', 'break continue while'),
1391 'from': 'import',
1392 'global': ('ref/global', 'NAMESPACES'),
1393 'if': ('ref/if', 'TRUTHVALUE'),
1394 'import': ('ref/import', 'MODULES'),
1395 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1396 'is': 'COMPARISON',
1397 'lambda': ('ref/lambda', 'FUNCTIONS'),
1398 'not': 'BOOLEAN',
1399 'or': 'BOOLEAN',
1400 'pass': 'PASS',
1401 'print': ('ref/print', ''),
1402 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001403 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001404 'try': ('ref/try', 'EXCEPTIONS'),
1405 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1406 }
1407
1408 topics = {
1409 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001410 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001411 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1412 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001413 'UNICODE': ('ref/unicode', 'encodings unicode TYPES STRING'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001414 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1415 'INTEGER': ('ref/integers', 'int range'),
1416 'FLOAT': ('ref/floating', 'float math'),
1417 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001418 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001419 'MAPPINGS': 'DICTIONARIES',
1420 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1421 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1422 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001423 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001424 'FRAMEOBJECTS': 'TYPES',
1425 'TRACEBACKS': 'TYPES',
1426 'NONE': ('lib/bltin-null-object', ''),
1427 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1428 'FILES': ('lib/bltin-file-objects', ''),
1429 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1430 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1431 'MODULES': ('lib/typesmodules', 'import'),
1432 'PACKAGES': 'import',
1433 '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'),
1434 'OPERATORS': 'EXPRESSIONS',
1435 'PRECEDENCE': 'EXPRESSIONS',
1436 'OBJECTS': ('ref/objects', 'TYPES'),
1437 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001438 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1439 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1440 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1441 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1442 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1443 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1444 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001445 'EXECUTION': ('ref/execframes', ''),
1446 'NAMESPACES': ('ref/execframes', 'global ASSIGNMENT DELETION'),
1447 'SCOPING': 'NAMESPACES',
1448 'FRAMES': 'NAMESPACES',
1449 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1450 'COERCIONS': 'CONVERSIONS',
1451 'CONVERSIONS': ('ref/conversions', ''),
1452 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1453 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001454 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001455 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1456 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001457 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001458 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001459 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001460 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001461 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1462 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001463 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1464 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1465 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1466 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1467 'POWER': ('ref/power', 'EXPRESSIONS'),
1468 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1469 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1470 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1471 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1472 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001473 'BOOLEAN': ('ref/lambda', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001474 'ASSERTION': 'assert',
1475 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001476 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001477 'DELETION': 'del',
1478 'PRINTING': 'print',
1479 'RETURNING': 'return',
1480 'IMPORTING': 'import',
1481 'CONDITIONAL': 'if',
1482 'LOOPING': ('ref/compound', 'for while break continue'),
1483 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001484 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001485 }
1486
1487 def __init__(self, input, output):
1488 self.input = input
1489 self.output = output
1490 self.docdir = None
1491 execdir = os.path.dirname(sys.executable)
1492 homedir = os.environ.get('PYTHONHOME')
1493 for dir in [os.environ.get('PYTHONDOCS'),
1494 homedir and os.path.join(homedir, 'doc'),
1495 os.path.join(execdir, 'doc'),
1496 '/usr/doc/python-docs-' + split(sys.version)[0],
1497 '/usr/doc/python-' + split(sys.version)[0],
1498 '/usr/doc/python-docs-' + sys.version[:3],
1499 '/usr/doc/python-' + sys.version[:3]]:
1500 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1501 self.docdir = dir
1502
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001503 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001504 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001505 self()
1506 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001507 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001508
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001509 def __call__(self, request=None):
1510 if request is not None:
1511 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001512 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001513 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001514 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001515 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001516You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001517If you want to ask for help on a particular object directly from the
1518interpreter, you can type "help(object)". Executing "help('string')"
1519has the same effect as typing a particular string at the help> prompt.
1520''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001521
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001522 def interact(self):
1523 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001524 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001525 self.output.write('help> ')
1526 self.output.flush()
1527 try:
1528 request = self.input.readline()
1529 if not request: break
1530 except KeyboardInterrupt: break
1531 request = strip(replace(request, '"', '', "'", ''))
1532 if lower(request) in ['q', 'quit']: break
1533 self.help(request)
1534
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001535 def help(self, request):
1536 if type(request) is type(''):
1537 if request == 'help': self.intro()
1538 elif request == 'keywords': self.listkeywords()
1539 elif request == 'topics': self.listtopics()
1540 elif request == 'modules': self.listmodules()
1541 elif request[:8] == 'modules ':
1542 self.listmodules(split(request)[1])
1543 elif self.keywords.has_key(request): self.showtopic(request)
1544 elif self.topics.has_key(request): self.showtopic(request)
1545 elif request: doc(request, 'Help on %s:')
1546 elif isinstance(request, Helper): self()
1547 else: doc(request, 'Help on %s:')
1548 self.output.write('\n')
1549
1550 def intro(self):
1551 self.output.write('''
1552Welcome to Python %s! This is the online help utility.
1553
1554If this is your first time using Python, you should definitely check out
1555the tutorial on the Internet at http://www.python.org/doc/tut/.
1556
1557Enter the name of any module, keyword, or topic to get help on writing
1558Python programs and using Python modules. To quit this help utility and
1559return to the interpreter, just type "quit".
1560
1561To get a list of available modules, keywords, or topics, type "modules",
1562"keywords", or "topics". Each module also comes with a one-line summary
1563of what it does; to list the modules whose summaries contain a given word
1564such as "spam", type "modules spam".
1565''' % sys.version[:3])
1566
1567 def list(self, items, columns=4, width=80):
1568 items = items[:]
1569 items.sort()
1570 colw = width / columns
1571 rows = (len(items) + columns - 1) / columns
1572 for row in range(rows):
1573 for col in range(columns):
1574 i = col * rows + row
1575 if i < len(items):
1576 self.output.write(items[i])
1577 if col < columns - 1:
1578 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1579 self.output.write('\n')
1580
1581 def listkeywords(self):
1582 self.output.write('''
1583Here is a list of the Python keywords. Enter any keyword to get more help.
1584
1585''')
1586 self.list(self.keywords.keys())
1587
1588 def listtopics(self):
1589 self.output.write('''
1590Here is a list of available topics. Enter any topic name to get more help.
1591
1592''')
1593 self.list(self.topics.keys())
1594
1595 def showtopic(self, topic):
1596 if not self.docdir:
1597 self.output.write('''
1598Sorry, topic and keyword documentation is not available because the Python
1599HTML documentation files could not be found. If you have installed them,
1600please set the environment variable PYTHONDOCS to indicate their location.
1601''')
1602 return
1603 target = self.topics.get(topic, self.keywords.get(topic))
1604 if not target:
1605 self.output.write('no documentation found for %s\n' % repr(topic))
1606 return
1607 if type(target) is type(''):
1608 return self.showtopic(target)
1609
1610 filename, xrefs = target
1611 filename = self.docdir + '/' + filename + '.html'
1612 try:
1613 file = open(filename)
1614 except:
1615 self.output.write('could not read docs from %s\n' % filename)
1616 return
1617
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001618 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1619 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001620 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1621 file.close()
1622
1623 import htmllib, formatter, StringIO
1624 buffer = StringIO.StringIO()
1625 parser = htmllib.HTMLParser(
1626 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1627 parser.start_table = parser.do_p
1628 parser.end_table = lambda parser=parser: parser.do_p({})
1629 parser.start_tr = parser.do_br
1630 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1631 parser.feed(document)
1632 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1633 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001634 if xrefs:
1635 buffer = StringIO.StringIO()
1636 formatter.DumbWriter(buffer).send_flowing_data(
1637 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1638 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001639
1640 def listmodules(self, key=''):
1641 if key:
1642 self.output.write('''
1643Here is a list of matching modules. Enter any module name to get more help.
1644
1645''')
1646 apropos(key)
1647 else:
1648 self.output.write('''
1649Please wait a moment while I gather a list of all available modules...
1650
1651''')
1652 modules = {}
1653 def callback(path, modname, desc, modules=modules):
1654 if modname and modname[-9:] == '.__init__':
1655 modname = modname[:-9] + ' (package)'
1656 if find(modname, '.') < 0:
1657 modules[modname] = 1
1658 ModuleScanner().run(callback)
1659 self.list(modules.keys())
1660 self.output.write('''
1661Enter any module name to get more help. Or, type "modules spam" to search
1662for modules whose descriptions contain the word "spam".
1663''')
1664
1665help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001666
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001667class Scanner:
1668 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001669 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001670 self.roots = roots[:]
1671 self.state = []
1672 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001673 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001674
1675 def next(self):
1676 if not self.state:
1677 if not self.roots:
1678 return None
1679 root = self.roots.pop(0)
1680 self.state = [(root, self.children(root))]
1681 node, children = self.state[-1]
1682 if not children:
1683 self.state.pop()
1684 return self.next()
1685 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001686 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001687 self.state.append((child, self.children(child)))
1688 return child
1689
1690class ModuleScanner(Scanner):
1691 """An interruptible scanner that searches module synopses."""
1692 def __init__(self):
1693 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001694 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
1695 self.inodes = map(lambda (dir, pkg): os.stat(dir)[1], roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001696
1697 def submodules(self, (dir, package)):
1698 children = []
1699 for file in os.listdir(dir):
1700 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001701 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001702 children.append((path, package + (package and '.') + file))
1703 else:
1704 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001705 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001706 return children
1707
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001708 def isnewpackage(self, (dir, package)):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001709 inode = os.path.exists(dir) and os.stat(dir)[1]
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001710 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001711 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001712 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001713 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001714
Ka-Ping Yee66246962001-04-12 11:59:50 +00001715 def run(self, callback, key=None, completer=None):
1716 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001717 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001718 seen = {}
1719
1720 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001721 if modname != '__main__':
1722 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001723 if key is None:
1724 callback(None, modname, '')
1725 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001726 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001727 if find(lower(modname + ' - ' + desc), key) >= 0:
1728 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001729
1730 while not self.quit:
1731 node = self.next()
1732 if not node: break
1733 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001734 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001735 if os.path.isfile(path) and modname:
1736 modname = package + (package and '.') + modname
1737 if not seen.has_key(modname):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001738 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001739 if key is None:
1740 callback(path, modname, '')
1741 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001742 desc = synopsis(path) or ''
1743 if find(lower(modname + ' - ' + desc), key) >= 0:
1744 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001745 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001746
1747def apropos(key):
1748 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001749 def callback(path, modname, desc):
1750 if modname[-9:] == '.__init__':
1751 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001752 print modname, desc and '- ' + desc
1753 try: import warnings
1754 except ImportError: pass
1755 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001756 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001757
1758# --------------------------------------------------- web browser interface
1759
Ka-Ping Yee66246962001-04-12 11:59:50 +00001760def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001761 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001762
1763 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1764 class Message(mimetools.Message):
1765 def __init__(self, fp, seekable=1):
1766 Message = self.__class__
1767 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1768 self.encodingheader = self.getheader('content-transfer-encoding')
1769 self.typeheader = self.getheader('content-type')
1770 self.parsetype()
1771 self.parseplist()
1772
1773 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1774 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001775 try:
1776 self.send_response(200)
1777 self.send_header('Content-Type', 'text/html')
1778 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001779 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001780 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001781
1782 def do_GET(self):
1783 path = self.path
1784 if path[-5:] == '.html': path = path[:-5]
1785 if path[:1] == '/': path = path[1:]
1786 if path and path != '.':
1787 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001788 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001789 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001790 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001791 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001792 if obj:
1793 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001794 else:
1795 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001796'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001797 else:
1798 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001799'<big><big><strong>Python: Index of Modules</strong></big></big>',
1800'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001801 def bltinlink(name):
1802 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001803 names = filter(lambda x: x != '__main__',
1804 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001805 contents = html.multicolumn(names, bltinlink)
1806 indices = ['<p>' + html.bigsection(
1807 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1808
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001809 seen = {}
1810 for dir in pathdirs():
1811 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001812 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001813<font color="#909090" face="helvetica, arial"><strong>
1814pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001815 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001816
1817 def log_message(self, *args): pass
1818
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001819 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001820 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001821 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001822 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001823 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001824 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001825 self.base.__init__(self, self.address, self.handler)
1826
1827 def serve_until_quit(self):
1828 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001829 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001830 while not self.quit:
1831 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1832 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001833
1834 def server_activate(self):
1835 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001836 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001837
1838 DocServer.base = BaseHTTPServer.HTTPServer
1839 DocServer.handler = DocHandler
1840 DocHandler.MessageClass = Message
1841 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001842 try:
1843 DocServer(port, callback).serve_until_quit()
1844 except (KeyboardInterrupt, select.error):
1845 pass
1846 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001847 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001848
1849# ----------------------------------------------------- graphical interface
1850
1851def gui():
1852 """Graphical interface (starts web server and pops up a control window)."""
1853 class GUI:
1854 def __init__(self, window, port=7464):
1855 self.window = window
1856 self.server = None
1857 self.scanner = None
1858
1859 import Tkinter
1860 self.server_frm = Tkinter.Frame(window)
1861 self.title_lbl = Tkinter.Label(self.server_frm,
1862 text='Starting server...\n ')
1863 self.open_btn = Tkinter.Button(self.server_frm,
1864 text='open browser', command=self.open, state='disabled')
1865 self.quit_btn = Tkinter.Button(self.server_frm,
1866 text='quit serving', command=self.quit, state='disabled')
1867
1868 self.search_frm = Tkinter.Frame(window)
1869 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1870 self.search_ent = Tkinter.Entry(self.search_frm)
1871 self.search_ent.bind('<Return>', self.search)
1872 self.stop_btn = Tkinter.Button(self.search_frm,
1873 text='stop', pady=0, command=self.stop, state='disabled')
1874 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001875 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001876 self.stop_btn.pack(side='right')
1877
1878 self.window.title('pydoc')
1879 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1880 self.title_lbl.pack(side='top', fill='x')
1881 self.open_btn.pack(side='left', fill='x', expand=1)
1882 self.quit_btn.pack(side='right', fill='x', expand=1)
1883 self.server_frm.pack(side='top', fill='x')
1884
1885 self.search_lbl.pack(side='left')
1886 self.search_ent.pack(side='right', fill='x', expand=1)
1887 self.search_frm.pack(side='top', fill='x')
1888 self.search_ent.focus_set()
1889
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001890 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001891 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001892 self.result_lst.bind('<Button-1>', self.select)
1893 self.result_lst.bind('<Double-Button-1>', self.goto)
1894 self.result_scr = Tkinter.Scrollbar(window,
1895 orient='vertical', command=self.result_lst.yview)
1896 self.result_lst.config(yscrollcommand=self.result_scr.set)
1897
1898 self.result_frm = Tkinter.Frame(window)
1899 self.goto_btn = Tkinter.Button(self.result_frm,
1900 text='go to selected', command=self.goto)
1901 self.hide_btn = Tkinter.Button(self.result_frm,
1902 text='hide results', command=self.hide)
1903 self.goto_btn.pack(side='left', fill='x', expand=1)
1904 self.hide_btn.pack(side='right', fill='x', expand=1)
1905
1906 self.window.update()
1907 self.minwidth = self.window.winfo_width()
1908 self.minheight = self.window.winfo_height()
1909 self.bigminheight = (self.server_frm.winfo_reqheight() +
1910 self.search_frm.winfo_reqheight() +
1911 self.result_lst.winfo_reqheight() +
1912 self.result_frm.winfo_reqheight())
1913 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1914 self.expanded = 0
1915 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1916 self.window.wm_minsize(self.minwidth, self.minheight)
1917
1918 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001919 threading.Thread(
1920 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001921
1922 def ready(self, server):
1923 self.server = server
1924 self.title_lbl.config(
1925 text='Python documentation server at\n' + server.url)
1926 self.open_btn.config(state='normal')
1927 self.quit_btn.config(state='normal')
1928
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001929 def open(self, event=None, url=None):
1930 url = url or self.server.url
1931 try:
1932 import webbrowser
1933 webbrowser.open(url)
1934 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001935 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001936 os.system('start "%s"' % url)
1937 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001938 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001939 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001940 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001941 else:
1942 rc = os.system('netscape -remote "openURL(%s)" &' % url)
1943 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001944
1945 def quit(self, event=None):
1946 if self.server:
1947 self.server.quit = 1
1948 self.window.quit()
1949
1950 def search(self, event=None):
1951 key = self.search_ent.get()
1952 self.stop_btn.pack(side='right')
1953 self.stop_btn.config(state='normal')
1954 self.search_lbl.config(text='Searching for "%s"...' % key)
1955 self.search_ent.forget()
1956 self.search_lbl.pack(side='left')
1957 self.result_lst.delete(0, 'end')
1958 self.goto_btn.config(state='disabled')
1959 self.expand()
1960
1961 import threading
1962 if self.scanner:
1963 self.scanner.quit = 1
1964 self.scanner = ModuleScanner()
1965 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00001966 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001967
1968 def update(self, path, modname, desc):
1969 if modname[-9:] == '.__init__':
1970 modname = modname[:-9] + ' (package)'
1971 self.result_lst.insert('end',
1972 modname + ' - ' + (desc or '(no description)'))
1973
1974 def stop(self, event=None):
1975 if self.scanner:
1976 self.scanner.quit = 1
1977 self.scanner = None
1978
1979 def done(self):
1980 self.scanner = None
1981 self.search_lbl.config(text='Search for')
1982 self.search_lbl.pack(side='left')
1983 self.search_ent.pack(side='right', fill='x', expand=1)
1984 if sys.platform != 'win32': self.stop_btn.forget()
1985 self.stop_btn.config(state='disabled')
1986
1987 def select(self, event=None):
1988 self.goto_btn.config(state='normal')
1989
1990 def goto(self, event=None):
1991 selection = self.result_lst.curselection()
1992 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001993 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001994 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001995
1996 def collapse(self):
1997 if not self.expanded: return
1998 self.result_frm.forget()
1999 self.result_scr.forget()
2000 self.result_lst.forget()
2001 self.bigwidth = self.window.winfo_width()
2002 self.bigheight = self.window.winfo_height()
2003 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2004 self.window.wm_minsize(self.minwidth, self.minheight)
2005 self.expanded = 0
2006
2007 def expand(self):
2008 if self.expanded: return
2009 self.result_frm.pack(side='bottom', fill='x')
2010 self.result_scr.pack(side='right', fill='y')
2011 self.result_lst.pack(side='top', fill='both', expand=1)
2012 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2013 self.window.wm_minsize(self.minwidth, self.bigminheight)
2014 self.expanded = 1
2015
2016 def hide(self, event=None):
2017 self.stop()
2018 self.collapse()
2019
2020 import Tkinter
2021 try:
2022 gui = GUI(Tkinter.Tk())
2023 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002024 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002025 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002026
2027# -------------------------------------------------- command-line interface
2028
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002029def ispath(x):
2030 return type(x) is types.StringType and find(x, os.sep) >= 0
2031
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002032def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002033 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002034 import getopt
2035 class BadUsage: pass
2036
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002037 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002038 scriptdir = os.path.dirname(sys.argv[0])
2039 if scriptdir in sys.path:
2040 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002041 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002042
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002043 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002044 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002045 writing = 0
2046
2047 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002048 if opt == '-g':
2049 gui()
2050 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002051 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002052 apropos(val)
2053 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002054 if opt == '-p':
2055 try:
2056 port = int(val)
2057 except ValueError:
2058 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002059 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002060 print 'pydoc server ready at %s' % server.url
2061 def stopped():
2062 print 'pydoc server stopped'
2063 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002064 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002065 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002066 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002067
2068 if not args: raise BadUsage
2069 for arg in args:
2070 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002071 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002072 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002073 if writing:
2074 if ispath(arg) and os.path.isdir(arg):
2075 writedocs(arg)
2076 else:
2077 writedoc(arg)
2078 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002079 doc(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002080 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002081 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002082
2083 except (getopt.error, BadUsage):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002084 cmd = sys.argv[0]
2085 print """pydoc - the Python documentation tool
2086
2087%s <name> ...
2088 Show text documentation on something. <name> may be the name of a
2089 function, module, or package, or a dotted reference to a class or
2090 function within a module or module in a package. If <name> contains
2091 a '%s', it is used as the path to a Python source file to document.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002092
2093%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002094 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002095
2096%s -p <port>
2097 Start an HTTP server on the given port on the local machine.
2098
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002099%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002100 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002101
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002102%s -w <name> ...
2103 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002104 directory. If <name> contains a '%s', it is treated as a filename; if
2105 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002106""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002107
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002108if __name__ == '__main__': cli()