blob: 9179721c71dde4b9f56789f50aab8643abe52bd4 [file] [log] [blame]
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001#!/usr/bin/env python
Guido van Rossumfce538c2002-08-06 17:29:38 +00002# -*- coding: Latin-1 -*-
Ka-Ping Yee1d384632001-03-01 00:24:32 +00003"""Generate Python documentation in HTML or text for interactive use.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00004
Ka-Ping Yeedd175342001-02-27 14:43:46 +00005In the Python interpreter, do "from pydoc import help" to provide online
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00006help. Calling help(thing) on a Python object documents the object.
7
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00008Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00009
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000010Run "pydoc <name>" to show documentation on something. <name> may be
11the name of a function, module, package, or a dotted reference to a
12class or function within a module or module in a package. If the
13argument contains a path segment delimiter (e.g. slash on Unix,
14backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000015
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000016Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000018
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000019Run "pydoc -p <port>" to start an HTTP server on a given port on the
20local machine to generate documentation web pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000021
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000022For platforms without a command line, "pydoc -g" starts the HTTP server
23and also pops up a little window for controlling it.
24
25Run "pydoc -w <name>" to write out the HTML documentation for a module
26to a file named "<name>.html".
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000027"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000028
29__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000030__date__ = "26 February 2001"
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000031__version__ = "$Revision$"
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000032__credits__ = """Guido van Rossum, for an excellent programming language.
33Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000034Paul Prescod, for all his work on onlinehelp.
35Richard Chamberlain, for the first implementation of textdoc.
36
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000037Mynd you, møøse bites Kan be pretty nasti..."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000038
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000039# Known bugs that can't be fixed here:
40# - imp.load_module() cannot be prevented from clobbering existing
41# loaded modules, so calling synopsis() on a binary module file
42# changes the contents of any existing module with the same name.
43# - If the __file__ attribute on a module is a relative path and
44# the current directory is changed with os.chdir(), an incorrect
45# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000046
Raymond Hettinger32200ae2002-06-01 19:51:15 +000047import sys, imp, os, re, types, inspect
Ka-Ping Yeedd175342001-02-27 14:43:46 +000048from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000049from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
Ka-Ping Yeedd175342001-02-27 14:43:46 +000050
51# --------------------------------------------------------- common routines
52
Ka-Ping Yeedd175342001-02-27 14:43:46 +000053def pathdirs():
54 """Convert sys.path into a list of absolute, existing, unique paths."""
55 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000056 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000057 for dir in sys.path:
58 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000059 normdir = os.path.normcase(dir)
60 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000061 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000062 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000063 return dirs
64
65def getdoc(object):
66 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000067 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000068 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000069
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000070def splitdoc(doc):
71 """Split a doc string into a synopsis line (if any) and the rest."""
72 lines = split(strip(doc), '\n')
73 if len(lines) == 1:
74 return lines[0], ''
75 elif len(lines) >= 2 and not rstrip(lines[1]):
76 return lines[0], join(lines[2:], '\n')
77 return '', join(lines, '\n')
78
Ka-Ping Yeedd175342001-02-27 14:43:46 +000079def classname(object, modname):
80 """Get a class name and qualify it with a module name if necessary."""
81 name = object.__name__
82 if object.__module__ != modname:
83 name = object.__module__ + '.' + name
84 return name
85
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000086def isdata(object):
87 """Check if an object is of a type that probably means it's data."""
88 return not (inspect.ismodule(object) or inspect.isclass(object) or
89 inspect.isroutine(object) or inspect.isframe(object) or
90 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +000091
92def replace(text, *pairs):
93 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +000094 while pairs:
95 text = join(split(text, pairs[0]), pairs[1])
96 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +000097 return text
98
99def cram(text, maxlen):
100 """Omit part of a string if needed to make it fit in a maximum length."""
101 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000102 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000103 post = max(0, maxlen-3-pre)
104 return text[:pre] + '...' + text[len(text)-post:]
105 return text
106
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000107def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000108 """Remove the hexadecimal id from a Python object representation."""
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000109 # The behaviour of %p is implementation-dependent; we check two cases.
Ka-Ping Yee45daeb02002-08-11 15:11:33 +0000110 for pattern in [' at 0x[0-9a-f]{6,}(>+)$', ' at [0-9A-F]{8,}(>+)$']:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000111 if re.search(pattern, repr(Exception)):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +0000112 return re.sub(pattern, '\\1', text)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000113 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000114
Tim Peters536d2262001-09-20 05:13:38 +0000115def _is_some_method(object):
116 return inspect.ismethod(object) or inspect.ismethoddescriptor(object)
117
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000118def allmethods(cl):
119 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000120 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000121 methods[key] = 1
122 for base in cl.__bases__:
123 methods.update(allmethods(base)) # all your base are belong to us
124 for key in methods.keys():
125 methods[key] = getattr(cl, key)
126 return methods
127
Tim Petersfa26f7c2001-09-24 08:05:11 +0000128def _split_list(s, predicate):
129 """Split sequence s via predicate, and return pair ([true], [false]).
130
131 The return value is a 2-tuple of lists,
132 ([x for x in s if predicate(x)],
133 [x for x in s if not predicate(x)])
134 """
135
Tim Peters28355492001-09-23 21:29:55 +0000136 yes = []
137 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000138 for x in s:
139 if predicate(x):
140 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000141 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000142 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000143 return yes, no
144
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000145# ----------------------------------------------------- module manipulation
146
147def ispackage(path):
148 """Guess whether a path refers to a package directory."""
149 if os.path.isdir(path):
150 for ext in ['.py', '.pyc', '.pyo']:
151 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000152 return True
153 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000154
155def synopsis(filename, cache={}):
156 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000157 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000158 lastupdate, result = cache.get(filename, (0, None))
159 if lastupdate < mtime:
160 info = inspect.getmoduleinfo(filename)
161 file = open(filename)
162 if info and 'b' in info[2]: # binary modules have to be imported
163 try: module = imp.load_module('__temp__', file, filename, info[1:])
164 except: return None
165 result = split(module.__doc__ or '', '\n')[0]
166 del sys.modules['__temp__']
167 else: # text modules can be directly examined
168 line = file.readline()
169 while line[:1] == '#' or not strip(line):
170 line = file.readline()
171 if not line: break
172 line = strip(line)
173 if line[:4] == 'r"""': line = line[1:]
174 if line[:3] == '"""':
175 line = line[3:]
176 if line[-1:] == '\\': line = line[:-1]
177 while not strip(line):
178 line = file.readline()
179 if not line: break
180 result = strip(split(line, '"""')[0])
181 else: result = None
182 file.close()
183 cache[filename] = (mtime, result)
184 return result
185
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000186class ErrorDuringImport(Exception):
187 """Errors that occurred while trying to import something to document it."""
188 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000189 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000190 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000191 self.value = value
192 self.tb = tb
193
194 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000195 exc = self.exc
196 if type(exc) is types.ClassType:
197 exc = exc.__name__
198 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000199
200def importfile(path):
201 """Import a Python source file or compiled file given its path."""
202 magic = imp.get_magic()
203 file = open(path, 'r')
204 if file.read(len(magic)) == magic:
205 kind = imp.PY_COMPILED
206 else:
207 kind = imp.PY_SOURCE
208 file.close()
209 filename = os.path.basename(path)
210 name, ext = os.path.splitext(filename)
211 file = open(path, 'r')
212 try:
213 module = imp.load_module(name, file, path, (ext, 'r', kind))
214 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000215 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000216 file.close()
217 return module
218
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000219def safeimport(path, forceload=0, cache={}):
220 """Import a module; handle errors; return None if the module isn't found.
221
222 If the module *is* found but an exception occurs, it's wrapped in an
223 ErrorDuringImport exception and reraised. Unlike __import__, if a
224 package path is specified, the module at the end of the path is returned,
225 not the package at the beginning. If the optional 'forceload' argument
226 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000227 if forceload and path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000228 # This is the only way to be sure. Checking the mtime of the file
229 # isn't good enough (e.g. what if the module contains a class that
230 # inherits from another module that has changed?).
231 if path not in sys.builtin_module_names:
232 # Python never loads a dynamic extension a second time from the
233 # same path, even if the file is changed or missing. Deleting
234 # the entry in sys.modules doesn't help for dynamic extensions,
235 # so we're not even going to try to keep them up to date.
236 info = inspect.getmoduleinfo(sys.modules[path].__file__)
237 if info[3] != imp.C_EXTENSION:
238 cache[path] = sys.modules[path] # prevent module from clearing
239 del sys.modules[path]
240 try:
241 module = __import__(path)
242 except:
243 # Did the error occur before or after the module was found?
244 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000245 if path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000246 # An error occured while executing the imported module.
247 raise ErrorDuringImport(sys.modules[path].__file__, info)
248 elif exc is SyntaxError:
249 # A SyntaxError occurred before we could execute the module.
250 raise ErrorDuringImport(value.filename, info)
251 elif exc is ImportError and \
252 split(lower(str(value)))[:2] == ['no', 'module']:
253 # The module was not found.
254 return None
255 else:
256 # Some other error occurred during the importing process.
257 raise ErrorDuringImport(path, sys.exc_info())
258 for part in split(path, '.')[1:]:
259 try: module = getattr(module, part)
260 except AttributeError: return None
261 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000262
263# ---------------------------------------------------- formatter base class
264
265class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000266 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000267 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000268 args = (object, name) + args
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000269 if inspect.ismodule(object): return apply(self.docmodule, args)
270 if inspect.isclass(object): return apply(self.docclass, args)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000271 if inspect.isroutine(object): return apply(self.docroutine, args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000272 return apply(self.docother, args)
273
274 def fail(self, object, name=None, *args):
275 """Raise an exception for unimplemented types."""
276 message = "don't know how to document object%s of type %s" % (
277 name and ' ' + repr(name), type(object).__name__)
278 raise TypeError, message
279
280 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000281
282# -------------------------------------------- HTML documentation generator
283
284class HTMLRepr(Repr):
285 """Class for safely making an HTML representation of a Python object."""
286 def __init__(self):
287 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000288 self.maxlist = self.maxtuple = 20
289 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000290 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000291
292 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000293 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000294
295 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000296 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000297
298 def repr1(self, x, level):
299 methodname = 'repr_' + join(split(type(x).__name__), '_')
300 if hasattr(self, methodname):
301 return getattr(self, methodname)(x, level)
302 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000303 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000304
305 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000306 test = cram(x, self.maxstring)
307 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000308 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000309 # Backslashes are only literal in the string and are never
310 # needed to make any special characters, so show a raw string.
311 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000312 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000313 r'<font color="#c040c0">\1</font>',
314 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000315
Skip Montanarodf708782002-03-07 22:58:02 +0000316 repr_str = repr_string
317
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000318 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 '''
Tim Peters59ed4482001-10-31 04:20:26 +0000338<!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 '''
Tim Peters59ed4482001-10-31 04:20:26 +0000349<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000350<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 = '''
Tim Peters59ed4482001-10-31 04:20:26 +0000363<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000364<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>'
Tim Peters59ed4482001-10-31 04:20:26 +0000400 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000401
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:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000407 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000408 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+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000446 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000447 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000448 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:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000455 url = escape(all).replace('"', '&quot;')
456 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000457 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000458 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
459 results.append('<a href="%s">%s</a>' % (url, escape(all)))
460 elif pep:
461 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000462 results.append('<a href="%s">%s</a>' % (url, escape(all)))
463 elif text[end:end+1] == '(':
464 results.append(self.namelink(name, methods, funcs, classes))
465 elif selfdot:
466 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000467 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000468 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000469 here = end
470 results.append(escape(text[here:]))
471 return join(results, '')
472
473 # ---------------------------------------------- type-specific routines
474
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000475 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000476 """Produce HTML for a class tree as given by inspect.getclasstree()."""
477 result = ''
478 for entry in tree:
479 if type(entry) is type(()):
480 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000481 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000482 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000483 if bases and bases != (parent,):
484 parents = []
485 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000486 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000487 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000488 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000489 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000490 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000491 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000492 return '<dl>\n%s</dl>\n' % result
493
Tim Peters8dd7ade2001-10-18 19:56:17 +0000494 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000495 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000496 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000497 parts = split(name, '.')
498 links = []
499 for i in range(len(parts)-1):
500 links.append(
501 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
502 (join(parts[:i+1], '.'), parts[i]))
503 linkedname = join(links + parts[-1:], '.')
504 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000505 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000506 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000507 url = path
508 if sys.platform == 'win32':
509 import nturl2path
510 url = nturl2path.pathname2url(path)
511 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000512 except TypeError:
513 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000514 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000515 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000516 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000517 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
518 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000519 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000520 if hasattr(object, '__date__'):
521 info.append(self.escape(str(object.__date__)))
522 if info:
523 head = head + ' (%s)' % join(info, ', ')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000524 result = self.heading(
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000525 head, '#ffffff', '#7799ee', '<a href=".">index</a><br>' + filelink)
526
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000527 modules = inspect.getmembers(object, inspect.ismodule)
528
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000529 classes, cdict = [], {}
530 for key, value in inspect.getmembers(object, inspect.isclass):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000531 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000532 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000533 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000534 for key, value in classes:
535 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000536 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000537 module = sys.modules.get(modname)
538 if modname != name and module and hasattr(module, key):
539 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000540 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000541 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000542 funcs, fdict = [], {}
543 for key, value in inspect.getmembers(object, inspect.isroutine):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000544 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000545 funcs.append((key, value))
546 fdict[key] = '#-' + key
547 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000548 data = []
549 for key, value in inspect.getmembers(object, isdata):
550 if key not in ['__builtins__', '__doc__']:
551 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000552
553 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
554 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000555 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000556
557 if hasattr(object, '__path__'):
558 modpkgs = []
559 modnames = []
560 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000561 path = os.path.join(object.__path__[0], file)
562 modname = inspect.getmodulename(file)
563 if modname and modname not in modnames:
564 modpkgs.append((modname, name, 0, 0))
565 modnames.append(modname)
566 elif ispackage(path):
567 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000568 modpkgs.sort()
569 contents = self.multicolumn(modpkgs, self.modpkglink)
570 result = result + self.bigsection(
571 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000572 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000573 contents = self.multicolumn(
574 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000575 result = result + self.bigsection(
576 'Modules', '#fffff', '#aa55cc', contents)
577
578 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000579 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000580 contents = [
581 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000582 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000583 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000584 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000585 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000586 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000587 contents = []
588 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000589 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000590 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000591 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000592 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000593 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000594 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000595 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000596 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000597 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000598 if hasattr(object, '__author__'):
599 contents = self.markup(str(object.__author__), self.preformat)
600 result = result + self.bigsection(
601 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000602 if hasattr(object, '__credits__'):
603 contents = self.markup(str(object.__credits__), self.preformat)
604 result = result + self.bigsection(
605 'Credits', '#ffffff', '#7799ee', contents)
606
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000607 return result
608
Tim Peters8dd7ade2001-10-18 19:56:17 +0000609 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
610 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000611 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000612 realname = object.__name__
613 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000614 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000615
Tim Petersb47879b2001-09-24 04:47:19 +0000616 contents = []
617 push = contents.append
618
Tim Petersfa26f7c2001-09-24 08:05:11 +0000619 # Cute little class to pump out a horizontal rule between sections.
620 class HorizontalRule:
621 def __init__(self):
622 self.needone = 0
623 def maybe(self):
624 if self.needone:
625 push('<hr>\n')
626 self.needone = 1
627 hr = HorizontalRule()
628
Tim Petersc86f6ca2001-09-26 21:31:51 +0000629 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +0000630 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000631 if len(mro) > 2:
632 hr.maybe()
633 push('<dl><dt>Method resolution order:</dt>\n')
634 for base in mro:
635 push('<dd>%s</dd>\n' % self.classlink(base,
636 object.__module__))
637 push('</dl>\n')
638
Tim Petersb47879b2001-09-24 04:47:19 +0000639 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000640 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000641 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000642 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000643 push(msg)
644 for name, kind, homecls, value in ok:
645 push(self.document(getattr(object, name), name, mod,
646 funcs, classes, mdict, object))
647 push('\n')
648 return attrs
649
Tim Petersfa26f7c2001-09-24 08:05:11 +0000650 def spillproperties(msg, attrs, predicate):
651 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000652 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000653 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000654 push(msg)
655 for name, kind, homecls, value in ok:
Tim Peters3e767d12001-09-25 00:01:06 +0000656 push('<dl><dt><strong>%s</strong></dt>\n' % name)
657 if value.__doc__ is not None:
658 doc = self.markup(value.__doc__, self.preformat,
659 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000660 push('<dd><tt>%s</tt></dd>\n' % doc)
Tim Petersf33532c2001-09-25 06:30:51 +0000661 for attr, tag in [("fget", " getter"),
662 ("fset", " setter"),
Tim Peters3e767d12001-09-25 00:01:06 +0000663 ("fdel", " deleter")]:
664 func = getattr(value, attr)
665 if func is not None:
666 base = self.document(func, name + tag, mod,
667 funcs, classes, mdict, object)
668 push('<dd>%s</dd>\n' % base)
669 push('</dl>\n')
Tim Petersb47879b2001-09-24 04:47:19 +0000670 return attrs
671
Tim Petersfa26f7c2001-09-24 08:05:11 +0000672 def spilldata(msg, attrs, predicate):
673 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000674 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000675 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000676 push(msg)
677 for name, kind, homecls, value in ok:
678 base = self.docother(getattr(object, name), name, mod)
Guido van Rossum5e355b22002-05-21 20:56:15 +0000679 if callable(value):
680 doc = getattr(value, "__doc__", None)
681 else:
682 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000683 if doc is None:
684 push('<dl><dt>%s</dl>\n' % base)
685 else:
686 doc = self.markup(getdoc(value), self.preformat,
687 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000688 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000689 push('<dl><dt>%s%s</dl>\n' % (base, doc))
690 push('\n')
691 return attrs
692
693 attrs = inspect.classify_class_attrs(object)
694 mdict = {}
695 for key, kind, homecls, value in attrs:
696 mdict[key] = anchor = '#' + name + '-' + key
697 value = getattr(object, key)
698 try:
699 # The value may not be hashable (e.g., a data attr with
700 # a dict or list value).
701 mdict[value] = anchor
702 except TypeError:
703 pass
704
Tim Petersfa26f7c2001-09-24 08:05:11 +0000705 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000706 if mro:
707 thisclass = mro.pop(0)
708 else:
709 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000710 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
711
Tim Petersb47879b2001-09-24 04:47:19 +0000712 if thisclass is object:
713 tag = "defined here"
714 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000715 tag = "inherited from %s" % self.classlink(thisclass,
Tim Petersb47879b2001-09-24 04:47:19 +0000716 object.__module__)
717 tag += ':<br>\n'
718
719 # Sort attrs by name.
720 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
721
722 # Pump out the attrs, segregated by kind.
723 attrs = spill("Methods %s" % tag, attrs,
724 lambda t: t[1] == 'method')
725 attrs = spill("Class methods %s" % tag, attrs,
726 lambda t: t[1] == 'class method')
727 attrs = spill("Static methods %s" % tag, attrs,
728 lambda t: t[1] == 'static method')
Tim Petersfa26f7c2001-09-24 08:05:11 +0000729 attrs = spillproperties("Properties %s" % tag, attrs,
730 lambda t: t[1] == 'property')
Tim Petersf33532c2001-09-25 06:30:51 +0000731 attrs = spilldata("Data and non-method functions %s" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000732 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000733 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000734 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000735
736 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000737
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000738 if name == realname:
739 title = '<a name="%s">class <strong>%s</strong></a>' % (
740 name, realname)
741 else:
742 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
743 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000744 if bases:
745 parents = []
746 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000747 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000748 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000749 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
750 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc or '&nbsp;'
Tim Petersc86f6ca2001-09-26 21:31:51 +0000751
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000752 return self.section(title, '#000000', '#ffc8d8', contents, 5, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000753
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000754 def formatvalue(self, object):
755 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000756 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000757
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000758 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000759 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000760 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000761 realname = object.__name__
762 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000763 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000764 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000765 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000766 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000767 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000768 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000769 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000770 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000771 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000772 if object.im_self:
773 note = ' method of %s instance' % self.classlink(
774 object.im_self.__class__, mod)
775 else:
776 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000777 object = object.im_func
778
779 if name == realname:
780 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
781 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000782 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000783 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000784 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000785 cl.__name__ + '-' + realname, realname)
786 skipdocs = 1
787 else:
788 reallink = realname
789 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
790 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000791 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000792 args, varargs, varkw, defaults = inspect.getargspec(object)
793 argspec = inspect.formatargspec(
794 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000795 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000796 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000797 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000798 else:
799 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000800
Tim Peters2306d242001-09-25 03:18:32 +0000801 decl = title + argspec + (note and self.grey(
802 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000803
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000804 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000805 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000806 else:
807 doc = self.markup(
808 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000809 doc = doc and '<dd><tt>%s</tt></dd>' % doc
810 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000811
Tim Peters8dd7ade2001-10-18 19:56:17 +0000812 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000813 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000814 lhs = name and '<strong>%s</strong> = ' % name or ''
815 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000816
817 def index(self, dir, shadowed=None):
818 """Generate an HTML index for a directory of modules."""
819 modpkgs = []
820 if shadowed is None: shadowed = {}
821 seen = {}
822 files = os.listdir(dir)
823
824 def found(name, ispackage,
825 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
Raymond Hettinger4f759d82002-11-02 02:02:46 +0000826 if name not in seen:
827 modpkgs.append((name, '', ispackage, name in shadowed))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000828 seen[name] = 1
829 shadowed[name] = 1
830
831 # Package spam/__init__.py takes precedence over module spam.py.
832 for file in files:
833 path = os.path.join(dir, file)
834 if ispackage(path): found(file, 1)
835 for file in files:
836 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000837 if os.path.isfile(path):
838 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000839 if modname: found(modname, 0)
840
841 modpkgs.sort()
842 contents = self.multicolumn(modpkgs, self.modpkglink)
843 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
844
845# -------------------------------------------- text documentation generator
846
847class TextRepr(Repr):
848 """Class for safely making a text representation of a Python object."""
849 def __init__(self):
850 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000851 self.maxlist = self.maxtuple = 20
852 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000853 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000854
855 def repr1(self, x, level):
856 methodname = 'repr_' + join(split(type(x).__name__), '_')
857 if hasattr(self, methodname):
858 return getattr(self, methodname)(x, level)
859 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000860 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000861
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000862 def repr_string(self, x, level):
863 test = cram(x, self.maxstring)
864 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000865 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000866 # Backslashes are only literal in the string and are never
867 # needed to make any special characters, so show a raw string.
868 return 'r' + testrepr[0] + test + testrepr[0]
869 return testrepr
870
Skip Montanarodf708782002-03-07 22:58:02 +0000871 repr_str = repr_string
872
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000873 def repr_instance(self, x, level):
874 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000875 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000876 except:
877 return '<%s instance>' % x.__class__.__name__
878
879class TextDoc(Doc):
880 """Formatter class for text documentation."""
881
882 # ------------------------------------------- text formatting utilities
883
884 _repr_instance = TextRepr()
885 repr = _repr_instance.repr
886
887 def bold(self, text):
888 """Format a string in bold by overstriking."""
889 return join(map(lambda ch: ch + '\b' + ch, text), '')
890
891 def indent(self, text, prefix=' '):
892 """Indent text by prepending a given prefix to each line."""
893 if not text: return ''
894 lines = split(text, '\n')
895 lines = map(lambda line, prefix=prefix: prefix + line, lines)
896 if lines: lines[-1] = rstrip(lines[-1])
897 return join(lines, '\n')
898
899 def section(self, title, contents):
900 """Format a section with a given heading."""
901 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
902
903 # ---------------------------------------------- type-specific routines
904
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000905 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000906 """Render in text a class tree as returned by inspect.getclasstree()."""
907 result = ''
908 for entry in tree:
909 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000910 c, bases = entry
911 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000912 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000913 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000914 result = result + '(%s)' % join(parents, ', ')
915 result = result + '\n'
916 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000917 result = result + self.formattree(
918 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000919 return result
920
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000921 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000922 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000923 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000924 synop, desc = splitdoc(getdoc(object))
925 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000926
927 try:
928 file = inspect.getabsfile(object)
929 except TypeError:
930 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000931 result = result + self.section('FILE', file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000932 if desc:
933 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000934
935 classes = []
936 for key, value in inspect.getmembers(object, inspect.isclass):
937 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000938 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000939 funcs = []
940 for key, value in inspect.getmembers(object, inspect.isroutine):
941 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000942 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000943 data = []
944 for key, value in inspect.getmembers(object, isdata):
945 if key not in ['__builtins__', '__doc__']:
946 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000947
948 if hasattr(object, '__path__'):
949 modpkgs = []
950 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000951 path = os.path.join(object.__path__[0], file)
952 modname = inspect.getmodulename(file)
953 if modname and modname not in modpkgs:
954 modpkgs.append(modname)
955 elif ispackage(path):
956 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000957 modpkgs.sort()
958 result = result + self.section(
959 'PACKAGE CONTENTS', join(modpkgs, '\n'))
960
961 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000962 classlist = map(lambda (key, value): value, classes)
963 contents = [self.formattree(
964 inspect.getclasstree(classlist, 1), name)]
965 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000966 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000967 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000968
969 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000970 contents = []
971 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000972 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000973 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000974
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000975 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000976 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000977 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000978 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000979 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000980
981 if hasattr(object, '__version__'):
982 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000983 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
984 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000985 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000986 if hasattr(object, '__date__'):
987 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000988 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000989 result = result + self.section('AUTHOR', str(object.__author__))
990 if hasattr(object, '__credits__'):
991 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000992 return result
993
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000994 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000995 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000996 realname = object.__name__
997 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000998 bases = object.__bases__
999
Tim Petersc86f6ca2001-09-26 21:31:51 +00001000 def makename(c, m=object.__module__):
1001 return classname(c, m)
1002
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001003 if name == realname:
1004 title = 'class ' + self.bold(realname)
1005 else:
1006 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001007 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001008 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001009 title = title + '(%s)' % join(parents, ', ')
1010
1011 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001012 contents = doc and [doc + '\n'] or []
1013 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001014
Tim Petersc86f6ca2001-09-26 21:31:51 +00001015 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +00001016 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001017 if len(mro) > 2:
1018 push("Method resolution order:")
1019 for base in mro:
1020 push(' ' + makename(base))
1021 push('')
1022
Tim Petersf4aad8e2001-09-24 22:40:47 +00001023 # Cute little class to pump out a horizontal rule between sections.
1024 class HorizontalRule:
1025 def __init__(self):
1026 self.needone = 0
1027 def maybe(self):
1028 if self.needone:
1029 push('-' * 70)
1030 self.needone = 1
1031 hr = HorizontalRule()
1032
Tim Peters28355492001-09-23 21:29:55 +00001033 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001034 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001035 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001036 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001037 push(msg)
1038 for name, kind, homecls, value in ok:
1039 push(self.document(getattr(object, name),
1040 name, mod, object))
1041 return attrs
1042
Tim Petersfa26f7c2001-09-24 08:05:11 +00001043 def spillproperties(msg, attrs, predicate):
1044 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001045 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001046 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001047 push(msg)
1048 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001049 push(name)
1050 need_blank_after_doc = 0
1051 doc = getdoc(value) or ''
1052 if doc:
1053 push(self.indent(doc))
1054 need_blank_after_doc = 1
Tim Petersf33532c2001-09-25 06:30:51 +00001055 for attr, tag in [("fget", " getter"),
1056 ("fset", " setter"),
Tim Petersf4aad8e2001-09-24 22:40:47 +00001057 ("fdel", " deleter")]:
1058 func = getattr(value, attr)
1059 if func is not None:
1060 if need_blank_after_doc:
1061 push('')
1062 need_blank_after_doc = 0
1063 base = self.docother(func, name + tag, mod, 70)
1064 push(self.indent(base))
1065 push('')
Tim Peters28355492001-09-23 21:29:55 +00001066 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001067
Tim Petersfa26f7c2001-09-24 08:05:11 +00001068 def spilldata(msg, attrs, predicate):
1069 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001070 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001071 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001072 push(msg)
1073 for name, kind, homecls, value in ok:
Guido van Rossum5e355b22002-05-21 20:56:15 +00001074 if callable(value):
1075 doc = getattr(value, "__doc__", None)
1076 else:
1077 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001078 push(self.docother(getattr(object, name),
1079 name, mod, 70, doc) + '\n')
1080 return attrs
1081
1082 attrs = inspect.classify_class_attrs(object)
Tim Petersfa26f7c2001-09-24 08:05:11 +00001083 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001084 if mro:
1085 thisclass = mro.pop(0)
1086 else:
1087 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001088 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1089
Tim Peters28355492001-09-23 21:29:55 +00001090 if thisclass is object:
1091 tag = "defined here"
1092 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001093 tag = "inherited from %s" % classname(thisclass,
1094 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001095
1096 # Sort attrs by name.
1097 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
1098
1099 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001100 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001101 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001102 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001103 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001104 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001105 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001106 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001107 lambda t: t[1] == 'property')
Tim Petersf33532c2001-09-25 06:30:51 +00001108 attrs = spilldata("Data and non-method functions %s:\n" % tag,
1109 attrs, lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001110 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001111 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001112
1113 contents = '\n'.join(contents)
1114 if not contents:
1115 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001116 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1117
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001118 def formatvalue(self, object):
1119 """Format an argument default value as text."""
1120 return '=' + self.repr(object)
1121
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001122 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001123 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001124 realname = object.__name__
1125 name = name or realname
1126 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001127 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001128 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001129 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001130 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001131 if imclass is not cl:
1132 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001133 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001134 if object.im_self:
1135 note = ' method of %s instance' % classname(
1136 object.im_self.__class__, mod)
1137 else:
1138 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001139 object = object.im_func
1140
1141 if name == realname:
1142 title = self.bold(realname)
1143 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001144 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001145 cl.__dict__[realname] is object):
1146 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001147 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001148 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001149 args, varargs, varkw, defaults = inspect.getargspec(object)
1150 argspec = inspect.formatargspec(
1151 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001152 if realname == '<lambda>':
1153 title = 'lambda'
1154 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001155 else:
1156 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001157 decl = title + argspec + note
1158
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001159 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001160 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001161 else:
1162 doc = getdoc(object) or ''
1163 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001164
Tim Peters28355492001-09-23 21:29:55 +00001165 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001166 """Produce text documentation for a data object."""
1167 repr = self.repr(object)
1168 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001169 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001170 chop = maxlen - len(line)
1171 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001172 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001173 if doc is not None:
1174 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001175 return line
1176
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001177# --------------------------------------------------------- user interfaces
1178
1179def pager(text):
1180 """The first time this is called, determine what kind of pager to use."""
1181 global pager
1182 pager = getpager()
1183 pager(text)
1184
1185def getpager():
1186 """Decide what method to use for paging through text."""
1187 if type(sys.stdout) is not types.FileType:
1188 return plainpager
1189 if not sys.stdin.isatty() or not sys.stdout.isatty():
1190 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001191 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001192 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001193 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001194 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001195 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1196 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1197 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001198 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001199 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001200 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001201 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001202 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001203 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001204
1205 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001206 (fd, filename) = tempfile.mkstemp()
1207 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001208 try:
1209 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1210 return lambda text: pipepager(text, 'more')
1211 else:
1212 return ttypager
1213 finally:
1214 os.unlink(filename)
1215
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001216def plain(text):
1217 """Remove boldface formatting from text."""
1218 return re.sub('.\b', '', text)
1219
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001220def pipepager(text, cmd):
1221 """Page through text by feeding it to another program."""
1222 pipe = os.popen(cmd, 'w')
1223 try:
1224 pipe.write(text)
1225 pipe.close()
1226 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001227 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001228
1229def tempfilepager(text, cmd):
1230 """Page through text by invoking a program on a temporary file."""
1231 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001232 (fd, filename) = tempfile.mkstemp()
1233 file = os.fdopen(fd, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001234 file.write(text)
1235 file.close()
1236 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001237 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001238 finally:
1239 os.unlink(filename)
1240
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001241def ttypager(text):
1242 """Page through text on a text terminal."""
1243 lines = split(plain(text), '\n')
1244 try:
1245 import tty
1246 fd = sys.stdin.fileno()
1247 old = tty.tcgetattr(fd)
1248 tty.setcbreak(fd)
1249 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001250 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001251 tty = None
1252 getchar = lambda: sys.stdin.readline()[:-1][:1]
1253
1254 try:
1255 r = inc = os.environ.get('LINES', 25) - 1
1256 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1257 while lines[r:]:
1258 sys.stdout.write('-- more --')
1259 sys.stdout.flush()
1260 c = getchar()
1261
1262 if c in ['q', 'Q']:
1263 sys.stdout.write('\r \r')
1264 break
1265 elif c in ['\r', '\n']:
1266 sys.stdout.write('\r \r' + lines[r] + '\n')
1267 r = r + 1
1268 continue
1269 if c in ['b', 'B', '\x1b']:
1270 r = r - inc - inc
1271 if r < 0: r = 0
1272 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1273 r = r + inc
1274
1275 finally:
1276 if tty:
1277 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1278
1279def plainpager(text):
1280 """Simply print unformatted text. This is the ultimate fallback."""
1281 sys.stdout.write(plain(text))
1282
1283def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001284 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001285 if inspect.ismodule(thing):
1286 if thing.__name__ in sys.builtin_module_names:
1287 return 'built-in module ' + thing.__name__
1288 if hasattr(thing, '__path__'):
1289 return 'package ' + thing.__name__
1290 else:
1291 return 'module ' + thing.__name__
1292 if inspect.isbuiltin(thing):
1293 return 'built-in function ' + thing.__name__
1294 if inspect.isclass(thing):
1295 return 'class ' + thing.__name__
1296 if inspect.isfunction(thing):
1297 return 'function ' + thing.__name__
1298 if inspect.ismethod(thing):
1299 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001300 if type(thing) is types.InstanceType:
1301 return 'instance of ' + thing.__class__.__name__
1302 return type(thing).__name__
1303
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001304def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001305 """Locate an object by name or dotted path, importing as necessary."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001306 parts = split(path, '.')
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001307 module, n = None, 0
1308 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001309 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001310 if nextmodule: module, n = nextmodule, n + 1
1311 else: break
1312 if module:
1313 object = module
1314 for part in parts[n:]:
1315 try: object = getattr(object, part)
1316 except AttributeError: return None
1317 return object
1318 else:
1319 import __builtin__
1320 if hasattr(__builtin__, path):
1321 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001322
1323# --------------------------------------- interactive interpreter interface
1324
1325text = TextDoc()
1326html = HTMLDoc()
1327
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001328def resolve(thing, forceload=0):
1329 """Given an object or a path to an object, get the object and its name."""
1330 if isinstance(thing, str):
1331 object = locate(thing, forceload)
1332 if not object:
1333 raise ImportError, 'no Python documentation found for %r' % thing
1334 return object, thing
1335 else:
1336 return thing, getattr(thing, '__name__', None)
1337
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001338def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001339 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001340 try:
1341 object, name = resolve(thing, forceload)
1342 desc = describe(object)
1343 module = inspect.getmodule(object)
1344 if name and '.' in name:
1345 desc += ' in ' + name[:name.rfind('.')]
1346 elif module and module is not object:
1347 desc += ' in module ' + module.__name__
1348 pager(title % desc + '\n\n' + text.document(object, name))
1349 except (ImportError, ErrorDuringImport), value:
1350 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001351
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001352def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001353 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001354 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001355 object, name = resolve(thing, forceload)
1356 page = html.page(describe(object), html.document(object, name))
1357 file = open(name + '.html', 'w')
1358 file.write(page)
1359 file.close()
1360 print 'wrote', name + '.html'
1361 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001362 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001363
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001364def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001365 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001366 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001367 for file in os.listdir(dir):
1368 path = os.path.join(dir, file)
1369 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001370 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001371 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001372 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001373 if modname:
1374 modname = pkgpath + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001375 if not modname in done:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001376 done[modname] = 1
1377 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001378
1379class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001380 keywords = {
1381 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001382 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001383 'break': ('ref/break', 'while for'),
1384 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1385 'continue': ('ref/continue', 'while for'),
1386 'def': ('ref/function', ''),
1387 'del': ('ref/del', 'BASICMETHODS'),
1388 'elif': 'if',
1389 'else': ('ref/if', 'while for'),
1390 'except': 'try',
1391 'exec': ('ref/exec', ''),
1392 'finally': 'try',
1393 'for': ('ref/for', 'break continue while'),
1394 'from': 'import',
1395 'global': ('ref/global', 'NAMESPACES'),
1396 'if': ('ref/if', 'TRUTHVALUE'),
1397 'import': ('ref/import', 'MODULES'),
1398 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1399 'is': 'COMPARISON',
1400 'lambda': ('ref/lambda', 'FUNCTIONS'),
1401 'not': 'BOOLEAN',
1402 'or': 'BOOLEAN',
1403 'pass': 'PASS',
1404 'print': ('ref/print', ''),
1405 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001406 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001407 'try': ('ref/try', 'EXCEPTIONS'),
1408 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001409 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001410 }
1411
1412 topics = {
1413 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001414 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001415 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1416 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001417 'UNICODE': ('ref/unicode', 'encodings unicode TYPES STRING'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001418 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1419 'INTEGER': ('ref/integers', 'int range'),
1420 'FLOAT': ('ref/floating', 'float math'),
1421 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001422 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001423 'MAPPINGS': 'DICTIONARIES',
1424 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1425 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1426 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001427 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001428 'FRAMEOBJECTS': 'TYPES',
1429 'TRACEBACKS': 'TYPES',
1430 'NONE': ('lib/bltin-null-object', ''),
1431 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1432 'FILES': ('lib/bltin-file-objects', ''),
1433 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1434 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1435 'MODULES': ('lib/typesmodules', 'import'),
1436 'PACKAGES': 'import',
1437 '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'),
1438 'OPERATORS': 'EXPRESSIONS',
1439 'PRECEDENCE': 'EXPRESSIONS',
1440 'OBJECTS': ('ref/objects', 'TYPES'),
1441 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001442 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1443 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1444 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1445 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1446 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1447 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1448 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001449 'EXECUTION': ('ref/execframes', ''),
1450 'NAMESPACES': ('ref/execframes', 'global ASSIGNMENT DELETION'),
1451 'SCOPING': 'NAMESPACES',
1452 'FRAMES': 'NAMESPACES',
1453 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1454 'COERCIONS': 'CONVERSIONS',
1455 'CONVERSIONS': ('ref/conversions', ''),
1456 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1457 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001458 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001459 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1460 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001461 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001462 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001463 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001464 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001465 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1466 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001467 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1468 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1469 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1470 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1471 'POWER': ('ref/power', 'EXPRESSIONS'),
1472 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1473 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1474 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1475 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1476 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001477 'BOOLEAN': ('ref/lambda', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001478 'ASSERTION': 'assert',
1479 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001480 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001481 'DELETION': 'del',
1482 'PRINTING': 'print',
1483 'RETURNING': 'return',
1484 'IMPORTING': 'import',
1485 'CONDITIONAL': 'if',
1486 'LOOPING': ('ref/compound', 'for while break continue'),
1487 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001488 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001489 }
1490
1491 def __init__(self, input, output):
1492 self.input = input
1493 self.output = output
1494 self.docdir = None
1495 execdir = os.path.dirname(sys.executable)
1496 homedir = os.environ.get('PYTHONHOME')
1497 for dir in [os.environ.get('PYTHONDOCS'),
1498 homedir and os.path.join(homedir, 'doc'),
1499 os.path.join(execdir, 'doc'),
1500 '/usr/doc/python-docs-' + split(sys.version)[0],
1501 '/usr/doc/python-' + split(sys.version)[0],
1502 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001503 '/usr/doc/python-' + sys.version[:3],
1504 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001505 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1506 self.docdir = dir
1507
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001508 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001509 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001510 self()
1511 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001512 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001513
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001514 def __call__(self, request=None):
1515 if request is not None:
1516 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001517 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001518 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001519 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001520 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001521You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001522If you want to ask for help on a particular object directly from the
1523interpreter, you can type "help(object)". Executing "help('string')"
1524has the same effect as typing a particular string at the help> prompt.
1525''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001526
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001527 def interact(self):
1528 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001529 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001530 self.output.write('help> ')
1531 self.output.flush()
1532 try:
1533 request = self.input.readline()
1534 if not request: break
1535 except KeyboardInterrupt: break
1536 request = strip(replace(request, '"', '', "'", ''))
1537 if lower(request) in ['q', 'quit']: break
1538 self.help(request)
1539
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001540 def help(self, request):
1541 if type(request) is type(''):
1542 if request == 'help': self.intro()
1543 elif request == 'keywords': self.listkeywords()
1544 elif request == 'topics': self.listtopics()
1545 elif request == 'modules': self.listmodules()
1546 elif request[:8] == 'modules ':
1547 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001548 elif request in self.keywords: self.showtopic(request)
1549 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001550 elif request: doc(request, 'Help on %s:')
1551 elif isinstance(request, Helper): self()
1552 else: doc(request, 'Help on %s:')
1553 self.output.write('\n')
1554
1555 def intro(self):
1556 self.output.write('''
1557Welcome to Python %s! This is the online help utility.
1558
1559If this is your first time using Python, you should definitely check out
1560the tutorial on the Internet at http://www.python.org/doc/tut/.
1561
1562Enter the name of any module, keyword, or topic to get help on writing
1563Python programs and using Python modules. To quit this help utility and
1564return to the interpreter, just type "quit".
1565
1566To get a list of available modules, keywords, or topics, type "modules",
1567"keywords", or "topics". Each module also comes with a one-line summary
1568of what it does; to list the modules whose summaries contain a given word
1569such as "spam", type "modules spam".
1570''' % sys.version[:3])
1571
1572 def list(self, items, columns=4, width=80):
1573 items = items[:]
1574 items.sort()
1575 colw = width / columns
1576 rows = (len(items) + columns - 1) / columns
1577 for row in range(rows):
1578 for col in range(columns):
1579 i = col * rows + row
1580 if i < len(items):
1581 self.output.write(items[i])
1582 if col < columns - 1:
1583 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1584 self.output.write('\n')
1585
1586 def listkeywords(self):
1587 self.output.write('''
1588Here is a list of the Python keywords. Enter any keyword to get more help.
1589
1590''')
1591 self.list(self.keywords.keys())
1592
1593 def listtopics(self):
1594 self.output.write('''
1595Here is a list of available topics. Enter any topic name to get more help.
1596
1597''')
1598 self.list(self.topics.keys())
1599
1600 def showtopic(self, topic):
1601 if not self.docdir:
1602 self.output.write('''
1603Sorry, topic and keyword documentation is not available because the Python
1604HTML documentation files could not be found. If you have installed them,
1605please set the environment variable PYTHONDOCS to indicate their location.
1606''')
1607 return
1608 target = self.topics.get(topic, self.keywords.get(topic))
1609 if not target:
1610 self.output.write('no documentation found for %s\n' % repr(topic))
1611 return
1612 if type(target) is type(''):
1613 return self.showtopic(target)
1614
1615 filename, xrefs = target
1616 filename = self.docdir + '/' + filename + '.html'
1617 try:
1618 file = open(filename)
1619 except:
1620 self.output.write('could not read docs from %s\n' % filename)
1621 return
1622
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001623 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1624 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001625 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1626 file.close()
1627
1628 import htmllib, formatter, StringIO
1629 buffer = StringIO.StringIO()
1630 parser = htmllib.HTMLParser(
1631 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1632 parser.start_table = parser.do_p
1633 parser.end_table = lambda parser=parser: parser.do_p({})
1634 parser.start_tr = parser.do_br
1635 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1636 parser.feed(document)
1637 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1638 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001639 if xrefs:
1640 buffer = StringIO.StringIO()
1641 formatter.DumbWriter(buffer).send_flowing_data(
1642 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1643 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001644
1645 def listmodules(self, key=''):
1646 if key:
1647 self.output.write('''
1648Here is a list of matching modules. Enter any module name to get more help.
1649
1650''')
1651 apropos(key)
1652 else:
1653 self.output.write('''
1654Please wait a moment while I gather a list of all available modules...
1655
1656''')
1657 modules = {}
1658 def callback(path, modname, desc, modules=modules):
1659 if modname and modname[-9:] == '.__init__':
1660 modname = modname[:-9] + ' (package)'
1661 if find(modname, '.') < 0:
1662 modules[modname] = 1
1663 ModuleScanner().run(callback)
1664 self.list(modules.keys())
1665 self.output.write('''
1666Enter any module name to get more help. Or, type "modules spam" to search
1667for modules whose descriptions contain the word "spam".
1668''')
1669
1670help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001671
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001672class Scanner:
1673 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001674 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001675 self.roots = roots[:]
1676 self.state = []
1677 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001678 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001679
1680 def next(self):
1681 if not self.state:
1682 if not self.roots:
1683 return None
1684 root = self.roots.pop(0)
1685 self.state = [(root, self.children(root))]
1686 node, children = self.state[-1]
1687 if not children:
1688 self.state.pop()
1689 return self.next()
1690 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001691 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001692 self.state.append((child, self.children(child)))
1693 return child
1694
1695class ModuleScanner(Scanner):
1696 """An interruptible scanner that searches module synopses."""
1697 def __init__(self):
1698 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001699 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001700 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001701
1702 def submodules(self, (dir, package)):
1703 children = []
1704 for file in os.listdir(dir):
1705 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001706 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001707 children.append((path, package + (package and '.') + file))
1708 else:
1709 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001710 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001711 return children
1712
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001713 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001714 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001715 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001716 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001717 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001718 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001719
Ka-Ping Yee66246962001-04-12 11:59:50 +00001720 def run(self, callback, key=None, completer=None):
1721 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001722 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001723 seen = {}
1724
1725 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001726 if modname != '__main__':
1727 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001728 if key is None:
1729 callback(None, modname, '')
1730 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001731 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001732 if find(lower(modname + ' - ' + desc), key) >= 0:
1733 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001734
1735 while not self.quit:
1736 node = self.next()
1737 if not node: break
1738 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001739 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001740 if os.path.isfile(path) and modname:
1741 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001742 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001743 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001744 if key is None:
1745 callback(path, modname, '')
1746 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001747 desc = synopsis(path) or ''
1748 if find(lower(modname + ' - ' + desc), key) >= 0:
1749 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001750 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001751
1752def apropos(key):
1753 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001754 def callback(path, modname, desc):
1755 if modname[-9:] == '.__init__':
1756 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001757 print modname, desc and '- ' + desc
1758 try: import warnings
1759 except ImportError: pass
1760 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001761 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001762
1763# --------------------------------------------------- web browser interface
1764
Ka-Ping Yee66246962001-04-12 11:59:50 +00001765def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001766 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001767
1768 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1769 class Message(mimetools.Message):
1770 def __init__(self, fp, seekable=1):
1771 Message = self.__class__
1772 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1773 self.encodingheader = self.getheader('content-transfer-encoding')
1774 self.typeheader = self.getheader('content-type')
1775 self.parsetype()
1776 self.parseplist()
1777
1778 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1779 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001780 try:
1781 self.send_response(200)
1782 self.send_header('Content-Type', 'text/html')
1783 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001784 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001785 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001786
1787 def do_GET(self):
1788 path = self.path
1789 if path[-5:] == '.html': path = path[:-5]
1790 if path[:1] == '/': path = path[1:]
1791 if path and path != '.':
1792 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001793 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001794 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001795 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001796 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001797 if obj:
1798 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001799 else:
1800 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001801'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001802 else:
1803 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001804'<big><big><strong>Python: Index of Modules</strong></big></big>',
1805'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001806 def bltinlink(name):
1807 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001808 names = filter(lambda x: x != '__main__',
1809 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001810 contents = html.multicolumn(names, bltinlink)
1811 indices = ['<p>' + html.bigsection(
1812 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1813
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001814 seen = {}
1815 for dir in pathdirs():
1816 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001817 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001818<font color="#909090" face="helvetica, arial"><strong>
1819pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001820 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001821
1822 def log_message(self, *args): pass
1823
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001824 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001825 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001826 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001827 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001828 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001829 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001830 self.base.__init__(self, self.address, self.handler)
1831
1832 def serve_until_quit(self):
1833 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001834 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001835 while not self.quit:
1836 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1837 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001838
1839 def server_activate(self):
1840 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001841 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001842
1843 DocServer.base = BaseHTTPServer.HTTPServer
1844 DocServer.handler = DocHandler
1845 DocHandler.MessageClass = Message
1846 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001847 try:
1848 DocServer(port, callback).serve_until_quit()
1849 except (KeyboardInterrupt, select.error):
1850 pass
1851 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001852 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001853
1854# ----------------------------------------------------- graphical interface
1855
1856def gui():
1857 """Graphical interface (starts web server and pops up a control window)."""
1858 class GUI:
1859 def __init__(self, window, port=7464):
1860 self.window = window
1861 self.server = None
1862 self.scanner = None
1863
1864 import Tkinter
1865 self.server_frm = Tkinter.Frame(window)
1866 self.title_lbl = Tkinter.Label(self.server_frm,
1867 text='Starting server...\n ')
1868 self.open_btn = Tkinter.Button(self.server_frm,
1869 text='open browser', command=self.open, state='disabled')
1870 self.quit_btn = Tkinter.Button(self.server_frm,
1871 text='quit serving', command=self.quit, state='disabled')
1872
1873 self.search_frm = Tkinter.Frame(window)
1874 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1875 self.search_ent = Tkinter.Entry(self.search_frm)
1876 self.search_ent.bind('<Return>', self.search)
1877 self.stop_btn = Tkinter.Button(self.search_frm,
1878 text='stop', pady=0, command=self.stop, state='disabled')
1879 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001880 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001881 self.stop_btn.pack(side='right')
1882
1883 self.window.title('pydoc')
1884 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1885 self.title_lbl.pack(side='top', fill='x')
1886 self.open_btn.pack(side='left', fill='x', expand=1)
1887 self.quit_btn.pack(side='right', fill='x', expand=1)
1888 self.server_frm.pack(side='top', fill='x')
1889
1890 self.search_lbl.pack(side='left')
1891 self.search_ent.pack(side='right', fill='x', expand=1)
1892 self.search_frm.pack(side='top', fill='x')
1893 self.search_ent.focus_set()
1894
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001895 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001896 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001897 self.result_lst.bind('<Button-1>', self.select)
1898 self.result_lst.bind('<Double-Button-1>', self.goto)
1899 self.result_scr = Tkinter.Scrollbar(window,
1900 orient='vertical', command=self.result_lst.yview)
1901 self.result_lst.config(yscrollcommand=self.result_scr.set)
1902
1903 self.result_frm = Tkinter.Frame(window)
1904 self.goto_btn = Tkinter.Button(self.result_frm,
1905 text='go to selected', command=self.goto)
1906 self.hide_btn = Tkinter.Button(self.result_frm,
1907 text='hide results', command=self.hide)
1908 self.goto_btn.pack(side='left', fill='x', expand=1)
1909 self.hide_btn.pack(side='right', fill='x', expand=1)
1910
1911 self.window.update()
1912 self.minwidth = self.window.winfo_width()
1913 self.minheight = self.window.winfo_height()
1914 self.bigminheight = (self.server_frm.winfo_reqheight() +
1915 self.search_frm.winfo_reqheight() +
1916 self.result_lst.winfo_reqheight() +
1917 self.result_frm.winfo_reqheight())
1918 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1919 self.expanded = 0
1920 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1921 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00001922 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001923
1924 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001925 threading.Thread(
1926 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001927
1928 def ready(self, server):
1929 self.server = server
1930 self.title_lbl.config(
1931 text='Python documentation server at\n' + server.url)
1932 self.open_btn.config(state='normal')
1933 self.quit_btn.config(state='normal')
1934
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001935 def open(self, event=None, url=None):
1936 url = url or self.server.url
1937 try:
1938 import webbrowser
1939 webbrowser.open(url)
1940 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001941 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001942 os.system('start "%s"' % url)
1943 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001944 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001945 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001946 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001947 else:
1948 rc = os.system('netscape -remote "openURL(%s)" &' % url)
1949 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001950
1951 def quit(self, event=None):
1952 if self.server:
1953 self.server.quit = 1
1954 self.window.quit()
1955
1956 def search(self, event=None):
1957 key = self.search_ent.get()
1958 self.stop_btn.pack(side='right')
1959 self.stop_btn.config(state='normal')
1960 self.search_lbl.config(text='Searching for "%s"...' % key)
1961 self.search_ent.forget()
1962 self.search_lbl.pack(side='left')
1963 self.result_lst.delete(0, 'end')
1964 self.goto_btn.config(state='disabled')
1965 self.expand()
1966
1967 import threading
1968 if self.scanner:
1969 self.scanner.quit = 1
1970 self.scanner = ModuleScanner()
1971 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00001972 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001973
1974 def update(self, path, modname, desc):
1975 if modname[-9:] == '.__init__':
1976 modname = modname[:-9] + ' (package)'
1977 self.result_lst.insert('end',
1978 modname + ' - ' + (desc or '(no description)'))
1979
1980 def stop(self, event=None):
1981 if self.scanner:
1982 self.scanner.quit = 1
1983 self.scanner = None
1984
1985 def done(self):
1986 self.scanner = None
1987 self.search_lbl.config(text='Search for')
1988 self.search_lbl.pack(side='left')
1989 self.search_ent.pack(side='right', fill='x', expand=1)
1990 if sys.platform != 'win32': self.stop_btn.forget()
1991 self.stop_btn.config(state='disabled')
1992
1993 def select(self, event=None):
1994 self.goto_btn.config(state='normal')
1995
1996 def goto(self, event=None):
1997 selection = self.result_lst.curselection()
1998 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001999 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002000 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002001
2002 def collapse(self):
2003 if not self.expanded: return
2004 self.result_frm.forget()
2005 self.result_scr.forget()
2006 self.result_lst.forget()
2007 self.bigwidth = self.window.winfo_width()
2008 self.bigheight = self.window.winfo_height()
2009 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2010 self.window.wm_minsize(self.minwidth, self.minheight)
2011 self.expanded = 0
2012
2013 def expand(self):
2014 if self.expanded: return
2015 self.result_frm.pack(side='bottom', fill='x')
2016 self.result_scr.pack(side='right', fill='y')
2017 self.result_lst.pack(side='top', fill='both', expand=1)
2018 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2019 self.window.wm_minsize(self.minwidth, self.bigminheight)
2020 self.expanded = 1
2021
2022 def hide(self, event=None):
2023 self.stop()
2024 self.collapse()
2025
2026 import Tkinter
2027 try:
2028 gui = GUI(Tkinter.Tk())
2029 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002030 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002031 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002032
2033# -------------------------------------------------- command-line interface
2034
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002035def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002036 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002037
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002038def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002039 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002040 import getopt
2041 class BadUsage: pass
2042
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002043 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002044 scriptdir = os.path.dirname(sys.argv[0])
2045 if scriptdir in sys.path:
2046 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002047 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002048
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002049 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002050 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002051 writing = 0
2052
2053 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002054 if opt == '-g':
2055 gui()
2056 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002057 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002058 apropos(val)
2059 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002060 if opt == '-p':
2061 try:
2062 port = int(val)
2063 except ValueError:
2064 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002065 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002066 print 'pydoc server ready at %s' % server.url
2067 def stopped():
2068 print 'pydoc server stopped'
2069 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002070 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002071 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002072 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002073
2074 if not args: raise BadUsage
2075 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002076 if ispath(arg) and not os.path.exists(arg):
2077 print 'file %r does not exist' % arg
2078 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002079 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002080 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002081 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002082 if writing:
2083 if ispath(arg) and os.path.isdir(arg):
2084 writedocs(arg)
2085 else:
2086 writedoc(arg)
2087 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002088 doc(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002089 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002090 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002091
2092 except (getopt.error, BadUsage):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002093 cmd = sys.argv[0]
2094 print """pydoc - the Python documentation tool
2095
2096%s <name> ...
2097 Show text documentation on something. <name> may be the name of a
2098 function, module, or package, or a dotted reference to a class or
2099 function within a module or module in a package. If <name> contains
2100 a '%s', it is used as the path to a Python source file to document.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002101
2102%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002103 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002104
2105%s -p <port>
2106 Start an HTTP server on the given port on the local machine.
2107
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002108%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002109 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002110
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002111%s -w <name> ...
2112 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002113 directory. If <name> contains a '%s', it is treated as a filename; if
2114 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002115""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002116
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002117if __name__ == '__main__': cli()