blob: ab11d00e450eb709a32134525cf6d59e3eb13c05 [file] [log] [blame]
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001#!/usr/bin/env python
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002"""Generate Python documentation in HTML or text for interactive use.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00003
Ka-Ping Yeedd175342001-02-27 14:43:46 +00004In the Python interpreter, do "from pydoc import help" to provide online
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00005help. Calling help(thing) on a Python object documents the object.
6
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00007Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00008
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00009Run "pydoc <name>" to show documentation on something. <name> may be
10the name of a function, module, package, or a dotted reference to a
11class or function within a module or module in a package. If the
12argument contains a path segment delimiter (e.g. slash on Unix,
13backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000014
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000015Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
16of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000017
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000018Run "pydoc -p <port>" to start an HTTP server on a given port on the
19local machine to generate documentation web pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000020
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000021For platforms without a command line, "pydoc -g" starts the HTTP server
22and also pops up a little window for controlling it.
23
24Run "pydoc -w <name>" to write out the HTML documentation for a module
25to a file named "<name>.html".
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000026"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000027
28__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000029__date__ = "26 February 2001"
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000030__version__ = "$Revision$"
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000031__credits__ = """Guido van Rossum, for an excellent programming language.
32Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000033Paul Prescod, for all his work on onlinehelp.
34Richard Chamberlain, for the first implementation of textdoc.
35
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000036Mynd you, møøse bites Kan be pretty nasti..."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000037
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000038# Known bugs that can't be fixed here:
39# - imp.load_module() cannot be prevented from clobbering existing
40# loaded modules, so calling synopsis() on a binary module file
41# changes the contents of any existing module with the same name.
42# - If the __file__ attribute on a module is a relative path and
43# the current directory is changed with os.chdir(), an incorrect
44# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000045
Ka-Ping Yeedd175342001-02-27 14:43:46 +000046import sys, imp, os, stat, re, types, inspect
47from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000048from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
Ka-Ping Yeedd175342001-02-27 14:43:46 +000049
50# --------------------------------------------------------- common routines
51
Ka-Ping Yeedd175342001-02-27 14:43:46 +000052def pathdirs():
53 """Convert sys.path into a list of absolute, existing, unique paths."""
54 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000055 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000056 for dir in sys.path:
57 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000058 normdir = os.path.normcase(dir)
59 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000060 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000061 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000062 return dirs
63
64def getdoc(object):
65 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000066 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000067 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000068
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000069def splitdoc(doc):
70 """Split a doc string into a synopsis line (if any) and the rest."""
71 lines = split(strip(doc), '\n')
72 if len(lines) == 1:
73 return lines[0], ''
74 elif len(lines) >= 2 and not rstrip(lines[1]):
75 return lines[0], join(lines[2:], '\n')
76 return '', join(lines, '\n')
77
Ka-Ping Yeedd175342001-02-27 14:43:46 +000078def classname(object, modname):
79 """Get a class name and qualify it with a module name if necessary."""
80 name = object.__name__
81 if object.__module__ != modname:
82 name = object.__module__ + '.' + name
83 return name
84
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000085def isdata(object):
86 """Check if an object is of a type that probably means it's data."""
87 return not (inspect.ismodule(object) or inspect.isclass(object) or
88 inspect.isroutine(object) or inspect.isframe(object) or
89 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +000090
91def replace(text, *pairs):
92 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +000093 while pairs:
94 text = join(split(text, pairs[0]), pairs[1])
95 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +000096 return text
97
98def cram(text, maxlen):
99 """Omit part of a string if needed to make it fit in a maximum length."""
100 if len(text) > maxlen:
101 pre = max(0, (maxlen-3)/2)
102 post = max(0, maxlen-3-pre)
103 return text[:pre] + '...' + text[len(text)-post:]
104 return text
105
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000106def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000107 """Remove the hexadecimal id from a Python object representation."""
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000108 # The behaviour of %p is implementation-dependent; we check two cases.
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000109 for pattern in [' at 0x[0-9a-f]{6,}>$', ' at [0-9A-F]{8,}>$']:
110 if re.search(pattern, repr(Exception)):
111 return re.sub(pattern, '>', text)
112 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000113
Tim Peters536d2262001-09-20 05:13:38 +0000114def _is_some_method(object):
115 return inspect.ismethod(object) or inspect.ismethoddescriptor(object)
116
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000117def allmethods(cl):
118 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000119 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000120 methods[key] = 1
121 for base in cl.__bases__:
122 methods.update(allmethods(base)) # all your base are belong to us
123 for key in methods.keys():
124 methods[key] = getattr(cl, key)
125 return methods
126
Tim Petersfa26f7c2001-09-24 08:05:11 +0000127def _split_list(s, predicate):
128 """Split sequence s via predicate, and return pair ([true], [false]).
129
130 The return value is a 2-tuple of lists,
131 ([x for x in s if predicate(x)],
132 [x for x in s if not predicate(x)])
133 """
134
Tim Peters28355492001-09-23 21:29:55 +0000135 yes = []
136 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000137 for x in s:
138 if predicate(x):
139 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000140 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000141 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000142 return yes, no
143
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000144# ----------------------------------------------------- module manipulation
145
146def ispackage(path):
147 """Guess whether a path refers to a package directory."""
148 if os.path.isdir(path):
149 for ext in ['.py', '.pyc', '.pyo']:
150 if os.path.isfile(os.path.join(path, '__init__' + ext)):
151 return 1
152
153def synopsis(filename, cache={}):
154 """Get the one-line summary out of a module file."""
155 mtime = os.stat(filename)[stat.ST_MTIME]
156 lastupdate, result = cache.get(filename, (0, None))
157 if lastupdate < mtime:
158 info = inspect.getmoduleinfo(filename)
159 file = open(filename)
160 if info and 'b' in info[2]: # binary modules have to be imported
161 try: module = imp.load_module('__temp__', file, filename, info[1:])
162 except: return None
163 result = split(module.__doc__ or '', '\n')[0]
164 del sys.modules['__temp__']
165 else: # text modules can be directly examined
166 line = file.readline()
167 while line[:1] == '#' or not strip(line):
168 line = file.readline()
169 if not line: break
170 line = strip(line)
171 if line[:4] == 'r"""': line = line[1:]
172 if line[:3] == '"""':
173 line = line[3:]
174 if line[-1:] == '\\': line = line[:-1]
175 while not strip(line):
176 line = file.readline()
177 if not line: break
178 result = strip(split(line, '"""')[0])
179 else: result = None
180 file.close()
181 cache[filename] = (mtime, result)
182 return result
183
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000184class ErrorDuringImport(Exception):
185 """Errors that occurred while trying to import something to document it."""
186 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000187 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000188 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000189 self.value = value
190 self.tb = tb
191
192 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000193 exc = self.exc
194 if type(exc) is types.ClassType:
195 exc = exc.__name__
196 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000197
198def importfile(path):
199 """Import a Python source file or compiled file given its path."""
200 magic = imp.get_magic()
201 file = open(path, 'r')
202 if file.read(len(magic)) == magic:
203 kind = imp.PY_COMPILED
204 else:
205 kind = imp.PY_SOURCE
206 file.close()
207 filename = os.path.basename(path)
208 name, ext = os.path.splitext(filename)
209 file = open(path, 'r')
210 try:
211 module = imp.load_module(name, file, path, (ext, 'r', kind))
212 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000213 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000214 file.close()
215 return module
216
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000217def safeimport(path, forceload=0, cache={}):
218 """Import a module; handle errors; return None if the module isn't found.
219
220 If the module *is* found but an exception occurs, it's wrapped in an
221 ErrorDuringImport exception and reraised. Unlike __import__, if a
222 package path is specified, the module at the end of the path is returned,
223 not the package at the beginning. If the optional 'forceload' argument
224 is 1, we reload the module from disk (unless it's a dynamic extension)."""
225 if forceload and sys.modules.has_key(path):
226 # This is the only way to be sure. Checking the mtime of the file
227 # isn't good enough (e.g. what if the module contains a class that
228 # inherits from another module that has changed?).
229 if path not in sys.builtin_module_names:
230 # Python never loads a dynamic extension a second time from the
231 # same path, even if the file is changed or missing. Deleting
232 # the entry in sys.modules doesn't help for dynamic extensions,
233 # so we're not even going to try to keep them up to date.
234 info = inspect.getmoduleinfo(sys.modules[path].__file__)
235 if info[3] != imp.C_EXTENSION:
236 cache[path] = sys.modules[path] # prevent module from clearing
237 del sys.modules[path]
238 try:
239 module = __import__(path)
240 except:
241 # Did the error occur before or after the module was found?
242 (exc, value, tb) = info = sys.exc_info()
243 if sys.modules.has_key(path):
244 # An error occured while executing the imported module.
245 raise ErrorDuringImport(sys.modules[path].__file__, info)
246 elif exc is SyntaxError:
247 # A SyntaxError occurred before we could execute the module.
248 raise ErrorDuringImport(value.filename, info)
249 elif exc is ImportError and \
250 split(lower(str(value)))[:2] == ['no', 'module']:
251 # The module was not found.
252 return None
253 else:
254 # Some other error occurred during the importing process.
255 raise ErrorDuringImport(path, sys.exc_info())
256 for part in split(path, '.')[1:]:
257 try: module = getattr(module, part)
258 except AttributeError: return None
259 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000260
261# ---------------------------------------------------- formatter base class
262
263class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000264 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000265 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000266 args = (object, name) + args
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000267 if inspect.ismodule(object): return apply(self.docmodule, args)
268 if inspect.isclass(object): return apply(self.docclass, args)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000269 if inspect.isroutine(object): return apply(self.docroutine, args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000270 return apply(self.docother, args)
271
272 def fail(self, object, name=None, *args):
273 """Raise an exception for unimplemented types."""
274 message = "don't know how to document object%s of type %s" % (
275 name and ' ' + repr(name), type(object).__name__)
276 raise TypeError, message
277
278 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000279
280# -------------------------------------------- HTML documentation generator
281
282class HTMLRepr(Repr):
283 """Class for safely making an HTML representation of a Python object."""
284 def __init__(self):
285 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000286 self.maxlist = self.maxtuple = 20
287 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000288 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000289
290 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000291 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000292
293 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000294 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000295
296 def repr1(self, x, level):
297 methodname = 'repr_' + join(split(type(x).__name__), '_')
298 if hasattr(self, methodname):
299 return getattr(self, methodname)(x, level)
300 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000301 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000302
303 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000304 test = cram(x, self.maxstring)
305 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000306 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000307 # Backslashes are only literal in the string and are never
308 # needed to make any special characters, so show a raw string.
309 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000310 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000311 r'<font color="#c040c0">\1</font>',
312 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000313
314 def repr_instance(self, x, level):
315 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000316 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000317 except:
318 return self.escape('<%s instance>' % x.__class__.__name__)
319
320 repr_unicode = repr_string
321
322class HTMLDoc(Doc):
323 """Formatter class for HTML documentation."""
324
325 # ------------------------------------------- HTML formatting utilities
326
327 _repr_instance = HTMLRepr()
328 repr = _repr_instance.repr
329 escape = _repr_instance.escape
330
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000331 def page(self, title, contents):
332 """Format an HTML page."""
333 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000334<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000335<html><head><title>Python: %s</title>
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000336<style type="text/css"><!--
Ka-Ping Yeed03f8fe2001-04-13 15:04:32 +0000337TT { font-family: lucidatypewriter, lucida console, courier }
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000338--></style></head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000339%s
340</body></html>''' % (title, contents)
341
342 def heading(self, title, fgcol, bgcol, extras=''):
343 """Format a page heading."""
344 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000345<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000346<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000347<td valign=bottom>&nbsp;<br>
348<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000349><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000350><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000351 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
352
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000353 def section(self, title, fgcol, bgcol, contents, width=10,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000354 prelude='', marginalia=None, gap='&nbsp;&nbsp;'):
355 """Format a section with a heading."""
356 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000357 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000358 result = '''
Tim Peters59ed4482001-10-31 04:20:26 +0000359<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000360<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000361<td colspan=3 valign=bottom>&nbsp;<br>
362<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000363 ''' % (bgcol, fgcol, title)
364 if prelude:
365 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000366<tr bgcolor="%s"><td rowspan=2>%s</td>
367<td colspan=2>%s</td></tr>
368<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
369 else:
370 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000371<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000372
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000373 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000374
375 def bigsection(self, title, *args):
376 """Format a section with a big heading."""
377 title = '<big><strong>%s</strong></big>' % title
378 return apply(self.section, (title,) + args)
379
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000380 def preformat(self, text):
381 """Format literal preformatted text."""
382 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000383 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
384 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000385
386 def multicolumn(self, list, format, cols=4):
387 """Format a list of items into a multi-column list."""
388 result = ''
389 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000390 for col in range(cols):
391 result = result + '<td width="%d%%" valign=top>' % (100/cols)
392 for i in range(rows*col, rows*col+rows):
393 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000394 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000395 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000396 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000397
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000398 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000399
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000400 def namelink(self, name, *dicts):
401 """Make a link for an identifier, given name-to-URL mappings."""
402 for dict in dicts:
403 if dict.has_key(name):
404 return '<a href="%s">%s</a>' % (dict[name], name)
405 return name
406
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000407 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000408 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000409 name, module = object.__name__, sys.modules.get(object.__module__)
410 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000411 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000412 module.__name__, name, classname(object, modname))
413 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000414
415 def modulelink(self, object):
416 """Make a link for a module."""
417 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
418
419 def modpkglink(self, (name, path, ispackage, shadowed)):
420 """Make a link for a module or package to display in an index."""
421 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000422 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000423 if path:
424 url = '%s.%s.html' % (path, name)
425 else:
426 url = '%s.html' % name
427 if ispackage:
428 text = '<strong>%s</strong>&nbsp;(package)' % name
429 else:
430 text = name
431 return '<a href="%s">%s</a>' % (url, text)
432
433 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
434 """Mark up some plain text, given a context of symbols to look for.
435 Each context dictionary maps object names to anchor names."""
436 escape = escape or self.escape
437 results = []
438 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000439 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
440 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000441 r'PEP[- ]?(\d+)|'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000442 r'(self\.)?(\w+))\b')
443 while 1:
444 match = pattern.search(text, here)
445 if not match: break
446 start, end = match.span()
447 results.append(escape(text[here:start]))
448
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000449 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000450 if scheme:
451 results.append('<a href="%s">%s</a>' % (all, escape(all)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000452 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000453 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
454 results.append('<a href="%s">%s</a>' % (url, escape(all)))
455 elif pep:
456 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000457 results.append('<a href="%s">%s</a>' % (url, escape(all)))
458 elif text[end:end+1] == '(':
459 results.append(self.namelink(name, methods, funcs, classes))
460 elif selfdot:
461 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000462 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000463 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000464 here = end
465 results.append(escape(text[here:]))
466 return join(results, '')
467
468 # ---------------------------------------------- type-specific routines
469
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000470 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000471 """Produce HTML for a class tree as given by inspect.getclasstree()."""
472 result = ''
473 for entry in tree:
474 if type(entry) is type(()):
475 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000476 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000477 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000478 if bases and bases != (parent,):
479 parents = []
480 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000481 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000482 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000483 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000484 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000485 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000486 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000487 return '<dl>\n%s</dl>\n' % result
488
Tim Peters8dd7ade2001-10-18 19:56:17 +0000489 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000490 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000491 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000492 parts = split(name, '.')
493 links = []
494 for i in range(len(parts)-1):
495 links.append(
496 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
497 (join(parts[:i+1], '.'), parts[i]))
498 linkedname = join(links + parts[-1:], '.')
499 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000500 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000501 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000502 url = path
503 if sys.platform == 'win32':
504 import nturl2path
505 url = nturl2path.pathname2url(path)
506 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000507 except TypeError:
508 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000509 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000510 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000511 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000512 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
513 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000514 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000515 if hasattr(object, '__date__'):
516 info.append(self.escape(str(object.__date__)))
517 if info:
518 head = head + ' (%s)' % join(info, ', ')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000519 result = self.heading(
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000520 head, '#ffffff', '#7799ee', '<a href=".">index</a><br>' + filelink)
521
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000522 modules = inspect.getmembers(object, inspect.ismodule)
523
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000524 classes, cdict = [], {}
525 for key, value in inspect.getmembers(object, inspect.isclass):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000526 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000527 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000528 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000529 for key, value in classes:
530 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000531 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000532 module = sys.modules.get(modname)
533 if modname != name and module and hasattr(module, key):
534 if getattr(module, key) is base:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000535 if not cdict.has_key(key):
536 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000537 funcs, fdict = [], {}
538 for key, value in inspect.getmembers(object, inspect.isroutine):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000539 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000540 funcs.append((key, value))
541 fdict[key] = '#-' + key
542 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000543 data = []
544 for key, value in inspect.getmembers(object, isdata):
545 if key not in ['__builtins__', '__doc__']:
546 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000547
548 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
549 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000550 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000551
552 if hasattr(object, '__path__'):
553 modpkgs = []
554 modnames = []
555 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000556 path = os.path.join(object.__path__[0], file)
557 modname = inspect.getmodulename(file)
558 if modname and modname not in modnames:
559 modpkgs.append((modname, name, 0, 0))
560 modnames.append(modname)
561 elif ispackage(path):
562 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000563 modpkgs.sort()
564 contents = self.multicolumn(modpkgs, self.modpkglink)
565 result = result + self.bigsection(
566 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000567 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000568 contents = self.multicolumn(
569 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000570 result = result + self.bigsection(
571 'Modules', '#fffff', '#aa55cc', contents)
572
573 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000574 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000575 contents = [
576 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000577 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000578 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000579 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000580 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000581 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000582 contents = []
583 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000584 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000585 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000586 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000587 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000588 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000589 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000590 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000591 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000592 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000593 if hasattr(object, '__author__'):
594 contents = self.markup(str(object.__author__), self.preformat)
595 result = result + self.bigsection(
596 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000597 if hasattr(object, '__credits__'):
598 contents = self.markup(str(object.__credits__), self.preformat)
599 result = result + self.bigsection(
600 'Credits', '#ffffff', '#7799ee', contents)
601
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000602 return result
603
Tim Peters8dd7ade2001-10-18 19:56:17 +0000604 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
605 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000606 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000607 realname = object.__name__
608 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000609 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000610
Tim Petersb47879b2001-09-24 04:47:19 +0000611 contents = []
612 push = contents.append
613
Tim Petersfa26f7c2001-09-24 08:05:11 +0000614 # Cute little class to pump out a horizontal rule between sections.
615 class HorizontalRule:
616 def __init__(self):
617 self.needone = 0
618 def maybe(self):
619 if self.needone:
620 push('<hr>\n')
621 self.needone = 1
622 hr = HorizontalRule()
623
Tim Petersc86f6ca2001-09-26 21:31:51 +0000624 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +0000625 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000626 if len(mro) > 2:
627 hr.maybe()
628 push('<dl><dt>Method resolution order:</dt>\n')
629 for base in mro:
630 push('<dd>%s</dd>\n' % self.classlink(base,
631 object.__module__))
632 push('</dl>\n')
633
Tim Petersb47879b2001-09-24 04:47:19 +0000634 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000635 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000636 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000637 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000638 push(msg)
639 for name, kind, homecls, value in ok:
640 push(self.document(getattr(object, name), name, mod,
641 funcs, classes, mdict, object))
642 push('\n')
643 return attrs
644
Tim Petersfa26f7c2001-09-24 08:05:11 +0000645 def spillproperties(msg, attrs, predicate):
646 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000647 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000648 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000649 push(msg)
650 for name, kind, homecls, value in ok:
Tim Peters3e767d12001-09-25 00:01:06 +0000651 push('<dl><dt><strong>%s</strong></dt>\n' % name)
652 if value.__doc__ is not None:
653 doc = self.markup(value.__doc__, self.preformat,
654 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000655 push('<dd><tt>%s</tt></dd>\n' % doc)
Tim Petersf33532c2001-09-25 06:30:51 +0000656 for attr, tag in [("fget", " getter"),
657 ("fset", " setter"),
Tim Peters3e767d12001-09-25 00:01:06 +0000658 ("fdel", " deleter")]:
659 func = getattr(value, attr)
660 if func is not None:
661 base = self.document(func, name + tag, mod,
662 funcs, classes, mdict, object)
663 push('<dd>%s</dd>\n' % base)
664 push('</dl>\n')
Tim Petersb47879b2001-09-24 04:47:19 +0000665 return attrs
666
Tim Petersfa26f7c2001-09-24 08:05:11 +0000667 def spilldata(msg, attrs, predicate):
668 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000669 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000670 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000671 push(msg)
672 for name, kind, homecls, value in ok:
673 base = self.docother(getattr(object, name), name, mod)
674 doc = getattr(value, "__doc__", None)
675 if doc is None:
676 push('<dl><dt>%s</dl>\n' % base)
677 else:
678 doc = self.markup(getdoc(value), self.preformat,
679 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000680 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000681 push('<dl><dt>%s%s</dl>\n' % (base, doc))
682 push('\n')
683 return attrs
684
685 attrs = inspect.classify_class_attrs(object)
686 mdict = {}
687 for key, kind, homecls, value in attrs:
688 mdict[key] = anchor = '#' + name + '-' + key
689 value = getattr(object, key)
690 try:
691 # The value may not be hashable (e.g., a data attr with
692 # a dict or list value).
693 mdict[value] = anchor
694 except TypeError:
695 pass
696
Tim Petersfa26f7c2001-09-24 08:05:11 +0000697 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000698 if mro:
699 thisclass = mro.pop(0)
700 else:
701 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000702 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
703
Tim Petersb47879b2001-09-24 04:47:19 +0000704 if thisclass is object:
705 tag = "defined here"
706 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000707 tag = "inherited from %s" % self.classlink(thisclass,
Tim Petersb47879b2001-09-24 04:47:19 +0000708 object.__module__)
709 tag += ':<br>\n'
710
711 # Sort attrs by name.
712 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
713
714 # Pump out the attrs, segregated by kind.
715 attrs = spill("Methods %s" % tag, attrs,
716 lambda t: t[1] == 'method')
717 attrs = spill("Class methods %s" % tag, attrs,
718 lambda t: t[1] == 'class method')
719 attrs = spill("Static methods %s" % tag, attrs,
720 lambda t: t[1] == 'static method')
Tim Petersfa26f7c2001-09-24 08:05:11 +0000721 attrs = spillproperties("Properties %s" % tag, attrs,
722 lambda t: t[1] == 'property')
Tim Petersf33532c2001-09-25 06:30:51 +0000723 attrs = spilldata("Data and non-method functions %s" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000724 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000725 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000726 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000727
728 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000729
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000730 if name == realname:
731 title = '<a name="%s">class <strong>%s</strong></a>' % (
732 name, realname)
733 else:
734 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
735 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000736 if bases:
737 parents = []
738 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000739 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000740 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000741 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
742 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc or '&nbsp;'
Tim Petersc86f6ca2001-09-26 21:31:51 +0000743
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000744 return self.section(title, '#000000', '#ffc8d8', contents, 5, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000745
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000746 def formatvalue(self, object):
747 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000748 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000749
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000750 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000751 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000752 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000753 realname = object.__name__
754 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000755 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000756 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000757 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000758 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000759 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000760 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000761 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000762 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000763 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000764 if object.im_self:
765 note = ' method of %s instance' % self.classlink(
766 object.im_self.__class__, mod)
767 else:
768 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000769 object = object.im_func
770
771 if name == realname:
772 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
773 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000774 if (cl and cl.__dict__.has_key(realname) and
775 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000776 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000777 cl.__name__ + '-' + realname, realname)
778 skipdocs = 1
779 else:
780 reallink = realname
781 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
782 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000783 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000784 args, varargs, varkw, defaults = inspect.getargspec(object)
785 argspec = inspect.formatargspec(
786 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000787 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000788 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000789 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000790 else:
791 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000792
Tim Peters2306d242001-09-25 03:18:32 +0000793 decl = title + argspec + (note and self.grey(
794 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000795
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000796 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000797 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000798 else:
799 doc = self.markup(
800 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000801 doc = doc and '<dd><tt>%s</tt></dd>' % doc
802 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000803
Tim Peters8dd7ade2001-10-18 19:56:17 +0000804 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000805 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000806 lhs = name and '<strong>%s</strong> = ' % name or ''
807 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000808
809 def index(self, dir, shadowed=None):
810 """Generate an HTML index for a directory of modules."""
811 modpkgs = []
812 if shadowed is None: shadowed = {}
813 seen = {}
814 files = os.listdir(dir)
815
816 def found(name, ispackage,
817 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
818 if not seen.has_key(name):
819 modpkgs.append((name, '', ispackage, shadowed.has_key(name)))
820 seen[name] = 1
821 shadowed[name] = 1
822
823 # Package spam/__init__.py takes precedence over module spam.py.
824 for file in files:
825 path = os.path.join(dir, file)
826 if ispackage(path): found(file, 1)
827 for file in files:
828 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000829 if os.path.isfile(path):
830 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000831 if modname: found(modname, 0)
832
833 modpkgs.sort()
834 contents = self.multicolumn(modpkgs, self.modpkglink)
835 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
836
837# -------------------------------------------- text documentation generator
838
839class TextRepr(Repr):
840 """Class for safely making a text representation of a Python object."""
841 def __init__(self):
842 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000843 self.maxlist = self.maxtuple = 20
844 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000845 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000846
847 def repr1(self, x, level):
848 methodname = 'repr_' + join(split(type(x).__name__), '_')
849 if hasattr(self, methodname):
850 return getattr(self, methodname)(x, level)
851 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000852 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000853
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000854 def repr_string(self, x, level):
855 test = cram(x, self.maxstring)
856 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000857 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000858 # Backslashes are only literal in the string and are never
859 # needed to make any special characters, so show a raw string.
860 return 'r' + testrepr[0] + test + testrepr[0]
861 return testrepr
862
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000863 def repr_instance(self, x, level):
864 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000865 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000866 except:
867 return '<%s instance>' % x.__class__.__name__
868
869class TextDoc(Doc):
870 """Formatter class for text documentation."""
871
872 # ------------------------------------------- text formatting utilities
873
874 _repr_instance = TextRepr()
875 repr = _repr_instance.repr
876
877 def bold(self, text):
878 """Format a string in bold by overstriking."""
879 return join(map(lambda ch: ch + '\b' + ch, text), '')
880
881 def indent(self, text, prefix=' '):
882 """Indent text by prepending a given prefix to each line."""
883 if not text: return ''
884 lines = split(text, '\n')
885 lines = map(lambda line, prefix=prefix: prefix + line, lines)
886 if lines: lines[-1] = rstrip(lines[-1])
887 return join(lines, '\n')
888
889 def section(self, title, contents):
890 """Format a section with a given heading."""
891 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
892
893 # ---------------------------------------------- type-specific routines
894
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000895 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000896 """Render in text a class tree as returned by inspect.getclasstree()."""
897 result = ''
898 for entry in tree:
899 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000900 c, bases = entry
901 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000902 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000903 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000904 result = result + '(%s)' % join(parents, ', ')
905 result = result + '\n'
906 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000907 result = result + self.formattree(
908 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000909 return result
910
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000911 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000912 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000913 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000914 synop, desc = splitdoc(getdoc(object))
915 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000916
917 try:
918 file = inspect.getabsfile(object)
919 except TypeError:
920 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000921 result = result + self.section('FILE', file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000922 if desc:
923 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000924
925 classes = []
926 for key, value in inspect.getmembers(object, inspect.isclass):
927 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000928 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000929 funcs = []
930 for key, value in inspect.getmembers(object, inspect.isroutine):
931 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000932 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000933 data = []
934 for key, value in inspect.getmembers(object, isdata):
935 if key not in ['__builtins__', '__doc__']:
936 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000937
938 if hasattr(object, '__path__'):
939 modpkgs = []
940 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000941 path = os.path.join(object.__path__[0], file)
942 modname = inspect.getmodulename(file)
943 if modname and modname not in modpkgs:
944 modpkgs.append(modname)
945 elif ispackage(path):
946 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000947 modpkgs.sort()
948 result = result + self.section(
949 'PACKAGE CONTENTS', join(modpkgs, '\n'))
950
951 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000952 classlist = map(lambda (key, value): value, classes)
953 contents = [self.formattree(
954 inspect.getclasstree(classlist, 1), name)]
955 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000956 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000957 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000958
959 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000960 contents = []
961 for key, value in funcs:
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('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000964
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000965 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000966 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000967 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000968 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000969 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000970
971 if hasattr(object, '__version__'):
972 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000973 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
974 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000975 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000976 if hasattr(object, '__date__'):
977 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000978 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000979 result = result + self.section('AUTHOR', str(object.__author__))
980 if hasattr(object, '__credits__'):
981 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000982 return result
983
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000984 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000985 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000986 realname = object.__name__
987 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000988 bases = object.__bases__
989
Tim Petersc86f6ca2001-09-26 21:31:51 +0000990 def makename(c, m=object.__module__):
991 return classname(c, m)
992
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000993 if name == realname:
994 title = 'class ' + self.bold(realname)
995 else:
996 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000997 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000998 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000999 title = title + '(%s)' % join(parents, ', ')
1000
1001 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001002 contents = doc and [doc + '\n'] or []
1003 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001004
Tim Petersc86f6ca2001-09-26 21:31:51 +00001005 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +00001006 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001007 if len(mro) > 2:
1008 push("Method resolution order:")
1009 for base in mro:
1010 push(' ' + makename(base))
1011 push('')
1012
Tim Petersf4aad8e2001-09-24 22:40:47 +00001013 # Cute little class to pump out a horizontal rule between sections.
1014 class HorizontalRule:
1015 def __init__(self):
1016 self.needone = 0
1017 def maybe(self):
1018 if self.needone:
1019 push('-' * 70)
1020 self.needone = 1
1021 hr = HorizontalRule()
1022
Tim Peters28355492001-09-23 21:29:55 +00001023 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001024 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001025 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001026 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001027 push(msg)
1028 for name, kind, homecls, value in ok:
1029 push(self.document(getattr(object, name),
1030 name, mod, object))
1031 return attrs
1032
Tim Petersfa26f7c2001-09-24 08:05:11 +00001033 def spillproperties(msg, attrs, predicate):
1034 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001035 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001036 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001037 push(msg)
1038 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001039 push(name)
1040 need_blank_after_doc = 0
1041 doc = getdoc(value) or ''
1042 if doc:
1043 push(self.indent(doc))
1044 need_blank_after_doc = 1
Tim Petersf33532c2001-09-25 06:30:51 +00001045 for attr, tag in [("fget", " getter"),
1046 ("fset", " setter"),
Tim Petersf4aad8e2001-09-24 22:40:47 +00001047 ("fdel", " deleter")]:
1048 func = getattr(value, attr)
1049 if func is not None:
1050 if need_blank_after_doc:
1051 push('')
1052 need_blank_after_doc = 0
1053 base = self.docother(func, name + tag, mod, 70)
1054 push(self.indent(base))
1055 push('')
Tim Peters28355492001-09-23 21:29:55 +00001056 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001057
Tim Petersfa26f7c2001-09-24 08:05:11 +00001058 def spilldata(msg, attrs, predicate):
1059 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001060 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001061 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001062 push(msg)
1063 for name, kind, homecls, value in ok:
1064 doc = getattr(value, "__doc__", None)
1065 push(self.docother(getattr(object, name),
1066 name, mod, 70, doc) + '\n')
1067 return attrs
1068
1069 attrs = inspect.classify_class_attrs(object)
Tim Petersfa26f7c2001-09-24 08:05:11 +00001070 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001071 if mro:
1072 thisclass = mro.pop(0)
1073 else:
1074 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001075 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1076
Tim Peters28355492001-09-23 21:29:55 +00001077 if thisclass is object:
1078 tag = "defined here"
1079 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001080 tag = "inherited from %s" % classname(thisclass,
1081 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001082
1083 # Sort attrs by name.
1084 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
1085
1086 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001087 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001088 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001089 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001090 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001091 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001092 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001093 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001094 lambda t: t[1] == 'property')
Tim Petersf33532c2001-09-25 06:30:51 +00001095 attrs = spilldata("Data and non-method functions %s:\n" % tag,
1096 attrs, lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001097 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001098 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001099
1100 contents = '\n'.join(contents)
1101 if not contents:
1102 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001103 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1104
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001105 def formatvalue(self, object):
1106 """Format an argument default value as text."""
1107 return '=' + self.repr(object)
1108
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001109 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001110 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001111 realname = object.__name__
1112 name = name or realname
1113 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001114 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001115 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001116 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001117 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001118 if imclass is not cl:
1119 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001120 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001121 if object.im_self:
1122 note = ' method of %s instance' % classname(
1123 object.im_self.__class__, mod)
1124 else:
1125 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001126 object = object.im_func
1127
1128 if name == realname:
1129 title = self.bold(realname)
1130 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001131 if (cl and cl.__dict__.has_key(realname) and
1132 cl.__dict__[realname] is object):
1133 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001134 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001135 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001136 args, varargs, varkw, defaults = inspect.getargspec(object)
1137 argspec = inspect.formatargspec(
1138 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001139 if realname == '<lambda>':
1140 title = 'lambda'
1141 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001142 else:
1143 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001144 decl = title + argspec + note
1145
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001146 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001147 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001148 else:
1149 doc = getdoc(object) or ''
1150 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001151
Tim Peters28355492001-09-23 21:29:55 +00001152 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001153 """Produce text documentation for a data object."""
1154 repr = self.repr(object)
1155 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001156 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001157 chop = maxlen - len(line)
1158 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001159 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001160 if doc is not None:
1161 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001162 return line
1163
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001164# --------------------------------------------------------- user interfaces
1165
1166def pager(text):
1167 """The first time this is called, determine what kind of pager to use."""
1168 global pager
1169 pager = getpager()
1170 pager(text)
1171
1172def getpager():
1173 """Decide what method to use for paging through text."""
1174 if type(sys.stdout) is not types.FileType:
1175 return plainpager
1176 if not sys.stdin.isatty() or not sys.stdout.isatty():
1177 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001178 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001179 return plainpager
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001180 if os.environ.has_key('PAGER'):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001181 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001182 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1183 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1184 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001185 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001186 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001187 if sys.platform == 'win32':
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001188 return lambda text: tempfilepager(plain(text), 'more <')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001189 if hasattr(os, 'system') and os.system('less 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001190 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001191
1192 import tempfile
1193 filename = tempfile.mktemp()
1194 open(filename, 'w').close()
1195 try:
1196 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1197 return lambda text: pipepager(text, 'more')
1198 else:
1199 return ttypager
1200 finally:
1201 os.unlink(filename)
1202
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001203def plain(text):
1204 """Remove boldface formatting from text."""
1205 return re.sub('.\b', '', text)
1206
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001207def pipepager(text, cmd):
1208 """Page through text by feeding it to another program."""
1209 pipe = os.popen(cmd, 'w')
1210 try:
1211 pipe.write(text)
1212 pipe.close()
1213 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001214 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001215
1216def tempfilepager(text, cmd):
1217 """Page through text by invoking a program on a temporary file."""
1218 import tempfile
1219 filename = tempfile.mktemp()
1220 file = open(filename, 'w')
1221 file.write(text)
1222 file.close()
1223 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001224 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001225 finally:
1226 os.unlink(filename)
1227
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001228def ttypager(text):
1229 """Page through text on a text terminal."""
1230 lines = split(plain(text), '\n')
1231 try:
1232 import tty
1233 fd = sys.stdin.fileno()
1234 old = tty.tcgetattr(fd)
1235 tty.setcbreak(fd)
1236 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001237 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001238 tty = None
1239 getchar = lambda: sys.stdin.readline()[:-1][:1]
1240
1241 try:
1242 r = inc = os.environ.get('LINES', 25) - 1
1243 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1244 while lines[r:]:
1245 sys.stdout.write('-- more --')
1246 sys.stdout.flush()
1247 c = getchar()
1248
1249 if c in ['q', 'Q']:
1250 sys.stdout.write('\r \r')
1251 break
1252 elif c in ['\r', '\n']:
1253 sys.stdout.write('\r \r' + lines[r] + '\n')
1254 r = r + 1
1255 continue
1256 if c in ['b', 'B', '\x1b']:
1257 r = r - inc - inc
1258 if r < 0: r = 0
1259 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1260 r = r + inc
1261
1262 finally:
1263 if tty:
1264 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1265
1266def plainpager(text):
1267 """Simply print unformatted text. This is the ultimate fallback."""
1268 sys.stdout.write(plain(text))
1269
1270def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001271 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001272 if inspect.ismodule(thing):
1273 if thing.__name__ in sys.builtin_module_names:
1274 return 'built-in module ' + thing.__name__
1275 if hasattr(thing, '__path__'):
1276 return 'package ' + thing.__name__
1277 else:
1278 return 'module ' + thing.__name__
1279 if inspect.isbuiltin(thing):
1280 return 'built-in function ' + thing.__name__
1281 if inspect.isclass(thing):
1282 return 'class ' + thing.__name__
1283 if inspect.isfunction(thing):
1284 return 'function ' + thing.__name__
1285 if inspect.ismethod(thing):
1286 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001287 if type(thing) is types.InstanceType:
1288 return 'instance of ' + thing.__class__.__name__
1289 return type(thing).__name__
1290
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001291def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001292 """Locate an object by name or dotted path, importing as necessary."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001293 parts = split(path, '.')
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001294 module, n = None, 0
1295 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001296 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001297 if nextmodule: module, n = nextmodule, n + 1
1298 else: break
1299 if module:
1300 object = module
1301 for part in parts[n:]:
1302 try: object = getattr(object, part)
1303 except AttributeError: return None
1304 return object
1305 else:
1306 import __builtin__
1307 if hasattr(__builtin__, path):
1308 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001309
1310# --------------------------------------- interactive interpreter interface
1311
1312text = TextDoc()
1313html = HTMLDoc()
1314
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001315def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001316 """Display text documentation, given an object or a path to an object."""
1317 suffix, name = '', None
1318 if type(thing) is type(''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001319 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001320 object = locate(thing, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001321 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001322 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001323 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001324 if not object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001325 print 'no Python documentation found for %s' % repr(thing)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001326 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001327 parts = split(thing, '.')
1328 if len(parts) > 1: suffix = ' in ' + join(parts[:-1], '.')
1329 name = parts[-1]
1330 thing = object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001331
1332 desc = describe(thing)
1333 module = inspect.getmodule(thing)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001334 if not suffix and module and module is not thing:
1335 suffix = ' in module ' + module.__name__
Ka-Ping Yee66246962001-04-12 11:59:50 +00001336 pager(title % (desc + suffix) + '\n\n' + text.document(thing, name))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001337
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001338def writedoc(key, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001339 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001340 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001341 object = locate(key, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001342 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001343 print value
1344 else:
1345 if object:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001346 page = html.page(describe(object),
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001347 html.document(object, object.__name__))
1348 file = open(key + '.html', 'w')
1349 file.write(page)
1350 file.close()
1351 print 'wrote', key + '.html'
1352 else:
1353 print 'no Python documentation found for %s' % repr(key)
1354
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001355def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001356 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001357 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001358 for file in os.listdir(dir):
1359 path = os.path.join(dir, file)
1360 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001361 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001362 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001363 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001364 if modname:
1365 modname = pkgpath + modname
1366 if not done.has_key(modname):
1367 done[modname] = 1
1368 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001369
1370class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001371 keywords = {
1372 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001373 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001374 'break': ('ref/break', 'while for'),
1375 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1376 'continue': ('ref/continue', 'while for'),
1377 'def': ('ref/function', ''),
1378 'del': ('ref/del', 'BASICMETHODS'),
1379 'elif': 'if',
1380 'else': ('ref/if', 'while for'),
1381 'except': 'try',
1382 'exec': ('ref/exec', ''),
1383 'finally': 'try',
1384 'for': ('ref/for', 'break continue while'),
1385 'from': 'import',
1386 'global': ('ref/global', 'NAMESPACES'),
1387 'if': ('ref/if', 'TRUTHVALUE'),
1388 'import': ('ref/import', 'MODULES'),
1389 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1390 'is': 'COMPARISON',
1391 'lambda': ('ref/lambda', 'FUNCTIONS'),
1392 'not': 'BOOLEAN',
1393 'or': 'BOOLEAN',
1394 'pass': 'PASS',
1395 'print': ('ref/print', ''),
1396 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001397 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001398 'try': ('ref/try', 'EXCEPTIONS'),
1399 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1400 }
1401
1402 topics = {
1403 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001404 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001405 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1406 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001407 'UNICODE': ('ref/unicode', 'encodings unicode TYPES STRING'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001408 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1409 'INTEGER': ('ref/integers', 'int range'),
1410 'FLOAT': ('ref/floating', 'float math'),
1411 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001412 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001413 'MAPPINGS': 'DICTIONARIES',
1414 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1415 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1416 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001417 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001418 'FRAMEOBJECTS': 'TYPES',
1419 'TRACEBACKS': 'TYPES',
1420 'NONE': ('lib/bltin-null-object', ''),
1421 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1422 'FILES': ('lib/bltin-file-objects', ''),
1423 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1424 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1425 'MODULES': ('lib/typesmodules', 'import'),
1426 'PACKAGES': 'import',
1427 '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'),
1428 'OPERATORS': 'EXPRESSIONS',
1429 'PRECEDENCE': 'EXPRESSIONS',
1430 'OBJECTS': ('ref/objects', 'TYPES'),
1431 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001432 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1433 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1434 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1435 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1436 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1437 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1438 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001439 'EXECUTION': ('ref/execframes', ''),
1440 'NAMESPACES': ('ref/execframes', 'global ASSIGNMENT DELETION'),
1441 'SCOPING': 'NAMESPACES',
1442 'FRAMES': 'NAMESPACES',
1443 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1444 'COERCIONS': 'CONVERSIONS',
1445 'CONVERSIONS': ('ref/conversions', ''),
1446 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1447 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001448 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001449 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1450 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001451 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001452 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001453 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001454 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001455 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1456 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001457 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1458 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1459 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1460 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1461 'POWER': ('ref/power', 'EXPRESSIONS'),
1462 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1463 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1464 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1465 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1466 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001467 'BOOLEAN': ('ref/lambda', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001468 'ASSERTION': 'assert',
1469 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001470 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001471 'DELETION': 'del',
1472 'PRINTING': 'print',
1473 'RETURNING': 'return',
1474 'IMPORTING': 'import',
1475 'CONDITIONAL': 'if',
1476 'LOOPING': ('ref/compound', 'for while break continue'),
1477 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001478 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001479 }
1480
1481 def __init__(self, input, output):
1482 self.input = input
1483 self.output = output
1484 self.docdir = None
1485 execdir = os.path.dirname(sys.executable)
1486 homedir = os.environ.get('PYTHONHOME')
1487 for dir in [os.environ.get('PYTHONDOCS'),
1488 homedir and os.path.join(homedir, 'doc'),
1489 os.path.join(execdir, 'doc'),
1490 '/usr/doc/python-docs-' + split(sys.version)[0],
1491 '/usr/doc/python-' + split(sys.version)[0],
1492 '/usr/doc/python-docs-' + sys.version[:3],
1493 '/usr/doc/python-' + sys.version[:3]]:
1494 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1495 self.docdir = dir
1496
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001497 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001498 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001499 self()
1500 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001501 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001502
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001503 def __call__(self, request=None):
1504 if request is not None:
1505 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001506 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001507 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001508 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001509 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001510You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001511If you want to ask for help on a particular object directly from the
1512interpreter, you can type "help(object)". Executing "help('string')"
1513has the same effect as typing a particular string at the help> prompt.
1514''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001515
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001516 def interact(self):
1517 self.output.write('\n')
1518 while 1:
1519 self.output.write('help> ')
1520 self.output.flush()
1521 try:
1522 request = self.input.readline()
1523 if not request: break
1524 except KeyboardInterrupt: break
1525 request = strip(replace(request, '"', '', "'", ''))
1526 if lower(request) in ['q', 'quit']: break
1527 self.help(request)
1528
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001529 def help(self, request):
1530 if type(request) is type(''):
1531 if request == 'help': self.intro()
1532 elif request == 'keywords': self.listkeywords()
1533 elif request == 'topics': self.listtopics()
1534 elif request == 'modules': self.listmodules()
1535 elif request[:8] == 'modules ':
1536 self.listmodules(split(request)[1])
1537 elif self.keywords.has_key(request): self.showtopic(request)
1538 elif self.topics.has_key(request): self.showtopic(request)
1539 elif request: doc(request, 'Help on %s:')
1540 elif isinstance(request, Helper): self()
1541 else: doc(request, 'Help on %s:')
1542 self.output.write('\n')
1543
1544 def intro(self):
1545 self.output.write('''
1546Welcome to Python %s! This is the online help utility.
1547
1548If this is your first time using Python, you should definitely check out
1549the tutorial on the Internet at http://www.python.org/doc/tut/.
1550
1551Enter the name of any module, keyword, or topic to get help on writing
1552Python programs and using Python modules. To quit this help utility and
1553return to the interpreter, just type "quit".
1554
1555To get a list of available modules, keywords, or topics, type "modules",
1556"keywords", or "topics". Each module also comes with a one-line summary
1557of what it does; to list the modules whose summaries contain a given word
1558such as "spam", type "modules spam".
1559''' % sys.version[:3])
1560
1561 def list(self, items, columns=4, width=80):
1562 items = items[:]
1563 items.sort()
1564 colw = width / columns
1565 rows = (len(items) + columns - 1) / columns
1566 for row in range(rows):
1567 for col in range(columns):
1568 i = col * rows + row
1569 if i < len(items):
1570 self.output.write(items[i])
1571 if col < columns - 1:
1572 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1573 self.output.write('\n')
1574
1575 def listkeywords(self):
1576 self.output.write('''
1577Here is a list of the Python keywords. Enter any keyword to get more help.
1578
1579''')
1580 self.list(self.keywords.keys())
1581
1582 def listtopics(self):
1583 self.output.write('''
1584Here is a list of available topics. Enter any topic name to get more help.
1585
1586''')
1587 self.list(self.topics.keys())
1588
1589 def showtopic(self, topic):
1590 if not self.docdir:
1591 self.output.write('''
1592Sorry, topic and keyword documentation is not available because the Python
1593HTML documentation files could not be found. If you have installed them,
1594please set the environment variable PYTHONDOCS to indicate their location.
1595''')
1596 return
1597 target = self.topics.get(topic, self.keywords.get(topic))
1598 if not target:
1599 self.output.write('no documentation found for %s\n' % repr(topic))
1600 return
1601 if type(target) is type(''):
1602 return self.showtopic(target)
1603
1604 filename, xrefs = target
1605 filename = self.docdir + '/' + filename + '.html'
1606 try:
1607 file = open(filename)
1608 except:
1609 self.output.write('could not read docs from %s\n' % filename)
1610 return
1611
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001612 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1613 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001614 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1615 file.close()
1616
1617 import htmllib, formatter, StringIO
1618 buffer = StringIO.StringIO()
1619 parser = htmllib.HTMLParser(
1620 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1621 parser.start_table = parser.do_p
1622 parser.end_table = lambda parser=parser: parser.do_p({})
1623 parser.start_tr = parser.do_br
1624 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1625 parser.feed(document)
1626 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1627 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001628 if xrefs:
1629 buffer = StringIO.StringIO()
1630 formatter.DumbWriter(buffer).send_flowing_data(
1631 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1632 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001633
1634 def listmodules(self, key=''):
1635 if key:
1636 self.output.write('''
1637Here is a list of matching modules. Enter any module name to get more help.
1638
1639''')
1640 apropos(key)
1641 else:
1642 self.output.write('''
1643Please wait a moment while I gather a list of all available modules...
1644
1645''')
1646 modules = {}
1647 def callback(path, modname, desc, modules=modules):
1648 if modname and modname[-9:] == '.__init__':
1649 modname = modname[:-9] + ' (package)'
1650 if find(modname, '.') < 0:
1651 modules[modname] = 1
1652 ModuleScanner().run(callback)
1653 self.list(modules.keys())
1654 self.output.write('''
1655Enter any module name to get more help. Or, type "modules spam" to search
1656for modules whose descriptions contain the word "spam".
1657''')
1658
1659help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001660
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001661class Scanner:
1662 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001663 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001664 self.roots = roots[:]
1665 self.state = []
1666 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001667 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001668
1669 def next(self):
1670 if not self.state:
1671 if not self.roots:
1672 return None
1673 root = self.roots.pop(0)
1674 self.state = [(root, self.children(root))]
1675 node, children = self.state[-1]
1676 if not children:
1677 self.state.pop()
1678 return self.next()
1679 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001680 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001681 self.state.append((child, self.children(child)))
1682 return child
1683
1684class ModuleScanner(Scanner):
1685 """An interruptible scanner that searches module synopses."""
1686 def __init__(self):
1687 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001688 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
1689 self.inodes = map(lambda (dir, pkg): os.stat(dir)[1], roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001690
1691 def submodules(self, (dir, package)):
1692 children = []
1693 for file in os.listdir(dir):
1694 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001695 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001696 children.append((path, package + (package and '.') + file))
1697 else:
1698 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001699 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001700 return children
1701
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001702 def isnewpackage(self, (dir, package)):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001703 inode = os.path.exists(dir) and os.stat(dir)[1]
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001704 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001705 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001706 return ispackage(dir)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001707
Ka-Ping Yee66246962001-04-12 11:59:50 +00001708 def run(self, callback, key=None, completer=None):
1709 if key: key = lower(key)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001710 self.quit = 0
1711 seen = {}
1712
1713 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001714 if modname != '__main__':
1715 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001716 if key is None:
1717 callback(None, modname, '')
1718 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001719 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001720 if find(lower(modname + ' - ' + desc), key) >= 0:
1721 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001722
1723 while not self.quit:
1724 node = self.next()
1725 if not node: break
1726 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001727 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001728 if os.path.isfile(path) and modname:
1729 modname = package + (package and '.') + modname
1730 if not seen.has_key(modname):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001731 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001732 if key is None:
1733 callback(path, modname, '')
1734 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001735 desc = synopsis(path) or ''
1736 if find(lower(modname + ' - ' + desc), key) >= 0:
1737 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001738 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001739
1740def apropos(key):
1741 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001742 def callback(path, modname, desc):
1743 if modname[-9:] == '.__init__':
1744 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001745 print modname, desc and '- ' + desc
1746 try: import warnings
1747 except ImportError: pass
1748 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001749 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001750
1751# --------------------------------------------------- web browser interface
1752
Ka-Ping Yee66246962001-04-12 11:59:50 +00001753def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001754 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001755
1756 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1757 class Message(mimetools.Message):
1758 def __init__(self, fp, seekable=1):
1759 Message = self.__class__
1760 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1761 self.encodingheader = self.getheader('content-transfer-encoding')
1762 self.typeheader = self.getheader('content-type')
1763 self.parsetype()
1764 self.parseplist()
1765
1766 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1767 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001768 try:
1769 self.send_response(200)
1770 self.send_header('Content-Type', 'text/html')
1771 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001772 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001773 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001774
1775 def do_GET(self):
1776 path = self.path
1777 if path[-5:] == '.html': path = path[:-5]
1778 if path[:1] == '/': path = path[1:]
1779 if path and path != '.':
1780 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001781 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001782 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001783 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001784 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001785 if obj:
1786 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001787 else:
1788 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001789'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001790 else:
1791 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001792'<big><big><strong>Python: Index of Modules</strong></big></big>',
1793'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001794 def bltinlink(name):
1795 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001796 names = filter(lambda x: x != '__main__',
1797 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001798 contents = html.multicolumn(names, bltinlink)
1799 indices = ['<p>' + html.bigsection(
1800 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1801
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001802 seen = {}
1803 for dir in pathdirs():
1804 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001805 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001806<font color="#909090" face="helvetica, arial"><strong>
1807pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001808 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001809
1810 def log_message(self, *args): pass
1811
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001812 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001813 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001814 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001815 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001816 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001817 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001818 self.base.__init__(self, self.address, self.handler)
1819
1820 def serve_until_quit(self):
1821 import select
1822 self.quit = 0
1823 while not self.quit:
1824 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1825 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001826
1827 def server_activate(self):
1828 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001829 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001830
1831 DocServer.base = BaseHTTPServer.HTTPServer
1832 DocServer.handler = DocHandler
1833 DocHandler.MessageClass = Message
1834 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001835 try:
1836 DocServer(port, callback).serve_until_quit()
1837 except (KeyboardInterrupt, select.error):
1838 pass
1839 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001840 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001841
1842# ----------------------------------------------------- graphical interface
1843
1844def gui():
1845 """Graphical interface (starts web server and pops up a control window)."""
1846 class GUI:
1847 def __init__(self, window, port=7464):
1848 self.window = window
1849 self.server = None
1850 self.scanner = None
1851
1852 import Tkinter
1853 self.server_frm = Tkinter.Frame(window)
1854 self.title_lbl = Tkinter.Label(self.server_frm,
1855 text='Starting server...\n ')
1856 self.open_btn = Tkinter.Button(self.server_frm,
1857 text='open browser', command=self.open, state='disabled')
1858 self.quit_btn = Tkinter.Button(self.server_frm,
1859 text='quit serving', command=self.quit, state='disabled')
1860
1861 self.search_frm = Tkinter.Frame(window)
1862 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1863 self.search_ent = Tkinter.Entry(self.search_frm)
1864 self.search_ent.bind('<Return>', self.search)
1865 self.stop_btn = Tkinter.Button(self.search_frm,
1866 text='stop', pady=0, command=self.stop, state='disabled')
1867 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001868 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001869 self.stop_btn.pack(side='right')
1870
1871 self.window.title('pydoc')
1872 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1873 self.title_lbl.pack(side='top', fill='x')
1874 self.open_btn.pack(side='left', fill='x', expand=1)
1875 self.quit_btn.pack(side='right', fill='x', expand=1)
1876 self.server_frm.pack(side='top', fill='x')
1877
1878 self.search_lbl.pack(side='left')
1879 self.search_ent.pack(side='right', fill='x', expand=1)
1880 self.search_frm.pack(side='top', fill='x')
1881 self.search_ent.focus_set()
1882
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001883 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001884 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001885 self.result_lst.bind('<Button-1>', self.select)
1886 self.result_lst.bind('<Double-Button-1>', self.goto)
1887 self.result_scr = Tkinter.Scrollbar(window,
1888 orient='vertical', command=self.result_lst.yview)
1889 self.result_lst.config(yscrollcommand=self.result_scr.set)
1890
1891 self.result_frm = Tkinter.Frame(window)
1892 self.goto_btn = Tkinter.Button(self.result_frm,
1893 text='go to selected', command=self.goto)
1894 self.hide_btn = Tkinter.Button(self.result_frm,
1895 text='hide results', command=self.hide)
1896 self.goto_btn.pack(side='left', fill='x', expand=1)
1897 self.hide_btn.pack(side='right', fill='x', expand=1)
1898
1899 self.window.update()
1900 self.minwidth = self.window.winfo_width()
1901 self.minheight = self.window.winfo_height()
1902 self.bigminheight = (self.server_frm.winfo_reqheight() +
1903 self.search_frm.winfo_reqheight() +
1904 self.result_lst.winfo_reqheight() +
1905 self.result_frm.winfo_reqheight())
1906 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1907 self.expanded = 0
1908 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1909 self.window.wm_minsize(self.minwidth, self.minheight)
1910
1911 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001912 threading.Thread(
1913 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001914
1915 def ready(self, server):
1916 self.server = server
1917 self.title_lbl.config(
1918 text='Python documentation server at\n' + server.url)
1919 self.open_btn.config(state='normal')
1920 self.quit_btn.config(state='normal')
1921
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001922 def open(self, event=None, url=None):
1923 url = url or self.server.url
1924 try:
1925 import webbrowser
1926 webbrowser.open(url)
1927 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001928 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001929 os.system('start "%s"' % url)
1930 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001931 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001932 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001933 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001934 else:
1935 rc = os.system('netscape -remote "openURL(%s)" &' % url)
1936 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001937
1938 def quit(self, event=None):
1939 if self.server:
1940 self.server.quit = 1
1941 self.window.quit()
1942
1943 def search(self, event=None):
1944 key = self.search_ent.get()
1945 self.stop_btn.pack(side='right')
1946 self.stop_btn.config(state='normal')
1947 self.search_lbl.config(text='Searching for "%s"...' % key)
1948 self.search_ent.forget()
1949 self.search_lbl.pack(side='left')
1950 self.result_lst.delete(0, 'end')
1951 self.goto_btn.config(state='disabled')
1952 self.expand()
1953
1954 import threading
1955 if self.scanner:
1956 self.scanner.quit = 1
1957 self.scanner = ModuleScanner()
1958 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00001959 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001960
1961 def update(self, path, modname, desc):
1962 if modname[-9:] == '.__init__':
1963 modname = modname[:-9] + ' (package)'
1964 self.result_lst.insert('end',
1965 modname + ' - ' + (desc or '(no description)'))
1966
1967 def stop(self, event=None):
1968 if self.scanner:
1969 self.scanner.quit = 1
1970 self.scanner = None
1971
1972 def done(self):
1973 self.scanner = None
1974 self.search_lbl.config(text='Search for')
1975 self.search_lbl.pack(side='left')
1976 self.search_ent.pack(side='right', fill='x', expand=1)
1977 if sys.platform != 'win32': self.stop_btn.forget()
1978 self.stop_btn.config(state='disabled')
1979
1980 def select(self, event=None):
1981 self.goto_btn.config(state='normal')
1982
1983 def goto(self, event=None):
1984 selection = self.result_lst.curselection()
1985 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001986 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001987 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001988
1989 def collapse(self):
1990 if not self.expanded: return
1991 self.result_frm.forget()
1992 self.result_scr.forget()
1993 self.result_lst.forget()
1994 self.bigwidth = self.window.winfo_width()
1995 self.bigheight = self.window.winfo_height()
1996 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1997 self.window.wm_minsize(self.minwidth, self.minheight)
1998 self.expanded = 0
1999
2000 def expand(self):
2001 if self.expanded: return
2002 self.result_frm.pack(side='bottom', fill='x')
2003 self.result_scr.pack(side='right', fill='y')
2004 self.result_lst.pack(side='top', fill='both', expand=1)
2005 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2006 self.window.wm_minsize(self.minwidth, self.bigminheight)
2007 self.expanded = 1
2008
2009 def hide(self, event=None):
2010 self.stop()
2011 self.collapse()
2012
2013 import Tkinter
2014 try:
2015 gui = GUI(Tkinter.Tk())
2016 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002017 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002018 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002019
2020# -------------------------------------------------- command-line interface
2021
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002022def ispath(x):
2023 return type(x) is types.StringType and find(x, os.sep) >= 0
2024
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002025def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002026 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002027 import getopt
2028 class BadUsage: pass
2029
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002030 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002031 scriptdir = os.path.dirname(sys.argv[0])
2032 if scriptdir in sys.path:
2033 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002034 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002035
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002036 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002037 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002038 writing = 0
2039
2040 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002041 if opt == '-g':
2042 gui()
2043 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002044 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002045 apropos(val)
2046 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002047 if opt == '-p':
2048 try:
2049 port = int(val)
2050 except ValueError:
2051 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002052 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002053 print 'pydoc server ready at %s' % server.url
2054 def stopped():
2055 print 'pydoc server stopped'
2056 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002057 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002058 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002059 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002060
2061 if not args: raise BadUsage
2062 for arg in args:
2063 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002064 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002065 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002066 if writing:
2067 if ispath(arg) and os.path.isdir(arg):
2068 writedocs(arg)
2069 else:
2070 writedoc(arg)
2071 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002072 doc(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002073 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002074 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002075
2076 except (getopt.error, BadUsage):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002077 cmd = sys.argv[0]
2078 print """pydoc - the Python documentation tool
2079
2080%s <name> ...
2081 Show text documentation on something. <name> may be the name of a
2082 function, module, or package, or a dotted reference to a class or
2083 function within a module or module in a package. If <name> contains
2084 a '%s', it is used as the path to a Python source file to document.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002085
2086%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002087 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002088
2089%s -p <port>
2090 Start an HTTP server on the given port on the local machine.
2091
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002092%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002093 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002094
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002095%s -w <name> ...
2096 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002097 directory. If <name> contains a '%s', it is treated as a filename; if
2098 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002099""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002100
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002101if __name__ == '__main__': cli()