blob: 8e5064a44db16f302f8c322afd2389be269a3b9f [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
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +000047import sys, imp, os, re, types, inspect, __builtin__
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 Yeed9e213e2003-03-28 16:35:51 +0000145def visiblename(name):
146 """Decide whether to show documentation on a variable."""
147 # Certain special names are redundant.
148 if name in ['__builtins__', '__doc__', '__file__', '__path__',
149 '__module__', '__name__']: return 0
150 # Private names are hidden, but special names are displayed.
151 if name.startswith('__') and name.endswith('__'): return 1
152 return not name.startswith('_')
153
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000154# ----------------------------------------------------- module manipulation
155
156def ispackage(path):
157 """Guess whether a path refers to a package directory."""
158 if os.path.isdir(path):
159 for ext in ['.py', '.pyc', '.pyo']:
160 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000161 return True
162 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000163
164def synopsis(filename, cache={}):
165 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000166 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000167 lastupdate, result = cache.get(filename, (0, None))
168 if lastupdate < mtime:
169 info = inspect.getmoduleinfo(filename)
170 file = open(filename)
171 if info and 'b' in info[2]: # binary modules have to be imported
172 try: module = imp.load_module('__temp__', file, filename, info[1:])
173 except: return None
174 result = split(module.__doc__ or '', '\n')[0]
175 del sys.modules['__temp__']
176 else: # text modules can be directly examined
177 line = file.readline()
178 while line[:1] == '#' or not strip(line):
179 line = file.readline()
180 if not line: break
181 line = strip(line)
182 if line[:4] == 'r"""': line = line[1:]
183 if line[:3] == '"""':
184 line = line[3:]
185 if line[-1:] == '\\': line = line[:-1]
186 while not strip(line):
187 line = file.readline()
188 if not line: break
189 result = strip(split(line, '"""')[0])
190 else: result = None
191 file.close()
192 cache[filename] = (mtime, result)
193 return result
194
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000195class ErrorDuringImport(Exception):
196 """Errors that occurred while trying to import something to document it."""
197 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000198 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000199 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000200 self.value = value
201 self.tb = tb
202
203 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000204 exc = self.exc
205 if type(exc) is types.ClassType:
206 exc = exc.__name__
207 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000208
209def importfile(path):
210 """Import a Python source file or compiled file given its path."""
211 magic = imp.get_magic()
212 file = open(path, 'r')
213 if file.read(len(magic)) == magic:
214 kind = imp.PY_COMPILED
215 else:
216 kind = imp.PY_SOURCE
217 file.close()
218 filename = os.path.basename(path)
219 name, ext = os.path.splitext(filename)
220 file = open(path, 'r')
221 try:
222 module = imp.load_module(name, file, path, (ext, 'r', kind))
223 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000224 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000225 file.close()
226 return module
227
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000228def safeimport(path, forceload=0, cache={}):
229 """Import a module; handle errors; return None if the module isn't found.
230
231 If the module *is* found but an exception occurs, it's wrapped in an
232 ErrorDuringImport exception and reraised. Unlike __import__, if a
233 package path is specified, the module at the end of the path is returned,
234 not the package at the beginning. If the optional 'forceload' argument
235 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000236 if forceload and path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000237 # This is the only way to be sure. Checking the mtime of the file
238 # isn't good enough (e.g. what if the module contains a class that
239 # inherits from another module that has changed?).
240 if path not in sys.builtin_module_names:
241 # Python never loads a dynamic extension a second time from the
242 # same path, even if the file is changed or missing. Deleting
243 # the entry in sys.modules doesn't help for dynamic extensions,
244 # so we're not even going to try to keep them up to date.
245 info = inspect.getmoduleinfo(sys.modules[path].__file__)
246 if info[3] != imp.C_EXTENSION:
247 cache[path] = sys.modules[path] # prevent module from clearing
248 del sys.modules[path]
249 try:
250 module = __import__(path)
251 except:
252 # Did the error occur before or after the module was found?
253 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000254 if path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000255 # An error occured while executing the imported module.
256 raise ErrorDuringImport(sys.modules[path].__file__, info)
257 elif exc is SyntaxError:
258 # A SyntaxError occurred before we could execute the module.
259 raise ErrorDuringImport(value.filename, info)
260 elif exc is ImportError and \
261 split(lower(str(value)))[:2] == ['no', 'module']:
262 # The module was not found.
263 return None
264 else:
265 # Some other error occurred during the importing process.
266 raise ErrorDuringImport(path, sys.exc_info())
267 for part in split(path, '.')[1:]:
268 try: module = getattr(module, part)
269 except AttributeError: return None
270 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000271
272# ---------------------------------------------------- formatter base class
273
274class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000275 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000276 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000277 args = (object, name) + args
Guido van Rossum68468eb2003-02-27 20:14:51 +0000278 if inspect.ismodule(object): return self.docmodule(*args)
279 if inspect.isclass(object): return self.docclass(*args)
Neal Norwitz4f959d22003-03-01 15:22:41 +0000280 if inspect.isroutine(object): return self.docroutine(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000281 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000282
283 def fail(self, object, name=None, *args):
284 """Raise an exception for unimplemented types."""
285 message = "don't know how to document object%s of type %s" % (
286 name and ' ' + repr(name), type(object).__name__)
287 raise TypeError, message
288
289 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000290
291# -------------------------------------------- HTML documentation generator
292
293class HTMLRepr(Repr):
294 """Class for safely making an HTML representation of a Python object."""
295 def __init__(self):
296 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000297 self.maxlist = self.maxtuple = 20
298 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000299 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000300
301 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000302 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000303
304 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000305 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000306
307 def repr1(self, x, level):
308 methodname = 'repr_' + join(split(type(x).__name__), '_')
309 if hasattr(self, methodname):
310 return getattr(self, methodname)(x, level)
311 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000312 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000313
314 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000315 test = cram(x, self.maxstring)
316 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000317 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000318 # Backslashes are only literal in the string and are never
319 # needed to make any special characters, so show a raw string.
320 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000321 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000322 r'<font color="#c040c0">\1</font>',
323 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000324
Skip Montanarodf708782002-03-07 22:58:02 +0000325 repr_str = repr_string
326
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000327 def repr_instance(self, x, level):
328 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000329 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000330 except:
331 return self.escape('<%s instance>' % x.__class__.__name__)
332
333 repr_unicode = repr_string
334
335class HTMLDoc(Doc):
336 """Formatter class for HTML documentation."""
337
338 # ------------------------------------------- HTML formatting utilities
339
340 _repr_instance = HTMLRepr()
341 repr = _repr_instance.repr
342 escape = _repr_instance.escape
343
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000344 def page(self, title, contents):
345 """Format an HTML page."""
346 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000347<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000348<html><head><title>Python: %s</title>
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000349</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000350%s
351</body></html>''' % (title, contents)
352
353 def heading(self, title, fgcol, bgcol, extras=''):
354 """Format a page heading."""
355 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000356<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000357<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000358<td valign=bottom>&nbsp;<br>
359<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000360><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000361><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000362 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
363
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000364 def section(self, title, fgcol, bgcol, contents, width=6,
365 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000366 """Format a section with a heading."""
367 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000368 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000369 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000370<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000371<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000372<td colspan=3 valign=bottom>&nbsp;<br>
373<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000374 ''' % (bgcol, fgcol, title)
375 if prelude:
376 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000377<tr bgcolor="%s"><td rowspan=2>%s</td>
378<td colspan=2>%s</td></tr>
379<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
380 else:
381 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000382<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000383
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000384 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000385
386 def bigsection(self, title, *args):
387 """Format a section with a big heading."""
388 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000389 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000390
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000391 def preformat(self, text):
392 """Format literal preformatted text."""
393 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000394 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
395 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000396
397 def multicolumn(self, list, format, cols=4):
398 """Format a list of items into a multi-column list."""
399 result = ''
400 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000401 for col in range(cols):
402 result = result + '<td width="%d%%" valign=top>' % (100/cols)
403 for i in range(rows*col, rows*col+rows):
404 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000405 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000406 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000407 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000408
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000409 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000410
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000411 def namelink(self, name, *dicts):
412 """Make a link for an identifier, given name-to-URL mappings."""
413 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000414 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000415 return '<a href="%s">%s</a>' % (dict[name], name)
416 return name
417
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000418 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000419 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000420 name, module = object.__name__, sys.modules.get(object.__module__)
421 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000422 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000423 module.__name__, name, classname(object, modname))
424 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000425
426 def modulelink(self, object):
427 """Make a link for a module."""
428 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
429
430 def modpkglink(self, (name, path, ispackage, shadowed)):
431 """Make a link for a module or package to display in an index."""
432 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000433 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000434 if path:
435 url = '%s.%s.html' % (path, name)
436 else:
437 url = '%s.html' % name
438 if ispackage:
439 text = '<strong>%s</strong>&nbsp;(package)' % name
440 else:
441 text = name
442 return '<a href="%s">%s</a>' % (url, text)
443
444 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
445 """Mark up some plain text, given a context of symbols to look for.
446 Each context dictionary maps object names to anchor names."""
447 escape = escape or self.escape
448 results = []
449 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000450 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
451 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000452 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000453 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000454 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000455 match = pattern.search(text, here)
456 if not match: break
457 start, end = match.span()
458 results.append(escape(text[here:start]))
459
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000460 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000461 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000462 url = escape(all).replace('"', '&quot;')
463 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000464 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000465 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
466 results.append('<a href="%s">%s</a>' % (url, escape(all)))
467 elif pep:
468 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000469 results.append('<a href="%s">%s</a>' % (url, escape(all)))
470 elif text[end:end+1] == '(':
471 results.append(self.namelink(name, methods, funcs, classes))
472 elif selfdot:
473 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000474 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000475 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000476 here = end
477 results.append(escape(text[here:]))
478 return join(results, '')
479
480 # ---------------------------------------------- type-specific routines
481
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000482 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000483 """Produce HTML for a class tree as given by inspect.getclasstree()."""
484 result = ''
485 for entry in tree:
486 if type(entry) is type(()):
487 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000488 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000489 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000490 if bases and bases != (parent,):
491 parents = []
492 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000493 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000494 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000495 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000496 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000497 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000498 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000499 return '<dl>\n%s</dl>\n' % result
500
Tim Peters8dd7ade2001-10-18 19:56:17 +0000501 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000502 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000503 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000504 parts = split(name, '.')
505 links = []
506 for i in range(len(parts)-1):
507 links.append(
508 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
509 (join(parts[:i+1], '.'), parts[i]))
510 linkedname = join(links + parts[-1:], '.')
511 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000512 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000513 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000514 url = path
515 if sys.platform == 'win32':
516 import nturl2path
517 url = nturl2path.pathname2url(path)
518 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000519 except TypeError:
520 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000521 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000522 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000523 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000524 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
525 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000526 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000527 if hasattr(object, '__date__'):
528 info.append(self.escape(str(object.__date__)))
529 if info:
530 head = head + ' (%s)' % join(info, ', ')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000531 result = self.heading(
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000532 head, '#ffffff', '#7799ee', '<a href=".">index</a><br>' + filelink)
533
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000534 modules = inspect.getmembers(object, inspect.ismodule)
535
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000536 classes, cdict = [], {}
537 for key, value in inspect.getmembers(object, inspect.isclass):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000538 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000539 if visiblename(key):
540 classes.append((key, value))
541 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000542 for key, value in classes:
543 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000544 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000545 module = sys.modules.get(modname)
546 if modname != name and module and hasattr(module, key):
547 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000548 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000549 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000550 funcs, fdict = [], {}
551 for key, value in inspect.getmembers(object, inspect.isroutine):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000552 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000553 if visiblename(key):
554 funcs.append((key, value))
555 fdict[key] = '#-' + key
556 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000557 data = []
558 for key, value in inspect.getmembers(object, isdata):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000559 if visiblename(key):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000560 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000561
562 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
563 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000564 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000565
566 if hasattr(object, '__path__'):
567 modpkgs = []
568 modnames = []
569 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000570 path = os.path.join(object.__path__[0], file)
571 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000572 if modname != '__init__':
573 if modname and modname not in modnames:
574 modpkgs.append((modname, name, 0, 0))
575 modnames.append(modname)
576 elif ispackage(path):
577 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000578 modpkgs.sort()
579 contents = self.multicolumn(modpkgs, self.modpkglink)
580 result = result + self.bigsection(
581 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000582 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000583 contents = self.multicolumn(
584 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000585 result = result + self.bigsection(
586 'Modules', '#fffff', '#aa55cc', contents)
587
588 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000589 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000590 contents = [
591 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000592 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000593 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000594 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000595 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000596 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000597 contents = []
598 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000599 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000600 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000601 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000602 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000603 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000604 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000605 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000606 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000607 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000608 if hasattr(object, '__author__'):
609 contents = self.markup(str(object.__author__), self.preformat)
610 result = result + self.bigsection(
611 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000612 if hasattr(object, '__credits__'):
613 contents = self.markup(str(object.__credits__), self.preformat)
614 result = result + self.bigsection(
615 'Credits', '#ffffff', '#7799ee', contents)
616
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000617 return result
618
Tim Peters8dd7ade2001-10-18 19:56:17 +0000619 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
620 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000621 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000622 realname = object.__name__
623 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000624 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000625
Tim Petersb47879b2001-09-24 04:47:19 +0000626 contents = []
627 push = contents.append
628
Tim Petersfa26f7c2001-09-24 08:05:11 +0000629 # Cute little class to pump out a horizontal rule between sections.
630 class HorizontalRule:
631 def __init__(self):
632 self.needone = 0
633 def maybe(self):
634 if self.needone:
635 push('<hr>\n')
636 self.needone = 1
637 hr = HorizontalRule()
638
Tim Petersc86f6ca2001-09-26 21:31:51 +0000639 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +0000640 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000641 if len(mro) > 2:
642 hr.maybe()
643 push('<dl><dt>Method resolution order:</dt>\n')
644 for base in mro:
645 push('<dd>%s</dd>\n' % self.classlink(base,
646 object.__module__))
647 push('</dl>\n')
648
Tim Petersb47879b2001-09-24 04:47:19 +0000649 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000650 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000651 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000652 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000653 push(msg)
654 for name, kind, homecls, value in ok:
655 push(self.document(getattr(object, name), name, mod,
656 funcs, classes, mdict, object))
657 push('\n')
658 return attrs
659
Tim Petersfa26f7c2001-09-24 08:05:11 +0000660 def spillproperties(msg, attrs, predicate):
661 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000662 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000663 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000664 push(msg)
665 for name, kind, homecls, value in ok:
Tim Peters3e767d12001-09-25 00:01:06 +0000666 push('<dl><dt><strong>%s</strong></dt>\n' % name)
667 if value.__doc__ is not None:
668 doc = self.markup(value.__doc__, self.preformat,
669 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000670 push('<dd><tt>%s</tt></dd>\n' % doc)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000671 for attr, tag in [('fget', '<em>get</em>'),
672 ('fset', '<em>set</em>'),
673 ('fdel', '<em>delete</em>')]:
Tim Peters3e767d12001-09-25 00:01:06 +0000674 func = getattr(value, attr)
675 if func is not None:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000676 base = self.document(func, tag, mod,
Tim Peters3e767d12001-09-25 00:01:06 +0000677 funcs, classes, mdict, object)
678 push('<dd>%s</dd>\n' % base)
679 push('</dl>\n')
Tim Petersb47879b2001-09-24 04:47:19 +0000680 return attrs
681
Tim Petersfa26f7c2001-09-24 08:05:11 +0000682 def spilldata(msg, attrs, predicate):
683 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000684 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000685 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000686 push(msg)
687 for name, kind, homecls, value in ok:
688 base = self.docother(getattr(object, name), name, mod)
Martin v. Löwise59e2ba2003-05-03 09:09:02 +0000689 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000690 doc = getattr(value, "__doc__", None)
691 else:
692 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000693 if doc is None:
694 push('<dl><dt>%s</dl>\n' % base)
695 else:
696 doc = self.markup(getdoc(value), self.preformat,
697 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000698 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000699 push('<dl><dt>%s%s</dl>\n' % (base, doc))
700 push('\n')
701 return attrs
702
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000703 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
704 inspect.classify_class_attrs(object))
Tim Petersb47879b2001-09-24 04:47:19 +0000705 mdict = {}
706 for key, kind, homecls, value in attrs:
707 mdict[key] = anchor = '#' + name + '-' + key
708 value = getattr(object, key)
709 try:
710 # The value may not be hashable (e.g., a data attr with
711 # a dict or list value).
712 mdict[value] = anchor
713 except TypeError:
714 pass
715
Tim Petersfa26f7c2001-09-24 08:05:11 +0000716 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000717 if mro:
718 thisclass = mro.pop(0)
719 else:
720 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000721 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
722
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000723 if thisclass is __builtin__.object:
724 attrs = inherited
725 continue
726 elif thisclass is object:
727 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000728 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000729 tag = 'inherited from %s' % self.classlink(thisclass,
730 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000731 tag += ':<br>\n'
732
733 # Sort attrs by name.
734 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0]))
735
736 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000737 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000738 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000739 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000740 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000741 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000742 lambda t: t[1] == 'static method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000743 attrs = spillproperties('Properties %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000744 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000745 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000746 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000747 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000748 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000749
750 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000751
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000752 if name == realname:
753 title = '<a name="%s">class <strong>%s</strong></a>' % (
754 name, realname)
755 else:
756 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
757 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000758 if bases:
759 parents = []
760 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000761 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000762 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000763 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000764 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000765
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000766 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000767
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000768 def formatvalue(self, object):
769 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000770 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000771
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000772 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000773 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000774 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000775 realname = object.__name__
776 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000777 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000778 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000779 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000780 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000781 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000782 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000783 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000784 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000785 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000786 if object.im_self:
787 note = ' method of %s instance' % self.classlink(
788 object.im_self.__class__, mod)
789 else:
790 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000791 object = object.im_func
792
793 if name == realname:
794 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
795 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000796 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000797 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000798 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000799 cl.__name__ + '-' + realname, realname)
800 skipdocs = 1
801 else:
802 reallink = realname
803 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
804 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000805 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000806 args, varargs, varkw, defaults = inspect.getargspec(object)
807 argspec = inspect.formatargspec(
808 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000809 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000810 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000811 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000812 else:
813 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000814
Tim Peters2306d242001-09-25 03:18:32 +0000815 decl = title + argspec + (note and self.grey(
816 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000817
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000818 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000819 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000820 else:
821 doc = self.markup(
822 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000823 doc = doc and '<dd><tt>%s</tt></dd>' % doc
824 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000825
Tim Peters8dd7ade2001-10-18 19:56:17 +0000826 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000827 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000828 lhs = name and '<strong>%s</strong> = ' % name or ''
829 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000830
831 def index(self, dir, shadowed=None):
832 """Generate an HTML index for a directory of modules."""
833 modpkgs = []
834 if shadowed is None: shadowed = {}
835 seen = {}
836 files = os.listdir(dir)
837
838 def found(name, ispackage,
839 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
Raymond Hettinger4f759d82002-11-02 02:02:46 +0000840 if name not in seen:
841 modpkgs.append((name, '', ispackage, name in shadowed))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000842 seen[name] = 1
843 shadowed[name] = 1
844
845 # Package spam/__init__.py takes precedence over module spam.py.
846 for file in files:
847 path = os.path.join(dir, file)
848 if ispackage(path): found(file, 1)
849 for file in files:
850 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000851 if os.path.isfile(path):
852 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000853 if modname: found(modname, 0)
854
855 modpkgs.sort()
856 contents = self.multicolumn(modpkgs, self.modpkglink)
857 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
858
859# -------------------------------------------- text documentation generator
860
861class TextRepr(Repr):
862 """Class for safely making a text representation of a Python object."""
863 def __init__(self):
864 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000865 self.maxlist = self.maxtuple = 20
866 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000867 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000868
869 def repr1(self, x, level):
870 methodname = 'repr_' + join(split(type(x).__name__), '_')
871 if hasattr(self, methodname):
872 return getattr(self, methodname)(x, level)
873 else:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000874 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000875
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000876 def repr_string(self, x, level):
877 test = cram(x, self.maxstring)
878 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000879 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000880 # Backslashes are only literal in the string and are never
881 # needed to make any special characters, so show a raw string.
882 return 'r' + testrepr[0] + test + testrepr[0]
883 return testrepr
884
Skip Montanarodf708782002-03-07 22:58:02 +0000885 repr_str = repr_string
886
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000887 def repr_instance(self, x, level):
888 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000889 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000890 except:
891 return '<%s instance>' % x.__class__.__name__
892
893class TextDoc(Doc):
894 """Formatter class for text documentation."""
895
896 # ------------------------------------------- text formatting utilities
897
898 _repr_instance = TextRepr()
899 repr = _repr_instance.repr
900
901 def bold(self, text):
902 """Format a string in bold by overstriking."""
903 return join(map(lambda ch: ch + '\b' + ch, text), '')
904
905 def indent(self, text, prefix=' '):
906 """Indent text by prepending a given prefix to each line."""
907 if not text: return ''
908 lines = split(text, '\n')
909 lines = map(lambda line, prefix=prefix: prefix + line, lines)
910 if lines: lines[-1] = rstrip(lines[-1])
911 return join(lines, '\n')
912
913 def section(self, title, contents):
914 """Format a section with a given heading."""
915 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
916
917 # ---------------------------------------------- type-specific routines
918
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000919 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000920 """Render in text a class tree as returned by inspect.getclasstree()."""
921 result = ''
922 for entry in tree:
923 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000924 c, bases = entry
925 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000926 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000927 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000928 result = result + '(%s)' % join(parents, ', ')
929 result = result + '\n'
930 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000931 result = result + self.formattree(
932 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000933 return result
934
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000935 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000936 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000937 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000938 synop, desc = splitdoc(getdoc(object))
939 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000940
941 try:
942 file = inspect.getabsfile(object)
943 except TypeError:
944 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000945 result = result + self.section('FILE', file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000946 if desc:
947 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000948
949 classes = []
950 for key, value in inspect.getmembers(object, inspect.isclass):
951 if (inspect.getmodule(value) or object) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000952 if visiblename(key):
953 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000954 funcs = []
955 for key, value in inspect.getmembers(object, inspect.isroutine):
956 if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000957 if visiblename(key):
958 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000959 data = []
960 for key, value in inspect.getmembers(object, isdata):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000961 if visiblename(key):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000962 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000963
964 if hasattr(object, '__path__'):
965 modpkgs = []
966 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000967 path = os.path.join(object.__path__[0], file)
968 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000969 if modname != '__init__':
970 if modname and modname not in modpkgs:
971 modpkgs.append(modname)
972 elif ispackage(path):
973 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000974 modpkgs.sort()
975 result = result + self.section(
976 'PACKAGE CONTENTS', join(modpkgs, '\n'))
977
978 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000979 classlist = map(lambda (key, value): value, classes)
980 contents = [self.formattree(
981 inspect.getclasstree(classlist, 1), name)]
982 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000983 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000984 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000985
986 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000987 contents = []
988 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000989 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000990 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000991
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000992 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000993 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000994 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000995 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000996 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000997
998 if hasattr(object, '__version__'):
999 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001000 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1001 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001002 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001003 if hasattr(object, '__date__'):
1004 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001005 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001006 result = result + self.section('AUTHOR', str(object.__author__))
1007 if hasattr(object, '__credits__'):
1008 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001009 return result
1010
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001011 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001012 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001013 realname = object.__name__
1014 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001015 bases = object.__bases__
1016
Tim Petersc86f6ca2001-09-26 21:31:51 +00001017 def makename(c, m=object.__module__):
1018 return classname(c, m)
1019
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001020 if name == realname:
1021 title = 'class ' + self.bold(realname)
1022 else:
1023 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001024 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001025 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001026 title = title + '(%s)' % join(parents, ', ')
1027
1028 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001029 contents = doc and [doc + '\n'] or []
1030 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001031
Tim Petersc86f6ca2001-09-26 21:31:51 +00001032 # List the mro, if non-trivial.
Tim Peters351e3622001-09-27 03:29:51 +00001033 mro = list(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001034 if len(mro) > 2:
1035 push("Method resolution order:")
1036 for base in mro:
1037 push(' ' + makename(base))
1038 push('')
1039
Tim Petersf4aad8e2001-09-24 22:40:47 +00001040 # Cute little class to pump out a horizontal rule between sections.
1041 class HorizontalRule:
1042 def __init__(self):
1043 self.needone = 0
1044 def maybe(self):
1045 if self.needone:
1046 push('-' * 70)
1047 self.needone = 1
1048 hr = HorizontalRule()
1049
Tim Peters28355492001-09-23 21:29:55 +00001050 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001051 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001052 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001053 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001054 push(msg)
1055 for name, kind, homecls, value in ok:
1056 push(self.document(getattr(object, name),
1057 name, mod, object))
1058 return attrs
1059
Tim Petersfa26f7c2001-09-24 08:05:11 +00001060 def spillproperties(msg, attrs, predicate):
1061 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001062 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001063 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001064 push(msg)
1065 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001066 push(name)
1067 need_blank_after_doc = 0
1068 doc = getdoc(value) or ''
1069 if doc:
1070 push(self.indent(doc))
1071 need_blank_after_doc = 1
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001072 for attr, tag in [('fget', '<get>'),
1073 ('fset', '<set>'),
1074 ('fdel', '<delete>')]:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001075 func = getattr(value, attr)
1076 if func is not None:
1077 if need_blank_after_doc:
1078 push('')
1079 need_blank_after_doc = 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001080 base = self.document(func, tag, mod)
Tim Petersf4aad8e2001-09-24 22:40:47 +00001081 push(self.indent(base))
Tim Peters28355492001-09-23 21:29:55 +00001082 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001083
Tim Petersfa26f7c2001-09-24 08:05:11 +00001084 def spilldata(msg, attrs, predicate):
1085 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001086 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001087 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001088 push(msg)
1089 for name, kind, homecls, value in ok:
Martin v. Löwise59e2ba2003-05-03 09:09:02 +00001090 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +00001091 doc = getattr(value, "__doc__", None)
1092 else:
1093 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001094 push(self.docother(getattr(object, name),
1095 name, mod, 70, doc) + '\n')
1096 return attrs
1097
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001098 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
1099 inspect.classify_class_attrs(object))
Tim Petersfa26f7c2001-09-24 08:05:11 +00001100 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001101 if mro:
1102 thisclass = mro.pop(0)
1103 else:
1104 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001105 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1106
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001107 if thisclass is __builtin__.object:
1108 attrs = inherited
1109 continue
1110 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001111 tag = "defined here"
1112 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001113 tag = "inherited from %s" % classname(thisclass,
1114 object.__module__)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001115 filter(lambda t: not t[0].startswith('_'), attrs)
Tim Peters28355492001-09-23 21:29:55 +00001116
1117 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001118 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001119
1120 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001121 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001122 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001123 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001124 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001125 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001126 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001127 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001128 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001129 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1130 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001131 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001132 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001133
1134 contents = '\n'.join(contents)
1135 if not contents:
1136 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001137 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1138
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001139 def formatvalue(self, object):
1140 """Format an argument default value as text."""
1141 return '=' + self.repr(object)
1142
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001143 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001144 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001145 realname = object.__name__
1146 name = name or realname
1147 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001148 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001149 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001150 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001151 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001152 if imclass is not cl:
1153 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001154 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001155 if object.im_self:
1156 note = ' method of %s instance' % classname(
1157 object.im_self.__class__, mod)
1158 else:
1159 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001160 object = object.im_func
1161
1162 if name == realname:
1163 title = self.bold(realname)
1164 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001165 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001166 cl.__dict__[realname] is object):
1167 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001168 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001169 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001170 args, varargs, varkw, defaults = inspect.getargspec(object)
1171 argspec = inspect.formatargspec(
1172 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001173 if realname == '<lambda>':
1174 title = 'lambda'
1175 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001176 else:
1177 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001178 decl = title + argspec + note
1179
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001180 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001181 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001182 else:
1183 doc = getdoc(object) or ''
1184 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001185
Tim Peters28355492001-09-23 21:29:55 +00001186 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001187 """Produce text documentation for a data object."""
1188 repr = self.repr(object)
1189 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001190 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001191 chop = maxlen - len(line)
1192 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001193 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001194 if doc is not None:
1195 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001196 return line
1197
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001198# --------------------------------------------------------- user interfaces
1199
1200def pager(text):
1201 """The first time this is called, determine what kind of pager to use."""
1202 global pager
1203 pager = getpager()
1204 pager(text)
1205
1206def getpager():
1207 """Decide what method to use for paging through text."""
1208 if type(sys.stdout) is not types.FileType:
1209 return plainpager
1210 if not sys.stdin.isatty() or not sys.stdout.isatty():
1211 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001212 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001213 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001214 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001215 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001216 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1217 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1218 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001219 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001220 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001221 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001222 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001223 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001224 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001225
1226 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001227 (fd, filename) = tempfile.mkstemp()
1228 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001229 try:
1230 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1231 return lambda text: pipepager(text, 'more')
1232 else:
1233 return ttypager
1234 finally:
1235 os.unlink(filename)
1236
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001237def plain(text):
1238 """Remove boldface formatting from text."""
1239 return re.sub('.\b', '', text)
1240
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001241def pipepager(text, cmd):
1242 """Page through text by feeding it to another program."""
1243 pipe = os.popen(cmd, 'w')
1244 try:
1245 pipe.write(text)
1246 pipe.close()
1247 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001248 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001249
1250def tempfilepager(text, cmd):
1251 """Page through text by invoking a program on a temporary file."""
1252 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001253 filename = tempfile.mktemp()
1254 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001255 file.write(text)
1256 file.close()
1257 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001258 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001259 finally:
1260 os.unlink(filename)
1261
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001262def ttypager(text):
1263 """Page through text on a text terminal."""
1264 lines = split(plain(text), '\n')
1265 try:
1266 import tty
1267 fd = sys.stdin.fileno()
1268 old = tty.tcgetattr(fd)
1269 tty.setcbreak(fd)
1270 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001271 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001272 tty = None
1273 getchar = lambda: sys.stdin.readline()[:-1][:1]
1274
1275 try:
1276 r = inc = os.environ.get('LINES', 25) - 1
1277 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1278 while lines[r:]:
1279 sys.stdout.write('-- more --')
1280 sys.stdout.flush()
1281 c = getchar()
1282
1283 if c in ['q', 'Q']:
1284 sys.stdout.write('\r \r')
1285 break
1286 elif c in ['\r', '\n']:
1287 sys.stdout.write('\r \r' + lines[r] + '\n')
1288 r = r + 1
1289 continue
1290 if c in ['b', 'B', '\x1b']:
1291 r = r - inc - inc
1292 if r < 0: r = 0
1293 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1294 r = r + inc
1295
1296 finally:
1297 if tty:
1298 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1299
1300def plainpager(text):
1301 """Simply print unformatted text. This is the ultimate fallback."""
1302 sys.stdout.write(plain(text))
1303
1304def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001305 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001306 if inspect.ismodule(thing):
1307 if thing.__name__ in sys.builtin_module_names:
1308 return 'built-in module ' + thing.__name__
1309 if hasattr(thing, '__path__'):
1310 return 'package ' + thing.__name__
1311 else:
1312 return 'module ' + thing.__name__
1313 if inspect.isbuiltin(thing):
1314 return 'built-in function ' + thing.__name__
1315 if inspect.isclass(thing):
1316 return 'class ' + thing.__name__
1317 if inspect.isfunction(thing):
1318 return 'function ' + thing.__name__
1319 if inspect.ismethod(thing):
1320 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001321 if type(thing) is types.InstanceType:
1322 return 'instance of ' + thing.__class__.__name__
1323 return type(thing).__name__
1324
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001325def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001326 """Locate an object by name or dotted path, importing as necessary."""
Guido van Rossum97dede02003-02-16 01:12:32 +00001327 parts = [part for part in split(path, '.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001328 module, n = None, 0
1329 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001330 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001331 if nextmodule: module, n = nextmodule, n + 1
1332 else: break
1333 if module:
1334 object = module
1335 for part in parts[n:]:
1336 try: object = getattr(object, part)
1337 except AttributeError: return None
1338 return object
1339 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001340 if hasattr(__builtin__, path):
1341 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001342
1343# --------------------------------------- interactive interpreter interface
1344
1345text = TextDoc()
1346html = HTMLDoc()
1347
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001348def resolve(thing, forceload=0):
1349 """Given an object or a path to an object, get the object and its name."""
1350 if isinstance(thing, str):
1351 object = locate(thing, forceload)
1352 if not object:
1353 raise ImportError, 'no Python documentation found for %r' % thing
1354 return object, thing
1355 else:
1356 return thing, getattr(thing, '__name__', None)
1357
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001358def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001359 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001360 try:
1361 object, name = resolve(thing, forceload)
1362 desc = describe(object)
1363 module = inspect.getmodule(object)
1364 if name and '.' in name:
1365 desc += ' in ' + name[:name.rfind('.')]
1366 elif module and module is not object:
1367 desc += ' in module ' + module.__name__
1368 pager(title % desc + '\n\n' + text.document(object, name))
1369 except (ImportError, ErrorDuringImport), value:
1370 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001371
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001372def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001373 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001374 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001375 object, name = resolve(thing, forceload)
1376 page = html.page(describe(object), html.document(object, name))
1377 file = open(name + '.html', 'w')
1378 file.write(page)
1379 file.close()
1380 print 'wrote', name + '.html'
1381 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001382 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001383
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001384def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001385 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001386 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001387 for file in os.listdir(dir):
1388 path = os.path.join(dir, file)
1389 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001390 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001391 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001392 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001393 if modname:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001394 if modname == '__init__':
1395 modname = pkgpath[:-1] # remove trailing period
1396 else:
1397 modname = pkgpath + modname
1398 if modname not in done:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001399 done[modname] = 1
1400 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001401
1402class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001403 keywords = {
1404 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001405 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001406 'break': ('ref/break', 'while for'),
1407 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1408 'continue': ('ref/continue', 'while for'),
1409 'def': ('ref/function', ''),
1410 'del': ('ref/del', 'BASICMETHODS'),
1411 'elif': 'if',
1412 'else': ('ref/if', 'while for'),
1413 'except': 'try',
1414 'exec': ('ref/exec', ''),
1415 'finally': 'try',
1416 'for': ('ref/for', 'break continue while'),
1417 'from': 'import',
1418 'global': ('ref/global', 'NAMESPACES'),
1419 'if': ('ref/if', 'TRUTHVALUE'),
1420 'import': ('ref/import', 'MODULES'),
1421 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1422 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001423 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001424 'not': 'BOOLEAN',
1425 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001426 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001427 'print': ('ref/print', ''),
1428 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001429 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001430 'try': ('ref/try', 'EXCEPTIONS'),
1431 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001432 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001433 }
1434
1435 topics = {
1436 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001437 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001438 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1439 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001440 'UNICODE': ('ref/strings', 'encodings unicode TYPES STRING'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001441 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1442 'INTEGER': ('ref/integers', 'int range'),
1443 'FLOAT': ('ref/floating', 'float math'),
1444 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001445 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001446 'MAPPINGS': 'DICTIONARIES',
1447 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1448 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1449 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001450 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001451 'FRAMEOBJECTS': 'TYPES',
1452 'TRACEBACKS': 'TYPES',
1453 'NONE': ('lib/bltin-null-object', ''),
1454 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1455 'FILES': ('lib/bltin-file-objects', ''),
1456 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1457 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1458 'MODULES': ('lib/typesmodules', 'import'),
1459 'PACKAGES': 'import',
1460 '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'),
1461 'OPERATORS': 'EXPRESSIONS',
1462 'PRECEDENCE': 'EXPRESSIONS',
1463 'OBJECTS': ('ref/objects', 'TYPES'),
1464 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001465 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1466 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1467 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1468 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1469 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1470 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1471 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz742dde42003-03-30 20:31:34 +00001472 'EXECUTION': ('ref/naming', ''),
1473 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001474 'SCOPING': 'NAMESPACES',
1475 'FRAMES': 'NAMESPACES',
1476 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1477 'COERCIONS': 'CONVERSIONS',
1478 'CONVERSIONS': ('ref/conversions', ''),
1479 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1480 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001481 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001482 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1483 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001484 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001485 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001486 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001487 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001488 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1489 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001490 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1491 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1492 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1493 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1494 'POWER': ('ref/power', 'EXPRESSIONS'),
1495 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1496 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1497 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1498 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1499 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001500 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001501 'ASSERTION': 'assert',
1502 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001503 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001504 'DELETION': 'del',
1505 'PRINTING': 'print',
1506 'RETURNING': 'return',
1507 'IMPORTING': 'import',
1508 'CONDITIONAL': 'if',
1509 'LOOPING': ('ref/compound', 'for while break continue'),
1510 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001511 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001512 }
1513
1514 def __init__(self, input, output):
1515 self.input = input
1516 self.output = output
1517 self.docdir = None
1518 execdir = os.path.dirname(sys.executable)
1519 homedir = os.environ.get('PYTHONHOME')
1520 for dir in [os.environ.get('PYTHONDOCS'),
1521 homedir and os.path.join(homedir, 'doc'),
1522 os.path.join(execdir, 'doc'),
1523 '/usr/doc/python-docs-' + split(sys.version)[0],
1524 '/usr/doc/python-' + split(sys.version)[0],
1525 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001526 '/usr/doc/python-' + sys.version[:3],
1527 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001528 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1529 self.docdir = dir
1530
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001531 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001532 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001533 self()
1534 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001535 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001536
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001537 def __call__(self, request=None):
1538 if request is not None:
1539 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001540 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001541 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001542 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001543 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001544You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001545If you want to ask for help on a particular object directly from the
1546interpreter, you can type "help(object)". Executing "help('string')"
1547has the same effect as typing a particular string at the help> prompt.
1548''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001549
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001550 def interact(self):
1551 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001552 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001553 self.output.write('help> ')
1554 self.output.flush()
1555 try:
1556 request = self.input.readline()
1557 if not request: break
1558 except KeyboardInterrupt: break
1559 request = strip(replace(request, '"', '', "'", ''))
1560 if lower(request) in ['q', 'quit']: break
1561 self.help(request)
1562
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001563 def help(self, request):
1564 if type(request) is type(''):
1565 if request == 'help': self.intro()
1566 elif request == 'keywords': self.listkeywords()
1567 elif request == 'topics': self.listtopics()
1568 elif request == 'modules': self.listmodules()
1569 elif request[:8] == 'modules ':
1570 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001571 elif request in self.keywords: self.showtopic(request)
1572 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001573 elif request: doc(request, 'Help on %s:')
1574 elif isinstance(request, Helper): self()
1575 else: doc(request, 'Help on %s:')
1576 self.output.write('\n')
1577
1578 def intro(self):
1579 self.output.write('''
1580Welcome to Python %s! This is the online help utility.
1581
1582If this is your first time using Python, you should definitely check out
1583the tutorial on the Internet at http://www.python.org/doc/tut/.
1584
1585Enter the name of any module, keyword, or topic to get help on writing
1586Python programs and using Python modules. To quit this help utility and
1587return to the interpreter, just type "quit".
1588
1589To get a list of available modules, keywords, or topics, type "modules",
1590"keywords", or "topics". Each module also comes with a one-line summary
1591of what it does; to list the modules whose summaries contain a given word
1592such as "spam", type "modules spam".
1593''' % sys.version[:3])
1594
1595 def list(self, items, columns=4, width=80):
1596 items = items[:]
1597 items.sort()
1598 colw = width / columns
1599 rows = (len(items) + columns - 1) / columns
1600 for row in range(rows):
1601 for col in range(columns):
1602 i = col * rows + row
1603 if i < len(items):
1604 self.output.write(items[i])
1605 if col < columns - 1:
1606 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1607 self.output.write('\n')
1608
1609 def listkeywords(self):
1610 self.output.write('''
1611Here is a list of the Python keywords. Enter any keyword to get more help.
1612
1613''')
1614 self.list(self.keywords.keys())
1615
1616 def listtopics(self):
1617 self.output.write('''
1618Here is a list of available topics. Enter any topic name to get more help.
1619
1620''')
1621 self.list(self.topics.keys())
1622
1623 def showtopic(self, topic):
1624 if not self.docdir:
1625 self.output.write('''
1626Sorry, topic and keyword documentation is not available because the Python
1627HTML documentation files could not be found. If you have installed them,
1628please set the environment variable PYTHONDOCS to indicate their location.
1629''')
1630 return
1631 target = self.topics.get(topic, self.keywords.get(topic))
1632 if not target:
1633 self.output.write('no documentation found for %s\n' % repr(topic))
1634 return
1635 if type(target) is type(''):
1636 return self.showtopic(target)
1637
1638 filename, xrefs = target
1639 filename = self.docdir + '/' + filename + '.html'
1640 try:
1641 file = open(filename)
1642 except:
1643 self.output.write('could not read docs from %s\n' % filename)
1644 return
1645
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001646 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1647 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001648 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1649 file.close()
1650
1651 import htmllib, formatter, StringIO
1652 buffer = StringIO.StringIO()
1653 parser = htmllib.HTMLParser(
1654 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1655 parser.start_table = parser.do_p
1656 parser.end_table = lambda parser=parser: parser.do_p({})
1657 parser.start_tr = parser.do_br
1658 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1659 parser.feed(document)
1660 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1661 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001662 if xrefs:
1663 buffer = StringIO.StringIO()
1664 formatter.DumbWriter(buffer).send_flowing_data(
1665 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1666 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001667
1668 def listmodules(self, key=''):
1669 if key:
1670 self.output.write('''
1671Here is a list of matching modules. Enter any module name to get more help.
1672
1673''')
1674 apropos(key)
1675 else:
1676 self.output.write('''
1677Please wait a moment while I gather a list of all available modules...
1678
1679''')
1680 modules = {}
1681 def callback(path, modname, desc, modules=modules):
1682 if modname and modname[-9:] == '.__init__':
1683 modname = modname[:-9] + ' (package)'
1684 if find(modname, '.') < 0:
1685 modules[modname] = 1
1686 ModuleScanner().run(callback)
1687 self.list(modules.keys())
1688 self.output.write('''
1689Enter any module name to get more help. Or, type "modules spam" to search
1690for modules whose descriptions contain the word "spam".
1691''')
1692
1693help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001694
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001695class Scanner:
1696 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001697 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001698 self.roots = roots[:]
1699 self.state = []
1700 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001701 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001702
1703 def next(self):
1704 if not self.state:
1705 if not self.roots:
1706 return None
1707 root = self.roots.pop(0)
1708 self.state = [(root, self.children(root))]
1709 node, children = self.state[-1]
1710 if not children:
1711 self.state.pop()
1712 return self.next()
1713 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001714 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001715 self.state.append((child, self.children(child)))
1716 return child
1717
1718class ModuleScanner(Scanner):
1719 """An interruptible scanner that searches module synopses."""
1720 def __init__(self):
1721 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001722 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001723 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001724
1725 def submodules(self, (dir, package)):
1726 children = []
1727 for file in os.listdir(dir):
1728 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001729 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001730 children.append((path, package + (package and '.') + file))
1731 else:
1732 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001733 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001734 return children
1735
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001736 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001737 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001738 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001739 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001740 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001741 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001742
Ka-Ping Yee66246962001-04-12 11:59:50 +00001743 def run(self, callback, key=None, completer=None):
1744 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001745 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001746 seen = {}
1747
1748 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001749 if modname != '__main__':
1750 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001751 if key is None:
1752 callback(None, modname, '')
1753 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001754 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001755 if find(lower(modname + ' - ' + desc), key) >= 0:
1756 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001757
1758 while not self.quit:
1759 node = self.next()
1760 if not node: break
1761 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001762 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001763 if os.path.isfile(path) and modname:
1764 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001765 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001766 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001767 if key is None:
1768 callback(path, modname, '')
1769 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001770 desc = synopsis(path) or ''
1771 if find(lower(modname + ' - ' + desc), key) >= 0:
1772 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001773 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001774
1775def apropos(key):
1776 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001777 def callback(path, modname, desc):
1778 if modname[-9:] == '.__init__':
1779 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001780 print modname, desc and '- ' + desc
1781 try: import warnings
1782 except ImportError: pass
1783 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001784 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001785
1786# --------------------------------------------------- web browser interface
1787
Ka-Ping Yee66246962001-04-12 11:59:50 +00001788def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001789 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001790
1791 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1792 class Message(mimetools.Message):
1793 def __init__(self, fp, seekable=1):
1794 Message = self.__class__
1795 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1796 self.encodingheader = self.getheader('content-transfer-encoding')
1797 self.typeheader = self.getheader('content-type')
1798 self.parsetype()
1799 self.parseplist()
1800
1801 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1802 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001803 try:
1804 self.send_response(200)
1805 self.send_header('Content-Type', 'text/html')
1806 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001807 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001808 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001809
1810 def do_GET(self):
1811 path = self.path
1812 if path[-5:] == '.html': path = path[:-5]
1813 if path[:1] == '/': path = path[1:]
1814 if path and path != '.':
1815 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001816 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001817 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001818 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001819 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001820 if obj:
1821 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001822 else:
1823 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001824'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001825 else:
1826 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001827'<big><big><strong>Python: Index of Modules</strong></big></big>',
1828'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001829 def bltinlink(name):
1830 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001831 names = filter(lambda x: x != '__main__',
1832 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001833 contents = html.multicolumn(names, bltinlink)
1834 indices = ['<p>' + html.bigsection(
1835 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1836
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001837 seen = {}
1838 for dir in pathdirs():
1839 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001840 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001841<font color="#909090" face="helvetica, arial"><strong>
1842pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001843 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001844
1845 def log_message(self, *args): pass
1846
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001847 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001848 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001849 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001850 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001851 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001852 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001853 self.base.__init__(self, self.address, self.handler)
1854
1855 def serve_until_quit(self):
1856 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001857 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001858 while not self.quit:
1859 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1860 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001861
1862 def server_activate(self):
1863 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001864 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001865
1866 DocServer.base = BaseHTTPServer.HTTPServer
1867 DocServer.handler = DocHandler
1868 DocHandler.MessageClass = Message
1869 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001870 try:
1871 DocServer(port, callback).serve_until_quit()
1872 except (KeyboardInterrupt, select.error):
1873 pass
1874 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001875 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001876
1877# ----------------------------------------------------- graphical interface
1878
1879def gui():
1880 """Graphical interface (starts web server and pops up a control window)."""
1881 class GUI:
1882 def __init__(self, window, port=7464):
1883 self.window = window
1884 self.server = None
1885 self.scanner = None
1886
1887 import Tkinter
1888 self.server_frm = Tkinter.Frame(window)
1889 self.title_lbl = Tkinter.Label(self.server_frm,
1890 text='Starting server...\n ')
1891 self.open_btn = Tkinter.Button(self.server_frm,
1892 text='open browser', command=self.open, state='disabled')
1893 self.quit_btn = Tkinter.Button(self.server_frm,
1894 text='quit serving', command=self.quit, state='disabled')
1895
1896 self.search_frm = Tkinter.Frame(window)
1897 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1898 self.search_ent = Tkinter.Entry(self.search_frm)
1899 self.search_ent.bind('<Return>', self.search)
1900 self.stop_btn = Tkinter.Button(self.search_frm,
1901 text='stop', pady=0, command=self.stop, state='disabled')
1902 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001903 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001904 self.stop_btn.pack(side='right')
1905
1906 self.window.title('pydoc')
1907 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1908 self.title_lbl.pack(side='top', fill='x')
1909 self.open_btn.pack(side='left', fill='x', expand=1)
1910 self.quit_btn.pack(side='right', fill='x', expand=1)
1911 self.server_frm.pack(side='top', fill='x')
1912
1913 self.search_lbl.pack(side='left')
1914 self.search_ent.pack(side='right', fill='x', expand=1)
1915 self.search_frm.pack(side='top', fill='x')
1916 self.search_ent.focus_set()
1917
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001918 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001919 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001920 self.result_lst.bind('<Button-1>', self.select)
1921 self.result_lst.bind('<Double-Button-1>', self.goto)
1922 self.result_scr = Tkinter.Scrollbar(window,
1923 orient='vertical', command=self.result_lst.yview)
1924 self.result_lst.config(yscrollcommand=self.result_scr.set)
1925
1926 self.result_frm = Tkinter.Frame(window)
1927 self.goto_btn = Tkinter.Button(self.result_frm,
1928 text='go to selected', command=self.goto)
1929 self.hide_btn = Tkinter.Button(self.result_frm,
1930 text='hide results', command=self.hide)
1931 self.goto_btn.pack(side='left', fill='x', expand=1)
1932 self.hide_btn.pack(side='right', fill='x', expand=1)
1933
1934 self.window.update()
1935 self.minwidth = self.window.winfo_width()
1936 self.minheight = self.window.winfo_height()
1937 self.bigminheight = (self.server_frm.winfo_reqheight() +
1938 self.search_frm.winfo_reqheight() +
1939 self.result_lst.winfo_reqheight() +
1940 self.result_frm.winfo_reqheight())
1941 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1942 self.expanded = 0
1943 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1944 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00001945 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001946
1947 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001948 threading.Thread(
1949 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001950
1951 def ready(self, server):
1952 self.server = server
1953 self.title_lbl.config(
1954 text='Python documentation server at\n' + server.url)
1955 self.open_btn.config(state='normal')
1956 self.quit_btn.config(state='normal')
1957
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001958 def open(self, event=None, url=None):
1959 url = url or self.server.url
1960 try:
1961 import webbrowser
1962 webbrowser.open(url)
1963 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001964 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001965 os.system('start "%s"' % url)
1966 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001967 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001968 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001969 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001970 else:
1971 rc = os.system('netscape -remote "openURL(%s)" &' % url)
1972 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001973
1974 def quit(self, event=None):
1975 if self.server:
1976 self.server.quit = 1
1977 self.window.quit()
1978
1979 def search(self, event=None):
1980 key = self.search_ent.get()
1981 self.stop_btn.pack(side='right')
1982 self.stop_btn.config(state='normal')
1983 self.search_lbl.config(text='Searching for "%s"...' % key)
1984 self.search_ent.forget()
1985 self.search_lbl.pack(side='left')
1986 self.result_lst.delete(0, 'end')
1987 self.goto_btn.config(state='disabled')
1988 self.expand()
1989
1990 import threading
1991 if self.scanner:
1992 self.scanner.quit = 1
1993 self.scanner = ModuleScanner()
1994 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00001995 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001996
1997 def update(self, path, modname, desc):
1998 if modname[-9:] == '.__init__':
1999 modname = modname[:-9] + ' (package)'
2000 self.result_lst.insert('end',
2001 modname + ' - ' + (desc or '(no description)'))
2002
2003 def stop(self, event=None):
2004 if self.scanner:
2005 self.scanner.quit = 1
2006 self.scanner = None
2007
2008 def done(self):
2009 self.scanner = None
2010 self.search_lbl.config(text='Search for')
2011 self.search_lbl.pack(side='left')
2012 self.search_ent.pack(side='right', fill='x', expand=1)
2013 if sys.platform != 'win32': self.stop_btn.forget()
2014 self.stop_btn.config(state='disabled')
2015
2016 def select(self, event=None):
2017 self.goto_btn.config(state='normal')
2018
2019 def goto(self, event=None):
2020 selection = self.result_lst.curselection()
2021 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002022 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002023 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002024
2025 def collapse(self):
2026 if not self.expanded: return
2027 self.result_frm.forget()
2028 self.result_scr.forget()
2029 self.result_lst.forget()
2030 self.bigwidth = self.window.winfo_width()
2031 self.bigheight = self.window.winfo_height()
2032 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2033 self.window.wm_minsize(self.minwidth, self.minheight)
2034 self.expanded = 0
2035
2036 def expand(self):
2037 if self.expanded: return
2038 self.result_frm.pack(side='bottom', fill='x')
2039 self.result_scr.pack(side='right', fill='y')
2040 self.result_lst.pack(side='top', fill='both', expand=1)
2041 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2042 self.window.wm_minsize(self.minwidth, self.bigminheight)
2043 self.expanded = 1
2044
2045 def hide(self, event=None):
2046 self.stop()
2047 self.collapse()
2048
2049 import Tkinter
2050 try:
2051 gui = GUI(Tkinter.Tk())
2052 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002053 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002054 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002055
2056# -------------------------------------------------- command-line interface
2057
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002058def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002059 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002060
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002061def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002062 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002063 import getopt
2064 class BadUsage: pass
2065
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002066 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002067 scriptdir = os.path.dirname(sys.argv[0])
2068 if scriptdir in sys.path:
2069 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002070 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002071
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002072 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002073 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002074 writing = 0
2075
2076 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002077 if opt == '-g':
2078 gui()
2079 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002080 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002081 apropos(val)
2082 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002083 if opt == '-p':
2084 try:
2085 port = int(val)
2086 except ValueError:
2087 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002088 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002089 print 'pydoc server ready at %s' % server.url
2090 def stopped():
2091 print 'pydoc server stopped'
2092 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002093 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002094 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002095 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002096
2097 if not args: raise BadUsage
2098 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002099 if ispath(arg) and not os.path.exists(arg):
2100 print 'file %r does not exist' % arg
2101 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002102 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002103 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002104 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002105 if writing:
2106 if ispath(arg) and os.path.isdir(arg):
2107 writedocs(arg)
2108 else:
2109 writedoc(arg)
2110 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002111 doc(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002112 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002113 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002114
2115 except (getopt.error, BadUsage):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002116 cmd = sys.argv[0]
2117 print """pydoc - the Python documentation tool
2118
2119%s <name> ...
2120 Show text documentation on something. <name> may be the name of a
2121 function, module, or package, or a dotted reference to a class or
2122 function within a module or module in a package. If <name> contains
2123 a '%s', it is used as the path to a Python source file to document.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002124
2125%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002126 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002127
2128%s -p <port>
2129 Start an HTTP server on the given port on the local machine.
2130
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002131%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002132 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002133
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002134%s -w <name> ...
2135 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002136 directory. If <name> contains a '%s', it is treated as a filename; if
2137 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002138""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002139
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002140if __name__ == '__main__': cli()