blob: c27da11ad6feed263a8d008ae66ff03824e13197 [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+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000444 r'(self\.)?(\w+))')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000445 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:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000453 url = escape(all).replace('"', '&quot;')
454 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000455 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000456 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
457 results.append('<a href="%s">%s</a>' % (url, escape(all)))
458 elif pep:
459 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000460 results.append('<a href="%s">%s</a>' % (url, escape(all)))
461 elif text[end:end+1] == '(':
462 results.append(self.namelink(name, methods, funcs, classes))
463 elif selfdot:
464 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000465 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000466 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000467 here = end
468 results.append(escape(text[here:]))
469 return join(results, '')
470
471 # ---------------------------------------------- type-specific routines
472
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000473 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000474 """Produce HTML for a class tree as given by inspect.getclasstree()."""
475 result = ''
476 for entry in tree:
477 if type(entry) is type(()):
478 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000479 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000480 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000481 if bases and bases != (parent,):
482 parents = []
483 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000484 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000485 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000486 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000487 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000488 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000489 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000490 return '<dl>\n%s</dl>\n' % result
491
Tim Peters8dd7ade2001-10-18 19:56:17 +0000492 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000493 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000494 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000495 parts = split(name, '.')
496 links = []
497 for i in range(len(parts)-1):
498 links.append(
499 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
500 (join(parts[:i+1], '.'), parts[i]))
501 linkedname = join(links + parts[-1:], '.')
502 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000503 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000504 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000505 url = path
506 if sys.platform == 'win32':
507 import nturl2path
508 url = nturl2path.pathname2url(path)
509 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000510 except TypeError:
511 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000512 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000513 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000514 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000515 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
516 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000517 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000518 if hasattr(object, '__date__'):
519 info.append(self.escape(str(object.__date__)))
520 if info:
521 head = head + ' (%s)' % join(info, ', ')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000522 result = self.heading(
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000523 head, '#ffffff', '#7799ee', '<a href=".">index</a><br>' + filelink)
524
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000525 modules = inspect.getmembers(object, inspect.ismodule)
526
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000527 classes, cdict = [], {}
528 for key, value in inspect.getmembers(object, inspect.isclass):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000529 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000530 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000531 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000532 for key, value in classes:
533 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000534 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000535 module = sys.modules.get(modname)
536 if modname != name and module and hasattr(module, key):
537 if getattr(module, key) is base:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000538 if not cdict.has_key(key):
539 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000540 funcs, fdict = [], {}
541 for key, value in inspect.getmembers(object, inspect.isroutine):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000542 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000543 funcs.append((key, value))
544 fdict[key] = '#-' + key
545 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000546 data = []
547 for key, value in inspect.getmembers(object, isdata):
548 if key not in ['__builtins__', '__doc__']:
549 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000550
551 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
552 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000553 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000554
555 if hasattr(object, '__path__'):
556 modpkgs = []
557 modnames = []
558 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000559 path = os.path.join(object.__path__[0], file)
560 modname = inspect.getmodulename(file)
561 if modname and modname not in modnames:
562 modpkgs.append((modname, name, 0, 0))
563 modnames.append(modname)
564 elif ispackage(path):
565 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000566 modpkgs.sort()
567 contents = self.multicolumn(modpkgs, self.modpkglink)
568 result = result + self.bigsection(
569 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000570 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000571 contents = self.multicolumn(
572 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000573 result = result + self.bigsection(
574 'Modules', '#fffff', '#aa55cc', contents)
575
576 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000577 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000578 contents = [
579 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000580 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000581 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000582 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000583 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000584 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000585 contents = []
586 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000587 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000588 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000589 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000590 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000591 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000592 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000593 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000594 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000595 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000596 if hasattr(object, '__author__'):
597 contents = self.markup(str(object.__author__), self.preformat)
598 result = result + self.bigsection(
599 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000600 if hasattr(object, '__credits__'):
601 contents = self.markup(str(object.__credits__), self.preformat)
602 result = result + self.bigsection(
603 'Credits', '#ffffff', '#7799ee', contents)
604
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000605 return result
606
Tim Peters8dd7ade2001-10-18 19:56:17 +0000607 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
608 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000609 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000610 realname = object.__name__
611 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000612 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000613
Tim Petersb47879b2001-09-24 04:47:19 +0000614 contents = []
615 push = contents.append
616
Tim Petersfa26f7c2001-09-24 08:05:11 +0000617 # Cute little class to pump out a horizontal rule between sections.
618 class HorizontalRule:
619 def __init__(self):
620 self.needone = 0
621 def maybe(self):
622 if self.needone:
623 push('<hr>\n')
624 self.needone = 1
625 hr = HorizontalRule()
626
Tim Petersc86f6ca2001-09-26 21:31:51 +0000627 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +0000628 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000629 if len(mro) > 2:
630 hr.maybe()
631 push('<dl><dt>Method resolution order:</dt>\n')
632 for base in mro:
633 push('<dd>%s</dd>\n' % self.classlink(base,
634 object.__module__))
635 push('</dl>\n')
636
Tim Petersb47879b2001-09-24 04:47:19 +0000637 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000638 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000639 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000640 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000641 push(msg)
642 for name, kind, homecls, value in ok:
643 push(self.document(getattr(object, name), name, mod,
644 funcs, classes, mdict, object))
645 push('\n')
646 return attrs
647
Tim Petersfa26f7c2001-09-24 08:05:11 +0000648 def spillproperties(msg, attrs, predicate):
649 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000650 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000651 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000652 push(msg)
653 for name, kind, homecls, value in ok:
Tim Peters3e767d12001-09-25 00:01:06 +0000654 push('<dl><dt><strong>%s</strong></dt>\n' % name)
655 if value.__doc__ is not None:
656 doc = self.markup(value.__doc__, self.preformat,
657 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000658 push('<dd><tt>%s</tt></dd>\n' % doc)
Tim Petersf33532c2001-09-25 06:30:51 +0000659 for attr, tag in [("fget", " getter"),
660 ("fset", " setter"),
Tim Peters3e767d12001-09-25 00:01:06 +0000661 ("fdel", " deleter")]:
662 func = getattr(value, attr)
663 if func is not None:
664 base = self.document(func, name + tag, mod,
665 funcs, classes, mdict, object)
666 push('<dd>%s</dd>\n' % base)
667 push('</dl>\n')
Tim Petersb47879b2001-09-24 04:47:19 +0000668 return attrs
669
Tim Petersfa26f7c2001-09-24 08:05:11 +0000670 def spilldata(msg, attrs, predicate):
671 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000672 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000673 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000674 push(msg)
675 for name, kind, homecls, value in ok:
676 base = self.docother(getattr(object, name), name, mod)
677 doc = getattr(value, "__doc__", None)
678 if doc is None:
679 push('<dl><dt>%s</dl>\n' % base)
680 else:
681 doc = self.markup(getdoc(value), self.preformat,
682 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000683 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000684 push('<dl><dt>%s%s</dl>\n' % (base, doc))
685 push('\n')
686 return attrs
687
688 attrs = inspect.classify_class_attrs(object)
689 mdict = {}
690 for key, kind, homecls, value in attrs:
691 mdict[key] = anchor = '#' + name + '-' + key
692 value = getattr(object, key)
693 try:
694 # The value may not be hashable (e.g., a data attr with
695 # a dict or list value).
696 mdict[value] = anchor
697 except TypeError:
698 pass
699
Tim Petersfa26f7c2001-09-24 08:05:11 +0000700 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000701 if mro:
702 thisclass = mro.pop(0)
703 else:
704 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000705 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
706
Tim Petersb47879b2001-09-24 04:47:19 +0000707 if thisclass is object:
708 tag = "defined here"
709 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000710 tag = "inherited from %s" % self.classlink(thisclass,
Tim Petersb47879b2001-09-24 04:47:19 +0000711 object.__module__)
712 tag += ':<br>\n'
713
714 # Sort attrs by name.
715 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
716
717 # Pump out the attrs, segregated by kind.
718 attrs = spill("Methods %s" % tag, attrs,
719 lambda t: t[1] == 'method')
720 attrs = spill("Class methods %s" % tag, attrs,
721 lambda t: t[1] == 'class method')
722 attrs = spill("Static methods %s" % tag, attrs,
723 lambda t: t[1] == 'static method')
Tim Petersfa26f7c2001-09-24 08:05:11 +0000724 attrs = spillproperties("Properties %s" % tag, attrs,
725 lambda t: t[1] == 'property')
Tim Petersf33532c2001-09-25 06:30:51 +0000726 attrs = spilldata("Data and non-method functions %s" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000727 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000728 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000729 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000730
731 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000732
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000733 if name == realname:
734 title = '<a name="%s">class <strong>%s</strong></a>' % (
735 name, realname)
736 else:
737 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
738 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000739 if bases:
740 parents = []
741 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000742 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000743 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000744 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
745 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc or '&nbsp;'
Tim Petersc86f6ca2001-09-26 21:31:51 +0000746
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000747 return self.section(title, '#000000', '#ffc8d8', contents, 5, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000748
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000749 def formatvalue(self, object):
750 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000751 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000752
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000753 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000754 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000755 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000756 realname = object.__name__
757 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000758 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000759 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000760 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000761 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000762 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000763 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000764 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000765 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000766 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000767 if object.im_self:
768 note = ' method of %s instance' % self.classlink(
769 object.im_self.__class__, mod)
770 else:
771 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000772 object = object.im_func
773
774 if name == realname:
775 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
776 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000777 if (cl and cl.__dict__.has_key(realname) and
778 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000779 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000780 cl.__name__ + '-' + realname, realname)
781 skipdocs = 1
782 else:
783 reallink = realname
784 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
785 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000786 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000787 args, varargs, varkw, defaults = inspect.getargspec(object)
788 argspec = inspect.formatargspec(
789 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000790 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000791 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000792 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000793 else:
794 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000795
Tim Peters2306d242001-09-25 03:18:32 +0000796 decl = title + argspec + (note and self.grey(
797 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000798
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000799 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000800 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000801 else:
802 doc = self.markup(
803 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000804 doc = doc and '<dd><tt>%s</tt></dd>' % doc
805 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000806
Tim Peters8dd7ade2001-10-18 19:56:17 +0000807 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000808 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000809 lhs = name and '<strong>%s</strong> = ' % name or ''
810 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000811
812 def index(self, dir, shadowed=None):
813 """Generate an HTML index for a directory of modules."""
814 modpkgs = []
815 if shadowed is None: shadowed = {}
816 seen = {}
817 files = os.listdir(dir)
818
819 def found(name, ispackage,
820 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
821 if not seen.has_key(name):
822 modpkgs.append((name, '', ispackage, shadowed.has_key(name)))
823 seen[name] = 1
824 shadowed[name] = 1
825
826 # Package spam/__init__.py takes precedence over module spam.py.
827 for file in files:
828 path = os.path.join(dir, file)
829 if ispackage(path): found(file, 1)
830 for file in files:
831 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000832 if os.path.isfile(path):
833 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000834 if modname: found(modname, 0)
835
836 modpkgs.sort()
837 contents = self.multicolumn(modpkgs, self.modpkglink)
838 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
839
840# -------------------------------------------- text documentation generator
841
842class TextRepr(Repr):
843 """Class for safely making a text representation of a Python object."""
844 def __init__(self):
845 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000846 self.maxlist = self.maxtuple = 20
847 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000848 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000849
850 def repr1(self, x, level):
851 methodname = 'repr_' + join(split(type(x).__name__), '_')
852 if hasattr(self, methodname):
853 return getattr(self, methodname)(x, level)
854 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000855 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000856
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000857 def repr_string(self, x, level):
858 test = cram(x, self.maxstring)
859 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000860 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000861 # Backslashes are only literal in the string and are never
862 # needed to make any special characters, so show a raw string.
863 return 'r' + testrepr[0] + test + testrepr[0]
864 return testrepr
865
Skip Montanarodf708782002-03-07 22:58:02 +0000866 repr_str = repr_string
867
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000868 def repr_instance(self, x, level):
869 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000870 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000871 except:
872 return '<%s instance>' % x.__class__.__name__
873
874class TextDoc(Doc):
875 """Formatter class for text documentation."""
876
877 # ------------------------------------------- text formatting utilities
878
879 _repr_instance = TextRepr()
880 repr = _repr_instance.repr
881
882 def bold(self, text):
883 """Format a string in bold by overstriking."""
884 return join(map(lambda ch: ch + '\b' + ch, text), '')
885
886 def indent(self, text, prefix=' '):
887 """Indent text by prepending a given prefix to each line."""
888 if not text: return ''
889 lines = split(text, '\n')
890 lines = map(lambda line, prefix=prefix: prefix + line, lines)
891 if lines: lines[-1] = rstrip(lines[-1])
892 return join(lines, '\n')
893
894 def section(self, title, contents):
895 """Format a section with a given heading."""
896 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
897
898 # ---------------------------------------------- type-specific routines
899
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000900 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000901 """Render in text a class tree as returned by inspect.getclasstree()."""
902 result = ''
903 for entry in tree:
904 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000905 c, bases = entry
906 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000907 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000908 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000909 result = result + '(%s)' % join(parents, ', ')
910 result = result + '\n'
911 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000912 result = result + self.formattree(
913 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000914 return result
915
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000916 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000917 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000918 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000919 synop, desc = splitdoc(getdoc(object))
920 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000921
922 try:
923 file = inspect.getabsfile(object)
924 except TypeError:
925 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000926 result = result + self.section('FILE', file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000927 if desc:
928 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000929
930 classes = []
931 for key, value in inspect.getmembers(object, inspect.isclass):
932 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000933 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000934 funcs = []
935 for key, value in inspect.getmembers(object, inspect.isroutine):
936 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000937 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000938 data = []
939 for key, value in inspect.getmembers(object, isdata):
940 if key not in ['__builtins__', '__doc__']:
941 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000942
943 if hasattr(object, '__path__'):
944 modpkgs = []
945 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000946 path = os.path.join(object.__path__[0], file)
947 modname = inspect.getmodulename(file)
948 if modname and modname not in modpkgs:
949 modpkgs.append(modname)
950 elif ispackage(path):
951 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000952 modpkgs.sort()
953 result = result + self.section(
954 'PACKAGE CONTENTS', join(modpkgs, '\n'))
955
956 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000957 classlist = map(lambda (key, value): value, classes)
958 contents = [self.formattree(
959 inspect.getclasstree(classlist, 1), name)]
960 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000961 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000962 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000963
964 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000965 contents = []
966 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000967 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000968 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000969
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000970 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000971 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000972 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000973 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000974 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000975
976 if hasattr(object, '__version__'):
977 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000978 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
979 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000980 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000981 if hasattr(object, '__date__'):
982 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000983 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000984 result = result + self.section('AUTHOR', str(object.__author__))
985 if hasattr(object, '__credits__'):
986 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000987 return result
988
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000989 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000990 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000991 realname = object.__name__
992 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000993 bases = object.__bases__
994
Tim Petersc86f6ca2001-09-26 21:31:51 +0000995 def makename(c, m=object.__module__):
996 return classname(c, m)
997
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000998 if name == realname:
999 title = 'class ' + self.bold(realname)
1000 else:
1001 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001002 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001003 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001004 title = title + '(%s)' % join(parents, ', ')
1005
1006 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001007 contents = doc and [doc + '\n'] or []
1008 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001009
Tim Petersc86f6ca2001-09-26 21:31:51 +00001010 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +00001011 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001012 if len(mro) > 2:
1013 push("Method resolution order:")
1014 for base in mro:
1015 push(' ' + makename(base))
1016 push('')
1017
Tim Petersf4aad8e2001-09-24 22:40:47 +00001018 # Cute little class to pump out a horizontal rule between sections.
1019 class HorizontalRule:
1020 def __init__(self):
1021 self.needone = 0
1022 def maybe(self):
1023 if self.needone:
1024 push('-' * 70)
1025 self.needone = 1
1026 hr = HorizontalRule()
1027
Tim Peters28355492001-09-23 21:29:55 +00001028 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001029 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001030 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001031 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001032 push(msg)
1033 for name, kind, homecls, value in ok:
1034 push(self.document(getattr(object, name),
1035 name, mod, object))
1036 return attrs
1037
Tim Petersfa26f7c2001-09-24 08:05:11 +00001038 def spillproperties(msg, attrs, predicate):
1039 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001040 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001041 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001042 push(msg)
1043 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001044 push(name)
1045 need_blank_after_doc = 0
1046 doc = getdoc(value) or ''
1047 if doc:
1048 push(self.indent(doc))
1049 need_blank_after_doc = 1
Tim Petersf33532c2001-09-25 06:30:51 +00001050 for attr, tag in [("fget", " getter"),
1051 ("fset", " setter"),
Tim Petersf4aad8e2001-09-24 22:40:47 +00001052 ("fdel", " deleter")]:
1053 func = getattr(value, attr)
1054 if func is not None:
1055 if need_blank_after_doc:
1056 push('')
1057 need_blank_after_doc = 0
1058 base = self.docother(func, name + tag, mod, 70)
1059 push(self.indent(base))
1060 push('')
Tim Peters28355492001-09-23 21:29:55 +00001061 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001062
Tim Petersfa26f7c2001-09-24 08:05:11 +00001063 def spilldata(msg, attrs, predicate):
1064 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001065 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001066 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001067 push(msg)
1068 for name, kind, homecls, value in ok:
1069 doc = getattr(value, "__doc__", None)
1070 push(self.docother(getattr(object, name),
1071 name, mod, 70, doc) + '\n')
1072 return attrs
1073
1074 attrs = inspect.classify_class_attrs(object)
Tim Petersfa26f7c2001-09-24 08:05:11 +00001075 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001076 if mro:
1077 thisclass = mro.pop(0)
1078 else:
1079 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001080 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1081
Tim Peters28355492001-09-23 21:29:55 +00001082 if thisclass is object:
1083 tag = "defined here"
1084 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001085 tag = "inherited from %s" % classname(thisclass,
1086 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001087
1088 # Sort attrs by name.
1089 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
1090
1091 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001092 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001093 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001094 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001095 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001096 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001097 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001098 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001099 lambda t: t[1] == 'property')
Tim Petersf33532c2001-09-25 06:30:51 +00001100 attrs = spilldata("Data and non-method functions %s:\n" % tag,
1101 attrs, lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001102 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001103 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001104
1105 contents = '\n'.join(contents)
1106 if not contents:
1107 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001108 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1109
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001110 def formatvalue(self, object):
1111 """Format an argument default value as text."""
1112 return '=' + self.repr(object)
1113
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001114 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001115 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001116 realname = object.__name__
1117 name = name or realname
1118 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001119 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001120 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001121 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001122 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001123 if imclass is not cl:
1124 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001125 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001126 if object.im_self:
1127 note = ' method of %s instance' % classname(
1128 object.im_self.__class__, mod)
1129 else:
1130 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001131 object = object.im_func
1132
1133 if name == realname:
1134 title = self.bold(realname)
1135 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001136 if (cl and cl.__dict__.has_key(realname) and
1137 cl.__dict__[realname] is object):
1138 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001139 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001140 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001141 args, varargs, varkw, defaults = inspect.getargspec(object)
1142 argspec = inspect.formatargspec(
1143 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001144 if realname == '<lambda>':
1145 title = 'lambda'
1146 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001147 else:
1148 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001149 decl = title + argspec + note
1150
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001151 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001152 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001153 else:
1154 doc = getdoc(object) or ''
1155 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001156
Tim Peters28355492001-09-23 21:29:55 +00001157 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001158 """Produce text documentation for a data object."""
1159 repr = self.repr(object)
1160 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001161 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001162 chop = maxlen - len(line)
1163 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001164 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001165 if doc is not None:
1166 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001167 return line
1168
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001169# --------------------------------------------------------- user interfaces
1170
1171def pager(text):
1172 """The first time this is called, determine what kind of pager to use."""
1173 global pager
1174 pager = getpager()
1175 pager(text)
1176
1177def getpager():
1178 """Decide what method to use for paging through text."""
1179 if type(sys.stdout) is not types.FileType:
1180 return plainpager
1181 if not sys.stdin.isatty() or not sys.stdout.isatty():
1182 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001183 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001184 return plainpager
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001185 if os.environ.has_key('PAGER'):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001186 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001187 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1188 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1189 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001190 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001191 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001192 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001193 return lambda text: tempfilepager(plain(text), 'more <')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001194 if hasattr(os, 'system') and os.system('less 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001195 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001196
1197 import tempfile
1198 filename = tempfile.mktemp()
1199 open(filename, 'w').close()
1200 try:
1201 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1202 return lambda text: pipepager(text, 'more')
1203 else:
1204 return ttypager
1205 finally:
1206 os.unlink(filename)
1207
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001208def plain(text):
1209 """Remove boldface formatting from text."""
1210 return re.sub('.\b', '', text)
1211
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001212def pipepager(text, cmd):
1213 """Page through text by feeding it to another program."""
1214 pipe = os.popen(cmd, 'w')
1215 try:
1216 pipe.write(text)
1217 pipe.close()
1218 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001219 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001220
1221def tempfilepager(text, cmd):
1222 """Page through text by invoking a program on a temporary file."""
1223 import tempfile
1224 filename = tempfile.mktemp()
1225 file = open(filename, 'w')
1226 file.write(text)
1227 file.close()
1228 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001229 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001230 finally:
1231 os.unlink(filename)
1232
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001233def ttypager(text):
1234 """Page through text on a text terminal."""
1235 lines = split(plain(text), '\n')
1236 try:
1237 import tty
1238 fd = sys.stdin.fileno()
1239 old = tty.tcgetattr(fd)
1240 tty.setcbreak(fd)
1241 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001242 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001243 tty = None
1244 getchar = lambda: sys.stdin.readline()[:-1][:1]
1245
1246 try:
1247 r = inc = os.environ.get('LINES', 25) - 1
1248 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1249 while lines[r:]:
1250 sys.stdout.write('-- more --')
1251 sys.stdout.flush()
1252 c = getchar()
1253
1254 if c in ['q', 'Q']:
1255 sys.stdout.write('\r \r')
1256 break
1257 elif c in ['\r', '\n']:
1258 sys.stdout.write('\r \r' + lines[r] + '\n')
1259 r = r + 1
1260 continue
1261 if c in ['b', 'B', '\x1b']:
1262 r = r - inc - inc
1263 if r < 0: r = 0
1264 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1265 r = r + inc
1266
1267 finally:
1268 if tty:
1269 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1270
1271def plainpager(text):
1272 """Simply print unformatted text. This is the ultimate fallback."""
1273 sys.stdout.write(plain(text))
1274
1275def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001276 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001277 if inspect.ismodule(thing):
1278 if thing.__name__ in sys.builtin_module_names:
1279 return 'built-in module ' + thing.__name__
1280 if hasattr(thing, '__path__'):
1281 return 'package ' + thing.__name__
1282 else:
1283 return 'module ' + thing.__name__
1284 if inspect.isbuiltin(thing):
1285 return 'built-in function ' + thing.__name__
1286 if inspect.isclass(thing):
1287 return 'class ' + thing.__name__
1288 if inspect.isfunction(thing):
1289 return 'function ' + thing.__name__
1290 if inspect.ismethod(thing):
1291 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001292 if type(thing) is types.InstanceType:
1293 return 'instance of ' + thing.__class__.__name__
1294 return type(thing).__name__
1295
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001296def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001297 """Locate an object by name or dotted path, importing as necessary."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001298 parts = split(path, '.')
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001299 module, n = None, 0
1300 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001301 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001302 if nextmodule: module, n = nextmodule, n + 1
1303 else: break
1304 if module:
1305 object = module
1306 for part in parts[n:]:
1307 try: object = getattr(object, part)
1308 except AttributeError: return None
1309 return object
1310 else:
1311 import __builtin__
1312 if hasattr(__builtin__, path):
1313 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001314
1315# --------------------------------------- interactive interpreter interface
1316
1317text = TextDoc()
1318html = HTMLDoc()
1319
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001320def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001321 """Display text documentation, given an object or a path to an object."""
1322 suffix, name = '', None
1323 if type(thing) is type(''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001324 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001325 object = locate(thing, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001326 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001327 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001328 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001329 if not object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001330 print 'no Python documentation found for %s' % repr(thing)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001331 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001332 parts = split(thing, '.')
1333 if len(parts) > 1: suffix = ' in ' + join(parts[:-1], '.')
1334 name = parts[-1]
1335 thing = object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001336
1337 desc = describe(thing)
1338 module = inspect.getmodule(thing)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001339 if not suffix and module and module is not thing:
1340 suffix = ' in module ' + module.__name__
Ka-Ping Yee66246962001-04-12 11:59:50 +00001341 pager(title % (desc + suffix) + '\n\n' + text.document(thing, name))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001342
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001343def writedoc(key, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001344 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001345 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001346 object = locate(key, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001347 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001348 print value
1349 else:
1350 if object:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001351 page = html.page(describe(object),
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001352 html.document(object, object.__name__))
1353 file = open(key + '.html', 'w')
1354 file.write(page)
1355 file.close()
1356 print 'wrote', key + '.html'
1357 else:
1358 print 'no Python documentation found for %s' % repr(key)
1359
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001360def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001361 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001362 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001363 for file in os.listdir(dir):
1364 path = os.path.join(dir, file)
1365 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001366 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001367 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001368 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001369 if modname:
1370 modname = pkgpath + modname
1371 if not done.has_key(modname):
1372 done[modname] = 1
1373 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001374
1375class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001376 keywords = {
1377 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001378 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001379 'break': ('ref/break', 'while for'),
1380 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1381 'continue': ('ref/continue', 'while for'),
1382 'def': ('ref/function', ''),
1383 'del': ('ref/del', 'BASICMETHODS'),
1384 'elif': 'if',
1385 'else': ('ref/if', 'while for'),
1386 'except': 'try',
1387 'exec': ('ref/exec', ''),
1388 'finally': 'try',
1389 'for': ('ref/for', 'break continue while'),
1390 'from': 'import',
1391 'global': ('ref/global', 'NAMESPACES'),
1392 'if': ('ref/if', 'TRUTHVALUE'),
1393 'import': ('ref/import', 'MODULES'),
1394 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1395 'is': 'COMPARISON',
1396 'lambda': ('ref/lambda', 'FUNCTIONS'),
1397 'not': 'BOOLEAN',
1398 'or': 'BOOLEAN',
1399 'pass': 'PASS',
1400 'print': ('ref/print', ''),
1401 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001402 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001403 'try': ('ref/try', 'EXCEPTIONS'),
1404 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1405 }
1406
1407 topics = {
1408 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001409 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001410 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1411 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001412 'UNICODE': ('ref/unicode', 'encodings unicode TYPES STRING'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001413 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1414 'INTEGER': ('ref/integers', 'int range'),
1415 'FLOAT': ('ref/floating', 'float math'),
1416 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001417 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001418 'MAPPINGS': 'DICTIONARIES',
1419 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1420 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1421 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001422 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001423 'FRAMEOBJECTS': 'TYPES',
1424 'TRACEBACKS': 'TYPES',
1425 'NONE': ('lib/bltin-null-object', ''),
1426 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1427 'FILES': ('lib/bltin-file-objects', ''),
1428 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1429 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1430 'MODULES': ('lib/typesmodules', 'import'),
1431 'PACKAGES': 'import',
1432 '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'),
1433 'OPERATORS': 'EXPRESSIONS',
1434 'PRECEDENCE': 'EXPRESSIONS',
1435 'OBJECTS': ('ref/objects', 'TYPES'),
1436 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001437 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1438 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1439 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1440 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1441 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1442 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1443 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001444 'EXECUTION': ('ref/execframes', ''),
1445 'NAMESPACES': ('ref/execframes', 'global ASSIGNMENT DELETION'),
1446 'SCOPING': 'NAMESPACES',
1447 'FRAMES': 'NAMESPACES',
1448 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1449 'COERCIONS': 'CONVERSIONS',
1450 'CONVERSIONS': ('ref/conversions', ''),
1451 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1452 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001453 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001454 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1455 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001456 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001457 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001458 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001459 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001460 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1461 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001462 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1463 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1464 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1465 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1466 'POWER': ('ref/power', 'EXPRESSIONS'),
1467 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1468 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1469 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1470 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1471 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001472 'BOOLEAN': ('ref/lambda', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001473 'ASSERTION': 'assert',
1474 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001475 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001476 'DELETION': 'del',
1477 'PRINTING': 'print',
1478 'RETURNING': 'return',
1479 'IMPORTING': 'import',
1480 'CONDITIONAL': 'if',
1481 'LOOPING': ('ref/compound', 'for while break continue'),
1482 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001483 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001484 }
1485
1486 def __init__(self, input, output):
1487 self.input = input
1488 self.output = output
1489 self.docdir = None
1490 execdir = os.path.dirname(sys.executable)
1491 homedir = os.environ.get('PYTHONHOME')
1492 for dir in [os.environ.get('PYTHONDOCS'),
1493 homedir and os.path.join(homedir, 'doc'),
1494 os.path.join(execdir, 'doc'),
1495 '/usr/doc/python-docs-' + split(sys.version)[0],
1496 '/usr/doc/python-' + split(sys.version)[0],
1497 '/usr/doc/python-docs-' + sys.version[:3],
1498 '/usr/doc/python-' + sys.version[:3]]:
1499 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1500 self.docdir = dir
1501
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001502 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001503 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001504 self()
1505 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001506 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001507
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001508 def __call__(self, request=None):
1509 if request is not None:
1510 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001511 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001512 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001513 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001514 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001515You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001516If you want to ask for help on a particular object directly from the
1517interpreter, you can type "help(object)". Executing "help('string')"
1518has the same effect as typing a particular string at the help> prompt.
1519''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001520
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001521 def interact(self):
1522 self.output.write('\n')
1523 while 1:
1524 self.output.write('help> ')
1525 self.output.flush()
1526 try:
1527 request = self.input.readline()
1528 if not request: break
1529 except KeyboardInterrupt: break
1530 request = strip(replace(request, '"', '', "'", ''))
1531 if lower(request) in ['q', 'quit']: break
1532 self.help(request)
1533
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001534 def help(self, request):
1535 if type(request) is type(''):
1536 if request == 'help': self.intro()
1537 elif request == 'keywords': self.listkeywords()
1538 elif request == 'topics': self.listtopics()
1539 elif request == 'modules': self.listmodules()
1540 elif request[:8] == 'modules ':
1541 self.listmodules(split(request)[1])
1542 elif self.keywords.has_key(request): self.showtopic(request)
1543 elif self.topics.has_key(request): self.showtopic(request)
1544 elif request: doc(request, 'Help on %s:')
1545 elif isinstance(request, Helper): self()
1546 else: doc(request, 'Help on %s:')
1547 self.output.write('\n')
1548
1549 def intro(self):
1550 self.output.write('''
1551Welcome to Python %s! This is the online help utility.
1552
1553If this is your first time using Python, you should definitely check out
1554the tutorial on the Internet at http://www.python.org/doc/tut/.
1555
1556Enter the name of any module, keyword, or topic to get help on writing
1557Python programs and using Python modules. To quit this help utility and
1558return to the interpreter, just type "quit".
1559
1560To get a list of available modules, keywords, or topics, type "modules",
1561"keywords", or "topics". Each module also comes with a one-line summary
1562of what it does; to list the modules whose summaries contain a given word
1563such as "spam", type "modules spam".
1564''' % sys.version[:3])
1565
1566 def list(self, items, columns=4, width=80):
1567 items = items[:]
1568 items.sort()
1569 colw = width / columns
1570 rows = (len(items) + columns - 1) / columns
1571 for row in range(rows):
1572 for col in range(columns):
1573 i = col * rows + row
1574 if i < len(items):
1575 self.output.write(items[i])
1576 if col < columns - 1:
1577 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1578 self.output.write('\n')
1579
1580 def listkeywords(self):
1581 self.output.write('''
1582Here is a list of the Python keywords. Enter any keyword to get more help.
1583
1584''')
1585 self.list(self.keywords.keys())
1586
1587 def listtopics(self):
1588 self.output.write('''
1589Here is a list of available topics. Enter any topic name to get more help.
1590
1591''')
1592 self.list(self.topics.keys())
1593
1594 def showtopic(self, topic):
1595 if not self.docdir:
1596 self.output.write('''
1597Sorry, topic and keyword documentation is not available because the Python
1598HTML documentation files could not be found. If you have installed them,
1599please set the environment variable PYTHONDOCS to indicate their location.
1600''')
1601 return
1602 target = self.topics.get(topic, self.keywords.get(topic))
1603 if not target:
1604 self.output.write('no documentation found for %s\n' % repr(topic))
1605 return
1606 if type(target) is type(''):
1607 return self.showtopic(target)
1608
1609 filename, xrefs = target
1610 filename = self.docdir + '/' + filename + '.html'
1611 try:
1612 file = open(filename)
1613 except:
1614 self.output.write('could not read docs from %s\n' % filename)
1615 return
1616
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001617 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1618 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001619 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1620 file.close()
1621
1622 import htmllib, formatter, StringIO
1623 buffer = StringIO.StringIO()
1624 parser = htmllib.HTMLParser(
1625 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1626 parser.start_table = parser.do_p
1627 parser.end_table = lambda parser=parser: parser.do_p({})
1628 parser.start_tr = parser.do_br
1629 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1630 parser.feed(document)
1631 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1632 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001633 if xrefs:
1634 buffer = StringIO.StringIO()
1635 formatter.DumbWriter(buffer).send_flowing_data(
1636 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1637 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001638
1639 def listmodules(self, key=''):
1640 if key:
1641 self.output.write('''
1642Here is a list of matching modules. Enter any module name to get more help.
1643
1644''')
1645 apropos(key)
1646 else:
1647 self.output.write('''
1648Please wait a moment while I gather a list of all available modules...
1649
1650''')
1651 modules = {}
1652 def callback(path, modname, desc, modules=modules):
1653 if modname and modname[-9:] == '.__init__':
1654 modname = modname[:-9] + ' (package)'
1655 if find(modname, '.') < 0:
1656 modules[modname] = 1
1657 ModuleScanner().run(callback)
1658 self.list(modules.keys())
1659 self.output.write('''
1660Enter any module name to get more help. Or, type "modules spam" to search
1661for modules whose descriptions contain the word "spam".
1662''')
1663
1664help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001665
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001666class Scanner:
1667 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001668 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001669 self.roots = roots[:]
1670 self.state = []
1671 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001672 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001673
1674 def next(self):
1675 if not self.state:
1676 if not self.roots:
1677 return None
1678 root = self.roots.pop(0)
1679 self.state = [(root, self.children(root))]
1680 node, children = self.state[-1]
1681 if not children:
1682 self.state.pop()
1683 return self.next()
1684 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001685 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001686 self.state.append((child, self.children(child)))
1687 return child
1688
1689class ModuleScanner(Scanner):
1690 """An interruptible scanner that searches module synopses."""
1691 def __init__(self):
1692 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001693 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
1694 self.inodes = map(lambda (dir, pkg): os.stat(dir)[1], roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001695
1696 def submodules(self, (dir, package)):
1697 children = []
1698 for file in os.listdir(dir):
1699 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001700 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001701 children.append((path, package + (package and '.') + file))
1702 else:
1703 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001704 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001705 return children
1706
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001707 def isnewpackage(self, (dir, package)):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001708 inode = os.path.exists(dir) and os.stat(dir)[1]
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001709 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001710 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001711 return ispackage(dir)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001712
Ka-Ping Yee66246962001-04-12 11:59:50 +00001713 def run(self, callback, key=None, completer=None):
1714 if key: key = lower(key)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001715 self.quit = 0
1716 seen = {}
1717
1718 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001719 if modname != '__main__':
1720 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001721 if key is None:
1722 callback(None, modname, '')
1723 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001724 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001725 if find(lower(modname + ' - ' + desc), key) >= 0:
1726 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001727
1728 while not self.quit:
1729 node = self.next()
1730 if not node: break
1731 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001732 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001733 if os.path.isfile(path) and modname:
1734 modname = package + (package and '.') + modname
1735 if not seen.has_key(modname):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001736 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001737 if key is None:
1738 callback(path, modname, '')
1739 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001740 desc = synopsis(path) or ''
1741 if find(lower(modname + ' - ' + desc), key) >= 0:
1742 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001743 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001744
1745def apropos(key):
1746 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001747 def callback(path, modname, desc):
1748 if modname[-9:] == '.__init__':
1749 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001750 print modname, desc and '- ' + desc
1751 try: import warnings
1752 except ImportError: pass
1753 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001754 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001755
1756# --------------------------------------------------- web browser interface
1757
Ka-Ping Yee66246962001-04-12 11:59:50 +00001758def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001759 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001760
1761 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1762 class Message(mimetools.Message):
1763 def __init__(self, fp, seekable=1):
1764 Message = self.__class__
1765 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1766 self.encodingheader = self.getheader('content-transfer-encoding')
1767 self.typeheader = self.getheader('content-type')
1768 self.parsetype()
1769 self.parseplist()
1770
1771 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1772 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001773 try:
1774 self.send_response(200)
1775 self.send_header('Content-Type', 'text/html')
1776 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001777 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001778 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001779
1780 def do_GET(self):
1781 path = self.path
1782 if path[-5:] == '.html': path = path[:-5]
1783 if path[:1] == '/': path = path[1:]
1784 if path and path != '.':
1785 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001786 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001787 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001788 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001789 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001790 if obj:
1791 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001792 else:
1793 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001794'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001795 else:
1796 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001797'<big><big><strong>Python: Index of Modules</strong></big></big>',
1798'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001799 def bltinlink(name):
1800 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001801 names = filter(lambda x: x != '__main__',
1802 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001803 contents = html.multicolumn(names, bltinlink)
1804 indices = ['<p>' + html.bigsection(
1805 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1806
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001807 seen = {}
1808 for dir in pathdirs():
1809 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001810 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001811<font color="#909090" face="helvetica, arial"><strong>
1812pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001813 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001814
1815 def log_message(self, *args): pass
1816
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001817 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001818 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001819 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001820 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001821 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001822 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001823 self.base.__init__(self, self.address, self.handler)
1824
1825 def serve_until_quit(self):
1826 import select
1827 self.quit = 0
1828 while not self.quit:
1829 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1830 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001831
1832 def server_activate(self):
1833 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001834 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001835
1836 DocServer.base = BaseHTTPServer.HTTPServer
1837 DocServer.handler = DocHandler
1838 DocHandler.MessageClass = Message
1839 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001840 try:
1841 DocServer(port, callback).serve_until_quit()
1842 except (KeyboardInterrupt, select.error):
1843 pass
1844 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001845 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001846
1847# ----------------------------------------------------- graphical interface
1848
1849def gui():
1850 """Graphical interface (starts web server and pops up a control window)."""
1851 class GUI:
1852 def __init__(self, window, port=7464):
1853 self.window = window
1854 self.server = None
1855 self.scanner = None
1856
1857 import Tkinter
1858 self.server_frm = Tkinter.Frame(window)
1859 self.title_lbl = Tkinter.Label(self.server_frm,
1860 text='Starting server...\n ')
1861 self.open_btn = Tkinter.Button(self.server_frm,
1862 text='open browser', command=self.open, state='disabled')
1863 self.quit_btn = Tkinter.Button(self.server_frm,
1864 text='quit serving', command=self.quit, state='disabled')
1865
1866 self.search_frm = Tkinter.Frame(window)
1867 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1868 self.search_ent = Tkinter.Entry(self.search_frm)
1869 self.search_ent.bind('<Return>', self.search)
1870 self.stop_btn = Tkinter.Button(self.search_frm,
1871 text='stop', pady=0, command=self.stop, state='disabled')
1872 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001873 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001874 self.stop_btn.pack(side='right')
1875
1876 self.window.title('pydoc')
1877 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1878 self.title_lbl.pack(side='top', fill='x')
1879 self.open_btn.pack(side='left', fill='x', expand=1)
1880 self.quit_btn.pack(side='right', fill='x', expand=1)
1881 self.server_frm.pack(side='top', fill='x')
1882
1883 self.search_lbl.pack(side='left')
1884 self.search_ent.pack(side='right', fill='x', expand=1)
1885 self.search_frm.pack(side='top', fill='x')
1886 self.search_ent.focus_set()
1887
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001888 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001889 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001890 self.result_lst.bind('<Button-1>', self.select)
1891 self.result_lst.bind('<Double-Button-1>', self.goto)
1892 self.result_scr = Tkinter.Scrollbar(window,
1893 orient='vertical', command=self.result_lst.yview)
1894 self.result_lst.config(yscrollcommand=self.result_scr.set)
1895
1896 self.result_frm = Tkinter.Frame(window)
1897 self.goto_btn = Tkinter.Button(self.result_frm,
1898 text='go to selected', command=self.goto)
1899 self.hide_btn = Tkinter.Button(self.result_frm,
1900 text='hide results', command=self.hide)
1901 self.goto_btn.pack(side='left', fill='x', expand=1)
1902 self.hide_btn.pack(side='right', fill='x', expand=1)
1903
1904 self.window.update()
1905 self.minwidth = self.window.winfo_width()
1906 self.minheight = self.window.winfo_height()
1907 self.bigminheight = (self.server_frm.winfo_reqheight() +
1908 self.search_frm.winfo_reqheight() +
1909 self.result_lst.winfo_reqheight() +
1910 self.result_frm.winfo_reqheight())
1911 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1912 self.expanded = 0
1913 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1914 self.window.wm_minsize(self.minwidth, self.minheight)
1915
1916 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001917 threading.Thread(
1918 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001919
1920 def ready(self, server):
1921 self.server = server
1922 self.title_lbl.config(
1923 text='Python documentation server at\n' + server.url)
1924 self.open_btn.config(state='normal')
1925 self.quit_btn.config(state='normal')
1926
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001927 def open(self, event=None, url=None):
1928 url = url or self.server.url
1929 try:
1930 import webbrowser
1931 webbrowser.open(url)
1932 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001933 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001934 os.system('start "%s"' % url)
1935 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001936 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001937 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001938 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001939 else:
1940 rc = os.system('netscape -remote "openURL(%s)" &' % url)
1941 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001942
1943 def quit(self, event=None):
1944 if self.server:
1945 self.server.quit = 1
1946 self.window.quit()
1947
1948 def search(self, event=None):
1949 key = self.search_ent.get()
1950 self.stop_btn.pack(side='right')
1951 self.stop_btn.config(state='normal')
1952 self.search_lbl.config(text='Searching for "%s"...' % key)
1953 self.search_ent.forget()
1954 self.search_lbl.pack(side='left')
1955 self.result_lst.delete(0, 'end')
1956 self.goto_btn.config(state='disabled')
1957 self.expand()
1958
1959 import threading
1960 if self.scanner:
1961 self.scanner.quit = 1
1962 self.scanner = ModuleScanner()
1963 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00001964 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001965
1966 def update(self, path, modname, desc):
1967 if modname[-9:] == '.__init__':
1968 modname = modname[:-9] + ' (package)'
1969 self.result_lst.insert('end',
1970 modname + ' - ' + (desc or '(no description)'))
1971
1972 def stop(self, event=None):
1973 if self.scanner:
1974 self.scanner.quit = 1
1975 self.scanner = None
1976
1977 def done(self):
1978 self.scanner = None
1979 self.search_lbl.config(text='Search for')
1980 self.search_lbl.pack(side='left')
1981 self.search_ent.pack(side='right', fill='x', expand=1)
1982 if sys.platform != 'win32': self.stop_btn.forget()
1983 self.stop_btn.config(state='disabled')
1984
1985 def select(self, event=None):
1986 self.goto_btn.config(state='normal')
1987
1988 def goto(self, event=None):
1989 selection = self.result_lst.curselection()
1990 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001991 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001992 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001993
1994 def collapse(self):
1995 if not self.expanded: return
1996 self.result_frm.forget()
1997 self.result_scr.forget()
1998 self.result_lst.forget()
1999 self.bigwidth = self.window.winfo_width()
2000 self.bigheight = self.window.winfo_height()
2001 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2002 self.window.wm_minsize(self.minwidth, self.minheight)
2003 self.expanded = 0
2004
2005 def expand(self):
2006 if self.expanded: return
2007 self.result_frm.pack(side='bottom', fill='x')
2008 self.result_scr.pack(side='right', fill='y')
2009 self.result_lst.pack(side='top', fill='both', expand=1)
2010 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2011 self.window.wm_minsize(self.minwidth, self.bigminheight)
2012 self.expanded = 1
2013
2014 def hide(self, event=None):
2015 self.stop()
2016 self.collapse()
2017
2018 import Tkinter
2019 try:
2020 gui = GUI(Tkinter.Tk())
2021 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002022 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002023 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002024
2025# -------------------------------------------------- command-line interface
2026
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002027def ispath(x):
2028 return type(x) is types.StringType and find(x, os.sep) >= 0
2029
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002030def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002031 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002032 import getopt
2033 class BadUsage: pass
2034
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002035 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002036 scriptdir = os.path.dirname(sys.argv[0])
2037 if scriptdir in sys.path:
2038 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002039 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002040
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002041 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002042 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002043 writing = 0
2044
2045 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002046 if opt == '-g':
2047 gui()
2048 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002049 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002050 apropos(val)
2051 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002052 if opt == '-p':
2053 try:
2054 port = int(val)
2055 except ValueError:
2056 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002057 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002058 print 'pydoc server ready at %s' % server.url
2059 def stopped():
2060 print 'pydoc server stopped'
2061 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002062 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002063 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002064 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002065
2066 if not args: raise BadUsage
2067 for arg in args:
2068 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002069 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002070 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002071 if writing:
2072 if ispath(arg) and os.path.isdir(arg):
2073 writedocs(arg)
2074 else:
2075 writedoc(arg)
2076 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002077 doc(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002078 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002079 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002080
2081 except (getopt.error, BadUsage):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002082 cmd = sys.argv[0]
2083 print """pydoc - the Python documentation tool
2084
2085%s <name> ...
2086 Show text documentation on something. <name> may be the name of a
2087 function, module, or package, or a dotted reference to a class or
2088 function within a module or module in a package. If <name> contains
2089 a '%s', it is used as the path to a Python source file to document.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002090
2091%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002092 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002093
2094%s -p <port>
2095 Start an HTTP server on the given port on the local machine.
2096
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002097%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002098 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002099
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002100%s -w <name> ...
2101 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002102 directory. If <name> contains a '%s', it is treated as a filename; if
2103 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002104""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002105
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002106if __name__ == '__main__': cli()