blob: 4bf194068d1ebcec9532575cdc90ca8b625ddb5c [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 Petersf4aad8e2001-09-24 22:40:47 +0000994 # Cute little class to pump out a horizontal rule between sections.
995 class HorizontalRule:
996 def __init__(self):
997 self.needone = 0
998 def maybe(self):
999 if self.needone:
1000 push('-' * 70)
1001 self.needone = 1
1002 hr = HorizontalRule()
1003
Tim Peters28355492001-09-23 21:29:55 +00001004 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001005 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001006 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001007 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001008 push(msg)
1009 for name, kind, homecls, value in ok:
1010 push(self.document(getattr(object, name),
1011 name, mod, object))
1012 return attrs
1013
Tim Petersfa26f7c2001-09-24 08:05:11 +00001014 def spillproperties(msg, attrs, predicate):
1015 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001016 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001017 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001018 push(msg)
1019 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001020 push(name)
1021 need_blank_after_doc = 0
1022 doc = getdoc(value) or ''
1023 if doc:
1024 push(self.indent(doc))
1025 need_blank_after_doc = 1
1026 for attr, tag in [("fset", " setter"),
1027 ("fget", " getter"),
1028 ("fdel", " deleter")]:
1029 func = getattr(value, attr)
1030 if func is not None:
1031 if need_blank_after_doc:
1032 push('')
1033 need_blank_after_doc = 0
1034 base = self.docother(func, name + tag, mod, 70)
1035 push(self.indent(base))
1036 push('')
Tim Peters28355492001-09-23 21:29:55 +00001037 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001038
Tim Petersfa26f7c2001-09-24 08:05:11 +00001039 def spilldata(msg, attrs, predicate):
1040 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001041 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001042 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001043 push(msg)
1044 for name, kind, homecls, value in ok:
1045 doc = getattr(value, "__doc__", None)
1046 push(self.docother(getattr(object, name),
1047 name, mod, 70, doc) + '\n')
1048 return attrs
1049
1050 attrs = inspect.classify_class_attrs(object)
1051
Tim Petersfa26f7c2001-09-24 08:05:11 +00001052 # Sort attrs by name of defining class.
1053 attrs.sort(lambda t1, t2: cmp(t1[2].__name__, t2[2].__name__))
Tim Peters28355492001-09-23 21:29:55 +00001054
Tim Petersfa26f7c2001-09-24 08:05:11 +00001055 thisclass = object # list attrs defined here first
1056 while attrs:
1057 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1058
Tim Peters28355492001-09-23 21:29:55 +00001059 if thisclass is object:
1060 tag = "defined here"
1061 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001062 tag = "inherited from %s" % classname(thisclass,
1063 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001064
1065 # Sort attrs by name.
1066 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
1067
1068 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001069 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001070 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001071 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001072 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001073 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001074 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001075 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001076 lambda t: t[1] == 'property')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001077 attrs = spilldata("Data %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001078 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001079 assert attrs == []
1080
1081 # Split off the attributes inherited from the next class (note
1082 # that inherited remains sorted by class name).
1083 if inherited:
1084 attrs = inherited
1085 thisclass = attrs[0][2]
Tim Peters28355492001-09-23 21:29:55 +00001086
1087 contents = '\n'.join(contents)
1088 if not contents:
1089 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001090 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1091
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001092 def formatvalue(self, object):
1093 """Format an argument default value as text."""
1094 return '=' + self.repr(object)
1095
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001096 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001097 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001098 realname = object.__name__
1099 name = name or realname
1100 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001101 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001102 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001103 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001104 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001105 if imclass is not cl:
1106 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001107 skipdocs = 1
1108 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001109 if object.im_self:
1110 note = ' method of %s instance' % classname(
1111 object.im_self.__class__, mod)
1112 else:
1113 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001114 object = object.im_func
1115
1116 if name == realname:
1117 title = self.bold(realname)
1118 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001119 if (cl and cl.__dict__.has_key(realname) and
1120 cl.__dict__[realname] is object):
1121 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001122 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001123 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001124 args, varargs, varkw, defaults = inspect.getargspec(object)
1125 argspec = inspect.formatargspec(
1126 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001127 if realname == '<lambda>':
1128 title = 'lambda'
1129 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001130 else:
1131 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001132 decl = title + argspec + note
1133
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001134 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001135 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001136 else:
1137 doc = getdoc(object) or ''
1138 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001139
Tim Peters28355492001-09-23 21:29:55 +00001140 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001141 """Produce text documentation for a data object."""
1142 repr = self.repr(object)
1143 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001144 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001145 chop = maxlen - len(line)
1146 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001147 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001148 if doc is not None:
1149 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001150 return line
1151
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001152# --------------------------------------------------------- user interfaces
1153
1154def pager(text):
1155 """The first time this is called, determine what kind of pager to use."""
1156 global pager
1157 pager = getpager()
1158 pager(text)
1159
1160def getpager():
1161 """Decide what method to use for paging through text."""
1162 if type(sys.stdout) is not types.FileType:
1163 return plainpager
1164 if not sys.stdin.isatty() or not sys.stdout.isatty():
1165 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001166 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001167 return plainpager
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001168 if os.environ.has_key('PAGER'):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001169 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001170 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1171 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1172 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001173 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001174 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001175 if sys.platform == 'win32':
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001176 return lambda text: tempfilepager(plain(text), 'more <')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001177 if hasattr(os, 'system') and os.system('less 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001178 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001179
1180 import tempfile
1181 filename = tempfile.mktemp()
1182 open(filename, 'w').close()
1183 try:
1184 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1185 return lambda text: pipepager(text, 'more')
1186 else:
1187 return ttypager
1188 finally:
1189 os.unlink(filename)
1190
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001191def plain(text):
1192 """Remove boldface formatting from text."""
1193 return re.sub('.\b', '', text)
1194
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001195def pipepager(text, cmd):
1196 """Page through text by feeding it to another program."""
1197 pipe = os.popen(cmd, 'w')
1198 try:
1199 pipe.write(text)
1200 pipe.close()
1201 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001202 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001203
1204def tempfilepager(text, cmd):
1205 """Page through text by invoking a program on a temporary file."""
1206 import tempfile
1207 filename = tempfile.mktemp()
1208 file = open(filename, 'w')
1209 file.write(text)
1210 file.close()
1211 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001212 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001213 finally:
1214 os.unlink(filename)
1215
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001216def ttypager(text):
1217 """Page through text on a text terminal."""
1218 lines = split(plain(text), '\n')
1219 try:
1220 import tty
1221 fd = sys.stdin.fileno()
1222 old = tty.tcgetattr(fd)
1223 tty.setcbreak(fd)
1224 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001225 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001226 tty = None
1227 getchar = lambda: sys.stdin.readline()[:-1][:1]
1228
1229 try:
1230 r = inc = os.environ.get('LINES', 25) - 1
1231 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1232 while lines[r:]:
1233 sys.stdout.write('-- more --')
1234 sys.stdout.flush()
1235 c = getchar()
1236
1237 if c in ['q', 'Q']:
1238 sys.stdout.write('\r \r')
1239 break
1240 elif c in ['\r', '\n']:
1241 sys.stdout.write('\r \r' + lines[r] + '\n')
1242 r = r + 1
1243 continue
1244 if c in ['b', 'B', '\x1b']:
1245 r = r - inc - inc
1246 if r < 0: r = 0
1247 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1248 r = r + inc
1249
1250 finally:
1251 if tty:
1252 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1253
1254def plainpager(text):
1255 """Simply print unformatted text. This is the ultimate fallback."""
1256 sys.stdout.write(plain(text))
1257
1258def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001259 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001260 if inspect.ismodule(thing):
1261 if thing.__name__ in sys.builtin_module_names:
1262 return 'built-in module ' + thing.__name__
1263 if hasattr(thing, '__path__'):
1264 return 'package ' + thing.__name__
1265 else:
1266 return 'module ' + thing.__name__
1267 if inspect.isbuiltin(thing):
1268 return 'built-in function ' + thing.__name__
1269 if inspect.isclass(thing):
1270 return 'class ' + thing.__name__
1271 if inspect.isfunction(thing):
1272 return 'function ' + thing.__name__
1273 if inspect.ismethod(thing):
1274 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001275 if type(thing) is types.InstanceType:
1276 return 'instance of ' + thing.__class__.__name__
1277 return type(thing).__name__
1278
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001279def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001280 """Locate an object by name or dotted path, importing as necessary."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001281 parts = split(path, '.')
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001282 module, n = None, 0
1283 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001284 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001285 if nextmodule: module, n = nextmodule, n + 1
1286 else: break
1287 if module:
1288 object = module
1289 for part in parts[n:]:
1290 try: object = getattr(object, part)
1291 except AttributeError: return None
1292 return object
1293 else:
1294 import __builtin__
1295 if hasattr(__builtin__, path):
1296 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001297
1298# --------------------------------------- interactive interpreter interface
1299
1300text = TextDoc()
1301html = HTMLDoc()
1302
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001303def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001304 """Display text documentation, given an object or a path to an object."""
1305 suffix, name = '', None
1306 if type(thing) is type(''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001307 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001308 object = locate(thing, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001309 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001310 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001311 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001312 if not object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001313 print 'no Python documentation found for %s' % repr(thing)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001314 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001315 parts = split(thing, '.')
1316 if len(parts) > 1: suffix = ' in ' + join(parts[:-1], '.')
1317 name = parts[-1]
1318 thing = object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001319
1320 desc = describe(thing)
1321 module = inspect.getmodule(thing)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001322 if not suffix and module and module is not thing:
1323 suffix = ' in module ' + module.__name__
Ka-Ping Yee66246962001-04-12 11:59:50 +00001324 pager(title % (desc + suffix) + '\n\n' + text.document(thing, name))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001325
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001326def writedoc(key, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001327 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001328 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001329 object = locate(key, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001330 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001331 print value
1332 else:
1333 if object:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001334 page = html.page(describe(object),
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001335 html.document(object, object.__name__))
1336 file = open(key + '.html', 'w')
1337 file.write(page)
1338 file.close()
1339 print 'wrote', key + '.html'
1340 else:
1341 print 'no Python documentation found for %s' % repr(key)
1342
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001343def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001344 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001345 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001346 for file in os.listdir(dir):
1347 path = os.path.join(dir, file)
1348 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001349 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001350 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001351 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001352 if modname:
1353 modname = pkgpath + modname
1354 if not done.has_key(modname):
1355 done[modname] = 1
1356 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001357
1358class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001359 keywords = {
1360 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001361 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001362 'break': ('ref/break', 'while for'),
1363 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1364 'continue': ('ref/continue', 'while for'),
1365 'def': ('ref/function', ''),
1366 'del': ('ref/del', 'BASICMETHODS'),
1367 'elif': 'if',
1368 'else': ('ref/if', 'while for'),
1369 'except': 'try',
1370 'exec': ('ref/exec', ''),
1371 'finally': 'try',
1372 'for': ('ref/for', 'break continue while'),
1373 'from': 'import',
1374 'global': ('ref/global', 'NAMESPACES'),
1375 'if': ('ref/if', 'TRUTHVALUE'),
1376 'import': ('ref/import', 'MODULES'),
1377 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1378 'is': 'COMPARISON',
1379 'lambda': ('ref/lambda', 'FUNCTIONS'),
1380 'not': 'BOOLEAN',
1381 'or': 'BOOLEAN',
1382 'pass': 'PASS',
1383 'print': ('ref/print', ''),
1384 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001385 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001386 'try': ('ref/try', 'EXCEPTIONS'),
1387 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1388 }
1389
1390 topics = {
1391 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001392 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001393 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1394 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001395 'UNICODE': ('ref/unicode', 'encodings unicode TYPES STRING'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001396 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1397 'INTEGER': ('ref/integers', 'int range'),
1398 'FLOAT': ('ref/floating', 'float math'),
1399 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001400 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001401 'MAPPINGS': 'DICTIONARIES',
1402 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1403 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1404 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001405 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001406 'FRAMEOBJECTS': 'TYPES',
1407 'TRACEBACKS': 'TYPES',
1408 'NONE': ('lib/bltin-null-object', ''),
1409 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1410 'FILES': ('lib/bltin-file-objects', ''),
1411 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1412 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1413 'MODULES': ('lib/typesmodules', 'import'),
1414 'PACKAGES': 'import',
1415 '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'),
1416 'OPERATORS': 'EXPRESSIONS',
1417 'PRECEDENCE': 'EXPRESSIONS',
1418 'OBJECTS': ('ref/objects', 'TYPES'),
1419 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001420 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1421 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1422 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1423 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1424 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1425 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1426 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001427 'EXECUTION': ('ref/execframes', ''),
1428 'NAMESPACES': ('ref/execframes', 'global ASSIGNMENT DELETION'),
1429 'SCOPING': 'NAMESPACES',
1430 'FRAMES': 'NAMESPACES',
1431 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1432 'COERCIONS': 'CONVERSIONS',
1433 'CONVERSIONS': ('ref/conversions', ''),
1434 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1435 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001436 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001437 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1438 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001439 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001440 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001441 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001442 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001443 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1444 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001445 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1446 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1447 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1448 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1449 'POWER': ('ref/power', 'EXPRESSIONS'),
1450 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1451 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1452 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1453 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1454 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001455 'BOOLEAN': ('ref/lambda', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001456 'ASSERTION': 'assert',
1457 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001458 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001459 'DELETION': 'del',
1460 'PRINTING': 'print',
1461 'RETURNING': 'return',
1462 'IMPORTING': 'import',
1463 'CONDITIONAL': 'if',
1464 'LOOPING': ('ref/compound', 'for while break continue'),
1465 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001466 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001467 }
1468
1469 def __init__(self, input, output):
1470 self.input = input
1471 self.output = output
1472 self.docdir = None
1473 execdir = os.path.dirname(sys.executable)
1474 homedir = os.environ.get('PYTHONHOME')
1475 for dir in [os.environ.get('PYTHONDOCS'),
1476 homedir and os.path.join(homedir, 'doc'),
1477 os.path.join(execdir, 'doc'),
1478 '/usr/doc/python-docs-' + split(sys.version)[0],
1479 '/usr/doc/python-' + split(sys.version)[0],
1480 '/usr/doc/python-docs-' + sys.version[:3],
1481 '/usr/doc/python-' + sys.version[:3]]:
1482 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1483 self.docdir = dir
1484
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001485 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001486 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001487 self()
1488 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001489 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001490
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001491 def __call__(self, request=None):
1492 if request is not None:
1493 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001494 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001495 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001496 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001497 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001498You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001499If you want to ask for help on a particular object directly from the
1500interpreter, you can type "help(object)". Executing "help('string')"
1501has the same effect as typing a particular string at the help> prompt.
1502''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001503
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001504 def interact(self):
1505 self.output.write('\n')
1506 while 1:
1507 self.output.write('help> ')
1508 self.output.flush()
1509 try:
1510 request = self.input.readline()
1511 if not request: break
1512 except KeyboardInterrupt: break
1513 request = strip(replace(request, '"', '', "'", ''))
1514 if lower(request) in ['q', 'quit']: break
1515 self.help(request)
1516
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001517 def help(self, request):
1518 if type(request) is type(''):
1519 if request == 'help': self.intro()
1520 elif request == 'keywords': self.listkeywords()
1521 elif request == 'topics': self.listtopics()
1522 elif request == 'modules': self.listmodules()
1523 elif request[:8] == 'modules ':
1524 self.listmodules(split(request)[1])
1525 elif self.keywords.has_key(request): self.showtopic(request)
1526 elif self.topics.has_key(request): self.showtopic(request)
1527 elif request: doc(request, 'Help on %s:')
1528 elif isinstance(request, Helper): self()
1529 else: doc(request, 'Help on %s:')
1530 self.output.write('\n')
1531
1532 def intro(self):
1533 self.output.write('''
1534Welcome to Python %s! This is the online help utility.
1535
1536If this is your first time using Python, you should definitely check out
1537the tutorial on the Internet at http://www.python.org/doc/tut/.
1538
1539Enter the name of any module, keyword, or topic to get help on writing
1540Python programs and using Python modules. To quit this help utility and
1541return to the interpreter, just type "quit".
1542
1543To get a list of available modules, keywords, or topics, type "modules",
1544"keywords", or "topics". Each module also comes with a one-line summary
1545of what it does; to list the modules whose summaries contain a given word
1546such as "spam", type "modules spam".
1547''' % sys.version[:3])
1548
1549 def list(self, items, columns=4, width=80):
1550 items = items[:]
1551 items.sort()
1552 colw = width / columns
1553 rows = (len(items) + columns - 1) / columns
1554 for row in range(rows):
1555 for col in range(columns):
1556 i = col * rows + row
1557 if i < len(items):
1558 self.output.write(items[i])
1559 if col < columns - 1:
1560 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1561 self.output.write('\n')
1562
1563 def listkeywords(self):
1564 self.output.write('''
1565Here is a list of the Python keywords. Enter any keyword to get more help.
1566
1567''')
1568 self.list(self.keywords.keys())
1569
1570 def listtopics(self):
1571 self.output.write('''
1572Here is a list of available topics. Enter any topic name to get more help.
1573
1574''')
1575 self.list(self.topics.keys())
1576
1577 def showtopic(self, topic):
1578 if not self.docdir:
1579 self.output.write('''
1580Sorry, topic and keyword documentation is not available because the Python
1581HTML documentation files could not be found. If you have installed them,
1582please set the environment variable PYTHONDOCS to indicate their location.
1583''')
1584 return
1585 target = self.topics.get(topic, self.keywords.get(topic))
1586 if not target:
1587 self.output.write('no documentation found for %s\n' % repr(topic))
1588 return
1589 if type(target) is type(''):
1590 return self.showtopic(target)
1591
1592 filename, xrefs = target
1593 filename = self.docdir + '/' + filename + '.html'
1594 try:
1595 file = open(filename)
1596 except:
1597 self.output.write('could not read docs from %s\n' % filename)
1598 return
1599
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001600 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1601 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001602 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1603 file.close()
1604
1605 import htmllib, formatter, StringIO
1606 buffer = StringIO.StringIO()
1607 parser = htmllib.HTMLParser(
1608 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1609 parser.start_table = parser.do_p
1610 parser.end_table = lambda parser=parser: parser.do_p({})
1611 parser.start_tr = parser.do_br
1612 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1613 parser.feed(document)
1614 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1615 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001616 if xrefs:
1617 buffer = StringIO.StringIO()
1618 formatter.DumbWriter(buffer).send_flowing_data(
1619 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1620 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001621
1622 def listmodules(self, key=''):
1623 if key:
1624 self.output.write('''
1625Here is a list of matching modules. Enter any module name to get more help.
1626
1627''')
1628 apropos(key)
1629 else:
1630 self.output.write('''
1631Please wait a moment while I gather a list of all available modules...
1632
1633''')
1634 modules = {}
1635 def callback(path, modname, desc, modules=modules):
1636 if modname and modname[-9:] == '.__init__':
1637 modname = modname[:-9] + ' (package)'
1638 if find(modname, '.') < 0:
1639 modules[modname] = 1
1640 ModuleScanner().run(callback)
1641 self.list(modules.keys())
1642 self.output.write('''
1643Enter any module name to get more help. Or, type "modules spam" to search
1644for modules whose descriptions contain the word "spam".
1645''')
1646
1647help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001648
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001649class Scanner:
1650 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001651 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001652 self.roots = roots[:]
1653 self.state = []
1654 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001655 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001656
1657 def next(self):
1658 if not self.state:
1659 if not self.roots:
1660 return None
1661 root = self.roots.pop(0)
1662 self.state = [(root, self.children(root))]
1663 node, children = self.state[-1]
1664 if not children:
1665 self.state.pop()
1666 return self.next()
1667 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001668 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001669 self.state.append((child, self.children(child)))
1670 return child
1671
1672class ModuleScanner(Scanner):
1673 """An interruptible scanner that searches module synopses."""
1674 def __init__(self):
1675 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001676 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
1677 self.inodes = map(lambda (dir, pkg): os.stat(dir)[1], roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001678
1679 def submodules(self, (dir, package)):
1680 children = []
1681 for file in os.listdir(dir):
1682 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001683 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001684 children.append((path, package + (package and '.') + file))
1685 else:
1686 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001687 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001688 return children
1689
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001690 def isnewpackage(self, (dir, package)):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001691 inode = os.path.exists(dir) and os.stat(dir)[1]
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001692 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001693 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001694 return ispackage(dir)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001695
Ka-Ping Yee66246962001-04-12 11:59:50 +00001696 def run(self, callback, key=None, completer=None):
1697 if key: key = lower(key)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001698 self.quit = 0
1699 seen = {}
1700
1701 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001702 if modname != '__main__':
1703 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001704 if key is None:
1705 callback(None, modname, '')
1706 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001707 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001708 if find(lower(modname + ' - ' + desc), key) >= 0:
1709 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001710
1711 while not self.quit:
1712 node = self.next()
1713 if not node: break
1714 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001715 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001716 if os.path.isfile(path) and modname:
1717 modname = package + (package and '.') + modname
1718 if not seen.has_key(modname):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001719 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001720 if key is None:
1721 callback(path, modname, '')
1722 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001723 desc = synopsis(path) or ''
1724 if find(lower(modname + ' - ' + desc), key) >= 0:
1725 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001726 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001727
1728def apropos(key):
1729 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001730 def callback(path, modname, desc):
1731 if modname[-9:] == '.__init__':
1732 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001733 print modname, desc and '- ' + desc
1734 try: import warnings
1735 except ImportError: pass
1736 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001737 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001738
1739# --------------------------------------------------- web browser interface
1740
Ka-Ping Yee66246962001-04-12 11:59:50 +00001741def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001742 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001743
1744 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1745 class Message(mimetools.Message):
1746 def __init__(self, fp, seekable=1):
1747 Message = self.__class__
1748 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1749 self.encodingheader = self.getheader('content-transfer-encoding')
1750 self.typeheader = self.getheader('content-type')
1751 self.parsetype()
1752 self.parseplist()
1753
1754 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1755 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001756 try:
1757 self.send_response(200)
1758 self.send_header('Content-Type', 'text/html')
1759 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001760 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001761 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001762
1763 def do_GET(self):
1764 path = self.path
1765 if path[-5:] == '.html': path = path[:-5]
1766 if path[:1] == '/': path = path[1:]
1767 if path and path != '.':
1768 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001769 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001770 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001771 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001772 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001773 if obj:
1774 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001775 else:
1776 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001777'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001778 else:
1779 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001780'<big><big><strong>Python: Index of Modules</strong></big></big>',
1781'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001782 def bltinlink(name):
1783 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001784 names = filter(lambda x: x != '__main__',
1785 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001786 contents = html.multicolumn(names, bltinlink)
1787 indices = ['<p>' + html.bigsection(
1788 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1789
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001790 seen = {}
1791 for dir in pathdirs():
1792 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001793 contents = heading + join(indices) + '''<p align=right>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001794<small><small><font color="#909090" face="helvetica, arial"><strong>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001795pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font></small></small>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001796 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001797
1798 def log_message(self, *args): pass
1799
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001800 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001801 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001802 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001803 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001804 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001805 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001806 self.base.__init__(self, self.address, self.handler)
1807
1808 def serve_until_quit(self):
1809 import select
1810 self.quit = 0
1811 while not self.quit:
1812 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1813 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001814
1815 def server_activate(self):
1816 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001817 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001818
1819 DocServer.base = BaseHTTPServer.HTTPServer
1820 DocServer.handler = DocHandler
1821 DocHandler.MessageClass = Message
1822 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001823 try:
1824 DocServer(port, callback).serve_until_quit()
1825 except (KeyboardInterrupt, select.error):
1826 pass
1827 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001828 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001829
1830# ----------------------------------------------------- graphical interface
1831
1832def gui():
1833 """Graphical interface (starts web server and pops up a control window)."""
1834 class GUI:
1835 def __init__(self, window, port=7464):
1836 self.window = window
1837 self.server = None
1838 self.scanner = None
1839
1840 import Tkinter
1841 self.server_frm = Tkinter.Frame(window)
1842 self.title_lbl = Tkinter.Label(self.server_frm,
1843 text='Starting server...\n ')
1844 self.open_btn = Tkinter.Button(self.server_frm,
1845 text='open browser', command=self.open, state='disabled')
1846 self.quit_btn = Tkinter.Button(self.server_frm,
1847 text='quit serving', command=self.quit, state='disabled')
1848
1849 self.search_frm = Tkinter.Frame(window)
1850 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1851 self.search_ent = Tkinter.Entry(self.search_frm)
1852 self.search_ent.bind('<Return>', self.search)
1853 self.stop_btn = Tkinter.Button(self.search_frm,
1854 text='stop', pady=0, command=self.stop, state='disabled')
1855 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001856 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001857 self.stop_btn.pack(side='right')
1858
1859 self.window.title('pydoc')
1860 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1861 self.title_lbl.pack(side='top', fill='x')
1862 self.open_btn.pack(side='left', fill='x', expand=1)
1863 self.quit_btn.pack(side='right', fill='x', expand=1)
1864 self.server_frm.pack(side='top', fill='x')
1865
1866 self.search_lbl.pack(side='left')
1867 self.search_ent.pack(side='right', fill='x', expand=1)
1868 self.search_frm.pack(side='top', fill='x')
1869 self.search_ent.focus_set()
1870
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001871 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001872 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001873 self.result_lst.bind('<Button-1>', self.select)
1874 self.result_lst.bind('<Double-Button-1>', self.goto)
1875 self.result_scr = Tkinter.Scrollbar(window,
1876 orient='vertical', command=self.result_lst.yview)
1877 self.result_lst.config(yscrollcommand=self.result_scr.set)
1878
1879 self.result_frm = Tkinter.Frame(window)
1880 self.goto_btn = Tkinter.Button(self.result_frm,
1881 text='go to selected', command=self.goto)
1882 self.hide_btn = Tkinter.Button(self.result_frm,
1883 text='hide results', command=self.hide)
1884 self.goto_btn.pack(side='left', fill='x', expand=1)
1885 self.hide_btn.pack(side='right', fill='x', expand=1)
1886
1887 self.window.update()
1888 self.minwidth = self.window.winfo_width()
1889 self.minheight = self.window.winfo_height()
1890 self.bigminheight = (self.server_frm.winfo_reqheight() +
1891 self.search_frm.winfo_reqheight() +
1892 self.result_lst.winfo_reqheight() +
1893 self.result_frm.winfo_reqheight())
1894 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1895 self.expanded = 0
1896 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1897 self.window.wm_minsize(self.minwidth, self.minheight)
1898
1899 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001900 threading.Thread(
1901 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001902
1903 def ready(self, server):
1904 self.server = server
1905 self.title_lbl.config(
1906 text='Python documentation server at\n' + server.url)
1907 self.open_btn.config(state='normal')
1908 self.quit_btn.config(state='normal')
1909
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001910 def open(self, event=None, url=None):
1911 url = url or self.server.url
1912 try:
1913 import webbrowser
1914 webbrowser.open(url)
1915 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001916 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001917 os.system('start "%s"' % url)
1918 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001919 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001920 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001921 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001922 else:
1923 rc = os.system('netscape -remote "openURL(%s)" &' % url)
1924 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001925
1926 def quit(self, event=None):
1927 if self.server:
1928 self.server.quit = 1
1929 self.window.quit()
1930
1931 def search(self, event=None):
1932 key = self.search_ent.get()
1933 self.stop_btn.pack(side='right')
1934 self.stop_btn.config(state='normal')
1935 self.search_lbl.config(text='Searching for "%s"...' % key)
1936 self.search_ent.forget()
1937 self.search_lbl.pack(side='left')
1938 self.result_lst.delete(0, 'end')
1939 self.goto_btn.config(state='disabled')
1940 self.expand()
1941
1942 import threading
1943 if self.scanner:
1944 self.scanner.quit = 1
1945 self.scanner = ModuleScanner()
1946 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00001947 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001948
1949 def update(self, path, modname, desc):
1950 if modname[-9:] == '.__init__':
1951 modname = modname[:-9] + ' (package)'
1952 self.result_lst.insert('end',
1953 modname + ' - ' + (desc or '(no description)'))
1954
1955 def stop(self, event=None):
1956 if self.scanner:
1957 self.scanner.quit = 1
1958 self.scanner = None
1959
1960 def done(self):
1961 self.scanner = None
1962 self.search_lbl.config(text='Search for')
1963 self.search_lbl.pack(side='left')
1964 self.search_ent.pack(side='right', fill='x', expand=1)
1965 if sys.platform != 'win32': self.stop_btn.forget()
1966 self.stop_btn.config(state='disabled')
1967
1968 def select(self, event=None):
1969 self.goto_btn.config(state='normal')
1970
1971 def goto(self, event=None):
1972 selection = self.result_lst.curselection()
1973 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001974 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001975 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001976
1977 def collapse(self):
1978 if not self.expanded: return
1979 self.result_frm.forget()
1980 self.result_scr.forget()
1981 self.result_lst.forget()
1982 self.bigwidth = self.window.winfo_width()
1983 self.bigheight = self.window.winfo_height()
1984 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1985 self.window.wm_minsize(self.minwidth, self.minheight)
1986 self.expanded = 0
1987
1988 def expand(self):
1989 if self.expanded: return
1990 self.result_frm.pack(side='bottom', fill='x')
1991 self.result_scr.pack(side='right', fill='y')
1992 self.result_lst.pack(side='top', fill='both', expand=1)
1993 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
1994 self.window.wm_minsize(self.minwidth, self.bigminheight)
1995 self.expanded = 1
1996
1997 def hide(self, event=None):
1998 self.stop()
1999 self.collapse()
2000
2001 import Tkinter
2002 try:
2003 gui = GUI(Tkinter.Tk())
2004 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002005 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002006 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002007
2008# -------------------------------------------------- command-line interface
2009
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002010def ispath(x):
2011 return type(x) is types.StringType and find(x, os.sep) >= 0
2012
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002013def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002014 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002015 import getopt
2016 class BadUsage: pass
2017
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002018 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002019 scriptdir = os.path.dirname(sys.argv[0])
2020 if scriptdir in sys.path:
2021 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002022 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002023
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002024 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002025 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002026 writing = 0
2027
2028 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002029 if opt == '-g':
2030 gui()
2031 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002032 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002033 apropos(val)
2034 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002035 if opt == '-p':
2036 try:
2037 port = int(val)
2038 except ValueError:
2039 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002040 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002041 print 'pydoc server ready at %s' % server.url
2042 def stopped():
2043 print 'pydoc server stopped'
2044 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002045 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002046 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002047 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002048
2049 if not args: raise BadUsage
2050 for arg in args:
2051 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002052 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002053 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002054 if writing:
2055 if ispath(arg) and os.path.isdir(arg):
2056 writedocs(arg)
2057 else:
2058 writedoc(arg)
2059 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002060 doc(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002061 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002062 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002063
2064 except (getopt.error, BadUsage):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002065 cmd = sys.argv[0]
2066 print """pydoc - the Python documentation tool
2067
2068%s <name> ...
2069 Show text documentation on something. <name> may be the name of a
2070 function, module, or package, or a dotted reference to a class or
2071 function within a module or module in a package. If <name> contains
2072 a '%s', it is used as the path to a Python source file to document.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002073
2074%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002075 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002076
2077%s -p <port>
2078 Start an HTTP server on the given port on the local machine.
2079
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002080%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002081 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002082
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002083%s -w <name> ...
2084 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002085 directory. If <name> contains a '%s', it is treated as a filename; if
2086 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002087""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002088
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002089if __name__ == '__main__': cli()