blob: a6778d6ac204c07941b07debb943442bafb45ee2 [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 Norwitz54f871e2003-05-26 13:49:54 +00001440 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
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 Norwitz54f871e2003-05-26 13:49:54 +00001472 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1473 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1474 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001475 'SCOPING': 'NAMESPACES',
1476 'FRAMES': 'NAMESPACES',
1477 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001478 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1479 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001480 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1481 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001482 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001483 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1484 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001485 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001486 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001487 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001488 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001489 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1490 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001491 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1492 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1493 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1494 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1495 'POWER': ('ref/power', 'EXPRESSIONS'),
1496 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1497 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1498 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1499 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1500 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001501 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001502 'ASSERTION': 'assert',
1503 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001504 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001505 'DELETION': 'del',
1506 'PRINTING': 'print',
1507 'RETURNING': 'return',
1508 'IMPORTING': 'import',
1509 'CONDITIONAL': 'if',
1510 'LOOPING': ('ref/compound', 'for while break continue'),
1511 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001512 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001513 }
1514
1515 def __init__(self, input, output):
1516 self.input = input
1517 self.output = output
1518 self.docdir = None
1519 execdir = os.path.dirname(sys.executable)
1520 homedir = os.environ.get('PYTHONHOME')
1521 for dir in [os.environ.get('PYTHONDOCS'),
1522 homedir and os.path.join(homedir, 'doc'),
1523 os.path.join(execdir, 'doc'),
1524 '/usr/doc/python-docs-' + split(sys.version)[0],
1525 '/usr/doc/python-' + split(sys.version)[0],
1526 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001527 '/usr/doc/python-' + sys.version[:3],
1528 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001529 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1530 self.docdir = dir
1531
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001532 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001533 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001534 self()
1535 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001536 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001537
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001538 def __call__(self, request=None):
1539 if request is not None:
1540 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001541 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001542 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001543 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001544 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001545You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001546If you want to ask for help on a particular object directly from the
1547interpreter, you can type "help(object)". Executing "help('string')"
1548has the same effect as typing a particular string at the help> prompt.
1549''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001550
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001551 def interact(self):
1552 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001553 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001554 self.output.write('help> ')
1555 self.output.flush()
1556 try:
1557 request = self.input.readline()
1558 if not request: break
1559 except KeyboardInterrupt: break
1560 request = strip(replace(request, '"', '', "'", ''))
1561 if lower(request) in ['q', 'quit']: break
1562 self.help(request)
1563
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001564 def help(self, request):
1565 if type(request) is type(''):
1566 if request == 'help': self.intro()
1567 elif request == 'keywords': self.listkeywords()
1568 elif request == 'topics': self.listtopics()
1569 elif request == 'modules': self.listmodules()
1570 elif request[:8] == 'modules ':
1571 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001572 elif request in self.keywords: self.showtopic(request)
1573 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001574 elif request: doc(request, 'Help on %s:')
1575 elif isinstance(request, Helper): self()
1576 else: doc(request, 'Help on %s:')
1577 self.output.write('\n')
1578
1579 def intro(self):
1580 self.output.write('''
1581Welcome to Python %s! This is the online help utility.
1582
1583If this is your first time using Python, you should definitely check out
1584the tutorial on the Internet at http://www.python.org/doc/tut/.
1585
1586Enter the name of any module, keyword, or topic to get help on writing
1587Python programs and using Python modules. To quit this help utility and
1588return to the interpreter, just type "quit".
1589
1590To get a list of available modules, keywords, or topics, type "modules",
1591"keywords", or "topics". Each module also comes with a one-line summary
1592of what it does; to list the modules whose summaries contain a given word
1593such as "spam", type "modules spam".
1594''' % sys.version[:3])
1595
1596 def list(self, items, columns=4, width=80):
1597 items = items[:]
1598 items.sort()
1599 colw = width / columns
1600 rows = (len(items) + columns - 1) / columns
1601 for row in range(rows):
1602 for col in range(columns):
1603 i = col * rows + row
1604 if i < len(items):
1605 self.output.write(items[i])
1606 if col < columns - 1:
1607 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1608 self.output.write('\n')
1609
1610 def listkeywords(self):
1611 self.output.write('''
1612Here is a list of the Python keywords. Enter any keyword to get more help.
1613
1614''')
1615 self.list(self.keywords.keys())
1616
1617 def listtopics(self):
1618 self.output.write('''
1619Here is a list of available topics. Enter any topic name to get more help.
1620
1621''')
1622 self.list(self.topics.keys())
1623
1624 def showtopic(self, topic):
1625 if not self.docdir:
1626 self.output.write('''
1627Sorry, topic and keyword documentation is not available because the Python
1628HTML documentation files could not be found. If you have installed them,
1629please set the environment variable PYTHONDOCS to indicate their location.
1630''')
1631 return
1632 target = self.topics.get(topic, self.keywords.get(topic))
1633 if not target:
1634 self.output.write('no documentation found for %s\n' % repr(topic))
1635 return
1636 if type(target) is type(''):
1637 return self.showtopic(target)
1638
1639 filename, xrefs = target
1640 filename = self.docdir + '/' + filename + '.html'
1641 try:
1642 file = open(filename)
1643 except:
1644 self.output.write('could not read docs from %s\n' % filename)
1645 return
1646
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001647 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1648 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001649 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1650 file.close()
1651
1652 import htmllib, formatter, StringIO
1653 buffer = StringIO.StringIO()
1654 parser = htmllib.HTMLParser(
1655 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1656 parser.start_table = parser.do_p
1657 parser.end_table = lambda parser=parser: parser.do_p({})
1658 parser.start_tr = parser.do_br
1659 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1660 parser.feed(document)
1661 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1662 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001663 if xrefs:
1664 buffer = StringIO.StringIO()
1665 formatter.DumbWriter(buffer).send_flowing_data(
1666 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1667 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001668
1669 def listmodules(self, key=''):
1670 if key:
1671 self.output.write('''
1672Here is a list of matching modules. Enter any module name to get more help.
1673
1674''')
1675 apropos(key)
1676 else:
1677 self.output.write('''
1678Please wait a moment while I gather a list of all available modules...
1679
1680''')
1681 modules = {}
1682 def callback(path, modname, desc, modules=modules):
1683 if modname and modname[-9:] == '.__init__':
1684 modname = modname[:-9] + ' (package)'
1685 if find(modname, '.') < 0:
1686 modules[modname] = 1
1687 ModuleScanner().run(callback)
1688 self.list(modules.keys())
1689 self.output.write('''
1690Enter any module name to get more help. Or, type "modules spam" to search
1691for modules whose descriptions contain the word "spam".
1692''')
1693
1694help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001695
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001696class Scanner:
1697 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001698 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001699 self.roots = roots[:]
1700 self.state = []
1701 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001702 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001703
1704 def next(self):
1705 if not self.state:
1706 if not self.roots:
1707 return None
1708 root = self.roots.pop(0)
1709 self.state = [(root, self.children(root))]
1710 node, children = self.state[-1]
1711 if not children:
1712 self.state.pop()
1713 return self.next()
1714 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001715 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001716 self.state.append((child, self.children(child)))
1717 return child
1718
1719class ModuleScanner(Scanner):
1720 """An interruptible scanner that searches module synopses."""
1721 def __init__(self):
1722 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001723 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001724 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001725
1726 def submodules(self, (dir, package)):
1727 children = []
1728 for file in os.listdir(dir):
1729 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001730 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001731 children.append((path, package + (package and '.') + file))
1732 else:
1733 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001734 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001735 return children
1736
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001737 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001738 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001739 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001740 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001741 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001742 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001743
Ka-Ping Yee66246962001-04-12 11:59:50 +00001744 def run(self, callback, key=None, completer=None):
1745 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001746 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001747 seen = {}
1748
1749 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001750 if modname != '__main__':
1751 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001752 if key is None:
1753 callback(None, modname, '')
1754 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001755 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001756 if find(lower(modname + ' - ' + desc), key) >= 0:
1757 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001758
1759 while not self.quit:
1760 node = self.next()
1761 if not node: break
1762 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001763 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001764 if os.path.isfile(path) and modname:
1765 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001766 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001767 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001768 if key is None:
1769 callback(path, modname, '')
1770 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001771 desc = synopsis(path) or ''
1772 if find(lower(modname + ' - ' + desc), key) >= 0:
1773 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001774 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001775
1776def apropos(key):
1777 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001778 def callback(path, modname, desc):
1779 if modname[-9:] == '.__init__':
1780 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001781 print modname, desc and '- ' + desc
1782 try: import warnings
1783 except ImportError: pass
1784 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001785 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001786
1787# --------------------------------------------------- web browser interface
1788
Ka-Ping Yee66246962001-04-12 11:59:50 +00001789def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001790 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001791
1792 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1793 class Message(mimetools.Message):
1794 def __init__(self, fp, seekable=1):
1795 Message = self.__class__
1796 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1797 self.encodingheader = self.getheader('content-transfer-encoding')
1798 self.typeheader = self.getheader('content-type')
1799 self.parsetype()
1800 self.parseplist()
1801
1802 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1803 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001804 try:
1805 self.send_response(200)
1806 self.send_header('Content-Type', 'text/html')
1807 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001808 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001809 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001810
1811 def do_GET(self):
1812 path = self.path
1813 if path[-5:] == '.html': path = path[:-5]
1814 if path[:1] == '/': path = path[1:]
1815 if path and path != '.':
1816 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001817 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001818 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001819 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001820 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001821 if obj:
1822 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001823 else:
1824 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001825'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001826 else:
1827 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001828'<big><big><strong>Python: Index of Modules</strong></big></big>',
1829'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001830 def bltinlink(name):
1831 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001832 names = filter(lambda x: x != '__main__',
1833 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001834 contents = html.multicolumn(names, bltinlink)
1835 indices = ['<p>' + html.bigsection(
1836 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1837
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001838 seen = {}
1839 for dir in pathdirs():
1840 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001841 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001842<font color="#909090" face="helvetica, arial"><strong>
1843pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001844 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001845
1846 def log_message(self, *args): pass
1847
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001848 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001849 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001850 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001851 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001852 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001853 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001854 self.base.__init__(self, self.address, self.handler)
1855
1856 def serve_until_quit(self):
1857 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001858 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001859 while not self.quit:
1860 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1861 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001862
1863 def server_activate(self):
1864 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001865 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001866
1867 DocServer.base = BaseHTTPServer.HTTPServer
1868 DocServer.handler = DocHandler
1869 DocHandler.MessageClass = Message
1870 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001871 try:
1872 DocServer(port, callback).serve_until_quit()
1873 except (KeyboardInterrupt, select.error):
1874 pass
1875 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001876 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001877
1878# ----------------------------------------------------- graphical interface
1879
1880def gui():
1881 """Graphical interface (starts web server and pops up a control window)."""
1882 class GUI:
1883 def __init__(self, window, port=7464):
1884 self.window = window
1885 self.server = None
1886 self.scanner = None
1887
1888 import Tkinter
1889 self.server_frm = Tkinter.Frame(window)
1890 self.title_lbl = Tkinter.Label(self.server_frm,
1891 text='Starting server...\n ')
1892 self.open_btn = Tkinter.Button(self.server_frm,
1893 text='open browser', command=self.open, state='disabled')
1894 self.quit_btn = Tkinter.Button(self.server_frm,
1895 text='quit serving', command=self.quit, state='disabled')
1896
1897 self.search_frm = Tkinter.Frame(window)
1898 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1899 self.search_ent = Tkinter.Entry(self.search_frm)
1900 self.search_ent.bind('<Return>', self.search)
1901 self.stop_btn = Tkinter.Button(self.search_frm,
1902 text='stop', pady=0, command=self.stop, state='disabled')
1903 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001904 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001905 self.stop_btn.pack(side='right')
1906
1907 self.window.title('pydoc')
1908 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1909 self.title_lbl.pack(side='top', fill='x')
1910 self.open_btn.pack(side='left', fill='x', expand=1)
1911 self.quit_btn.pack(side='right', fill='x', expand=1)
1912 self.server_frm.pack(side='top', fill='x')
1913
1914 self.search_lbl.pack(side='left')
1915 self.search_ent.pack(side='right', fill='x', expand=1)
1916 self.search_frm.pack(side='top', fill='x')
1917 self.search_ent.focus_set()
1918
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001919 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001920 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001921 self.result_lst.bind('<Button-1>', self.select)
1922 self.result_lst.bind('<Double-Button-1>', self.goto)
1923 self.result_scr = Tkinter.Scrollbar(window,
1924 orient='vertical', command=self.result_lst.yview)
1925 self.result_lst.config(yscrollcommand=self.result_scr.set)
1926
1927 self.result_frm = Tkinter.Frame(window)
1928 self.goto_btn = Tkinter.Button(self.result_frm,
1929 text='go to selected', command=self.goto)
1930 self.hide_btn = Tkinter.Button(self.result_frm,
1931 text='hide results', command=self.hide)
1932 self.goto_btn.pack(side='left', fill='x', expand=1)
1933 self.hide_btn.pack(side='right', fill='x', expand=1)
1934
1935 self.window.update()
1936 self.minwidth = self.window.winfo_width()
1937 self.minheight = self.window.winfo_height()
1938 self.bigminheight = (self.server_frm.winfo_reqheight() +
1939 self.search_frm.winfo_reqheight() +
1940 self.result_lst.winfo_reqheight() +
1941 self.result_frm.winfo_reqheight())
1942 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
1943 self.expanded = 0
1944 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
1945 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00001946 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001947
1948 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001949 threading.Thread(
1950 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001951
1952 def ready(self, server):
1953 self.server = server
1954 self.title_lbl.config(
1955 text='Python documentation server at\n' + server.url)
1956 self.open_btn.config(state='normal')
1957 self.quit_btn.config(state='normal')
1958
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001959 def open(self, event=None, url=None):
1960 url = url or self.server.url
1961 try:
1962 import webbrowser
1963 webbrowser.open(url)
1964 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001965 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001966 os.system('start "%s"' % url)
1967 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001968 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001969 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001970 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001971 else:
1972 rc = os.system('netscape -remote "openURL(%s)" &' % url)
1973 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001974
1975 def quit(self, event=None):
1976 if self.server:
1977 self.server.quit = 1
1978 self.window.quit()
1979
1980 def search(self, event=None):
1981 key = self.search_ent.get()
1982 self.stop_btn.pack(side='right')
1983 self.stop_btn.config(state='normal')
1984 self.search_lbl.config(text='Searching for "%s"...' % key)
1985 self.search_ent.forget()
1986 self.search_lbl.pack(side='left')
1987 self.result_lst.delete(0, 'end')
1988 self.goto_btn.config(state='disabled')
1989 self.expand()
1990
1991 import threading
1992 if self.scanner:
1993 self.scanner.quit = 1
1994 self.scanner = ModuleScanner()
1995 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00001996 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001997
1998 def update(self, path, modname, desc):
1999 if modname[-9:] == '.__init__':
2000 modname = modname[:-9] + ' (package)'
2001 self.result_lst.insert('end',
2002 modname + ' - ' + (desc or '(no description)'))
2003
2004 def stop(self, event=None):
2005 if self.scanner:
2006 self.scanner.quit = 1
2007 self.scanner = None
2008
2009 def done(self):
2010 self.scanner = None
2011 self.search_lbl.config(text='Search for')
2012 self.search_lbl.pack(side='left')
2013 self.search_ent.pack(side='right', fill='x', expand=1)
2014 if sys.platform != 'win32': self.stop_btn.forget()
2015 self.stop_btn.config(state='disabled')
2016
2017 def select(self, event=None):
2018 self.goto_btn.config(state='normal')
2019
2020 def goto(self, event=None):
2021 selection = self.result_lst.curselection()
2022 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002023 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002024 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002025
2026 def collapse(self):
2027 if not self.expanded: return
2028 self.result_frm.forget()
2029 self.result_scr.forget()
2030 self.result_lst.forget()
2031 self.bigwidth = self.window.winfo_width()
2032 self.bigheight = self.window.winfo_height()
2033 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2034 self.window.wm_minsize(self.minwidth, self.minheight)
2035 self.expanded = 0
2036
2037 def expand(self):
2038 if self.expanded: return
2039 self.result_frm.pack(side='bottom', fill='x')
2040 self.result_scr.pack(side='right', fill='y')
2041 self.result_lst.pack(side='top', fill='both', expand=1)
2042 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2043 self.window.wm_minsize(self.minwidth, self.bigminheight)
2044 self.expanded = 1
2045
2046 def hide(self, event=None):
2047 self.stop()
2048 self.collapse()
2049
2050 import Tkinter
2051 try:
2052 gui = GUI(Tkinter.Tk())
2053 Tkinter.mainloop()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002054 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002055 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002056
2057# -------------------------------------------------- command-line interface
2058
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002059def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002060 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002061
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002062def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002063 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002064 import getopt
2065 class BadUsage: pass
2066
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002067 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002068 scriptdir = os.path.dirname(sys.argv[0])
2069 if scriptdir in sys.path:
2070 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002071 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002072
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002073 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002074 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002075 writing = 0
2076
2077 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002078 if opt == '-g':
2079 gui()
2080 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002081 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002082 apropos(val)
2083 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002084 if opt == '-p':
2085 try:
2086 port = int(val)
2087 except ValueError:
2088 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002089 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002090 print 'pydoc server ready at %s' % server.url
2091 def stopped():
2092 print 'pydoc server stopped'
2093 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002094 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002095 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002096 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002097
2098 if not args: raise BadUsage
2099 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002100 if ispath(arg) and not os.path.exists(arg):
2101 print 'file %r does not exist' % arg
2102 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002103 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002104 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002105 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002106 if writing:
2107 if ispath(arg) and os.path.isdir(arg):
2108 writedocs(arg)
2109 else:
2110 writedoc(arg)
2111 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002112 doc(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002113 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002114 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002115
2116 except (getopt.error, BadUsage):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002117 cmd = sys.argv[0]
2118 print """pydoc - the Python documentation tool
2119
2120%s <name> ...
2121 Show text documentation on something. <name> may be the name of a
2122 function, module, or package, or a dotted reference to a class or
2123 function within a module or module in a package. If <name> contains
2124 a '%s', it is used as the path to a Python source file to document.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002125
2126%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002127 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002128
2129%s -p <port>
2130 Start an HTTP server on the given port on the local machine.
2131
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002132%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002133 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002134
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002135%s -w <name> ...
2136 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002137 directory. If <name> contains a '%s', it is treated as a filename; if
2138 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002139""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002140
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002141if __name__ == '__main__': cli()