blob: 78ec71439f80180df67c59ab2d80e6f6354afb4d [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">
Tim Peters2306d242001-09-25 03:18:32 +0000351<td valign=bottom>&nbsp;<br>
352<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">
Tim Peters2306d242001-09-25 03:18:32 +0000365<td colspan=3 valign=bottom>&nbsp;<br>
366<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000367 ''' % (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 grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000403
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000404 def namelink(self, name, *dicts):
405 """Make a link for an identifier, given name-to-URL mappings."""
406 for dict in dicts:
407 if dict.has_key(name):
408 return '<a href="%s">%s</a>' % (dict[name], name)
409 return name
410
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000411 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000412 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000413 name, module = object.__name__, sys.modules.get(object.__module__)
414 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000415 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000416 module.__name__, name, classname(object, modname))
417 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000418
419 def modulelink(self, object):
420 """Make a link for a module."""
421 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
422
423 def modpkglink(self, (name, path, ispackage, shadowed)):
424 """Make a link for a module or package to display in an index."""
425 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000426 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000427 if path:
428 url = '%s.%s.html' % (path, name)
429 else:
430 url = '%s.html' % name
431 if ispackage:
432 text = '<strong>%s</strong>&nbsp;(package)' % name
433 else:
434 text = name
435 return '<a href="%s">%s</a>' % (url, text)
436
437 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
438 """Mark up some plain text, given a context of symbols to look for.
439 Each context dictionary maps object names to anchor names."""
440 escape = escape or self.escape
441 results = []
442 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000443 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
444 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000445 r'PEP[- ]?(\d+)|'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000446 r'(self\.)?(\w+))\b')
447 while 1:
448 match = pattern.search(text, here)
449 if not match: break
450 start, end = match.span()
451 results.append(escape(text[here:start]))
452
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000453 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000454 if scheme:
455 results.append('<a href="%s">%s</a>' % (all, escape(all)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000456 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000457 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
458 results.append('<a href="%s">%s</a>' % (url, escape(all)))
459 elif pep:
460 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000461 results.append('<a href="%s">%s</a>' % (url, escape(all)))
462 elif text[end:end+1] == '(':
463 results.append(self.namelink(name, methods, funcs, classes))
464 elif selfdot:
465 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000466 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000467 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000468 here = end
469 results.append(escape(text[here:]))
470 return join(results, '')
471
472 # ---------------------------------------------- type-specific routines
473
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000474 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000475 """Produce HTML for a class tree as given by inspect.getclasstree()."""
476 result = ''
477 for entry in tree:
478 if type(entry) is type(()):
479 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000480 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000481 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000482 if bases and bases != (parent,):
483 parents = []
484 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000485 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000486 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000487 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000488 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000489 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000490 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000491 return '<dl>\n%s</dl>\n' % result
492
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000493 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000494 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000495 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000496 parts = split(name, '.')
497 links = []
498 for i in range(len(parts)-1):
499 links.append(
500 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
501 (join(parts[:i+1], '.'), parts[i]))
502 linkedname = join(links + parts[-1:], '.')
503 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000504 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000505 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000506 url = path
507 if sys.platform == 'win32':
508 import nturl2path
509 url = nturl2path.pathname2url(path)
510 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000511 except TypeError:
512 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000513 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000514 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000515 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000516 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
517 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000518 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000519 if hasattr(object, '__date__'):
520 info.append(self.escape(str(object.__date__)))
521 if info:
522 head = head + ' (%s)' % join(info, ', ')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000523 result = self.heading(
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000524 head, '#ffffff', '#7799ee', '<a href=".">index</a><br>' + filelink)
525
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000526 modules = inspect.getmembers(object, inspect.ismodule)
527
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000528 classes, cdict = [], {}
529 for key, value in inspect.getmembers(object, inspect.isclass):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000530 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000531 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000532 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000533 for key, value in classes:
534 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000535 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000536 module = sys.modules.get(modname)
537 if modname != name and module and hasattr(module, key):
538 if getattr(module, key) is base:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000539 if not cdict.has_key(key):
540 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000541 funcs, fdict = [], {}
542 for key, value in inspect.getmembers(object, inspect.isroutine):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000543 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000544 funcs.append((key, value))
545 fdict[key] = '#-' + key
546 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000547 data = []
548 for key, value in inspect.getmembers(object, isdata):
549 if key not in ['__builtins__', '__doc__']:
550 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000551
552 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
553 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000554 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000555
556 if hasattr(object, '__path__'):
557 modpkgs = []
558 modnames = []
559 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000560 path = os.path.join(object.__path__[0], file)
561 modname = inspect.getmodulename(file)
562 if modname and modname not in modnames:
563 modpkgs.append((modname, name, 0, 0))
564 modnames.append(modname)
565 elif ispackage(path):
566 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000567 modpkgs.sort()
568 contents = self.multicolumn(modpkgs, self.modpkglink)
569 result = result + self.bigsection(
570 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000571 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000572 contents = self.multicolumn(
573 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000574 result = result + self.bigsection(
575 'Modules', '#fffff', '#aa55cc', contents)
576
577 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000578 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000579 contents = [
580 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000581 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000582 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000583 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000584 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000585 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000586 contents = []
587 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000588 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000589 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000590 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000591 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000592 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000593 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000594 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000595 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000596 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000597 if hasattr(object, '__author__'):
598 contents = self.markup(str(object.__author__), self.preformat)
599 result = result + self.bigsection(
600 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000601 if hasattr(object, '__credits__'):
602 contents = self.markup(str(object.__credits__), self.preformat)
603 result = result + self.bigsection(
604 'Credits', '#ffffff', '#7799ee', contents)
605
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000606 return result
607
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000608 def docclass(self, object, name=None, mod=None, funcs={}, classes={}):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000609 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000610 realname = object.__name__
611 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000612 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000613
Tim Petersb47879b2001-09-24 04:47:19 +0000614 contents = []
615 push = contents.append
616
Tim Petersfa26f7c2001-09-24 08:05:11 +0000617 # Cute little class to pump out a horizontal rule between sections.
618 class HorizontalRule:
619 def __init__(self):
620 self.needone = 0
621 def maybe(self):
622 if self.needone:
623 push('<hr>\n')
624 self.needone = 1
625 hr = HorizontalRule()
626
Tim Petersb47879b2001-09-24 04:47:19 +0000627 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000628 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000629 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000630 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000631 push(msg)
632 for name, kind, homecls, value in ok:
633 push(self.document(getattr(object, name), name, mod,
634 funcs, classes, mdict, object))
635 push('\n')
636 return attrs
637
Tim Petersfa26f7c2001-09-24 08:05:11 +0000638 def spillproperties(msg, attrs, predicate):
639 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000640 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000641 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000642 push(msg)
643 for name, kind, homecls, value in ok:
Tim Peters3e767d12001-09-25 00:01:06 +0000644 push('<dl><dt><strong>%s</strong></dt>\n' % name)
645 if value.__doc__ is not None:
646 doc = self.markup(value.__doc__, self.preformat,
647 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000648 push('<dd><tt>%s</tt></dd>\n' % doc)
Tim Peters3e767d12001-09-25 00:01:06 +0000649 for attr, tag in [("fset", " setter"),
650 ("fget", " getter"),
651 ("fdel", " deleter")]:
652 func = getattr(value, attr)
653 if func is not None:
654 base = self.document(func, name + tag, mod,
655 funcs, classes, mdict, object)
656 push('<dd>%s</dd>\n' % base)
657 push('</dl>\n')
Tim Petersb47879b2001-09-24 04:47:19 +0000658 return attrs
659
Tim Petersfa26f7c2001-09-24 08:05:11 +0000660 def spilldata(msg, attrs, predicate):
661 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000662 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000663 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000664 push(msg)
665 for name, kind, homecls, value in ok:
666 base = self.docother(getattr(object, name), name, mod)
667 doc = getattr(value, "__doc__", None)
668 if doc is None:
669 push('<dl><dt>%s</dl>\n' % base)
670 else:
671 doc = self.markup(getdoc(value), self.preformat,
672 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000673 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000674 push('<dl><dt>%s%s</dl>\n' % (base, doc))
675 push('\n')
676 return attrs
677
678 attrs = inspect.classify_class_attrs(object)
679 mdict = {}
680 for key, kind, homecls, value in attrs:
681 mdict[key] = anchor = '#' + name + '-' + key
682 value = getattr(object, key)
683 try:
684 # The value may not be hashable (e.g., a data attr with
685 # a dict or list value).
686 mdict[value] = anchor
687 except TypeError:
688 pass
689
Tim Petersfa26f7c2001-09-24 08:05:11 +0000690 # Sort attrs by name of defining class.
691 attrs.sort(lambda t1, t2: cmp(t1[2].__name__, t2[2].__name__))
Tim Petersb47879b2001-09-24 04:47:19 +0000692
Tim Petersfa26f7c2001-09-24 08:05:11 +0000693 thisclass = object # list attrs defined here first
694 while attrs:
695 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
696
Tim Petersb47879b2001-09-24 04:47:19 +0000697 if thisclass is object:
698 tag = "defined here"
699 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000700 tag = "inherited from %s" % self.classlink(thisclass,
Tim Petersb47879b2001-09-24 04:47:19 +0000701 object.__module__)
702 tag += ':<br>\n'
703
704 # Sort attrs by name.
705 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
706
707 # Pump out the attrs, segregated by kind.
708 attrs = spill("Methods %s" % tag, attrs,
709 lambda t: t[1] == 'method')
710 attrs = spill("Class methods %s" % tag, attrs,
711 lambda t: t[1] == 'class method')
712 attrs = spill("Static methods %s" % tag, attrs,
713 lambda t: t[1] == 'static method')
Tim Petersfa26f7c2001-09-24 08:05:11 +0000714 attrs = spillproperties("Properties %s" % tag, attrs,
715 lambda t: t[1] == 'property')
716 attrs = spilldata("Data %s" % tag, attrs,
717 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000718 assert attrs == []
719
720 # Split off the attributes inherited from the next class (note
721 # that inherited remains sorted by class name).
722 if inherited:
723 attrs = inherited
724 thisclass = attrs[0][2]
Tim Petersb47879b2001-09-24 04:47:19 +0000725
726 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000727
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000728 if name == realname:
729 title = '<a name="%s">class <strong>%s</strong></a>' % (
730 name, realname)
731 else:
732 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
733 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000734 if bases:
735 parents = []
736 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000737 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000738 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000739 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
740 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc or '&nbsp;'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000741 return self.section(title, '#000000', '#ffc8d8', contents, 5, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000742
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000743 def formatvalue(self, object):
744 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000745 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000746
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000747 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000748 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000749 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000750 realname = object.__name__
751 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000752 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000753 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000754 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000755 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000756 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000757 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000758 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000759 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000760 skipdocs = 1
761 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000762 if object.im_self:
763 note = ' method of %s instance' % self.classlink(
764 object.im_self.__class__, mod)
765 else:
766 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000767 object = object.im_func
768
769 if name == realname:
770 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
771 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000772 if (cl and cl.__dict__.has_key(realname) and
773 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000774 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000775 cl.__name__ + '-' + realname, realname)
776 skipdocs = 1
777 else:
778 reallink = realname
779 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
780 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000781 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000782 args, varargs, varkw, defaults = inspect.getargspec(object)
783 argspec = inspect.formatargspec(
784 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000785 if realname == '<lambda>':
786 decl = '<em>lambda</em>'
787 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000788 else:
789 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000790
Tim Peters2306d242001-09-25 03:18:32 +0000791 decl = title + argspec + (note and self.grey(
792 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000793
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000794 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000795 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000796 else:
797 doc = self.markup(
798 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000799 doc = doc and '<dd><tt>%s</tt></dd>' % doc
800 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000801
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000802 def docother(self, object, name=None, mod=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000803 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000804 lhs = name and '<strong>%s</strong> = ' % name or ''
805 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000806
807 def index(self, dir, shadowed=None):
808 """Generate an HTML index for a directory of modules."""
809 modpkgs = []
810 if shadowed is None: shadowed = {}
811 seen = {}
812 files = os.listdir(dir)
813
814 def found(name, ispackage,
815 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
816 if not seen.has_key(name):
817 modpkgs.append((name, '', ispackage, shadowed.has_key(name)))
818 seen[name] = 1
819 shadowed[name] = 1
820
821 # Package spam/__init__.py takes precedence over module spam.py.
822 for file in files:
823 path = os.path.join(dir, file)
824 if ispackage(path): found(file, 1)
825 for file in files:
826 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000827 if os.path.isfile(path):
828 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000829 if modname: found(modname, 0)
830
831 modpkgs.sort()
832 contents = self.multicolumn(modpkgs, self.modpkglink)
833 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
834
835# -------------------------------------------- text documentation generator
836
837class TextRepr(Repr):
838 """Class for safely making a text representation of a Python object."""
839 def __init__(self):
840 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000841 self.maxlist = self.maxtuple = 20
842 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000843 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000844
845 def repr1(self, x, level):
846 methodname = 'repr_' + join(split(type(x).__name__), '_')
847 if hasattr(self, methodname):
848 return getattr(self, methodname)(x, level)
849 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000850 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000851
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000852 def repr_string(self, x, level):
853 test = cram(x, self.maxstring)
854 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000855 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000856 # Backslashes are only literal in the string and are never
857 # needed to make any special characters, so show a raw string.
858 return 'r' + testrepr[0] + test + testrepr[0]
859 return testrepr
860
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000861 def repr_instance(self, x, level):
862 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000863 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000864 except:
865 return '<%s instance>' % x.__class__.__name__
866
867class TextDoc(Doc):
868 """Formatter class for text documentation."""
869
870 # ------------------------------------------- text formatting utilities
871
872 _repr_instance = TextRepr()
873 repr = _repr_instance.repr
874
875 def bold(self, text):
876 """Format a string in bold by overstriking."""
877 return join(map(lambda ch: ch + '\b' + ch, text), '')
878
879 def indent(self, text, prefix=' '):
880 """Indent text by prepending a given prefix to each line."""
881 if not text: return ''
882 lines = split(text, '\n')
883 lines = map(lambda line, prefix=prefix: prefix + line, lines)
884 if lines: lines[-1] = rstrip(lines[-1])
885 return join(lines, '\n')
886
887 def section(self, title, contents):
888 """Format a section with a given heading."""
889 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
890
891 # ---------------------------------------------- type-specific routines
892
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000893 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000894 """Render in text a class tree as returned by inspect.getclasstree()."""
895 result = ''
896 for entry in tree:
897 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000898 c, bases = entry
899 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000900 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000901 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000902 result = result + '(%s)' % join(parents, ', ')
903 result = result + '\n'
904 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000905 result = result + self.formattree(
906 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000907 return result
908
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000909 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000910 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000911 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000912 synop, desc = splitdoc(getdoc(object))
913 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000914
915 try:
916 file = inspect.getabsfile(object)
917 except TypeError:
918 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000919 result = result + self.section('FILE', file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000920 if desc:
921 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000922
923 classes = []
924 for key, value in inspect.getmembers(object, inspect.isclass):
925 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000926 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000927 funcs = []
928 for key, value in inspect.getmembers(object, inspect.isroutine):
929 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000930 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000931 data = []
932 for key, value in inspect.getmembers(object, isdata):
933 if key not in ['__builtins__', '__doc__']:
934 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000935
936 if hasattr(object, '__path__'):
937 modpkgs = []
938 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000939 path = os.path.join(object.__path__[0], file)
940 modname = inspect.getmodulename(file)
941 if modname and modname not in modpkgs:
942 modpkgs.append(modname)
943 elif ispackage(path):
944 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000945 modpkgs.sort()
946 result = result + self.section(
947 'PACKAGE CONTENTS', join(modpkgs, '\n'))
948
949 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000950 classlist = map(lambda (key, value): value, classes)
951 contents = [self.formattree(
952 inspect.getclasstree(classlist, 1), name)]
953 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000954 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000955 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000956
957 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000958 contents = []
959 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000960 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000961 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000962
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000963 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000964 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000965 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000966 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000967 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000968
969 if hasattr(object, '__version__'):
970 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000971 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
972 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000973 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000974 if hasattr(object, '__date__'):
975 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000976 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000977 result = result + self.section('AUTHOR', str(object.__author__))
978 if hasattr(object, '__credits__'):
979 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000980 return result
981
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000982 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000983 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000984 realname = object.__name__
985 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000986 bases = object.__bases__
987
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000988 if name == realname:
989 title = 'class ' + self.bold(realname)
990 else:
991 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000992 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000993 def makename(c, m=object.__module__): return classname(c, m)
994 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000995 title = title + '(%s)' % join(parents, ', ')
996
997 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +0000998 contents = doc and [doc + '\n'] or []
999 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001000
Tim Petersf4aad8e2001-09-24 22:40:47 +00001001 # Cute little class to pump out a horizontal rule between sections.
1002 class HorizontalRule:
1003 def __init__(self):
1004 self.needone = 0
1005 def maybe(self):
1006 if self.needone:
1007 push('-' * 70)
1008 self.needone = 1
1009 hr = HorizontalRule()
1010
Tim Peters28355492001-09-23 21:29:55 +00001011 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001012 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001013 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001014 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001015 push(msg)
1016 for name, kind, homecls, value in ok:
1017 push(self.document(getattr(object, name),
1018 name, mod, object))
1019 return attrs
1020
Tim Petersfa26f7c2001-09-24 08:05:11 +00001021 def spillproperties(msg, attrs, predicate):
1022 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001023 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001024 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001025 push(msg)
1026 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001027 push(name)
1028 need_blank_after_doc = 0
1029 doc = getdoc(value) or ''
1030 if doc:
1031 push(self.indent(doc))
1032 need_blank_after_doc = 1
1033 for attr, tag in [("fset", " setter"),
1034 ("fget", " getter"),
1035 ("fdel", " deleter")]:
1036 func = getattr(value, attr)
1037 if func is not None:
1038 if need_blank_after_doc:
1039 push('')
1040 need_blank_after_doc = 0
1041 base = self.docother(func, name + tag, mod, 70)
1042 push(self.indent(base))
1043 push('')
Tim Peters28355492001-09-23 21:29:55 +00001044 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001045
Tim Petersfa26f7c2001-09-24 08:05:11 +00001046 def spilldata(msg, attrs, predicate):
1047 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001048 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001049 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001050 push(msg)
1051 for name, kind, homecls, value in ok:
1052 doc = getattr(value, "__doc__", None)
1053 push(self.docother(getattr(object, name),
1054 name, mod, 70, doc) + '\n')
1055 return attrs
1056
1057 attrs = inspect.classify_class_attrs(object)
1058
Tim Petersfa26f7c2001-09-24 08:05:11 +00001059 # Sort attrs by name of defining class.
1060 attrs.sort(lambda t1, t2: cmp(t1[2].__name__, t2[2].__name__))
Tim Peters28355492001-09-23 21:29:55 +00001061
Tim Petersfa26f7c2001-09-24 08:05:11 +00001062 thisclass = object # list attrs defined here first
1063 while attrs:
1064 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1065
Tim Peters28355492001-09-23 21:29:55 +00001066 if thisclass is object:
1067 tag = "defined here"
1068 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001069 tag = "inherited from %s" % classname(thisclass,
1070 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001071
1072 # Sort attrs by name.
1073 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
1074
1075 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001076 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001077 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001078 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001079 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001080 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001081 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001082 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001083 lambda t: t[1] == 'property')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001084 attrs = spilldata("Data %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001085 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001086 assert attrs == []
1087
1088 # Split off the attributes inherited from the next class (note
1089 # that inherited remains sorted by class name).
1090 if inherited:
1091 attrs = inherited
1092 thisclass = attrs[0][2]
Tim Peters28355492001-09-23 21:29:55 +00001093
1094 contents = '\n'.join(contents)
1095 if not contents:
1096 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001097 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1098
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001099 def formatvalue(self, object):
1100 """Format an argument default value as text."""
1101 return '=' + self.repr(object)
1102
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001103 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001104 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001105 realname = object.__name__
1106 name = name or realname
1107 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001108 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001109 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001110 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001111 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001112 if imclass is not cl:
1113 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001114 skipdocs = 1
1115 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001116 if object.im_self:
1117 note = ' method of %s instance' % classname(
1118 object.im_self.__class__, mod)
1119 else:
1120 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001121 object = object.im_func
1122
1123 if name == realname:
1124 title = self.bold(realname)
1125 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001126 if (cl and cl.__dict__.has_key(realname) and
1127 cl.__dict__[realname] is object):
1128 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001129 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001130 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001131 args, varargs, varkw, defaults = inspect.getargspec(object)
1132 argspec = inspect.formatargspec(
1133 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001134 if realname == '<lambda>':
1135 title = 'lambda'
1136 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001137 else:
1138 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001139 decl = title + argspec + note
1140
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001141 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001142 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001143 else:
1144 doc = getdoc(object) or ''
1145 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001146
Tim Peters28355492001-09-23 21:29:55 +00001147 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001148 """Produce text documentation for a data object."""
1149 repr = self.repr(object)
1150 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001151 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001152 chop = maxlen - len(line)
1153 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001154 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001155 if doc is not None:
1156 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001157 return line
1158
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001159# --------------------------------------------------------- user interfaces
1160
1161def pager(text):
1162 """The first time this is called, determine what kind of pager to use."""
1163 global pager
1164 pager = getpager()
1165 pager(text)
1166
1167def getpager():
1168 """Decide what method to use for paging through text."""
1169 if type(sys.stdout) is not types.FileType:
1170 return plainpager
1171 if not sys.stdin.isatty() or not sys.stdout.isatty():
1172 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001173 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001174 return plainpager
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001175 if os.environ.has_key('PAGER'):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001176 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001177 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1178 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1179 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001180 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001181 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001182 if sys.platform == 'win32':
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001183 return lambda text: tempfilepager(plain(text), 'more <')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001184 if hasattr(os, 'system') and os.system('less 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001185 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001186
1187 import tempfile
1188 filename = tempfile.mktemp()
1189 open(filename, 'w').close()
1190 try:
1191 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1192 return lambda text: pipepager(text, 'more')
1193 else:
1194 return ttypager
1195 finally:
1196 os.unlink(filename)
1197
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001198def plain(text):
1199 """Remove boldface formatting from text."""
1200 return re.sub('.\b', '', text)
1201
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001202def pipepager(text, cmd):
1203 """Page through text by feeding it to another program."""
1204 pipe = os.popen(cmd, 'w')
1205 try:
1206 pipe.write(text)
1207 pipe.close()
1208 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001209 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001210
1211def tempfilepager(text, cmd):
1212 """Page through text by invoking a program on a temporary file."""
1213 import tempfile
1214 filename = tempfile.mktemp()
1215 file = open(filename, 'w')
1216 file.write(text)
1217 file.close()
1218 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001219 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001220 finally:
1221 os.unlink(filename)
1222
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001223def ttypager(text):
1224 """Page through text on a text terminal."""
1225 lines = split(plain(text), '\n')
1226 try:
1227 import tty
1228 fd = sys.stdin.fileno()
1229 old = tty.tcgetattr(fd)
1230 tty.setcbreak(fd)
1231 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001232 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001233 tty = None
1234 getchar = lambda: sys.stdin.readline()[:-1][:1]
1235
1236 try:
1237 r = inc = os.environ.get('LINES', 25) - 1
1238 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1239 while lines[r:]:
1240 sys.stdout.write('-- more --')
1241 sys.stdout.flush()
1242 c = getchar()
1243
1244 if c in ['q', 'Q']:
1245 sys.stdout.write('\r \r')
1246 break
1247 elif c in ['\r', '\n']:
1248 sys.stdout.write('\r \r' + lines[r] + '\n')
1249 r = r + 1
1250 continue
1251 if c in ['b', 'B', '\x1b']:
1252 r = r - inc - inc
1253 if r < 0: r = 0
1254 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1255 r = r + inc
1256
1257 finally:
1258 if tty:
1259 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1260
1261def plainpager(text):
1262 """Simply print unformatted text. This is the ultimate fallback."""
1263 sys.stdout.write(plain(text))
1264
1265def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001266 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001267 if inspect.ismodule(thing):
1268 if thing.__name__ in sys.builtin_module_names:
1269 return 'built-in module ' + thing.__name__
1270 if hasattr(thing, '__path__'):
1271 return 'package ' + thing.__name__
1272 else:
1273 return 'module ' + thing.__name__
1274 if inspect.isbuiltin(thing):
1275 return 'built-in function ' + thing.__name__
1276 if inspect.isclass(thing):
1277 return 'class ' + thing.__name__
1278 if inspect.isfunction(thing):
1279 return 'function ' + thing.__name__
1280 if inspect.ismethod(thing):
1281 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001282 if type(thing) is types.InstanceType:
1283 return 'instance of ' + thing.__class__.__name__
1284 return type(thing).__name__
1285
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001286def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001287 """Locate an object by name or dotted path, importing as necessary."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001288 parts = split(path, '.')
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001289 module, n = None, 0
1290 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001291 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001292 if nextmodule: module, n = nextmodule, n + 1
1293 else: break
1294 if module:
1295 object = module
1296 for part in parts[n:]:
1297 try: object = getattr(object, part)
1298 except AttributeError: return None
1299 return object
1300 else:
1301 import __builtin__
1302 if hasattr(__builtin__, path):
1303 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001304
1305# --------------------------------------- interactive interpreter interface
1306
1307text = TextDoc()
1308html = HTMLDoc()
1309
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001310def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001311 """Display text documentation, given an object or a path to an object."""
1312 suffix, name = '', None
1313 if type(thing) is type(''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001314 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001315 object = locate(thing, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001316 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001317 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001318 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001319 if not object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001320 print 'no Python documentation found for %s' % repr(thing)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001321 return
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001322 parts = split(thing, '.')
1323 if len(parts) > 1: suffix = ' in ' + join(parts[:-1], '.')
1324 name = parts[-1]
1325 thing = object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001326
1327 desc = describe(thing)
1328 module = inspect.getmodule(thing)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001329 if not suffix and module and module is not thing:
1330 suffix = ' in module ' + module.__name__
Ka-Ping Yee66246962001-04-12 11:59:50 +00001331 pager(title % (desc + suffix) + '\n\n' + text.document(thing, name))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001332
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001333def writedoc(key, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001334 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001335 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001336 object = locate(key, forceload)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001337 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001338 print value
1339 else:
1340 if object:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001341 page = html.page(describe(object),
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001342 html.document(object, object.__name__))
1343 file = open(key + '.html', 'w')
1344 file.write(page)
1345 file.close()
1346 print 'wrote', key + '.html'
1347 else:
1348 print 'no Python documentation found for %s' % repr(key)
1349
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001350def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001351 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001352 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001353 for file in os.listdir(dir):
1354 path = os.path.join(dir, file)
1355 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001356 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001357 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001358 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001359 if modname:
1360 modname = pkgpath + modname
1361 if not done.has_key(modname):
1362 done[modname] = 1
1363 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001364
1365class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001366 keywords = {
1367 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001368 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001369 'break': ('ref/break', 'while for'),
1370 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1371 'continue': ('ref/continue', 'while for'),
1372 'def': ('ref/function', ''),
1373 'del': ('ref/del', 'BASICMETHODS'),
1374 'elif': 'if',
1375 'else': ('ref/if', 'while for'),
1376 'except': 'try',
1377 'exec': ('ref/exec', ''),
1378 'finally': 'try',
1379 'for': ('ref/for', 'break continue while'),
1380 'from': 'import',
1381 'global': ('ref/global', 'NAMESPACES'),
1382 'if': ('ref/if', 'TRUTHVALUE'),
1383 'import': ('ref/import', 'MODULES'),
1384 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1385 'is': 'COMPARISON',
1386 'lambda': ('ref/lambda', 'FUNCTIONS'),
1387 'not': 'BOOLEAN',
1388 'or': 'BOOLEAN',
1389 'pass': 'PASS',
1390 'print': ('ref/print', ''),
1391 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001392 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001393 'try': ('ref/try', 'EXCEPTIONS'),
1394 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1395 }
1396
1397 topics = {
1398 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001399 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001400 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1401 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001402 'UNICODE': ('ref/unicode', 'encodings unicode TYPES STRING'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001403 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1404 'INTEGER': ('ref/integers', 'int range'),
1405 'FLOAT': ('ref/floating', 'float math'),
1406 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001407 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001408 'MAPPINGS': 'DICTIONARIES',
1409 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1410 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1411 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001412 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001413 'FRAMEOBJECTS': 'TYPES',
1414 'TRACEBACKS': 'TYPES',
1415 'NONE': ('lib/bltin-null-object', ''),
1416 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1417 'FILES': ('lib/bltin-file-objects', ''),
1418 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1419 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1420 'MODULES': ('lib/typesmodules', 'import'),
1421 'PACKAGES': 'import',
1422 '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'),
1423 'OPERATORS': 'EXPRESSIONS',
1424 'PRECEDENCE': 'EXPRESSIONS',
1425 'OBJECTS': ('ref/objects', 'TYPES'),
1426 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001427 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1428 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1429 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1430 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1431 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1432 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1433 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001434 'EXECUTION': ('ref/execframes', ''),
1435 'NAMESPACES': ('ref/execframes', 'global ASSIGNMENT DELETION'),
1436 'SCOPING': 'NAMESPACES',
1437 'FRAMES': 'NAMESPACES',
1438 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1439 'COERCIONS': 'CONVERSIONS',
1440 'CONVERSIONS': ('ref/conversions', ''),
1441 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1442 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001443 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001444 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1445 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001446 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001447 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001448 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001449 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001450 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1451 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001452 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1453 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1454 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1455 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1456 'POWER': ('ref/power', 'EXPRESSIONS'),
1457 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1458 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1459 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1460 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1461 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001462 'BOOLEAN': ('ref/lambda', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001463 'ASSERTION': 'assert',
1464 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001465 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001466 'DELETION': 'del',
1467 'PRINTING': 'print',
1468 'RETURNING': 'return',
1469 'IMPORTING': 'import',
1470 'CONDITIONAL': 'if',
1471 'LOOPING': ('ref/compound', 'for while break continue'),
1472 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001473 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001474 }
1475
1476 def __init__(self, input, output):
1477 self.input = input
1478 self.output = output
1479 self.docdir = None
1480 execdir = os.path.dirname(sys.executable)
1481 homedir = os.environ.get('PYTHONHOME')
1482 for dir in [os.environ.get('PYTHONDOCS'),
1483 homedir and os.path.join(homedir, 'doc'),
1484 os.path.join(execdir, 'doc'),
1485 '/usr/doc/python-docs-' + split(sys.version)[0],
1486 '/usr/doc/python-' + split(sys.version)[0],
1487 '/usr/doc/python-docs-' + sys.version[:3],
1488 '/usr/doc/python-' + sys.version[:3]]:
1489 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1490 self.docdir = dir
1491
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001492 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001493 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001494 self()
1495 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001496 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001497
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001498 def __call__(self, request=None):
1499 if request is not None:
1500 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001501 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001502 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001503 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001504 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001505You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001506If you want to ask for help on a particular object directly from the
1507interpreter, you can type "help(object)". Executing "help('string')"
1508has the same effect as typing a particular string at the help> prompt.
1509''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001510
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001511 def interact(self):
1512 self.output.write('\n')
1513 while 1:
1514 self.output.write('help> ')
1515 self.output.flush()
1516 try:
1517 request = self.input.readline()
1518 if not request: break
1519 except KeyboardInterrupt: break
1520 request = strip(replace(request, '"', '', "'", ''))
1521 if lower(request) in ['q', 'quit']: break
1522 self.help(request)
1523
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001524 def help(self, request):
1525 if type(request) is type(''):
1526 if request == 'help': self.intro()
1527 elif request == 'keywords': self.listkeywords()
1528 elif request == 'topics': self.listtopics()
1529 elif request == 'modules': self.listmodules()
1530 elif request[:8] == 'modules ':
1531 self.listmodules(split(request)[1])
1532 elif self.keywords.has_key(request): self.showtopic(request)
1533 elif self.topics.has_key(request): self.showtopic(request)
1534 elif request: doc(request, 'Help on %s:')
1535 elif isinstance(request, Helper): self()
1536 else: doc(request, 'Help on %s:')
1537 self.output.write('\n')
1538
1539 def intro(self):
1540 self.output.write('''
1541Welcome to Python %s! This is the online help utility.
1542
1543If this is your first time using Python, you should definitely check out
1544the tutorial on the Internet at http://www.python.org/doc/tut/.
1545
1546Enter the name of any module, keyword, or topic to get help on writing
1547Python programs and using Python modules. To quit this help utility and
1548return to the interpreter, just type "quit".
1549
1550To get a list of available modules, keywords, or topics, type "modules",
1551"keywords", or "topics". Each module also comes with a one-line summary
1552of what it does; to list the modules whose summaries contain a given word
1553such as "spam", type "modules spam".
1554''' % sys.version[:3])
1555
1556 def list(self, items, columns=4, width=80):
1557 items = items[:]
1558 items.sort()
1559 colw = width / columns
1560 rows = (len(items) + columns - 1) / columns
1561 for row in range(rows):
1562 for col in range(columns):
1563 i = col * rows + row
1564 if i < len(items):
1565 self.output.write(items[i])
1566 if col < columns - 1:
1567 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1568 self.output.write('\n')
1569
1570 def listkeywords(self):
1571 self.output.write('''
1572Here is a list of the Python keywords. Enter any keyword to get more help.
1573
1574''')
1575 self.list(self.keywords.keys())
1576
1577 def listtopics(self):
1578 self.output.write('''
1579Here is a list of available topics. Enter any topic name to get more help.
1580
1581''')
1582 self.list(self.topics.keys())
1583
1584 def showtopic(self, topic):
1585 if not self.docdir:
1586 self.output.write('''
1587Sorry, topic and keyword documentation is not available because the Python
1588HTML documentation files could not be found. If you have installed them,
1589please set the environment variable PYTHONDOCS to indicate their location.
1590''')
1591 return
1592 target = self.topics.get(topic, self.keywords.get(topic))
1593 if not target:
1594 self.output.write('no documentation found for %s\n' % repr(topic))
1595 return
1596 if type(target) is type(''):
1597 return self.showtopic(target)
1598
1599 filename, xrefs = target
1600 filename = self.docdir + '/' + filename + '.html'
1601 try:
1602 file = open(filename)
1603 except:
1604 self.output.write('could not read docs from %s\n' % filename)
1605 return
1606
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001607 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1608 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001609 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1610 file.close()
1611
1612 import htmllib, formatter, StringIO
1613 buffer = StringIO.StringIO()
1614 parser = htmllib.HTMLParser(
1615 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1616 parser.start_table = parser.do_p
1617 parser.end_table = lambda parser=parser: parser.do_p({})
1618 parser.start_tr = parser.do_br
1619 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1620 parser.feed(document)
1621 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1622 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001623 if xrefs:
1624 buffer = StringIO.StringIO()
1625 formatter.DumbWriter(buffer).send_flowing_data(
1626 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1627 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001628
1629 def listmodules(self, key=''):
1630 if key:
1631 self.output.write('''
1632Here is a list of matching modules. Enter any module name to get more help.
1633
1634''')
1635 apropos(key)
1636 else:
1637 self.output.write('''
1638Please wait a moment while I gather a list of all available modules...
1639
1640''')
1641 modules = {}
1642 def callback(path, modname, desc, modules=modules):
1643 if modname and modname[-9:] == '.__init__':
1644 modname = modname[:-9] + ' (package)'
1645 if find(modname, '.') < 0:
1646 modules[modname] = 1
1647 ModuleScanner().run(callback)
1648 self.list(modules.keys())
1649 self.output.write('''
1650Enter any module name to get more help. Or, type "modules spam" to search
1651for modules whose descriptions contain the word "spam".
1652''')
1653
1654help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001655
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001656class Scanner:
1657 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001658 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001659 self.roots = roots[:]
1660 self.state = []
1661 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001662 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001663
1664 def next(self):
1665 if not self.state:
1666 if not self.roots:
1667 return None
1668 root = self.roots.pop(0)
1669 self.state = [(root, self.children(root))]
1670 node, children = self.state[-1]
1671 if not children:
1672 self.state.pop()
1673 return self.next()
1674 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001675 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001676 self.state.append((child, self.children(child)))
1677 return child
1678
1679class ModuleScanner(Scanner):
1680 """An interruptible scanner that searches module synopses."""
1681 def __init__(self):
1682 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001683 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
1684 self.inodes = map(lambda (dir, pkg): os.stat(dir)[1], roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001685
1686 def submodules(self, (dir, package)):
1687 children = []
1688 for file in os.listdir(dir):
1689 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001690 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001691 children.append((path, package + (package and '.') + file))
1692 else:
1693 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001694 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001695 return children
1696
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001697 def isnewpackage(self, (dir, package)):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001698 inode = os.path.exists(dir) and os.stat(dir)[1]
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001699 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001700 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001701 return ispackage(dir)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001702
Ka-Ping Yee66246962001-04-12 11:59:50 +00001703 def run(self, callback, key=None, completer=None):
1704 if key: key = lower(key)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001705 self.quit = 0
1706 seen = {}
1707
1708 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001709 if modname != '__main__':
1710 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001711 if key is None:
1712 callback(None, modname, '')
1713 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001714 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001715 if find(lower(modname + ' - ' + desc), key) >= 0:
1716 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001717
1718 while not self.quit:
1719 node = self.next()
1720 if not node: break
1721 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001722 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001723 if os.path.isfile(path) and modname:
1724 modname = package + (package and '.') + modname
1725 if not seen.has_key(modname):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001726 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001727 if key is None:
1728 callback(path, modname, '')
1729 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001730 desc = synopsis(path) or ''
1731 if find(lower(modname + ' - ' + desc), key) >= 0:
1732 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001733 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001734
1735def apropos(key):
1736 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001737 def callback(path, modname, desc):
1738 if modname[-9:] == '.__init__':
1739 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001740 print modname, desc and '- ' + desc
1741 try: import warnings
1742 except ImportError: pass
1743 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001744 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001745
1746# --------------------------------------------------- web browser interface
1747
Ka-Ping Yee66246962001-04-12 11:59:50 +00001748def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001749 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001750
1751 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1752 class Message(mimetools.Message):
1753 def __init__(self, fp, seekable=1):
1754 Message = self.__class__
1755 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1756 self.encodingheader = self.getheader('content-transfer-encoding')
1757 self.typeheader = self.getheader('content-type')
1758 self.parsetype()
1759 self.parseplist()
1760
1761 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1762 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001763 try:
1764 self.send_response(200)
1765 self.send_header('Content-Type', 'text/html')
1766 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001767 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001768 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001769
1770 def do_GET(self):
1771 path = self.path
1772 if path[-5:] == '.html': path = path[:-5]
1773 if path[:1] == '/': path = path[1:]
1774 if path and path != '.':
1775 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001776 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001777 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001778 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001779 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001780 if obj:
1781 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001782 else:
1783 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001784'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001785 else:
1786 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001787'<big><big><strong>Python: Index of Modules</strong></big></big>',
1788'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001789 def bltinlink(name):
1790 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001791 names = filter(lambda x: x != '__main__',
1792 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001793 contents = html.multicolumn(names, bltinlink)
1794 indices = ['<p>' + html.bigsection(
1795 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1796
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001797 seen = {}
1798 for dir in pathdirs():
1799 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001800 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001801<font color="#909090" face="helvetica, arial"><strong>
1802pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001803 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001804
1805 def log_message(self, *args): pass
1806
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001807 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001808 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001809 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001810 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001811 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001812 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001813 self.base.__init__(self, self.address, self.handler)
1814
1815 def serve_until_quit(self):
1816 import select
1817 self.quit = 0
1818 while not self.quit:
1819 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1820 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001821
1822 def server_activate(self):
1823 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001824 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001825
1826 DocServer.base = BaseHTTPServer.HTTPServer
1827 DocServer.handler = DocHandler
1828 DocHandler.MessageClass = Message
1829 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001830 try:
1831 DocServer(port, callback).serve_until_quit()
1832 except (KeyboardInterrupt, select.error):
1833 pass
1834 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001835 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001836
1837# ----------------------------------------------------- graphical interface
1838
1839def gui():
1840 """Graphical interface (starts web server and pops up a control window)."""
1841 class GUI:
1842 def __init__(self, window, port=7464):
1843 self.window = window
1844 self.server = None
1845 self.scanner = None
1846
1847 import Tkinter
1848 self.server_frm = Tkinter.Frame(window)
1849 self.title_lbl = Tkinter.Label(self.server_frm,
1850 text='Starting server...\n ')
1851 self.open_btn = Tkinter.Button(self.server_frm,
1852 text='open browser', command=self.open, state='disabled')
1853 self.quit_btn = Tkinter.Button(self.server_frm,
1854 text='quit serving', command=self.quit, state='disabled')
1855
1856 self.search_frm = Tkinter.Frame(window)
1857 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1858 self.search_ent = Tkinter.Entry(self.search_frm)
1859 self.search_ent.bind('<Return>', self.search)
1860 self.stop_btn = Tkinter.Button(self.search_frm,
1861 text='stop', pady=0, command=self.stop, state='disabled')
1862 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001863 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001864 self.stop_btn.pack(side='right')
1865
1866 self.window.title('pydoc')
1867 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1868 self.title_lbl.pack(side='top', fill='x')
1869 self.open_btn.pack(side='left', fill='x', expand=1)
1870 self.quit_btn.pack(side='right', fill='x', expand=1)
1871 self.server_frm.pack(side='top', fill='x')
1872
1873 self.search_lbl.pack(side='left')
1874 self.search_ent.pack(side='right', fill='x', expand=1)
1875 self.search_frm.pack(side='top', fill='x')
1876 self.search_ent.focus_set()
1877
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001878 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001879 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001880 self.result_lst.bind('<Button-1>', self.select)
1881 self.result_lst.bind('<Double-Button-1>', self.goto)
1882 self.result_scr = Tkinter.Scrollbar(window,
1883 orient='vertical', command=self.result_lst.yview)
1884 self.result_lst.config(yscrollcommand=self.result_scr.set)
1885
1886 self.result_frm = Tkinter.Frame(window)
1887 self.goto_btn = Tkinter.Button(self.result_frm,
1888 text='go to selected', command=self.goto)
1889 self.hide_btn = Tkinter.Button(self.result_frm,
1890 text='hide results', command=self.hide)
1891 self.goto_btn.pack(side='left', fill='x', expand=1)
1892 self.hide_btn.pack(side='right', fill='x', expand=1)
1893
1894 self.window.update()
1895 self.minwidth = self.window.winfo_width()
1896 self.minheight = self.window.winfo_height()
1897 self.bigminheight = (self.server_frm.winfo_reqheight() +
1898 self.search_frm.winfo_reqheight() +
1899 self.result_lst.winfo_reqheight() +
1900 self.result_frm.winfo_reqheight())
1901 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1902 self.expanded = 0
1903 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1904 self.window.wm_minsize(self.minwidth, self.minheight)
1905
1906 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001907 threading.Thread(
1908 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001909
1910 def ready(self, server):
1911 self.server = server
1912 self.title_lbl.config(
1913 text='Python documentation server at\n' + server.url)
1914 self.open_btn.config(state='normal')
1915 self.quit_btn.config(state='normal')
1916
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001917 def open(self, event=None, url=None):
1918 url = url or self.server.url
1919 try:
1920 import webbrowser
1921 webbrowser.open(url)
1922 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001923 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001924 os.system('start "%s"' % url)
1925 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001926 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001927 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001928 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001929 else:
1930 rc = os.system('netscape -remote "openURL(%s)" &' % url)
1931 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001932
1933 def quit(self, event=None):
1934 if self.server:
1935 self.server.quit = 1
1936 self.window.quit()
1937
1938 def search(self, event=None):
1939 key = self.search_ent.get()
1940 self.stop_btn.pack(side='right')
1941 self.stop_btn.config(state='normal')
1942 self.search_lbl.config(text='Searching for "%s"...' % key)
1943 self.search_ent.forget()
1944 self.search_lbl.pack(side='left')
1945 self.result_lst.delete(0, 'end')
1946 self.goto_btn.config(state='disabled')
1947 self.expand()
1948
1949 import threading
1950 if self.scanner:
1951 self.scanner.quit = 1
1952 self.scanner = ModuleScanner()
1953 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00001954 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001955
1956 def update(self, path, modname, desc):
1957 if modname[-9:] == '.__init__':
1958 modname = modname[:-9] + ' (package)'
1959 self.result_lst.insert('end',
1960 modname + ' - ' + (desc or '(no description)'))
1961
1962 def stop(self, event=None):
1963 if self.scanner:
1964 self.scanner.quit = 1
1965 self.scanner = None
1966
1967 def done(self):
1968 self.scanner = None
1969 self.search_lbl.config(text='Search for')
1970 self.search_lbl.pack(side='left')
1971 self.search_ent.pack(side='right', fill='x', expand=1)
1972 if sys.platform != 'win32': self.stop_btn.forget()
1973 self.stop_btn.config(state='disabled')
1974
1975 def select(self, event=None):
1976 self.goto_btn.config(state='normal')
1977
1978 def goto(self, event=None):
1979 selection = self.result_lst.curselection()
1980 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001981 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001982 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001983
1984 def collapse(self):
1985 if not self.expanded: return
1986 self.result_frm.forget()
1987 self.result_scr.forget()
1988 self.result_lst.forget()
1989 self.bigwidth = self.window.winfo_width()
1990 self.bigheight = self.window.winfo_height()
1991 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1992 self.window.wm_minsize(self.minwidth, self.minheight)
1993 self.expanded = 0
1994
1995 def expand(self):
1996 if self.expanded: return
1997 self.result_frm.pack(side='bottom', fill='x')
1998 self.result_scr.pack(side='right', fill='y')
1999 self.result_lst.pack(side='top', fill='both', expand=1)
2000 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2001 self.window.wm_minsize(self.minwidth, self.bigminheight)
2002 self.expanded = 1
2003
2004 def hide(self, event=None):
2005 self.stop()
2006 self.collapse()
2007
2008 import Tkinter
2009 try:
2010 gui = GUI(Tkinter.Tk())
2011 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002012 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002013 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002014
2015# -------------------------------------------------- command-line interface
2016
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002017def ispath(x):
2018 return type(x) is types.StringType and find(x, os.sep) >= 0
2019
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002020def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002021 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002022 import getopt
2023 class BadUsage: pass
2024
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002025 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002026 scriptdir = os.path.dirname(sys.argv[0])
2027 if scriptdir in sys.path:
2028 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002029 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002030
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002031 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002032 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002033 writing = 0
2034
2035 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002036 if opt == '-g':
2037 gui()
2038 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002039 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002040 apropos(val)
2041 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002042 if opt == '-p':
2043 try:
2044 port = int(val)
2045 except ValueError:
2046 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002047 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002048 print 'pydoc server ready at %s' % server.url
2049 def stopped():
2050 print 'pydoc server stopped'
2051 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002052 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002053 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002054 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002055
2056 if not args: raise BadUsage
2057 for arg in args:
2058 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002059 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002060 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002061 if writing:
2062 if ispath(arg) and os.path.isdir(arg):
2063 writedocs(arg)
2064 else:
2065 writedoc(arg)
2066 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002067 doc(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002068 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002069 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002070
2071 except (getopt.error, BadUsage):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002072 cmd = sys.argv[0]
2073 print """pydoc - the Python documentation tool
2074
2075%s <name> ...
2076 Show text documentation on something. <name> may be the name of a
2077 function, module, or package, or a dotted reference to a class or
2078 function within a module or module in a package. If <name> contains
2079 a '%s', it is used as the path to a Python source file to document.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002080
2081%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002082 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002083
2084%s -p <port>
2085 Start an HTTP server on the given port on the local machine.
2086
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002087%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002088 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002089
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002090%s -w <name> ...
2091 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002092 directory. If <name> contains a '%s', it is treated as a filename; if
2093 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002094""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002095
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002096if __name__ == '__main__': cli()