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