blob: 5b27a09aa632b455c6ab428f0414152f1ab345ab [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)):
151 return 1
152
153def synopsis(filename, cache={}):
154 """Get the one-line summary out of a module file."""
155 mtime = os.stat(filename)[stat.ST_MTIME]
156 lastupdate, result = cache.get(filename, (0, None))
157 if lastupdate < mtime:
158 info = inspect.getmoduleinfo(filename)
159 file = open(filename)
160 if info and 'b' in info[2]: # binary modules have to be imported
161 try: module = imp.load_module('__temp__', file, filename, info[1:])
162 except: return None
163 result = split(module.__doc__ or '', '\n')[0]
164 del sys.modules['__temp__']
165 else: # text modules can be directly examined
166 line = file.readline()
167 while line[:1] == '#' or not strip(line):
168 line = file.readline()
169 if not line: break
170 line = strip(line)
171 if line[:4] == 'r"""': line = line[1:]
172 if line[:3] == '"""':
173 line = line[3:]
174 if line[-1:] == '\\': line = line[:-1]
175 while not strip(line):
176 line = file.readline()
177 if not line: break
178 result = strip(split(line, '"""')[0])
179 else: result = None
180 file.close()
181 cache[filename] = (mtime, result)
182 return result
183
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000184class ErrorDuringImport(Exception):
185 """Errors that occurred while trying to import something to document it."""
186 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000187 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000188 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000189 self.value = value
190 self.tb = tb
191
192 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000193 exc = self.exc
194 if type(exc) is types.ClassType:
195 exc = exc.__name__
196 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000197
198def importfile(path):
199 """Import a Python source file or compiled file given its path."""
200 magic = imp.get_magic()
201 file = open(path, 'r')
202 if file.read(len(magic)) == magic:
203 kind = imp.PY_COMPILED
204 else:
205 kind = imp.PY_SOURCE
206 file.close()
207 filename = os.path.basename(path)
208 name, ext = os.path.splitext(filename)
209 file = open(path, 'r')
210 try:
211 module = imp.load_module(name, file, path, (ext, 'r', kind))
212 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000213 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000214 file.close()
215 return module
216
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000217def safeimport(path, forceload=0, cache={}):
218 """Import a module; handle errors; return None if the module isn't found.
219
220 If the module *is* found but an exception occurs, it's wrapped in an
221 ErrorDuringImport exception and reraised. Unlike __import__, if a
222 package path is specified, the module at the end of the path is returned,
223 not the package at the beginning. If the optional 'forceload' argument
224 is 1, we reload the module from disk (unless it's a dynamic extension)."""
225 if forceload and sys.modules.has_key(path):
226 # This is the only way to be sure. Checking the mtime of the file
227 # isn't good enough (e.g. what if the module contains a class that
228 # inherits from another module that has changed?).
229 if path not in sys.builtin_module_names:
230 # Python never loads a dynamic extension a second time from the
231 # same path, even if the file is changed or missing. Deleting
232 # the entry in sys.modules doesn't help for dynamic extensions,
233 # so we're not even going to try to keep them up to date.
234 info = inspect.getmoduleinfo(sys.modules[path].__file__)
235 if info[3] != imp.C_EXTENSION:
236 cache[path] = sys.modules[path] # prevent module from clearing
237 del sys.modules[path]
238 try:
239 module = __import__(path)
240 except:
241 # Did the error occur before or after the module was found?
242 (exc, value, tb) = info = sys.exc_info()
243 if sys.modules.has_key(path):
244 # An error occured while executing the imported module.
245 raise ErrorDuringImport(sys.modules[path].__file__, info)
246 elif exc is SyntaxError:
247 # A SyntaxError occurred before we could execute the module.
248 raise ErrorDuringImport(value.filename, info)
249 elif exc is ImportError and \
250 split(lower(str(value)))[:2] == ['no', 'module']:
251 # The module was not found.
252 return None
253 else:
254 # Some other error occurred during the importing process.
255 raise ErrorDuringImport(path, sys.exc_info())
256 for part in split(path, '.')[1:]:
257 try: module = getattr(module, part)
258 except AttributeError: return None
259 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000260
261# ---------------------------------------------------- formatter base class
262
263class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000264 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000265 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000266 args = (object, name) + args
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000267 if inspect.ismodule(object): return apply(self.docmodule, args)
268 if inspect.isclass(object): return apply(self.docclass, args)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000269 if inspect.isroutine(object): return apply(self.docroutine, args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000270 return apply(self.docother, args)
271
272 def fail(self, object, name=None, *args):
273 """Raise an exception for unimplemented types."""
274 message = "don't know how to document object%s of type %s" % (
275 name and ' ' + repr(name), type(object).__name__)
276 raise TypeError, message
277
278 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000279
280# -------------------------------------------- HTML documentation generator
281
282class HTMLRepr(Repr):
283 """Class for safely making an HTML representation of a Python object."""
284 def __init__(self):
285 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000286 self.maxlist = self.maxtuple = 20
287 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000288 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000289
290 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000291 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000292
293 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000294 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000295
296 def repr1(self, x, level):
297 methodname = 'repr_' + join(split(type(x).__name__), '_')
298 if hasattr(self, methodname):
299 return getattr(self, methodname)(x, level)
300 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000301 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000302
303 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000304 test = cram(x, self.maxstring)
305 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000306 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000307 # Backslashes are only literal in the string and are never
308 # needed to make any special characters, so show a raw string.
309 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000310 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000311 r'<font color="#c040c0">\1</font>',
312 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000313
Skip Montanarodf708782002-03-07 22:58:02 +0000314 repr_str = repr_string
315
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000316 def repr_instance(self, x, level):
317 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000318 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000319 except:
320 return self.escape('<%s instance>' % x.__class__.__name__)
321
322 repr_unicode = repr_string
323
324class HTMLDoc(Doc):
325 """Formatter class for HTML documentation."""
326
327 # ------------------------------------------- HTML formatting utilities
328
329 _repr_instance = HTMLRepr()
330 repr = _repr_instance.repr
331 escape = _repr_instance.escape
332
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000333 def page(self, title, contents):
334 """Format an HTML page."""
335 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000336<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000337<html><head><title>Python: %s</title>
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000338<style type="text/css"><!--
Ka-Ping Yeed03f8fe2001-04-13 15:04:32 +0000339TT { font-family: lucidatypewriter, lucida console, courier }
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000340--></style></head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000341%s
342</body></html>''' % (title, contents)
343
344 def heading(self, title, fgcol, bgcol, extras=''):
345 """Format a page heading."""
346 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000347<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000348<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000349<td valign=bottom>&nbsp;<br>
350<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000351><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000352><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000353 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
354
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000355 def section(self, title, fgcol, bgcol, contents, width=10,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000356 prelude='', marginalia=None, gap='&nbsp;&nbsp;'):
357 """Format a section with a heading."""
358 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000359 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000360 result = '''
Tim Peters59ed4482001-10-31 04:20:26 +0000361<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000362<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000363<td colspan=3 valign=bottom>&nbsp;<br>
364<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000365 ''' % (bgcol, fgcol, title)
366 if prelude:
367 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000368<tr bgcolor="%s"><td rowspan=2>%s</td>
369<td colspan=2>%s</td></tr>
370<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
371 else:
372 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000373<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000374
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000375 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000376
377 def bigsection(self, title, *args):
378 """Format a section with a big heading."""
379 title = '<big><strong>%s</strong></big>' % title
380 return apply(self.section, (title,) + args)
381
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000382 def preformat(self, text):
383 """Format literal preformatted text."""
384 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000385 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
386 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000387
388 def multicolumn(self, list, format, cols=4):
389 """Format a list of items into a multi-column list."""
390 result = ''
391 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000392 for col in range(cols):
393 result = result + '<td width="%d%%" valign=top>' % (100/cols)
394 for i in range(rows*col, rows*col+rows):
395 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000396 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000397 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000398 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000399
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000400 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000401
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000402 def namelink(self, name, *dicts):
403 """Make a link for an identifier, given name-to-URL mappings."""
404 for dict in dicts:
405 if dict.has_key(name):
406 return '<a href="%s">%s</a>' % (dict[name], name)
407 return name
408
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000409 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000410 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000411 name, module = object.__name__, sys.modules.get(object.__module__)
412 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000413 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000414 module.__name__, name, classname(object, modname))
415 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000416
417 def modulelink(self, object):
418 """Make a link for a module."""
419 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
420
421 def modpkglink(self, (name, path, ispackage, shadowed)):
422 """Make a link for a module or package to display in an index."""
423 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000424 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000425 if path:
426 url = '%s.%s.html' % (path, name)
427 else:
428 url = '%s.html' % name
429 if ispackage:
430 text = '<strong>%s</strong>&nbsp;(package)' % name
431 else:
432 text = name
433 return '<a href="%s">%s</a>' % (url, text)
434
435 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
436 """Mark up some plain text, given a context of symbols to look for.
437 Each context dictionary maps object names to anchor names."""
438 escape = escape or self.escape
439 results = []
440 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000441 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
442 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000443 r'PEP[- ]?(\d+)|'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000444 r'(self\.)?(\w+))\b')
445 while 1:
446 match = pattern.search(text, here)
447 if not match: break
448 start, end = match.span()
449 results.append(escape(text[here:start]))
450
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000451 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000452 if scheme:
453 results.append('<a href="%s">%s</a>' % (all, escape(all)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000454 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000455 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
456 results.append('<a href="%s">%s</a>' % (url, escape(all)))
457 elif pep:
458 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000459 results.append('<a href="%s">%s</a>' % (url, escape(all)))
460 elif text[end:end+1] == '(':
461 results.append(self.namelink(name, methods, funcs, classes))
462 elif selfdot:
463 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000464 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000465 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000466 here = end
467 results.append(escape(text[here:]))
468 return join(results, '')
469
470 # ---------------------------------------------- type-specific routines
471
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000472 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000473 """Produce HTML for a class tree as given by inspect.getclasstree()."""
474 result = ''
475 for entry in tree:
476 if type(entry) is type(()):
477 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000478 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000479 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000480 if bases and bases != (parent,):
481 parents = []
482 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000483 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000484 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000485 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000486 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000487 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000488 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000489 return '<dl>\n%s</dl>\n' % result
490
Tim Peters8dd7ade2001-10-18 19:56:17 +0000491 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000492 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000493 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000494 parts = split(name, '.')
495 links = []
496 for i in range(len(parts)-1):
497 links.append(
498 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
499 (join(parts[:i+1], '.'), parts[i]))
500 linkedname = join(links + parts[-1:], '.')
501 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000502 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000503 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000504 url = path
505 if sys.platform == 'win32':
506 import nturl2path
507 url = nturl2path.pathname2url(path)
508 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000509 except TypeError:
510 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000511 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000512 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000513 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000514 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
515 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000516 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000517 if hasattr(object, '__date__'):
518 info.append(self.escape(str(object.__date__)))
519 if info:
520 head = head + ' (%s)' % join(info, ', ')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000521 result = self.heading(
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000522 head, '#ffffff', '#7799ee', '<a href=".">index</a><br>' + filelink)
523
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000524 modules = inspect.getmembers(object, inspect.ismodule)
525
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000526 classes, cdict = [], {}
527 for key, value in inspect.getmembers(object, inspect.isclass):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000528 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000529 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000530 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000531 for key, value in classes:
532 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000533 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000534 module = sys.modules.get(modname)
535 if modname != name and module and hasattr(module, key):
536 if getattr(module, key) is base:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000537 if not cdict.has_key(key):
538 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000539 funcs, fdict = [], {}
540 for key, value in inspect.getmembers(object, inspect.isroutine):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000541 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000542 funcs.append((key, value))
543 fdict[key] = '#-' + key
544 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000545 data = []
546 for key, value in inspect.getmembers(object, isdata):
547 if key not in ['__builtins__', '__doc__']:
548 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000549
550 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
551 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000552 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000553
554 if hasattr(object, '__path__'):
555 modpkgs = []
556 modnames = []
557 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000558 path = os.path.join(object.__path__[0], file)
559 modname = inspect.getmodulename(file)
560 if modname and modname not in modnames:
561 modpkgs.append((modname, name, 0, 0))
562 modnames.append(modname)
563 elif ispackage(path):
564 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000565 modpkgs.sort()
566 contents = self.multicolumn(modpkgs, self.modpkglink)
567 result = result + self.bigsection(
568 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000569 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000570 contents = self.multicolumn(
571 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000572 result = result + self.bigsection(
573 'Modules', '#fffff', '#aa55cc', contents)
574
575 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000576 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000577 contents = [
578 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000579 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000580 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000581 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000582 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000583 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000584 contents = []
585 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000586 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000587 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000588 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000589 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000590 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000591 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000592 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000593 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000594 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000595 if hasattr(object, '__author__'):
596 contents = self.markup(str(object.__author__), self.preformat)
597 result = result + self.bigsection(
598 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000599 if hasattr(object, '__credits__'):
600 contents = self.markup(str(object.__credits__), self.preformat)
601 result = result + self.bigsection(
602 'Credits', '#ffffff', '#7799ee', contents)
603
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000604 return result
605
Tim Peters8dd7ade2001-10-18 19:56:17 +0000606 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
607 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000608 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000609 realname = object.__name__
610 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000611 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000612
Tim Petersb47879b2001-09-24 04:47:19 +0000613 contents = []
614 push = contents.append
615
Tim Petersfa26f7c2001-09-24 08:05:11 +0000616 # Cute little class to pump out a horizontal rule between sections.
617 class HorizontalRule:
618 def __init__(self):
619 self.needone = 0
620 def maybe(self):
621 if self.needone:
622 push('<hr>\n')
623 self.needone = 1
624 hr = HorizontalRule()
625
Tim Petersc86f6ca2001-09-26 21:31:51 +0000626 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +0000627 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000628 if len(mro) > 2:
629 hr.maybe()
630 push('<dl><dt>Method resolution order:</dt>\n')
631 for base in mro:
632 push('<dd>%s</dd>\n' % self.classlink(base,
633 object.__module__))
634 push('</dl>\n')
635
Tim Petersb47879b2001-09-24 04:47:19 +0000636 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000637 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000638 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000639 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000640 push(msg)
641 for name, kind, homecls, value in ok:
642 push(self.document(getattr(object, name), name, mod,
643 funcs, classes, mdict, object))
644 push('\n')
645 return attrs
646
Tim Petersfa26f7c2001-09-24 08:05:11 +0000647 def spillproperties(msg, attrs, predicate):
648 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000649 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000650 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000651 push(msg)
652 for name, kind, homecls, value in ok:
Tim Peters3e767d12001-09-25 00:01:06 +0000653 push('<dl><dt><strong>%s</strong></dt>\n' % name)
654 if value.__doc__ is not None:
655 doc = self.markup(value.__doc__, self.preformat,
656 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000657 push('<dd><tt>%s</tt></dd>\n' % doc)
Tim Petersf33532c2001-09-25 06:30:51 +0000658 for attr, tag in [("fget", " getter"),
659 ("fset", " setter"),
Tim Peters3e767d12001-09-25 00:01:06 +0000660 ("fdel", " deleter")]:
661 func = getattr(value, attr)
662 if func is not None:
663 base = self.document(func, name + tag, mod,
664 funcs, classes, mdict, object)
665 push('<dd>%s</dd>\n' % base)
666 push('</dl>\n')
Tim Petersb47879b2001-09-24 04:47:19 +0000667 return attrs
668
Tim Petersfa26f7c2001-09-24 08:05:11 +0000669 def spilldata(msg, attrs, predicate):
670 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000671 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000672 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000673 push(msg)
674 for name, kind, homecls, value in ok:
675 base = self.docother(getattr(object, name), name, mod)
676 doc = getattr(value, "__doc__", None)
677 if doc is None:
678 push('<dl><dt>%s</dl>\n' % base)
679 else:
680 doc = self.markup(getdoc(value), self.preformat,
681 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000682 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000683 push('<dl><dt>%s%s</dl>\n' % (base, doc))
684 push('\n')
685 return attrs
686
687 attrs = inspect.classify_class_attrs(object)
688 mdict = {}
689 for key, kind, homecls, value in attrs:
690 mdict[key] = anchor = '#' + name + '-' + key
691 value = getattr(object, key)
692 try:
693 # The value may not be hashable (e.g., a data attr with
694 # a dict or list value).
695 mdict[value] = anchor
696 except TypeError:
697 pass
698
Tim Petersfa26f7c2001-09-24 08:05:11 +0000699 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000700 if mro:
701 thisclass = mro.pop(0)
702 else:
703 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000704 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
705
Tim Petersb47879b2001-09-24 04:47:19 +0000706 if thisclass is object:
707 tag = "defined here"
708 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000709 tag = "inherited from %s" % self.classlink(thisclass,
Tim Petersb47879b2001-09-24 04:47:19 +0000710 object.__module__)
711 tag += ':<br>\n'
712
713 # Sort attrs by name.
714 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
715
716 # Pump out the attrs, segregated by kind.
717 attrs = spill("Methods %s" % tag, attrs,
718 lambda t: t[1] == 'method')
719 attrs = spill("Class methods %s" % tag, attrs,
720 lambda t: t[1] == 'class method')
721 attrs = spill("Static methods %s" % tag, attrs,
722 lambda t: t[1] == 'static method')
Tim Petersfa26f7c2001-09-24 08:05:11 +0000723 attrs = spillproperties("Properties %s" % tag, attrs,
724 lambda t: t[1] == 'property')
Tim Petersf33532c2001-09-25 06:30:51 +0000725 attrs = spilldata("Data and non-method functions %s" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000726 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000727 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000728 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000729
730 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000731
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000732 if name == realname:
733 title = '<a name="%s">class <strong>%s</strong></a>' % (
734 name, realname)
735 else:
736 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
737 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000738 if bases:
739 parents = []
740 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000741 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000742 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000743 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
744 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc or '&nbsp;'
Tim Petersc86f6ca2001-09-26 21:31:51 +0000745
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000746 return self.section(title, '#000000', '#ffc8d8', contents, 5, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000747
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000748 def formatvalue(self, object):
749 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000750 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000751
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000752 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000753 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000754 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000755 realname = object.__name__
756 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000757 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000758 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000759 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000760 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000761 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000762 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000763 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000764 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000765 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000766 if object.im_self:
767 note = ' method of %s instance' % self.classlink(
768 object.im_self.__class__, mod)
769 else:
770 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000771 object = object.im_func
772
773 if name == realname:
774 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
775 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000776 if (cl and cl.__dict__.has_key(realname) and
777 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000778 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000779 cl.__name__ + '-' + realname, realname)
780 skipdocs = 1
781 else:
782 reallink = realname
783 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
784 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000785 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000786 args, varargs, varkw, defaults = inspect.getargspec(object)
787 argspec = inspect.formatargspec(
788 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000789 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000790 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000791 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000792 else:
793 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000794
Tim Peters2306d242001-09-25 03:18:32 +0000795 decl = title + argspec + (note and self.grey(
796 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000797
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000798 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000799 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000800 else:
801 doc = self.markup(
802 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000803 doc = doc and '<dd><tt>%s</tt></dd>' % doc
804 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000805
Tim Peters8dd7ade2001-10-18 19:56:17 +0000806 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000807 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000808 lhs = name and '<strong>%s</strong> = ' % name or ''
809 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000810
811 def index(self, dir, shadowed=None):
812 """Generate an HTML index for a directory of modules."""
813 modpkgs = []
814 if shadowed is None: shadowed = {}
815 seen = {}
816 files = os.listdir(dir)
817
818 def found(name, ispackage,
819 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
820 if not seen.has_key(name):
821 modpkgs.append((name, '', ispackage, shadowed.has_key(name)))
822 seen[name] = 1
823 shadowed[name] = 1
824
825 # Package spam/__init__.py takes precedence over module spam.py.
826 for file in files:
827 path = os.path.join(dir, file)
828 if ispackage(path): found(file, 1)
829 for file in files:
830 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000831 if os.path.isfile(path):
832 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000833 if modname: found(modname, 0)
834
835 modpkgs.sort()
836 contents = self.multicolumn(modpkgs, self.modpkglink)
837 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
838
839# -------------------------------------------- text documentation generator
840
841class TextRepr(Repr):
842 """Class for safely making a text representation of a Python object."""
843 def __init__(self):
844 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000845 self.maxlist = self.maxtuple = 20
846 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000847 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000848
849 def repr1(self, x, level):
850 methodname = 'repr_' + join(split(type(x).__name__), '_')
851 if hasattr(self, methodname):
852 return getattr(self, methodname)(x, level)
853 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000854 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000855
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000856 def repr_string(self, x, level):
857 test = cram(x, self.maxstring)
858 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000859 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000860 # Backslashes are only literal in the string and are never
861 # needed to make any special characters, so show a raw string.
862 return 'r' + testrepr[0] + test + testrepr[0]
863 return testrepr
864
Skip Montanarodf708782002-03-07 22:58:02 +0000865 repr_str = repr_string
866
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000867 def repr_instance(self, x, level):
868 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000869 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000870 except:
871 return '<%s instance>' % x.__class__.__name__
872
873class TextDoc(Doc):
874 """Formatter class for text documentation."""
875
876 # ------------------------------------------- text formatting utilities
877
878 _repr_instance = TextRepr()
879 repr = _repr_instance.repr
880
881 def bold(self, text):
882 """Format a string in bold by overstriking."""
883 return join(map(lambda ch: ch + '\b' + ch, text), '')
884
885 def indent(self, text, prefix=' '):
886 """Indent text by prepending a given prefix to each line."""
887 if not text: return ''
888 lines = split(text, '\n')
889 lines = map(lambda line, prefix=prefix: prefix + line, lines)
890 if lines: lines[-1] = rstrip(lines[-1])
891 return join(lines, '\n')
892
893 def section(self, title, contents):
894 """Format a section with a given heading."""
895 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
896
897 # ---------------------------------------------- type-specific routines
898
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000899 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000900 """Render in text a class tree as returned by inspect.getclasstree()."""
901 result = ''
902 for entry in tree:
903 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000904 c, bases = entry
905 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000906 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000907 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000908 result = result + '(%s)' % join(parents, ', ')
909 result = result + '\n'
910 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000911 result = result + self.formattree(
912 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000913 return result
914
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000915 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000916 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000917 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000918 synop, desc = splitdoc(getdoc(object))
919 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000920
921 try:
922 file = inspect.getabsfile(object)
923 except TypeError:
924 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000925 result = result + self.section('FILE', file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000926 if desc:
927 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000928
929 classes = []
930 for key, value in inspect.getmembers(object, inspect.isclass):
931 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000932 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000933 funcs = []
934 for key, value in inspect.getmembers(object, inspect.isroutine):
935 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000936 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000937 data = []
938 for key, value in inspect.getmembers(object, isdata):
939 if key not in ['__builtins__', '__doc__']:
940 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000941
942 if hasattr(object, '__path__'):
943 modpkgs = []
944 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000945 path = os.path.join(object.__path__[0], file)
946 modname = inspect.getmodulename(file)
947 if modname and modname not in modpkgs:
948 modpkgs.append(modname)
949 elif ispackage(path):
950 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000951 modpkgs.sort()
952 result = result + self.section(
953 'PACKAGE CONTENTS', join(modpkgs, '\n'))
954
955 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000956 classlist = map(lambda (key, value): value, classes)
957 contents = [self.formattree(
958 inspect.getclasstree(classlist, 1), name)]
959 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000960 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000961 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000962
963 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000964 contents = []
965 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000966 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000967 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000968
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000969 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000970 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000971 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000972 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000973 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000974
975 if hasattr(object, '__version__'):
976 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000977 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
978 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000979 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000980 if hasattr(object, '__date__'):
981 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000982 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000983 result = result + self.section('AUTHOR', str(object.__author__))
984 if hasattr(object, '__credits__'):
985 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000986 return result
987
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000988 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000989 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000990 realname = object.__name__
991 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000992 bases = object.__bases__
993
Tim Petersc86f6ca2001-09-26 21:31:51 +0000994 def makename(c, m=object.__module__):
995 return classname(c, m)
996
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000997 if name == realname:
998 title = 'class ' + self.bold(realname)
999 else:
1000 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001001 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001002 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001003 title = title + '(%s)' % join(parents, ', ')
1004
1005 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001006 contents = doc and [doc + '\n'] or []
1007 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001008
Tim Petersc86f6ca2001-09-26 21:31:51 +00001009 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +00001010 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001011 if len(mro) > 2:
1012 push("Method resolution order:")
1013 for base in mro:
1014 push(' ' + makename(base))
1015 push('')
1016
Tim Petersf4aad8e2001-09-24 22:40:47 +00001017 # Cute little class to pump out a horizontal rule between sections.
1018 class HorizontalRule:
1019 def __init__(self):
1020 self.needone = 0
1021 def maybe(self):
1022 if self.needone:
1023 push('-' * 70)
1024 self.needone = 1
1025 hr = HorizontalRule()
1026
Tim Peters28355492001-09-23 21:29:55 +00001027 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001028 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001029 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001030 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001031 push(msg)
1032 for name, kind, homecls, value in ok:
1033 push(self.document(getattr(object, name),
1034 name, mod, object))
1035 return attrs
1036
Tim Petersfa26f7c2001-09-24 08:05:11 +00001037 def spillproperties(msg, attrs, predicate):
1038 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001039 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001040 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001041 push(msg)
1042 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001043 push(name)
1044 need_blank_after_doc = 0
1045 doc = getdoc(value) or ''
1046 if doc:
1047 push(self.indent(doc))
1048 need_blank_after_doc = 1
Tim Petersf33532c2001-09-25 06:30:51 +00001049 for attr, tag in [("fget", " getter"),
1050 ("fset", " setter"),
Tim Petersf4aad8e2001-09-24 22:40:47 +00001051 ("fdel", " deleter")]:
1052 func = getattr(value, attr)
1053 if func is not None:
1054 if need_blank_after_doc:
1055 push('')
1056 need_blank_after_doc = 0
1057 base = self.docother(func, name + tag, mod, 70)
1058 push(self.indent(base))
1059 push('')
Tim Peters28355492001-09-23 21:29:55 +00001060 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001061
Tim Petersfa26f7c2001-09-24 08:05:11 +00001062 def spilldata(msg, attrs, predicate):
1063 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001064 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001065 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001066 push(msg)
1067 for name, kind, homecls, value in ok:
1068 doc = getattr(value, "__doc__", None)
1069 push(self.docother(getattr(object, name),
1070 name, mod, 70, doc) + '\n')
1071 return attrs
1072
1073 attrs = inspect.classify_class_attrs(object)
Tim Petersfa26f7c2001-09-24 08:05:11 +00001074 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001075 if mro:
1076 thisclass = mro.pop(0)
1077 else:
1078 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001079 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1080
Tim Peters28355492001-09-23 21:29:55 +00001081 if thisclass is object:
1082 tag = "defined here"
1083 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001084 tag = "inherited from %s" % classname(thisclass,
1085 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001086
1087 # Sort attrs by name.
1088 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
1089
1090 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001091 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001092 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001093 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001094 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001095 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001096 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001097 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001098 lambda t: t[1] == 'property')
Tim Petersf33532c2001-09-25 06:30:51 +00001099 attrs = spilldata("Data and non-method functions %s:\n" % tag,
1100 attrs, lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001101 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001102 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001103
1104 contents = '\n'.join(contents)
1105 if not contents:
1106 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001107 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1108
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001109 def formatvalue(self, object):
1110 """Format an argument default value as text."""
1111 return '=' + self.repr(object)
1112
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001113 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001114 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001115 realname = object.__name__
1116 name = name or realname
1117 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001118 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001119 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001120 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001121 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001122 if imclass is not cl:
1123 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001124 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001125 if object.im_self:
1126 note = ' method of %s instance' % classname(
1127 object.im_self.__class__, mod)
1128 else:
1129 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001130 object = object.im_func
1131
1132 if name == realname:
1133 title = self.bold(realname)
1134 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001135 if (cl and cl.__dict__.has_key(realname) and
1136 cl.__dict__[realname] is object):
1137 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001138 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001139 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001140 args, varargs, varkw, defaults = inspect.getargspec(object)
1141 argspec = inspect.formatargspec(
1142 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001143 if realname == '<lambda>':
1144 title = 'lambda'
1145 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001146 else:
1147 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001148 decl = title + argspec + note
1149
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001150 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001151 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001152 else:
1153 doc = getdoc(object) or ''
1154 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001155
Tim Peters28355492001-09-23 21:29:55 +00001156 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001157 """Produce text documentation for a data object."""
1158 repr = self.repr(object)
1159 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001160 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001161 chop = maxlen - len(line)
1162 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001163 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001164 if doc is not None:
1165 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001166 return line
1167
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001168# --------------------------------------------------------- user interfaces
1169
1170def pager(text):
1171 """The first time this is called, determine what kind of pager to use."""
1172 global pager
1173 pager = getpager()
1174 pager(text)
1175
1176def getpager():
1177 """Decide what method to use for paging through text."""
1178 if type(sys.stdout) is not types.FileType:
1179 return plainpager
1180 if not sys.stdin.isatty() or not sys.stdout.isatty():
1181 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001182 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001183 return plainpager
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001184 if os.environ.has_key('PAGER'):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001185 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001186 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1187 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1188 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001189 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001190 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001191 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001192 return lambda text: tempfilepager(plain(text), 'more <')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001193 if hasattr(os, 'system') and os.system('less 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001194 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001195
1196 import tempfile
1197 filename = tempfile.mktemp()
1198 open(filename, 'w').close()
1199 try:
1200 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1201 return lambda text: pipepager(text, 'more')
1202 else:
1203 return ttypager
1204 finally:
1205 os.unlink(filename)
1206
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001207def plain(text):
1208 """Remove boldface formatting from text."""
1209 return re.sub('.\b', '', text)
1210
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001211def pipepager(text, cmd):
1212 """Page through text by feeding it to another program."""
1213 pipe = os.popen(cmd, 'w')
1214 try:
1215 pipe.write(text)
1216 pipe.close()
1217 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001218 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001219
1220def tempfilepager(text, cmd):
1221 """Page through text by invoking a program on a temporary file."""
1222 import tempfile
1223 filename = tempfile.mktemp()
1224 file = open(filename, 'w')
1225 file.write(text)
1226 file.close()
1227 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001228 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001229 finally:
1230 os.unlink(filename)
1231
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001232def ttypager(text):
1233 """Page through text on a text terminal."""
1234 lines = split(plain(text), '\n')
1235 try:
1236 import tty
1237 fd = sys.stdin.fileno()
1238 old = tty.tcgetattr(fd)
1239 tty.setcbreak(fd)
1240 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001241 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001242 tty = None
1243 getchar = lambda: sys.stdin.readline()[:-1][:1]
1244
1245 try:
1246 r = inc = os.environ.get('LINES', 25) - 1
1247 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1248 while lines[r:]:
1249 sys.stdout.write('-- more --')
1250 sys.stdout.flush()
1251 c = getchar()
1252
1253 if c in ['q', 'Q']:
1254 sys.stdout.write('\r \r')
1255 break
1256 elif c in ['\r', '\n']:
1257 sys.stdout.write('\r \r' + lines[r] + '\n')
1258 r = r + 1
1259 continue
1260 if c in ['b', 'B', '\x1b']:
1261 r = r - inc - inc
1262 if r < 0: r = 0
1263 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1264 r = r + inc
1265
1266 finally:
1267 if tty:
1268 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1269
1270def plainpager(text):
1271 """Simply print unformatted text. This is the ultimate fallback."""
1272 sys.stdout.write(plain(text))
1273
1274def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001275 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001276 if inspect.ismodule(thing):
1277 if thing.__name__ in sys.builtin_module_names:
1278 return 'built-in module ' + thing.__name__
1279 if hasattr(thing, '__path__'):
1280 return 'package ' + thing.__name__
1281 else:
1282 return 'module ' + thing.__name__
1283 if inspect.isbuiltin(thing):
1284 return 'built-in function ' + thing.__name__
1285 if inspect.isclass(thing):
1286 return 'class ' + thing.__name__
1287 if inspect.isfunction(thing):
1288 return 'function ' + thing.__name__
1289 if inspect.ismethod(thing):
1290 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001291 if type(thing) is types.InstanceType:
1292 return 'instance of ' + thing.__class__.__name__
1293 return type(thing).__name__
1294
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001295def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001296 """Locate an object by name or dotted path, importing as necessary."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001297 parts = split(path, '.')
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001298 module, n = None, 0
1299 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001300 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001301 if nextmodule: module, n = nextmodule, n + 1
1302 else: break
1303 if module:
1304 object = module
1305 for part in parts[n:]:
1306 try: object = getattr(object, part)
1307 except AttributeError: return None
1308 return object
1309 else:
1310 import __builtin__
1311 if hasattr(__builtin__, path):
1312 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001313
1314# --------------------------------------- interactive interpreter interface
1315
1316text = TextDoc()
1317html = HTMLDoc()
1318
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001319def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001320 """Display text documentation, given an object or a path to an object."""
1321 suffix, name = '', None
1322 if type(thing) is type(''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001323 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001324 object = locate(thing, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001325 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001326 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001327 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001328 if not object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001329 print 'no Python documentation found for %s' % repr(thing)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001330 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001331 parts = split(thing, '.')
1332 if len(parts) > 1: suffix = ' in ' + join(parts[:-1], '.')
1333 name = parts[-1]
1334 thing = object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001335
1336 desc = describe(thing)
1337 module = inspect.getmodule(thing)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001338 if not suffix and module and module is not thing:
1339 suffix = ' in module ' + module.__name__
Ka-Ping Yee66246962001-04-12 11:59:50 +00001340 pager(title % (desc + suffix) + '\n\n' + text.document(thing, name))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001341
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001342def writedoc(key, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001343 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001344 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001345 object = locate(key, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001346 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001347 print value
1348 else:
1349 if object:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001350 page = html.page(describe(object),
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001351 html.document(object, object.__name__))
1352 file = open(key + '.html', 'w')
1353 file.write(page)
1354 file.close()
1355 print 'wrote', key + '.html'
1356 else:
1357 print 'no Python documentation found for %s' % repr(key)
1358
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001359def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001360 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001361 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001362 for file in os.listdir(dir):
1363 path = os.path.join(dir, file)
1364 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001365 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001366 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001367 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001368 if modname:
1369 modname = pkgpath + modname
1370 if not done.has_key(modname):
1371 done[modname] = 1
1372 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001373
1374class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001375 keywords = {
1376 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001377 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001378 'break': ('ref/break', 'while for'),
1379 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1380 'continue': ('ref/continue', 'while for'),
1381 'def': ('ref/function', ''),
1382 'del': ('ref/del', 'BASICMETHODS'),
1383 'elif': 'if',
1384 'else': ('ref/if', 'while for'),
1385 'except': 'try',
1386 'exec': ('ref/exec', ''),
1387 'finally': 'try',
1388 'for': ('ref/for', 'break continue while'),
1389 'from': 'import',
1390 'global': ('ref/global', 'NAMESPACES'),
1391 'if': ('ref/if', 'TRUTHVALUE'),
1392 'import': ('ref/import', 'MODULES'),
1393 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1394 'is': 'COMPARISON',
1395 'lambda': ('ref/lambda', 'FUNCTIONS'),
1396 'not': 'BOOLEAN',
1397 'or': 'BOOLEAN',
1398 'pass': 'PASS',
1399 'print': ('ref/print', ''),
1400 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001401 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001402 'try': ('ref/try', 'EXCEPTIONS'),
1403 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1404 }
1405
1406 topics = {
1407 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001408 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001409 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1410 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001411 'UNICODE': ('ref/unicode', 'encodings unicode TYPES STRING'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001412 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1413 'INTEGER': ('ref/integers', 'int range'),
1414 'FLOAT': ('ref/floating', 'float math'),
1415 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001416 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001417 'MAPPINGS': 'DICTIONARIES',
1418 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1419 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1420 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001421 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001422 'FRAMEOBJECTS': 'TYPES',
1423 'TRACEBACKS': 'TYPES',
1424 'NONE': ('lib/bltin-null-object', ''),
1425 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1426 'FILES': ('lib/bltin-file-objects', ''),
1427 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1428 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1429 'MODULES': ('lib/typesmodules', 'import'),
1430 'PACKAGES': 'import',
1431 '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'),
1432 'OPERATORS': 'EXPRESSIONS',
1433 'PRECEDENCE': 'EXPRESSIONS',
1434 'OBJECTS': ('ref/objects', 'TYPES'),
1435 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001436 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1437 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1438 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1439 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1440 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1441 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1442 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001443 'EXECUTION': ('ref/execframes', ''),
1444 'NAMESPACES': ('ref/execframes', 'global ASSIGNMENT DELETION'),
1445 'SCOPING': 'NAMESPACES',
1446 'FRAMES': 'NAMESPACES',
1447 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1448 'COERCIONS': 'CONVERSIONS',
1449 'CONVERSIONS': ('ref/conversions', ''),
1450 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1451 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001452 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001453 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1454 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001455 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001456 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001457 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001458 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001459 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1460 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001461 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1462 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1463 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1464 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1465 'POWER': ('ref/power', 'EXPRESSIONS'),
1466 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1467 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1468 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1469 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1470 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001471 'BOOLEAN': ('ref/lambda', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001472 'ASSERTION': 'assert',
1473 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001474 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001475 'DELETION': 'del',
1476 'PRINTING': 'print',
1477 'RETURNING': 'return',
1478 'IMPORTING': 'import',
1479 'CONDITIONAL': 'if',
1480 'LOOPING': ('ref/compound', 'for while break continue'),
1481 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001482 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001483 }
1484
1485 def __init__(self, input, output):
1486 self.input = input
1487 self.output = output
1488 self.docdir = None
1489 execdir = os.path.dirname(sys.executable)
1490 homedir = os.environ.get('PYTHONHOME')
1491 for dir in [os.environ.get('PYTHONDOCS'),
1492 homedir and os.path.join(homedir, 'doc'),
1493 os.path.join(execdir, 'doc'),
1494 '/usr/doc/python-docs-' + split(sys.version)[0],
1495 '/usr/doc/python-' + split(sys.version)[0],
1496 '/usr/doc/python-docs-' + sys.version[:3],
1497 '/usr/doc/python-' + sys.version[:3]]:
1498 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1499 self.docdir = dir
1500
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001501 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001502 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001503 self()
1504 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001505 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001506
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001507 def __call__(self, request=None):
1508 if request is not None:
1509 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001510 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001511 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001512 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001513 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001514You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001515If you want to ask for help on a particular object directly from the
1516interpreter, you can type "help(object)". Executing "help('string')"
1517has the same effect as typing a particular string at the help> prompt.
1518''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001519
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001520 def interact(self):
1521 self.output.write('\n')
1522 while 1:
1523 self.output.write('help> ')
1524 self.output.flush()
1525 try:
1526 request = self.input.readline()
1527 if not request: break
1528 except KeyboardInterrupt: break
1529 request = strip(replace(request, '"', '', "'", ''))
1530 if lower(request) in ['q', 'quit']: break
1531 self.help(request)
1532
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001533 def help(self, request):
1534 if type(request) is type(''):
1535 if request == 'help': self.intro()
1536 elif request == 'keywords': self.listkeywords()
1537 elif request == 'topics': self.listtopics()
1538 elif request == 'modules': self.listmodules()
1539 elif request[:8] == 'modules ':
1540 self.listmodules(split(request)[1])
1541 elif self.keywords.has_key(request): self.showtopic(request)
1542 elif self.topics.has_key(request): self.showtopic(request)
1543 elif request: doc(request, 'Help on %s:')
1544 elif isinstance(request, Helper): self()
1545 else: doc(request, 'Help on %s:')
1546 self.output.write('\n')
1547
1548 def intro(self):
1549 self.output.write('''
1550Welcome to Python %s! This is the online help utility.
1551
1552If this is your first time using Python, you should definitely check out
1553the tutorial on the Internet at http://www.python.org/doc/tut/.
1554
1555Enter the name of any module, keyword, or topic to get help on writing
1556Python programs and using Python modules. To quit this help utility and
1557return to the interpreter, just type "quit".
1558
1559To get a list of available modules, keywords, or topics, type "modules",
1560"keywords", or "topics". Each module also comes with a one-line summary
1561of what it does; to list the modules whose summaries contain a given word
1562such as "spam", type "modules spam".
1563''' % sys.version[:3])
1564
1565 def list(self, items, columns=4, width=80):
1566 items = items[:]
1567 items.sort()
1568 colw = width / columns
1569 rows = (len(items) + columns - 1) / columns
1570 for row in range(rows):
1571 for col in range(columns):
1572 i = col * rows + row
1573 if i < len(items):
1574 self.output.write(items[i])
1575 if col < columns - 1:
1576 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1577 self.output.write('\n')
1578
1579 def listkeywords(self):
1580 self.output.write('''
1581Here is a list of the Python keywords. Enter any keyword to get more help.
1582
1583''')
1584 self.list(self.keywords.keys())
1585
1586 def listtopics(self):
1587 self.output.write('''
1588Here is a list of available topics. Enter any topic name to get more help.
1589
1590''')
1591 self.list(self.topics.keys())
1592
1593 def showtopic(self, topic):
1594 if not self.docdir:
1595 self.output.write('''
1596Sorry, topic and keyword documentation is not available because the Python
1597HTML documentation files could not be found. If you have installed them,
1598please set the environment variable PYTHONDOCS to indicate their location.
1599''')
1600 return
1601 target = self.topics.get(topic, self.keywords.get(topic))
1602 if not target:
1603 self.output.write('no documentation found for %s\n' % repr(topic))
1604 return
1605 if type(target) is type(''):
1606 return self.showtopic(target)
1607
1608 filename, xrefs = target
1609 filename = self.docdir + '/' + filename + '.html'
1610 try:
1611 file = open(filename)
1612 except:
1613 self.output.write('could not read docs from %s\n' % filename)
1614 return
1615
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001616 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1617 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001618 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1619 file.close()
1620
1621 import htmllib, formatter, StringIO
1622 buffer = StringIO.StringIO()
1623 parser = htmllib.HTMLParser(
1624 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1625 parser.start_table = parser.do_p
1626 parser.end_table = lambda parser=parser: parser.do_p({})
1627 parser.start_tr = parser.do_br
1628 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1629 parser.feed(document)
1630 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1631 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001632 if xrefs:
1633 buffer = StringIO.StringIO()
1634 formatter.DumbWriter(buffer).send_flowing_data(
1635 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1636 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001637
1638 def listmodules(self, key=''):
1639 if key:
1640 self.output.write('''
1641Here is a list of matching modules. Enter any module name to get more help.
1642
1643''')
1644 apropos(key)
1645 else:
1646 self.output.write('''
1647Please wait a moment while I gather a list of all available modules...
1648
1649''')
1650 modules = {}
1651 def callback(path, modname, desc, modules=modules):
1652 if modname and modname[-9:] == '.__init__':
1653 modname = modname[:-9] + ' (package)'
1654 if find(modname, '.') < 0:
1655 modules[modname] = 1
1656 ModuleScanner().run(callback)
1657 self.list(modules.keys())
1658 self.output.write('''
1659Enter any module name to get more help. Or, type "modules spam" to search
1660for modules whose descriptions contain the word "spam".
1661''')
1662
1663help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001664
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001665class Scanner:
1666 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001667 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001668 self.roots = roots[:]
1669 self.state = []
1670 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001671 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001672
1673 def next(self):
1674 if not self.state:
1675 if not self.roots:
1676 return None
1677 root = self.roots.pop(0)
1678 self.state = [(root, self.children(root))]
1679 node, children = self.state[-1]
1680 if not children:
1681 self.state.pop()
1682 return self.next()
1683 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001684 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001685 self.state.append((child, self.children(child)))
1686 return child
1687
1688class ModuleScanner(Scanner):
1689 """An interruptible scanner that searches module synopses."""
1690 def __init__(self):
1691 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001692 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
1693 self.inodes = map(lambda (dir, pkg): os.stat(dir)[1], roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001694
1695 def submodules(self, (dir, package)):
1696 children = []
1697 for file in os.listdir(dir):
1698 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001699 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001700 children.append((path, package + (package and '.') + file))
1701 else:
1702 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001703 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001704 return children
1705
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001706 def isnewpackage(self, (dir, package)):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001707 inode = os.path.exists(dir) and os.stat(dir)[1]
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001708 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001709 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001710 return ispackage(dir)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001711
Ka-Ping Yee66246962001-04-12 11:59:50 +00001712 def run(self, callback, key=None, completer=None):
1713 if key: key = lower(key)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001714 self.quit = 0
1715 seen = {}
1716
1717 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001718 if modname != '__main__':
1719 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001720 if key is None:
1721 callback(None, modname, '')
1722 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001723 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001724 if find(lower(modname + ' - ' + desc), key) >= 0:
1725 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001726
1727 while not self.quit:
1728 node = self.next()
1729 if not node: break
1730 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001731 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001732 if os.path.isfile(path) and modname:
1733 modname = package + (package and '.') + modname
1734 if not seen.has_key(modname):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001735 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001736 if key is None:
1737 callback(path, modname, '')
1738 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001739 desc = synopsis(path) or ''
1740 if find(lower(modname + ' - ' + desc), key) >= 0:
1741 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001742 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001743
1744def apropos(key):
1745 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001746 def callback(path, modname, desc):
1747 if modname[-9:] == '.__init__':
1748 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001749 print modname, desc and '- ' + desc
1750 try: import warnings
1751 except ImportError: pass
1752 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001753 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001754
1755# --------------------------------------------------- web browser interface
1756
Ka-Ping Yee66246962001-04-12 11:59:50 +00001757def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001758 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001759
1760 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1761 class Message(mimetools.Message):
1762 def __init__(self, fp, seekable=1):
1763 Message = self.__class__
1764 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1765 self.encodingheader = self.getheader('content-transfer-encoding')
1766 self.typeheader = self.getheader('content-type')
1767 self.parsetype()
1768 self.parseplist()
1769
1770 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1771 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001772 try:
1773 self.send_response(200)
1774 self.send_header('Content-Type', 'text/html')
1775 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001776 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001777 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001778
1779 def do_GET(self):
1780 path = self.path
1781 if path[-5:] == '.html': path = path[:-5]
1782 if path[:1] == '/': path = path[1:]
1783 if path and path != '.':
1784 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001785 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001786 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001787 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001788 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001789 if obj:
1790 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001791 else:
1792 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001793'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001794 else:
1795 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001796'<big><big><strong>Python: Index of Modules</strong></big></big>',
1797'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001798 def bltinlink(name):
1799 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001800 names = filter(lambda x: x != '__main__',
1801 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001802 contents = html.multicolumn(names, bltinlink)
1803 indices = ['<p>' + html.bigsection(
1804 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1805
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001806 seen = {}
1807 for dir in pathdirs():
1808 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001809 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001810<font color="#909090" face="helvetica, arial"><strong>
1811pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001812 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001813
1814 def log_message(self, *args): pass
1815
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001816 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001817 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001818 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001819 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001820 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001821 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001822 self.base.__init__(self, self.address, self.handler)
1823
1824 def serve_until_quit(self):
1825 import select
1826 self.quit = 0
1827 while not self.quit:
1828 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1829 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001830
1831 def server_activate(self):
1832 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001833 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001834
1835 DocServer.base = BaseHTTPServer.HTTPServer
1836 DocServer.handler = DocHandler
1837 DocHandler.MessageClass = Message
1838 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001839 try:
1840 DocServer(port, callback).serve_until_quit()
1841 except (KeyboardInterrupt, select.error):
1842 pass
1843 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001844 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001845
1846# ----------------------------------------------------- graphical interface
1847
1848def gui():
1849 """Graphical interface (starts web server and pops up a control window)."""
1850 class GUI:
1851 def __init__(self, window, port=7464):
1852 self.window = window
1853 self.server = None
1854 self.scanner = None
1855
1856 import Tkinter
1857 self.server_frm = Tkinter.Frame(window)
1858 self.title_lbl = Tkinter.Label(self.server_frm,
1859 text='Starting server...\n ')
1860 self.open_btn = Tkinter.Button(self.server_frm,
1861 text='open browser', command=self.open, state='disabled')
1862 self.quit_btn = Tkinter.Button(self.server_frm,
1863 text='quit serving', command=self.quit, state='disabled')
1864
1865 self.search_frm = Tkinter.Frame(window)
1866 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1867 self.search_ent = Tkinter.Entry(self.search_frm)
1868 self.search_ent.bind('<Return>', self.search)
1869 self.stop_btn = Tkinter.Button(self.search_frm,
1870 text='stop', pady=0, command=self.stop, state='disabled')
1871 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001872 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001873 self.stop_btn.pack(side='right')
1874
1875 self.window.title('pydoc')
1876 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1877 self.title_lbl.pack(side='top', fill='x')
1878 self.open_btn.pack(side='left', fill='x', expand=1)
1879 self.quit_btn.pack(side='right', fill='x', expand=1)
1880 self.server_frm.pack(side='top', fill='x')
1881
1882 self.search_lbl.pack(side='left')
1883 self.search_ent.pack(side='right', fill='x', expand=1)
1884 self.search_frm.pack(side='top', fill='x')
1885 self.search_ent.focus_set()
1886
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001887 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001888 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001889 self.result_lst.bind('<Button-1>', self.select)
1890 self.result_lst.bind('<Double-Button-1>', self.goto)
1891 self.result_scr = Tkinter.Scrollbar(window,
1892 orient='vertical', command=self.result_lst.yview)
1893 self.result_lst.config(yscrollcommand=self.result_scr.set)
1894
1895 self.result_frm = Tkinter.Frame(window)
1896 self.goto_btn = Tkinter.Button(self.result_frm,
1897 text='go to selected', command=self.goto)
1898 self.hide_btn = Tkinter.Button(self.result_frm,
1899 text='hide results', command=self.hide)
1900 self.goto_btn.pack(side='left', fill='x', expand=1)
1901 self.hide_btn.pack(side='right', fill='x', expand=1)
1902
1903 self.window.update()
1904 self.minwidth = self.window.winfo_width()
1905 self.minheight = self.window.winfo_height()
1906 self.bigminheight = (self.server_frm.winfo_reqheight() +
1907 self.search_frm.winfo_reqheight() +
1908 self.result_lst.winfo_reqheight() +
1909 self.result_frm.winfo_reqheight())
1910 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1911 self.expanded = 0
1912 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1913 self.window.wm_minsize(self.minwidth, self.minheight)
1914
1915 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001916 threading.Thread(
1917 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001918
1919 def ready(self, server):
1920 self.server = server
1921 self.title_lbl.config(
1922 text='Python documentation server at\n' + server.url)
1923 self.open_btn.config(state='normal')
1924 self.quit_btn.config(state='normal')
1925
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001926 def open(self, event=None, url=None):
1927 url = url or self.server.url
1928 try:
1929 import webbrowser
1930 webbrowser.open(url)
1931 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001932 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001933 os.system('start "%s"' % url)
1934 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001935 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001936 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001937 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001938 else:
1939 rc = os.system('netscape -remote "openURL(%s)" &' % url)
1940 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001941
1942 def quit(self, event=None):
1943 if self.server:
1944 self.server.quit = 1
1945 self.window.quit()
1946
1947 def search(self, event=None):
1948 key = self.search_ent.get()
1949 self.stop_btn.pack(side='right')
1950 self.stop_btn.config(state='normal')
1951 self.search_lbl.config(text='Searching for "%s"...' % key)
1952 self.search_ent.forget()
1953 self.search_lbl.pack(side='left')
1954 self.result_lst.delete(0, 'end')
1955 self.goto_btn.config(state='disabled')
1956 self.expand()
1957
1958 import threading
1959 if self.scanner:
1960 self.scanner.quit = 1
1961 self.scanner = ModuleScanner()
1962 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00001963 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001964
1965 def update(self, path, modname, desc):
1966 if modname[-9:] == '.__init__':
1967 modname = modname[:-9] + ' (package)'
1968 self.result_lst.insert('end',
1969 modname + ' - ' + (desc or '(no description)'))
1970
1971 def stop(self, event=None):
1972 if self.scanner:
1973 self.scanner.quit = 1
1974 self.scanner = None
1975
1976 def done(self):
1977 self.scanner = None
1978 self.search_lbl.config(text='Search for')
1979 self.search_lbl.pack(side='left')
1980 self.search_ent.pack(side='right', fill='x', expand=1)
1981 if sys.platform != 'win32': self.stop_btn.forget()
1982 self.stop_btn.config(state='disabled')
1983
1984 def select(self, event=None):
1985 self.goto_btn.config(state='normal')
1986
1987 def goto(self, event=None):
1988 selection = self.result_lst.curselection()
1989 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001990 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001991 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001992
1993 def collapse(self):
1994 if not self.expanded: return
1995 self.result_frm.forget()
1996 self.result_scr.forget()
1997 self.result_lst.forget()
1998 self.bigwidth = self.window.winfo_width()
1999 self.bigheight = self.window.winfo_height()
2000 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2001 self.window.wm_minsize(self.minwidth, self.minheight)
2002 self.expanded = 0
2003
2004 def expand(self):
2005 if self.expanded: return
2006 self.result_frm.pack(side='bottom', fill='x')
2007 self.result_scr.pack(side='right', fill='y')
2008 self.result_lst.pack(side='top', fill='both', expand=1)
2009 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2010 self.window.wm_minsize(self.minwidth, self.bigminheight)
2011 self.expanded = 1
2012
2013 def hide(self, event=None):
2014 self.stop()
2015 self.collapse()
2016
2017 import Tkinter
2018 try:
2019 gui = GUI(Tkinter.Tk())
2020 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002021 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002022 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002023
2024# -------------------------------------------------- command-line interface
2025
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002026def ispath(x):
2027 return type(x) is types.StringType and find(x, os.sep) >= 0
2028
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002029def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002030 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002031 import getopt
2032 class BadUsage: pass
2033
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002034 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002035 scriptdir = os.path.dirname(sys.argv[0])
2036 if scriptdir in sys.path:
2037 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002038 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002039
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002040 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002041 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002042 writing = 0
2043
2044 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002045 if opt == '-g':
2046 gui()
2047 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002048 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002049 apropos(val)
2050 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002051 if opt == '-p':
2052 try:
2053 port = int(val)
2054 except ValueError:
2055 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002056 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002057 print 'pydoc server ready at %s' % server.url
2058 def stopped():
2059 print 'pydoc server stopped'
2060 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002061 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002062 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002063 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002064
2065 if not args: raise BadUsage
2066 for arg in args:
2067 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002068 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002069 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002070 if writing:
2071 if ispath(arg) and os.path.isdir(arg):
2072 writedocs(arg)
2073 else:
2074 writedoc(arg)
2075 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002076 doc(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002077 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002078 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002079
2080 except (getopt.error, BadUsage):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002081 cmd = sys.argv[0]
2082 print """pydoc - the Python documentation tool
2083
2084%s <name> ...
2085 Show text documentation on something. <name> may be the name of a
2086 function, module, or package, or a dotted reference to a class or
2087 function within a module or module in a package. If <name> contains
2088 a '%s', it is used as the path to a Python source file to document.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002089
2090%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002091 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002092
2093%s -p <port>
2094 Start an HTTP server on the given port on the local machine.
2095
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002096%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002097 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002098
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002099%s -w <name> ...
2100 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002101 directory. If <name> contains a '%s', it is treated as a filename; if
2102 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002103""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002104
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002105if __name__ == '__main__': cli()