blob: a6f9fa98e477c41d6a54be9cda71c81f0ff29a71 [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 Yee66efbc72001-03-01 13:55:20 +000038# Note: this module is designed to deploy instantly and run under any
39# version of Python from 1.5 and up. That's why it's a single file and
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000040# some 2.0 features (like string methods) are conspicuously absent.
41
42# Known bugs that can't be fixed here:
43# - imp.load_module() cannot be prevented from clobbering existing
44# loaded modules, so calling synopsis() on a binary module file
45# changes the contents of any existing module with the same name.
46# - If the __file__ attribute on a module is a relative path and
47# the current directory is changed with os.chdir(), an incorrect
48# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000049
Ka-Ping Yeedd175342001-02-27 14:43:46 +000050import sys, imp, os, stat, re, types, inspect
51from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000052from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
Ka-Ping Yeedd175342001-02-27 14:43:46 +000053
54# --------------------------------------------------------- common routines
55
Ka-Ping Yeedd175342001-02-27 14:43:46 +000056def pathdirs():
57 """Convert sys.path into a list of absolute, existing, unique paths."""
58 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000059 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000060 for dir in sys.path:
61 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000062 normdir = os.path.normcase(dir)
63 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000064 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000065 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000066 return dirs
67
68def getdoc(object):
69 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000070 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000071 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000072
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000073def splitdoc(doc):
74 """Split a doc string into a synopsis line (if any) and the rest."""
75 lines = split(strip(doc), '\n')
76 if len(lines) == 1:
77 return lines[0], ''
78 elif len(lines) >= 2 and not rstrip(lines[1]):
79 return lines[0], join(lines[2:], '\n')
80 return '', join(lines, '\n')
81
Ka-Ping Yeedd175342001-02-27 14:43:46 +000082def classname(object, modname):
83 """Get a class name and qualify it with a module name if necessary."""
84 name = object.__name__
85 if object.__module__ != modname:
86 name = object.__module__ + '.' + name
87 return name
88
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000089def isdata(object):
90 """Check if an object is of a type that probably means it's data."""
91 return not (inspect.ismodule(object) or inspect.isclass(object) or
92 inspect.isroutine(object) or inspect.isframe(object) or
93 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +000094
95def replace(text, *pairs):
96 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +000097 while pairs:
98 text = join(split(text, pairs[0]), pairs[1])
99 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000100 return text
101
102def cram(text, maxlen):
103 """Omit part of a string if needed to make it fit in a maximum length."""
104 if len(text) > maxlen:
105 pre = max(0, (maxlen-3)/2)
106 post = max(0, maxlen-3-pre)
107 return text[:pre] + '...' + text[len(text)-post:]
108 return text
109
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000110def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000111 """Remove the hexadecimal id from a Python object representation."""
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000112 # The behaviour of %p is implementation-dependent; we check two cases.
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000113 for pattern in [' at 0x[0-9a-f]{6,}>$', ' at [0-9A-F]{8,}>$']:
114 if re.search(pattern, repr(Exception)):
115 return re.sub(pattern, '>', text)
116 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000117
Tim Peters536d2262001-09-20 05:13:38 +0000118def _is_some_method(object):
119 return inspect.ismethod(object) or inspect.ismethoddescriptor(object)
120
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000121def allmethods(cl):
122 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000123 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000124 methods[key] = 1
125 for base in cl.__bases__:
126 methods.update(allmethods(base)) # all your base are belong to us
127 for key in methods.keys():
128 methods[key] = getattr(cl, key)
129 return methods
130
Tim Petersfa26f7c2001-09-24 08:05:11 +0000131def _split_list(s, predicate):
132 """Split sequence s via predicate, and return pair ([true], [false]).
133
134 The return value is a 2-tuple of lists,
135 ([x for x in s if predicate(x)],
136 [x for x in s if not predicate(x)])
137 """
138
Tim Peters28355492001-09-23 21:29:55 +0000139 yes = []
140 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000141 for x in s:
142 if predicate(x):
143 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000144 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000145 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000146 return yes, no
147
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000148# ----------------------------------------------------- module manipulation
149
150def ispackage(path):
151 """Guess whether a path refers to a package directory."""
152 if os.path.isdir(path):
153 for ext in ['.py', '.pyc', '.pyo']:
154 if os.path.isfile(os.path.join(path, '__init__' + ext)):
155 return 1
156
157def synopsis(filename, cache={}):
158 """Get the one-line summary out of a module file."""
159 mtime = os.stat(filename)[stat.ST_MTIME]
160 lastupdate, result = cache.get(filename, (0, None))
161 if lastupdate < mtime:
162 info = inspect.getmoduleinfo(filename)
163 file = open(filename)
164 if info and 'b' in info[2]: # binary modules have to be imported
165 try: module = imp.load_module('__temp__', file, filename, info[1:])
166 except: return None
167 result = split(module.__doc__ or '', '\n')[0]
168 del sys.modules['__temp__']
169 else: # text modules can be directly examined
170 line = file.readline()
171 while line[:1] == '#' or not strip(line):
172 line = file.readline()
173 if not line: break
174 line = strip(line)
175 if line[:4] == 'r"""': line = line[1:]
176 if line[:3] == '"""':
177 line = line[3:]
178 if line[-1:] == '\\': line = line[:-1]
179 while not strip(line):
180 line = file.readline()
181 if not line: break
182 result = strip(split(line, '"""')[0])
183 else: result = None
184 file.close()
185 cache[filename] = (mtime, result)
186 return result
187
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000188class ErrorDuringImport(Exception):
189 """Errors that occurred while trying to import something to document it."""
190 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000191 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000192 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000193 self.value = value
194 self.tb = tb
195
196 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000197 exc = self.exc
198 if type(exc) is types.ClassType:
199 exc = exc.__name__
200 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000201
202def importfile(path):
203 """Import a Python source file or compiled file given its path."""
204 magic = imp.get_magic()
205 file = open(path, 'r')
206 if file.read(len(magic)) == magic:
207 kind = imp.PY_COMPILED
208 else:
209 kind = imp.PY_SOURCE
210 file.close()
211 filename = os.path.basename(path)
212 name, ext = os.path.splitext(filename)
213 file = open(path, 'r')
214 try:
215 module = imp.load_module(name, file, path, (ext, 'r', kind))
216 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000217 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000218 file.close()
219 return module
220
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000221def safeimport(path, forceload=0, cache={}):
222 """Import a module; handle errors; return None if the module isn't found.
223
224 If the module *is* found but an exception occurs, it's wrapped in an
225 ErrorDuringImport exception and reraised. Unlike __import__, if a
226 package path is specified, the module at the end of the path is returned,
227 not the package at the beginning. If the optional 'forceload' argument
228 is 1, we reload the module from disk (unless it's a dynamic extension)."""
229 if forceload and sys.modules.has_key(path):
230 # This is the only way to be sure. Checking the mtime of the file
231 # isn't good enough (e.g. what if the module contains a class that
232 # inherits from another module that has changed?).
233 if path not in sys.builtin_module_names:
234 # Python never loads a dynamic extension a second time from the
235 # same path, even if the file is changed or missing. Deleting
236 # the entry in sys.modules doesn't help for dynamic extensions,
237 # so we're not even going to try to keep them up to date.
238 info = inspect.getmoduleinfo(sys.modules[path].__file__)
239 if info[3] != imp.C_EXTENSION:
240 cache[path] = sys.modules[path] # prevent module from clearing
241 del sys.modules[path]
242 try:
243 module = __import__(path)
244 except:
245 # Did the error occur before or after the module was found?
246 (exc, value, tb) = info = sys.exc_info()
247 if sys.modules.has_key(path):
248 # An error occured while executing the imported module.
249 raise ErrorDuringImport(sys.modules[path].__file__, info)
250 elif exc is SyntaxError:
251 # A SyntaxError occurred before we could execute the module.
252 raise ErrorDuringImport(value.filename, info)
253 elif exc is ImportError and \
254 split(lower(str(value)))[:2] == ['no', 'module']:
255 # The module was not found.
256 return None
257 else:
258 # Some other error occurred during the importing process.
259 raise ErrorDuringImport(path, sys.exc_info())
260 for part in split(path, '.')[1:]:
261 try: module = getattr(module, part)
262 except AttributeError: return None
263 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000264
265# ---------------------------------------------------- formatter base class
266
267class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000268 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000269 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000270 args = (object, name) + args
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000271 if inspect.ismodule(object): return apply(self.docmodule, args)
272 if inspect.isclass(object): return apply(self.docclass, args)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000273 if inspect.isroutine(object): return apply(self.docroutine, args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000274 return apply(self.docother, args)
275
276 def fail(self, object, name=None, *args):
277 """Raise an exception for unimplemented types."""
278 message = "don't know how to document object%s of type %s" % (
279 name and ' ' + repr(name), type(object).__name__)
280 raise TypeError, message
281
282 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000283
284# -------------------------------------------- HTML documentation generator
285
286class HTMLRepr(Repr):
287 """Class for safely making an HTML representation of a Python object."""
288 def __init__(self):
289 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000290 self.maxlist = self.maxtuple = 20
291 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000292 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000293
294 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000295 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000296
297 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000298 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000299
300 def repr1(self, x, level):
301 methodname = 'repr_' + join(split(type(x).__name__), '_')
302 if hasattr(self, methodname):
303 return getattr(self, methodname)(x, level)
304 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000305 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000306
307 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000308 test = cram(x, self.maxstring)
309 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000310 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000311 # Backslashes are only literal in the string and are never
312 # needed to make any special characters, so show a raw string.
313 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000314 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000315 r'<font color="#c040c0">\1</font>',
316 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000317
318 def repr_instance(self, x, level):
319 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000320 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000321 except:
322 return self.escape('<%s instance>' % x.__class__.__name__)
323
324 repr_unicode = repr_string
325
326class HTMLDoc(Doc):
327 """Formatter class for HTML documentation."""
328
329 # ------------------------------------------- HTML formatting utilities
330
331 _repr_instance = HTMLRepr()
332 repr = _repr_instance.repr
333 escape = _repr_instance.escape
334
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000335 def page(self, title, contents):
336 """Format an HTML page."""
337 return '''
338<!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000339<html><head><title>Python: %s</title>
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000340<style type="text/css"><!--
Ka-Ping Yeed03f8fe2001-04-13 15:04:32 +0000341TT { font-family: lucidatypewriter, lucida console, courier }
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000342--></style></head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000343%s
344</body></html>''' % (title, contents)
345
346 def heading(self, title, fgcol, bgcol, extras=''):
347 """Format a page heading."""
348 return '''
349<table width="100%%" cellspacing=0 cellpadding=2 border=0>
350<tr bgcolor="%s">
351<td valign=bottom><small>&nbsp;<br></small
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000352><font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000353><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000354><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000355 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
356
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000357 def section(self, title, fgcol, bgcol, contents, width=10,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000358 prelude='', marginalia=None, gap='&nbsp;&nbsp;'):
359 """Format a section with a heading."""
360 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000361 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000362 result = '''
363<p><table width="100%%" cellspacing=0 cellpadding=2 border=0>
364<tr bgcolor="%s">
365<td colspan=3 valign=bottom><small><small>&nbsp;<br></small></small
366><font color="%s" face="helvetica, arial">%s</font></td></tr>
367 ''' % (bgcol, fgcol, title)
368 if prelude:
369 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000370<tr bgcolor="%s"><td rowspan=2>%s</td>
371<td colspan=2>%s</td></tr>
372<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
373 else:
374 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000375<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000376
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000377 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000378
379 def bigsection(self, title, *args):
380 """Format a section with a big heading."""
381 title = '<big><strong>%s</strong></big>' % title
382 return apply(self.section, (title,) + args)
383
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000384 def preformat(self, text):
385 """Format literal preformatted text."""
386 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000387 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
388 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000389
390 def multicolumn(self, list, format, cols=4):
391 """Format a list of items into a multi-column list."""
392 result = ''
393 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000394 for col in range(cols):
395 result = result + '<td width="%d%%" valign=top>' % (100/cols)
396 for i in range(rows*col, rows*col+rows):
397 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000398 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000399 result = result + '</td>'
400 return '<table width="100%%"><tr>%s</tr></table>' % result
401
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000402 def small(self, text): return '<small>%s</small>' % text
403 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000404
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000405 def namelink(self, name, *dicts):
406 """Make a link for an identifier, given name-to-URL mappings."""
407 for dict in dicts:
408 if dict.has_key(name):
409 return '<a href="%s">%s</a>' % (dict[name], name)
410 return name
411
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000412 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000413 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000414 name, module = object.__name__, sys.modules.get(object.__module__)
415 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000416 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000417 module.__name__, name, classname(object, modname))
418 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000419
420 def modulelink(self, object):
421 """Make a link for a module."""
422 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
423
424 def modpkglink(self, (name, path, ispackage, shadowed)):
425 """Make a link for a module or package to display in an index."""
426 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000427 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000428 if path:
429 url = '%s.%s.html' % (path, name)
430 else:
431 url = '%s.html' % name
432 if ispackage:
433 text = '<strong>%s</strong>&nbsp;(package)' % name
434 else:
435 text = name
436 return '<a href="%s">%s</a>' % (url, text)
437
438 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
439 """Mark up some plain text, given a context of symbols to look for.
440 Each context dictionary maps object names to anchor names."""
441 escape = escape or self.escape
442 results = []
443 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000444 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
445 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000446 r'PEP[- ]?(\d+)|'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000447 r'(self\.)?(\w+))\b')
448 while 1:
449 match = pattern.search(text, here)
450 if not match: break
451 start, end = match.span()
452 results.append(escape(text[here:start]))
453
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000454 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000455 if scheme:
456 results.append('<a href="%s">%s</a>' % (all, escape(all)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000457 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000458 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
459 results.append('<a href="%s">%s</a>' % (url, escape(all)))
460 elif pep:
461 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000462 results.append('<a href="%s">%s</a>' % (url, escape(all)))
463 elif text[end:end+1] == '(':
464 results.append(self.namelink(name, methods, funcs, classes))
465 elif selfdot:
466 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000467 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000468 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000469 here = end
470 results.append(escape(text[here:]))
471 return join(results, '')
472
473 # ---------------------------------------------- type-specific routines
474
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000475 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000476 """Produce HTML for a class tree as given by inspect.getclasstree()."""
477 result = ''
478 for entry in tree:
479 if type(entry) is type(()):
480 c, bases = entry
481 result = result + '<dt><font face="helvetica, arial"><small>'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000482 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000483 if bases and bases != (parent,):
484 parents = []
485 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000486 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000487 result = result + '(' + join(parents, ', ') + ')'
488 result = result + '\n</small></font></dt>'
489 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000490 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000491 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000492 return '<dl>\n%s</dl>\n' % result
493
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000494 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000495 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000496 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000497 parts = split(name, '.')
498 links = []
499 for i in range(len(parts)-1):
500 links.append(
501 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
502 (join(parts[:i+1], '.'), parts[i]))
503 linkedname = join(links + parts[-1:], '.')
504 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000505 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000506 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000507 url = path
508 if sys.platform == 'win32':
509 import nturl2path
510 url = nturl2path.pathname2url(path)
511 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000512 except TypeError:
513 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000514 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000515 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000516 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000517 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
518 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000519 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000520 if hasattr(object, '__date__'):
521 info.append(self.escape(str(object.__date__)))
522 if info:
523 head = head + ' (%s)' % join(info, ', ')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000524 result = self.heading(
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000525 head, '#ffffff', '#7799ee', '<a href=".">index</a><br>' + filelink)
526
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000527 modules = inspect.getmembers(object, inspect.ismodule)
528
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000529 classes, cdict = [], {}
530 for key, value in inspect.getmembers(object, inspect.isclass):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000531 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000532 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000533 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000534 for key, value in classes:
535 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000536 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000537 module = sys.modules.get(modname)
538 if modname != name and module and hasattr(module, key):
539 if getattr(module, key) is base:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000540 if not cdict.has_key(key):
541 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000542 funcs, fdict = [], {}
543 for key, value in inspect.getmembers(object, inspect.isroutine):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000544 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000545 funcs.append((key, value))
546 fdict[key] = '#-' + key
547 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000548 data = []
549 for key, value in inspect.getmembers(object, isdata):
550 if key not in ['__builtins__', '__doc__']:
551 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000552
553 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
554 doc = doc and '<tt>%s</tt>' % doc
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000555 result = result + '<p>%s</p>\n' % self.small(doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000556
557 if hasattr(object, '__path__'):
558 modpkgs = []
559 modnames = []
560 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000561 path = os.path.join(object.__path__[0], file)
562 modname = inspect.getmodulename(file)
563 if modname and modname not in modnames:
564 modpkgs.append((modname, name, 0, 0))
565 modnames.append(modname)
566 elif ispackage(path):
567 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000568 modpkgs.sort()
569 contents = self.multicolumn(modpkgs, self.modpkglink)
570 result = result + self.bigsection(
571 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000572 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000573 contents = self.multicolumn(
574 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000575 result = result + self.bigsection(
576 'Modules', '#fffff', '#aa55cc', contents)
577
578 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000579 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000580 contents = [
581 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000582 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000583 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000584 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000585 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000586 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000587 contents = []
588 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000589 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000590 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000591 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000592 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000593 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000594 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000595 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000596 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000597 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000598 if hasattr(object, '__author__'):
599 contents = self.markup(str(object.__author__), self.preformat)
600 result = result + self.bigsection(
601 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000602 if hasattr(object, '__credits__'):
603 contents = self.markup(str(object.__credits__), self.preformat)
604 result = result + self.bigsection(
605 'Credits', '#ffffff', '#7799ee', contents)
606
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000607 return result
608
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000609 def docclass(self, object, name=None, mod=None, funcs={}, classes={}):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000610 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000611 realname = object.__name__
612 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000613 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000614
Tim Petersb47879b2001-09-24 04:47:19 +0000615 contents = []
616 push = contents.append
617
Tim Petersfa26f7c2001-09-24 08:05:11 +0000618 # Cute little class to pump out a horizontal rule between sections.
619 class HorizontalRule:
620 def __init__(self):
621 self.needone = 0
622 def maybe(self):
623 if self.needone:
624 push('<hr>\n')
625 self.needone = 1
626 hr = HorizontalRule()
627
Tim Petersb47879b2001-09-24 04:47:19 +0000628 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000629 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000630 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000631 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000632 push(msg)
633 for name, kind, homecls, value in ok:
634 push(self.document(getattr(object, name), name, mod,
635 funcs, classes, mdict, object))
636 push('\n')
637 return attrs
638
639 # pydoc can't make any reasonable sense of properties on its own,
640 # and it doesn't appear that the getter, setter and del'er methods
641 # are discoverable. For now, just pump out their names.
Tim Petersfa26f7c2001-09-24 08:05:11 +0000642 def spillproperties(msg, attrs, predicate):
643 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000644 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000645 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000646 push(msg)
647 for name, kind, homecls, value in ok:
648 push('<dl><dt><strong>%s</strong></dl>\n' % name)
649 return attrs
650
Tim Petersfa26f7c2001-09-24 08:05:11 +0000651 def spilldata(msg, attrs, predicate):
652 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000653 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000654 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000655 push(msg)
656 for name, kind, homecls, value in ok:
657 base = self.docother(getattr(object, name), name, mod)
658 doc = getattr(value, "__doc__", None)
659 if doc is None:
660 push('<dl><dt>%s</dl>\n' % base)
661 else:
662 doc = self.markup(getdoc(value), self.preformat,
663 funcs, classes, mdict)
664 doc = '<dd>' + self.small('<tt>%s</tt>' % doc)
665 push('<dl><dt>%s%s</dl>\n' % (base, doc))
666 push('\n')
667 return attrs
668
669 attrs = inspect.classify_class_attrs(object)
670 mdict = {}
671 for key, kind, homecls, value in attrs:
672 mdict[key] = anchor = '#' + name + '-' + key
673 value = getattr(object, key)
674 try:
675 # The value may not be hashable (e.g., a data attr with
676 # a dict or list value).
677 mdict[value] = anchor
678 except TypeError:
679 pass
680
Tim Petersfa26f7c2001-09-24 08:05:11 +0000681 # Sort attrs by name of defining class.
682 attrs.sort(lambda t1, t2: cmp(t1[2].__name__, t2[2].__name__))
Tim Petersb47879b2001-09-24 04:47:19 +0000683
Tim Petersfa26f7c2001-09-24 08:05:11 +0000684 thisclass = object # list attrs defined here first
685 while attrs:
686 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
687
Tim Petersb47879b2001-09-24 04:47:19 +0000688 if thisclass is object:
689 tag = "defined here"
690 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000691 tag = "inherited from %s" % self.classlink(thisclass,
Tim Petersb47879b2001-09-24 04:47:19 +0000692 object.__module__)
693 tag += ':<br>\n'
694
695 # Sort attrs by name.
696 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
697
698 # Pump out the attrs, segregated by kind.
699 attrs = spill("Methods %s" % tag, attrs,
700 lambda t: t[1] == 'method')
701 attrs = spill("Class methods %s" % tag, attrs,
702 lambda t: t[1] == 'class method')
703 attrs = spill("Static methods %s" % tag, attrs,
704 lambda t: t[1] == 'static method')
Tim Petersfa26f7c2001-09-24 08:05:11 +0000705 attrs = spillproperties("Properties %s" % tag, attrs,
706 lambda t: t[1] == 'property')
707 attrs = spilldata("Data %s" % tag, attrs,
708 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000709 assert attrs == []
710
711 # Split off the attributes inherited from the next class (note
712 # that inherited remains sorted by class name).
713 if inherited:
714 attrs = inherited
715 thisclass = attrs[0][2]
Tim Petersb47879b2001-09-24 04:47:19 +0000716
717 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000718
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000719 if name == realname:
720 title = '<a name="%s">class <strong>%s</strong></a>' % (
721 name, realname)
722 else:
723 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
724 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000725 if bases:
726 parents = []
727 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000728 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000729 title = title + '(%s)' % join(parents, ', ')
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000730 doc = self.markup(
731 getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000732 doc = self.small(doc and '<tt>%s<br>&nbsp;</tt>' % doc or
733 self.small('&nbsp;'))
734 return self.section(title, '#000000', '#ffc8d8', contents, 5, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000735
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000736 def formatvalue(self, object):
737 """Format an argument default value as text."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000738 return self.small(self.grey('=' + self.repr(object)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000739
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000740 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000741 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000742 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000743 realname = object.__name__
744 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000745 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000746 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000747 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000748 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000749 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000750 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000751 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000752 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000753 skipdocs = 1
754 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000755 if object.im_self:
756 note = ' method of %s instance' % self.classlink(
757 object.im_self.__class__, mod)
758 else:
759 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000760 object = object.im_func
761
762 if name == realname:
763 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
764 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000765 if (cl and cl.__dict__.has_key(realname) and
766 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000767 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000768 cl.__name__ + '-' + realname, realname)
769 skipdocs = 1
770 else:
771 reallink = realname
772 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
773 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000774 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000775 args, varargs, varkw, defaults = inspect.getargspec(object)
776 argspec = inspect.formatargspec(
777 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000778 if realname == '<lambda>':
779 decl = '<em>lambda</em>'
780 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000781 else:
782 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000783
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000784 decl = title + argspec + (note and self.small(self.grey(
785 '<font face="helvetica, arial">%s</font>' % note)))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000786
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000787 if skipdocs:
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000788 return '<dl><dt>%s</dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000789 else:
790 doc = self.markup(
791 getdoc(object), self.preformat, funcs, classes, methods)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000792 doc = doc and '<dd>' + self.small('<tt>%s</tt>' % doc)
793 return '<dl><dt>%s%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000794
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000795 def docother(self, object, name=None, mod=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000796 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000797 lhs = name and '<strong>%s</strong> = ' % name or ''
798 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000799
800 def index(self, dir, shadowed=None):
801 """Generate an HTML index for a directory of modules."""
802 modpkgs = []
803 if shadowed is None: shadowed = {}
804 seen = {}
805 files = os.listdir(dir)
806
807 def found(name, ispackage,
808 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
809 if not seen.has_key(name):
810 modpkgs.append((name, '', ispackage, shadowed.has_key(name)))
811 seen[name] = 1
812 shadowed[name] = 1
813
814 # Package spam/__init__.py takes precedence over module spam.py.
815 for file in files:
816 path = os.path.join(dir, file)
817 if ispackage(path): found(file, 1)
818 for file in files:
819 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000820 if os.path.isfile(path):
821 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000822 if modname: found(modname, 0)
823
824 modpkgs.sort()
825 contents = self.multicolumn(modpkgs, self.modpkglink)
826 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
827
828# -------------------------------------------- text documentation generator
829
830class TextRepr(Repr):
831 """Class for safely making a text representation of a Python object."""
832 def __init__(self):
833 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000834 self.maxlist = self.maxtuple = 20
835 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000836 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000837
838 def repr1(self, x, level):
839 methodname = 'repr_' + join(split(type(x).__name__), '_')
840 if hasattr(self, methodname):
841 return getattr(self, methodname)(x, level)
842 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000843 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000844
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000845 def repr_string(self, x, level):
846 test = cram(x, self.maxstring)
847 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000848 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000849 # Backslashes are only literal in the string and are never
850 # needed to make any special characters, so show a raw string.
851 return 'r' + testrepr[0] + test + testrepr[0]
852 return testrepr
853
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000854 def repr_instance(self, x, level):
855 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000856 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000857 except:
858 return '<%s instance>' % x.__class__.__name__
859
860class TextDoc(Doc):
861 """Formatter class for text documentation."""
862
863 # ------------------------------------------- text formatting utilities
864
865 _repr_instance = TextRepr()
866 repr = _repr_instance.repr
867
868 def bold(self, text):
869 """Format a string in bold by overstriking."""
870 return join(map(lambda ch: ch + '\b' + ch, text), '')
871
872 def indent(self, text, prefix=' '):
873 """Indent text by prepending a given prefix to each line."""
874 if not text: return ''
875 lines = split(text, '\n')
876 lines = map(lambda line, prefix=prefix: prefix + line, lines)
877 if lines: lines[-1] = rstrip(lines[-1])
878 return join(lines, '\n')
879
880 def section(self, title, contents):
881 """Format a section with a given heading."""
882 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
883
884 # ---------------------------------------------- type-specific routines
885
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000886 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000887 """Render in text a class tree as returned by inspect.getclasstree()."""
888 result = ''
889 for entry in tree:
890 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000891 c, bases = entry
892 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000893 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000894 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000895 result = result + '(%s)' % join(parents, ', ')
896 result = result + '\n'
897 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000898 result = result + self.formattree(
899 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000900 return result
901
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000902 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000903 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000904 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000905 synop, desc = splitdoc(getdoc(object))
906 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000907
908 try:
909 file = inspect.getabsfile(object)
910 except TypeError:
911 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000912 result = result + self.section('FILE', file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000913 if desc:
914 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000915
916 classes = []
917 for key, value in inspect.getmembers(object, inspect.isclass):
918 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000919 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000920 funcs = []
921 for key, value in inspect.getmembers(object, inspect.isroutine):
922 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000923 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000924 data = []
925 for key, value in inspect.getmembers(object, isdata):
926 if key not in ['__builtins__', '__doc__']:
927 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000928
929 if hasattr(object, '__path__'):
930 modpkgs = []
931 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000932 path = os.path.join(object.__path__[0], file)
933 modname = inspect.getmodulename(file)
934 if modname and modname not in modpkgs:
935 modpkgs.append(modname)
936 elif ispackage(path):
937 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000938 modpkgs.sort()
939 result = result + self.section(
940 'PACKAGE CONTENTS', join(modpkgs, '\n'))
941
942 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000943 classlist = map(lambda (key, value): value, classes)
944 contents = [self.formattree(
945 inspect.getclasstree(classlist, 1), name)]
946 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000947 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000948 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000949
950 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000951 contents = []
952 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000953 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000954 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000955
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000956 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000957 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000958 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000959 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000960 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000961
962 if hasattr(object, '__version__'):
963 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000964 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
965 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000966 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000967 if hasattr(object, '__date__'):
968 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000969 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000970 result = result + self.section('AUTHOR', str(object.__author__))
971 if hasattr(object, '__credits__'):
972 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000973 return result
974
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000975 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000976 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000977 realname = object.__name__
978 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000979 bases = object.__bases__
980
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000981 if name == realname:
982 title = 'class ' + self.bold(realname)
983 else:
984 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000985 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000986 def makename(c, m=object.__module__): return classname(c, m)
987 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000988 title = title + '(%s)' % join(parents, ', ')
989
990 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +0000991 contents = doc and [doc + '\n'] or []
992 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000993
Tim Peters28355492001-09-23 21:29:55 +0000994 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000995 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +0000996 if ok:
997 push(msg)
998 for name, kind, homecls, value in ok:
999 push(self.document(getattr(object, name),
1000 name, mod, object))
1001 return attrs
1002
1003 # pydoc can't make any reasonable sense of properties on its own,
1004 # and it doesn't appear that the getter, setter and del'er methods
1005 # are discoverable. For now, just pump out their names.
Tim Petersfa26f7c2001-09-24 08:05:11 +00001006 def spillproperties(msg, attrs, predicate):
1007 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001008 if ok:
1009 push(msg)
1010 for name, kind, homecls, value in ok:
1011 push(name + '\n')
1012 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001013
Tim Petersfa26f7c2001-09-24 08:05:11 +00001014 def spilldata(msg, attrs, predicate):
1015 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001016 if ok:
1017 push(msg)
1018 for name, kind, homecls, value in ok:
1019 doc = getattr(value, "__doc__", None)
1020 push(self.docother(getattr(object, name),
1021 name, mod, 70, doc) + '\n')
1022 return attrs
1023
1024 attrs = inspect.classify_class_attrs(object)
1025
Tim Petersfa26f7c2001-09-24 08:05:11 +00001026 # Sort attrs by name of defining class.
1027 attrs.sort(lambda t1, t2: cmp(t1[2].__name__, t2[2].__name__))
Tim Peters28355492001-09-23 21:29:55 +00001028
Tim Petersfa26f7c2001-09-24 08:05:11 +00001029 thisclass = object # list attrs defined here first
1030 while attrs:
1031 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1032
Tim Peters28355492001-09-23 21:29:55 +00001033 if thisclass is object:
1034 tag = "defined here"
1035 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001036 tag = "inherited from %s" % classname(thisclass,
1037 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001038
1039 # Sort attrs by name.
1040 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
1041
1042 # Pump out the attrs, segregated by kind.
Tim Petersfa26f7c2001-09-24 08:05:11 +00001043 attrs = spill("* Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001044 lambda t: t[1] == 'method')
Tim Petersfa26f7c2001-09-24 08:05:11 +00001045 attrs = spill("* Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001046 lambda t: t[1] == 'class method')
Tim Petersfa26f7c2001-09-24 08:05:11 +00001047 attrs = spill("* Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001048 lambda t: t[1] == 'static method')
Tim Petersfa26f7c2001-09-24 08:05:11 +00001049 attrs = spillproperties("* Properties %s:\n" % tag, attrs,
1050 lambda t: t[1] == 'property')
1051 attrs = spilldata("* Data %s:\n" % tag, attrs,
1052 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001053 assert attrs == []
1054
1055 # Split off the attributes inherited from the next class (note
1056 # that inherited remains sorted by class name).
1057 if inherited:
1058 attrs = inherited
1059 thisclass = attrs[0][2]
Tim Peters28355492001-09-23 21:29:55 +00001060
1061 contents = '\n'.join(contents)
1062 if not contents:
1063 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001064 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1065
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001066 def formatvalue(self, object):
1067 """Format an argument default value as text."""
1068 return '=' + self.repr(object)
1069
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001070 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001071 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001072 realname = object.__name__
1073 name = name or realname
1074 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001075 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001076 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001077 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001078 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001079 if imclass is not cl:
1080 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001081 skipdocs = 1
1082 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001083 if object.im_self:
1084 note = ' method of %s instance' % classname(
1085 object.im_self.__class__, mod)
1086 else:
1087 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001088 object = object.im_func
1089
1090 if name == realname:
1091 title = self.bold(realname)
1092 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001093 if (cl and cl.__dict__.has_key(realname) and
1094 cl.__dict__[realname] is object):
1095 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001096 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001097 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001098 args, varargs, varkw, defaults = inspect.getargspec(object)
1099 argspec = inspect.formatargspec(
1100 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001101 if realname == '<lambda>':
1102 title = 'lambda'
1103 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001104 else:
1105 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001106 decl = title + argspec + note
1107
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001108 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001109 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001110 else:
1111 doc = getdoc(object) or ''
1112 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001113
Tim Peters28355492001-09-23 21:29:55 +00001114 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001115 """Produce text documentation for a data object."""
1116 repr = self.repr(object)
1117 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001118 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001119 chop = maxlen - len(line)
1120 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001121 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001122 if doc is not None:
1123 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001124 return line
1125
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001126# --------------------------------------------------------- user interfaces
1127
1128def pager(text):
1129 """The first time this is called, determine what kind of pager to use."""
1130 global pager
1131 pager = getpager()
1132 pager(text)
1133
1134def getpager():
1135 """Decide what method to use for paging through text."""
1136 if type(sys.stdout) is not types.FileType:
1137 return plainpager
1138 if not sys.stdin.isatty() or not sys.stdout.isatty():
1139 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001140 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001141 return plainpager
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001142 if os.environ.has_key('PAGER'):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001143 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001144 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1145 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1146 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001147 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001148 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001149 if sys.platform == 'win32':
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001150 return lambda text: tempfilepager(plain(text), 'more <')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001151 if hasattr(os, 'system') and os.system('less 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001152 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001153
1154 import tempfile
1155 filename = tempfile.mktemp()
1156 open(filename, 'w').close()
1157 try:
1158 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1159 return lambda text: pipepager(text, 'more')
1160 else:
1161 return ttypager
1162 finally:
1163 os.unlink(filename)
1164
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001165def plain(text):
1166 """Remove boldface formatting from text."""
1167 return re.sub('.\b', '', text)
1168
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001169def pipepager(text, cmd):
1170 """Page through text by feeding it to another program."""
1171 pipe = os.popen(cmd, 'w')
1172 try:
1173 pipe.write(text)
1174 pipe.close()
1175 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001176 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001177
1178def tempfilepager(text, cmd):
1179 """Page through text by invoking a program on a temporary file."""
1180 import tempfile
1181 filename = tempfile.mktemp()
1182 file = open(filename, 'w')
1183 file.write(text)
1184 file.close()
1185 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001186 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001187 finally:
1188 os.unlink(filename)
1189
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001190def ttypager(text):
1191 """Page through text on a text terminal."""
1192 lines = split(plain(text), '\n')
1193 try:
1194 import tty
1195 fd = sys.stdin.fileno()
1196 old = tty.tcgetattr(fd)
1197 tty.setcbreak(fd)
1198 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001199 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001200 tty = None
1201 getchar = lambda: sys.stdin.readline()[:-1][:1]
1202
1203 try:
1204 r = inc = os.environ.get('LINES', 25) - 1
1205 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1206 while lines[r:]:
1207 sys.stdout.write('-- more --')
1208 sys.stdout.flush()
1209 c = getchar()
1210
1211 if c in ['q', 'Q']:
1212 sys.stdout.write('\r \r')
1213 break
1214 elif c in ['\r', '\n']:
1215 sys.stdout.write('\r \r' + lines[r] + '\n')
1216 r = r + 1
1217 continue
1218 if c in ['b', 'B', '\x1b']:
1219 r = r - inc - inc
1220 if r < 0: r = 0
1221 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1222 r = r + inc
1223
1224 finally:
1225 if tty:
1226 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1227
1228def plainpager(text):
1229 """Simply print unformatted text. This is the ultimate fallback."""
1230 sys.stdout.write(plain(text))
1231
1232def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001233 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001234 if inspect.ismodule(thing):
1235 if thing.__name__ in sys.builtin_module_names:
1236 return 'built-in module ' + thing.__name__
1237 if hasattr(thing, '__path__'):
1238 return 'package ' + thing.__name__
1239 else:
1240 return 'module ' + thing.__name__
1241 if inspect.isbuiltin(thing):
1242 return 'built-in function ' + thing.__name__
1243 if inspect.isclass(thing):
1244 return 'class ' + thing.__name__
1245 if inspect.isfunction(thing):
1246 return 'function ' + thing.__name__
1247 if inspect.ismethod(thing):
1248 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001249 if type(thing) is types.InstanceType:
1250 return 'instance of ' + thing.__class__.__name__
1251 return type(thing).__name__
1252
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001253def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001254 """Locate an object by name or dotted path, importing as necessary."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001255 parts = split(path, '.')
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001256 module, n = None, 0
1257 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001258 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001259 if nextmodule: module, n = nextmodule, n + 1
1260 else: break
1261 if module:
1262 object = module
1263 for part in parts[n:]:
1264 try: object = getattr(object, part)
1265 except AttributeError: return None
1266 return object
1267 else:
1268 import __builtin__
1269 if hasattr(__builtin__, path):
1270 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001271
1272# --------------------------------------- interactive interpreter interface
1273
1274text = TextDoc()
1275html = HTMLDoc()
1276
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001277def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001278 """Display text documentation, given an object or a path to an object."""
1279 suffix, name = '', None
1280 if type(thing) is type(''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001281 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001282 object = locate(thing, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001283 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001284 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001285 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001286 if not object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001287 print 'no Python documentation found for %s' % repr(thing)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001288 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001289 parts = split(thing, '.')
1290 if len(parts) > 1: suffix = ' in ' + join(parts[:-1], '.')
1291 name = parts[-1]
1292 thing = object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001293
1294 desc = describe(thing)
1295 module = inspect.getmodule(thing)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001296 if not suffix and module and module is not thing:
1297 suffix = ' in module ' + module.__name__
Ka-Ping Yee66246962001-04-12 11:59:50 +00001298 pager(title % (desc + suffix) + '\n\n' + text.document(thing, name))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001299
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001300def writedoc(key, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001301 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001302 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001303 object = locate(key, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001304 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001305 print value
1306 else:
1307 if object:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001308 page = html.page(describe(object),
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001309 html.document(object, object.__name__))
1310 file = open(key + '.html', 'w')
1311 file.write(page)
1312 file.close()
1313 print 'wrote', key + '.html'
1314 else:
1315 print 'no Python documentation found for %s' % repr(key)
1316
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001317def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001318 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001319 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001320 for file in os.listdir(dir):
1321 path = os.path.join(dir, file)
1322 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001323 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001324 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001325 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001326 if modname:
1327 modname = pkgpath + modname
1328 if not done.has_key(modname):
1329 done[modname] = 1
1330 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001331
1332class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001333 keywords = {
1334 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001335 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001336 'break': ('ref/break', 'while for'),
1337 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1338 'continue': ('ref/continue', 'while for'),
1339 'def': ('ref/function', ''),
1340 'del': ('ref/del', 'BASICMETHODS'),
1341 'elif': 'if',
1342 'else': ('ref/if', 'while for'),
1343 'except': 'try',
1344 'exec': ('ref/exec', ''),
1345 'finally': 'try',
1346 'for': ('ref/for', 'break continue while'),
1347 'from': 'import',
1348 'global': ('ref/global', 'NAMESPACES'),
1349 'if': ('ref/if', 'TRUTHVALUE'),
1350 'import': ('ref/import', 'MODULES'),
1351 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1352 'is': 'COMPARISON',
1353 'lambda': ('ref/lambda', 'FUNCTIONS'),
1354 'not': 'BOOLEAN',
1355 'or': 'BOOLEAN',
1356 'pass': 'PASS',
1357 'print': ('ref/print', ''),
1358 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001359 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001360 'try': ('ref/try', 'EXCEPTIONS'),
1361 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1362 }
1363
1364 topics = {
1365 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001366 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001367 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1368 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001369 'UNICODE': ('ref/unicode', 'encodings unicode TYPES STRING'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001370 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1371 'INTEGER': ('ref/integers', 'int range'),
1372 'FLOAT': ('ref/floating', 'float math'),
1373 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001374 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001375 'MAPPINGS': 'DICTIONARIES',
1376 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1377 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1378 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001379 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001380 'FRAMEOBJECTS': 'TYPES',
1381 'TRACEBACKS': 'TYPES',
1382 'NONE': ('lib/bltin-null-object', ''),
1383 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1384 'FILES': ('lib/bltin-file-objects', ''),
1385 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1386 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1387 'MODULES': ('lib/typesmodules', 'import'),
1388 'PACKAGES': 'import',
1389 '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'),
1390 'OPERATORS': 'EXPRESSIONS',
1391 'PRECEDENCE': 'EXPRESSIONS',
1392 'OBJECTS': ('ref/objects', 'TYPES'),
1393 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001394 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1395 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1396 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1397 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1398 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1399 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1400 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001401 'EXECUTION': ('ref/execframes', ''),
1402 'NAMESPACES': ('ref/execframes', 'global ASSIGNMENT DELETION'),
1403 'SCOPING': 'NAMESPACES',
1404 'FRAMES': 'NAMESPACES',
1405 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1406 'COERCIONS': 'CONVERSIONS',
1407 'CONVERSIONS': ('ref/conversions', ''),
1408 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1409 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001410 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001411 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1412 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001413 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001414 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001415 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001416 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001417 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1418 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001419 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1420 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1421 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1422 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1423 'POWER': ('ref/power', 'EXPRESSIONS'),
1424 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1425 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1426 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1427 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1428 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001429 'BOOLEAN': ('ref/lambda', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001430 'ASSERTION': 'assert',
1431 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001432 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001433 'DELETION': 'del',
1434 'PRINTING': 'print',
1435 'RETURNING': 'return',
1436 'IMPORTING': 'import',
1437 'CONDITIONAL': 'if',
1438 'LOOPING': ('ref/compound', 'for while break continue'),
1439 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001440 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001441 }
1442
1443 def __init__(self, input, output):
1444 self.input = input
1445 self.output = output
1446 self.docdir = None
1447 execdir = os.path.dirname(sys.executable)
1448 homedir = os.environ.get('PYTHONHOME')
1449 for dir in [os.environ.get('PYTHONDOCS'),
1450 homedir and os.path.join(homedir, 'doc'),
1451 os.path.join(execdir, 'doc'),
1452 '/usr/doc/python-docs-' + split(sys.version)[0],
1453 '/usr/doc/python-' + split(sys.version)[0],
1454 '/usr/doc/python-docs-' + sys.version[:3],
1455 '/usr/doc/python-' + sys.version[:3]]:
1456 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1457 self.docdir = dir
1458
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001459 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001460 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001461 self()
1462 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001463 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001464
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001465 def __call__(self, request=None):
1466 if request is not None:
1467 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001468 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001469 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001470 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001471 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001472You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001473If you want to ask for help on a particular object directly from the
1474interpreter, you can type "help(object)". Executing "help('string')"
1475has the same effect as typing a particular string at the help> prompt.
1476''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001477
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001478 def interact(self):
1479 self.output.write('\n')
1480 while 1:
1481 self.output.write('help> ')
1482 self.output.flush()
1483 try:
1484 request = self.input.readline()
1485 if not request: break
1486 except KeyboardInterrupt: break
1487 request = strip(replace(request, '"', '', "'", ''))
1488 if lower(request) in ['q', 'quit']: break
1489 self.help(request)
1490
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001491 def help(self, request):
1492 if type(request) is type(''):
1493 if request == 'help': self.intro()
1494 elif request == 'keywords': self.listkeywords()
1495 elif request == 'topics': self.listtopics()
1496 elif request == 'modules': self.listmodules()
1497 elif request[:8] == 'modules ':
1498 self.listmodules(split(request)[1])
1499 elif self.keywords.has_key(request): self.showtopic(request)
1500 elif self.topics.has_key(request): self.showtopic(request)
1501 elif request: doc(request, 'Help on %s:')
1502 elif isinstance(request, Helper): self()
1503 else: doc(request, 'Help on %s:')
1504 self.output.write('\n')
1505
1506 def intro(self):
1507 self.output.write('''
1508Welcome to Python %s! This is the online help utility.
1509
1510If this is your first time using Python, you should definitely check out
1511the tutorial on the Internet at http://www.python.org/doc/tut/.
1512
1513Enter the name of any module, keyword, or topic to get help on writing
1514Python programs and using Python modules. To quit this help utility and
1515return to the interpreter, just type "quit".
1516
1517To get a list of available modules, keywords, or topics, type "modules",
1518"keywords", or "topics". Each module also comes with a one-line summary
1519of what it does; to list the modules whose summaries contain a given word
1520such as "spam", type "modules spam".
1521''' % sys.version[:3])
1522
1523 def list(self, items, columns=4, width=80):
1524 items = items[:]
1525 items.sort()
1526 colw = width / columns
1527 rows = (len(items) + columns - 1) / columns
1528 for row in range(rows):
1529 for col in range(columns):
1530 i = col * rows + row
1531 if i < len(items):
1532 self.output.write(items[i])
1533 if col < columns - 1:
1534 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1535 self.output.write('\n')
1536
1537 def listkeywords(self):
1538 self.output.write('''
1539Here is a list of the Python keywords. Enter any keyword to get more help.
1540
1541''')
1542 self.list(self.keywords.keys())
1543
1544 def listtopics(self):
1545 self.output.write('''
1546Here is a list of available topics. Enter any topic name to get more help.
1547
1548''')
1549 self.list(self.topics.keys())
1550
1551 def showtopic(self, topic):
1552 if not self.docdir:
1553 self.output.write('''
1554Sorry, topic and keyword documentation is not available because the Python
1555HTML documentation files could not be found. If you have installed them,
1556please set the environment variable PYTHONDOCS to indicate their location.
1557''')
1558 return
1559 target = self.topics.get(topic, self.keywords.get(topic))
1560 if not target:
1561 self.output.write('no documentation found for %s\n' % repr(topic))
1562 return
1563 if type(target) is type(''):
1564 return self.showtopic(target)
1565
1566 filename, xrefs = target
1567 filename = self.docdir + '/' + filename + '.html'
1568 try:
1569 file = open(filename)
1570 except:
1571 self.output.write('could not read docs from %s\n' % filename)
1572 return
1573
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001574 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1575 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001576 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1577 file.close()
1578
1579 import htmllib, formatter, StringIO
1580 buffer = StringIO.StringIO()
1581 parser = htmllib.HTMLParser(
1582 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1583 parser.start_table = parser.do_p
1584 parser.end_table = lambda parser=parser: parser.do_p({})
1585 parser.start_tr = parser.do_br
1586 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1587 parser.feed(document)
1588 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1589 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001590 if xrefs:
1591 buffer = StringIO.StringIO()
1592 formatter.DumbWriter(buffer).send_flowing_data(
1593 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1594 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001595
1596 def listmodules(self, key=''):
1597 if key:
1598 self.output.write('''
1599Here is a list of matching modules. Enter any module name to get more help.
1600
1601''')
1602 apropos(key)
1603 else:
1604 self.output.write('''
1605Please wait a moment while I gather a list of all available modules...
1606
1607''')
1608 modules = {}
1609 def callback(path, modname, desc, modules=modules):
1610 if modname and modname[-9:] == '.__init__':
1611 modname = modname[:-9] + ' (package)'
1612 if find(modname, '.') < 0:
1613 modules[modname] = 1
1614 ModuleScanner().run(callback)
1615 self.list(modules.keys())
1616 self.output.write('''
1617Enter any module name to get more help. Or, type "modules spam" to search
1618for modules whose descriptions contain the word "spam".
1619''')
1620
1621help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001622
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001623class Scanner:
1624 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001625 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001626 self.roots = roots[:]
1627 self.state = []
1628 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001629 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001630
1631 def next(self):
1632 if not self.state:
1633 if not self.roots:
1634 return None
1635 root = self.roots.pop(0)
1636 self.state = [(root, self.children(root))]
1637 node, children = self.state[-1]
1638 if not children:
1639 self.state.pop()
1640 return self.next()
1641 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001642 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001643 self.state.append((child, self.children(child)))
1644 return child
1645
1646class ModuleScanner(Scanner):
1647 """An interruptible scanner that searches module synopses."""
1648 def __init__(self):
1649 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001650 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
1651 self.inodes = map(lambda (dir, pkg): os.stat(dir)[1], roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001652
1653 def submodules(self, (dir, package)):
1654 children = []
1655 for file in os.listdir(dir):
1656 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001657 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001658 children.append((path, package + (package and '.') + file))
1659 else:
1660 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001661 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001662 return children
1663
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001664 def isnewpackage(self, (dir, package)):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001665 inode = os.path.exists(dir) and os.stat(dir)[1]
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001666 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001667 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001668 return ispackage(dir)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001669
Ka-Ping Yee66246962001-04-12 11:59:50 +00001670 def run(self, callback, key=None, completer=None):
1671 if key: key = lower(key)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001672 self.quit = 0
1673 seen = {}
1674
1675 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001676 if modname != '__main__':
1677 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001678 if key is None:
1679 callback(None, modname, '')
1680 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001681 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001682 if find(lower(modname + ' - ' + desc), key) >= 0:
1683 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001684
1685 while not self.quit:
1686 node = self.next()
1687 if not node: break
1688 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001689 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001690 if os.path.isfile(path) and modname:
1691 modname = package + (package and '.') + modname
1692 if not seen.has_key(modname):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001693 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001694 if key is None:
1695 callback(path, modname, '')
1696 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001697 desc = synopsis(path) or ''
1698 if find(lower(modname + ' - ' + desc), key) >= 0:
1699 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001700 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001701
1702def apropos(key):
1703 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001704 def callback(path, modname, desc):
1705 if modname[-9:] == '.__init__':
1706 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001707 print modname, desc and '- ' + desc
1708 try: import warnings
1709 except ImportError: pass
1710 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001711 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001712
1713# --------------------------------------------------- web browser interface
1714
Ka-Ping Yee66246962001-04-12 11:59:50 +00001715def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001716 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001717
1718 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1719 class Message(mimetools.Message):
1720 def __init__(self, fp, seekable=1):
1721 Message = self.__class__
1722 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1723 self.encodingheader = self.getheader('content-transfer-encoding')
1724 self.typeheader = self.getheader('content-type')
1725 self.parsetype()
1726 self.parseplist()
1727
1728 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1729 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001730 try:
1731 self.send_response(200)
1732 self.send_header('Content-Type', 'text/html')
1733 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001734 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001735 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001736
1737 def do_GET(self):
1738 path = self.path
1739 if path[-5:] == '.html': path = path[:-5]
1740 if path[:1] == '/': path = path[1:]
1741 if path and path != '.':
1742 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001743 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001744 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001745 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001746 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001747 if obj:
1748 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001749 else:
1750 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001751'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001752 else:
1753 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001754'<big><big><strong>Python: Index of Modules</strong></big></big>',
1755'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001756 def bltinlink(name):
1757 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001758 names = filter(lambda x: x != '__main__',
1759 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001760 contents = html.multicolumn(names, bltinlink)
1761 indices = ['<p>' + html.bigsection(
1762 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1763
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001764 seen = {}
1765 for dir in pathdirs():
1766 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001767 contents = heading + join(indices) + '''<p align=right>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001768<small><small><font color="#909090" face="helvetica, arial"><strong>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001769pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font></small></small>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001770 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001771
1772 def log_message(self, *args): pass
1773
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001774 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001775 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001776 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001777 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001778 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001779 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001780 self.base.__init__(self, self.address, self.handler)
1781
1782 def serve_until_quit(self):
1783 import select
1784 self.quit = 0
1785 while not self.quit:
1786 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1787 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001788
1789 def server_activate(self):
1790 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001791 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001792
1793 DocServer.base = BaseHTTPServer.HTTPServer
1794 DocServer.handler = DocHandler
1795 DocHandler.MessageClass = Message
1796 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001797 try:
1798 DocServer(port, callback).serve_until_quit()
1799 except (KeyboardInterrupt, select.error):
1800 pass
1801 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001802 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001803
1804# ----------------------------------------------------- graphical interface
1805
1806def gui():
1807 """Graphical interface (starts web server and pops up a control window)."""
1808 class GUI:
1809 def __init__(self, window, port=7464):
1810 self.window = window
1811 self.server = None
1812 self.scanner = None
1813
1814 import Tkinter
1815 self.server_frm = Tkinter.Frame(window)
1816 self.title_lbl = Tkinter.Label(self.server_frm,
1817 text='Starting server...\n ')
1818 self.open_btn = Tkinter.Button(self.server_frm,
1819 text='open browser', command=self.open, state='disabled')
1820 self.quit_btn = Tkinter.Button(self.server_frm,
1821 text='quit serving', command=self.quit, state='disabled')
1822
1823 self.search_frm = Tkinter.Frame(window)
1824 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1825 self.search_ent = Tkinter.Entry(self.search_frm)
1826 self.search_ent.bind('<Return>', self.search)
1827 self.stop_btn = Tkinter.Button(self.search_frm,
1828 text='stop', pady=0, command=self.stop, state='disabled')
1829 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001830 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001831 self.stop_btn.pack(side='right')
1832
1833 self.window.title('pydoc')
1834 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1835 self.title_lbl.pack(side='top', fill='x')
1836 self.open_btn.pack(side='left', fill='x', expand=1)
1837 self.quit_btn.pack(side='right', fill='x', expand=1)
1838 self.server_frm.pack(side='top', fill='x')
1839
1840 self.search_lbl.pack(side='left')
1841 self.search_ent.pack(side='right', fill='x', expand=1)
1842 self.search_frm.pack(side='top', fill='x')
1843 self.search_ent.focus_set()
1844
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001845 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001846 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001847 self.result_lst.bind('<Button-1>', self.select)
1848 self.result_lst.bind('<Double-Button-1>', self.goto)
1849 self.result_scr = Tkinter.Scrollbar(window,
1850 orient='vertical', command=self.result_lst.yview)
1851 self.result_lst.config(yscrollcommand=self.result_scr.set)
1852
1853 self.result_frm = Tkinter.Frame(window)
1854 self.goto_btn = Tkinter.Button(self.result_frm,
1855 text='go to selected', command=self.goto)
1856 self.hide_btn = Tkinter.Button(self.result_frm,
1857 text='hide results', command=self.hide)
1858 self.goto_btn.pack(side='left', fill='x', expand=1)
1859 self.hide_btn.pack(side='right', fill='x', expand=1)
1860
1861 self.window.update()
1862 self.minwidth = self.window.winfo_width()
1863 self.minheight = self.window.winfo_height()
1864 self.bigminheight = (self.server_frm.winfo_reqheight() +
1865 self.search_frm.winfo_reqheight() +
1866 self.result_lst.winfo_reqheight() +
1867 self.result_frm.winfo_reqheight())
1868 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1869 self.expanded = 0
1870 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1871 self.window.wm_minsize(self.minwidth, self.minheight)
1872
1873 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001874 threading.Thread(
1875 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001876
1877 def ready(self, server):
1878 self.server = server
1879 self.title_lbl.config(
1880 text='Python documentation server at\n' + server.url)
1881 self.open_btn.config(state='normal')
1882 self.quit_btn.config(state='normal')
1883
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001884 def open(self, event=None, url=None):
1885 url = url or self.server.url
1886 try:
1887 import webbrowser
1888 webbrowser.open(url)
1889 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001890 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001891 os.system('start "%s"' % url)
1892 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001893 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001894 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001895 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001896 else:
1897 rc = os.system('netscape -remote "openURL(%s)" &' % url)
1898 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001899
1900 def quit(self, event=None):
1901 if self.server:
1902 self.server.quit = 1
1903 self.window.quit()
1904
1905 def search(self, event=None):
1906 key = self.search_ent.get()
1907 self.stop_btn.pack(side='right')
1908 self.stop_btn.config(state='normal')
1909 self.search_lbl.config(text='Searching for "%s"...' % key)
1910 self.search_ent.forget()
1911 self.search_lbl.pack(side='left')
1912 self.result_lst.delete(0, 'end')
1913 self.goto_btn.config(state='disabled')
1914 self.expand()
1915
1916 import threading
1917 if self.scanner:
1918 self.scanner.quit = 1
1919 self.scanner = ModuleScanner()
1920 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00001921 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001922
1923 def update(self, path, modname, desc):
1924 if modname[-9:] == '.__init__':
1925 modname = modname[:-9] + ' (package)'
1926 self.result_lst.insert('end',
1927 modname + ' - ' + (desc or '(no description)'))
1928
1929 def stop(self, event=None):
1930 if self.scanner:
1931 self.scanner.quit = 1
1932 self.scanner = None
1933
1934 def done(self):
1935 self.scanner = None
1936 self.search_lbl.config(text='Search for')
1937 self.search_lbl.pack(side='left')
1938 self.search_ent.pack(side='right', fill='x', expand=1)
1939 if sys.platform != 'win32': self.stop_btn.forget()
1940 self.stop_btn.config(state='disabled')
1941
1942 def select(self, event=None):
1943 self.goto_btn.config(state='normal')
1944
1945 def goto(self, event=None):
1946 selection = self.result_lst.curselection()
1947 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001948 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001949 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001950
1951 def collapse(self):
1952 if not self.expanded: return
1953 self.result_frm.forget()
1954 self.result_scr.forget()
1955 self.result_lst.forget()
1956 self.bigwidth = self.window.winfo_width()
1957 self.bigheight = self.window.winfo_height()
1958 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1959 self.window.wm_minsize(self.minwidth, self.minheight)
1960 self.expanded = 0
1961
1962 def expand(self):
1963 if self.expanded: return
1964 self.result_frm.pack(side='bottom', fill='x')
1965 self.result_scr.pack(side='right', fill='y')
1966 self.result_lst.pack(side='top', fill='both', expand=1)
1967 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
1968 self.window.wm_minsize(self.minwidth, self.bigminheight)
1969 self.expanded = 1
1970
1971 def hide(self, event=None):
1972 self.stop()
1973 self.collapse()
1974
1975 import Tkinter
1976 try:
1977 gui = GUI(Tkinter.Tk())
1978 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001979 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001980 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001981
1982# -------------------------------------------------- command-line interface
1983
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001984def ispath(x):
1985 return type(x) is types.StringType and find(x, os.sep) >= 0
1986
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001987def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001988 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001989 import getopt
1990 class BadUsage: pass
1991
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001992 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00001993 scriptdir = os.path.dirname(sys.argv[0])
1994 if scriptdir in sys.path:
1995 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001996 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001997
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001998 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001999 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002000 writing = 0
2001
2002 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002003 if opt == '-g':
2004 gui()
2005 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002006 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002007 apropos(val)
2008 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002009 if opt == '-p':
2010 try:
2011 port = int(val)
2012 except ValueError:
2013 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002014 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002015 print 'pydoc server ready at %s' % server.url
2016 def stopped():
2017 print 'pydoc server stopped'
2018 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002019 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002020 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002021 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002022
2023 if not args: raise BadUsage
2024 for arg in args:
2025 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002026 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002027 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002028 if writing:
2029 if ispath(arg) and os.path.isdir(arg):
2030 writedocs(arg)
2031 else:
2032 writedoc(arg)
2033 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002034 doc(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002035 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002036 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002037
2038 except (getopt.error, BadUsage):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002039 cmd = sys.argv[0]
2040 print """pydoc - the Python documentation tool
2041
2042%s <name> ...
2043 Show text documentation on something. <name> may be the name of a
2044 function, module, or package, or a dotted reference to a class or
2045 function within a module or module in a package. If <name> contains
2046 a '%s', it is used as the path to a Python source file to document.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002047
2048%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002049 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002050
2051%s -p <port>
2052 Start an HTTP server on the given port on the local machine.
2053
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002054%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002055 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002056
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002057%s -w <name> ...
2058 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002059 directory. If <name> contains a '%s', it is treated as a filename; if
2060 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002061""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002062
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002063if __name__ == '__main__': cli()