blob: 16d5585b8a6db67b189ba54645de704de8abe2ed [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".
Skip Montanaro4997a692003-09-10 16:47:51 +000027
28Module docs for core modules are assumed to be in
29
30 http://www.python.org/doc/current/lib/
31
32This can be overridden by setting the PYTHONDOCS environment variable
33to a different URL or to a local directory containing the Library
34Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000035"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000036
37__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000038__date__ = "26 February 2001"
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000039__version__ = "$Revision$"
Martin v. Löwis6fe8f192004-11-14 10:21:04 +000040__credits__ = """Guido van Rossum, for an excellent programming language.
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000041Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000042Paul Prescod, for all his work on onlinehelp.
43Richard Chamberlain, for the first implementation of textdoc.
Raymond Hettingered2dbe32005-01-01 07:51:01 +000044"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000045
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000046# Known bugs that can't be fixed here:
47# - imp.load_module() cannot be prevented from clobbering existing
48# loaded modules, so calling synopsis() on a binary module file
49# changes the contents of any existing module with the same name.
50# - If the __file__ attribute on a module is a relative path and
51# the current directory is changed with os.chdir(), an incorrect
52# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000053
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +000054import sys, imp, os, re, types, inspect, __builtin__
Ka-Ping Yeedd175342001-02-27 14:43:46 +000055from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000056from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
Raymond Hettinger756b3f32004-01-29 06:37:52 +000057from collections import deque
Ka-Ping Yeedd175342001-02-27 14:43:46 +000058
59# --------------------------------------------------------- common routines
60
Ka-Ping Yeedd175342001-02-27 14:43:46 +000061def pathdirs():
62 """Convert sys.path into a list of absolute, existing, unique paths."""
63 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000064 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000065 for dir in sys.path:
66 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000067 normdir = os.path.normcase(dir)
68 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000069 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000070 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000071 return dirs
72
73def getdoc(object):
74 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000075 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000076 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000077
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000078def splitdoc(doc):
79 """Split a doc string into a synopsis line (if any) and the rest."""
80 lines = split(strip(doc), '\n')
81 if len(lines) == 1:
82 return lines[0], ''
83 elif len(lines) >= 2 and not rstrip(lines[1]):
84 return lines[0], join(lines[2:], '\n')
85 return '', join(lines, '\n')
86
Ka-Ping Yeedd175342001-02-27 14:43:46 +000087def classname(object, modname):
88 """Get a class name and qualify it with a module name if necessary."""
89 name = object.__name__
90 if object.__module__ != modname:
91 name = object.__module__ + '.' + name
92 return name
93
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000094def isdata(object):
95 """Check if an object is of a type that probably means it's data."""
96 return not (inspect.ismodule(object) or inspect.isclass(object) or
97 inspect.isroutine(object) or inspect.isframe(object) or
98 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +000099
100def replace(text, *pairs):
101 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000102 while pairs:
103 text = join(split(text, pairs[0]), pairs[1])
104 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000105 return text
106
107def cram(text, maxlen):
108 """Omit part of a string if needed to make it fit in a maximum length."""
109 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000110 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000111 post = max(0, maxlen-3-pre)
112 return text[:pre] + '...' + text[len(text)-post:]
113 return text
114
Brett Cannon84601f12004-06-19 01:22:48 +0000115_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000116def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000117 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000118 # The behaviour of %p is implementation-dependent in terms of case.
119 if _re_stripid.search(repr(Exception)):
120 return _re_stripid.sub(r'\1', text)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000121 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000122
Brett Cannonc6c1f472004-06-19 01:02:51 +0000123def _is_some_method(obj):
124 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000125
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000126def allmethods(cl):
127 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000128 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000129 methods[key] = 1
130 for base in cl.__bases__:
131 methods.update(allmethods(base)) # all your base are belong to us
132 for key in methods.keys():
133 methods[key] = getattr(cl, key)
134 return methods
135
Tim Petersfa26f7c2001-09-24 08:05:11 +0000136def _split_list(s, predicate):
137 """Split sequence s via predicate, and return pair ([true], [false]).
138
139 The return value is a 2-tuple of lists,
140 ([x for x in s if predicate(x)],
141 [x for x in s if not predicate(x)])
142 """
143
Tim Peters28355492001-09-23 21:29:55 +0000144 yes = []
145 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000146 for x in s:
147 if predicate(x):
148 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000149 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000150 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000151 return yes, no
152
Skip Montanaroa5616d22004-06-11 04:46:12 +0000153def visiblename(name, all=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000154 """Decide whether to show documentation on a variable."""
155 # Certain special names are redundant.
156 if name in ['__builtins__', '__doc__', '__file__', '__path__',
157 '__module__', '__name__']: return 0
158 # Private names are hidden, but special names are displayed.
159 if name.startswith('__') and name.endswith('__'): return 1
Skip Montanaroa5616d22004-06-11 04:46:12 +0000160 if all is not None:
161 # only document that which the programmer exported in __all__
162 return name in all
163 else:
164 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000165
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000166# ----------------------------------------------------- module manipulation
167
168def ispackage(path):
169 """Guess whether a path refers to a package directory."""
170 if os.path.isdir(path):
171 for ext in ['.py', '.pyc', '.pyo']:
172 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000173 return True
174 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000175
176def synopsis(filename, cache={}):
177 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000178 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000179 lastupdate, result = cache.get(filename, (0, None))
180 if lastupdate < mtime:
181 info = inspect.getmoduleinfo(filename)
182 file = open(filename)
183 if info and 'b' in info[2]: # binary modules have to be imported
184 try: module = imp.load_module('__temp__', file, filename, info[1:])
185 except: return None
186 result = split(module.__doc__ or '', '\n')[0]
187 del sys.modules['__temp__']
188 else: # text modules can be directly examined
189 line = file.readline()
190 while line[:1] == '#' or not strip(line):
191 line = file.readline()
192 if not line: break
193 line = strip(line)
194 if line[:4] == 'r"""': line = line[1:]
195 if line[:3] == '"""':
196 line = line[3:]
197 if line[-1:] == '\\': line = line[:-1]
198 while not strip(line):
199 line = file.readline()
200 if not line: break
201 result = strip(split(line, '"""')[0])
202 else: result = None
203 file.close()
204 cache[filename] = (mtime, result)
205 return result
206
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000207class ErrorDuringImport(Exception):
208 """Errors that occurred while trying to import something to document it."""
209 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000210 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000211 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000212 self.value = value
213 self.tb = tb
214
215 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000216 exc = self.exc
217 if type(exc) is types.ClassType:
218 exc = exc.__name__
219 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000220
221def importfile(path):
222 """Import a Python source file or compiled file given its path."""
223 magic = imp.get_magic()
224 file = open(path, 'r')
225 if file.read(len(magic)) == magic:
226 kind = imp.PY_COMPILED
227 else:
228 kind = imp.PY_SOURCE
229 file.close()
230 filename = os.path.basename(path)
231 name, ext = os.path.splitext(filename)
232 file = open(path, 'r')
233 try:
234 module = imp.load_module(name, file, path, (ext, 'r', kind))
235 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000236 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000237 file.close()
238 return module
239
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000240def safeimport(path, forceload=0, cache={}):
241 """Import a module; handle errors; return None if the module isn't found.
242
243 If the module *is* found but an exception occurs, it's wrapped in an
244 ErrorDuringImport exception and reraised. Unlike __import__, if a
245 package path is specified, the module at the end of the path is returned,
246 not the package at the beginning. If the optional 'forceload' argument
247 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000248 if forceload and path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000249 # This is the only way to be sure. Checking the mtime of the file
250 # isn't good enough (e.g. what if the module contains a class that
251 # inherits from another module that has changed?).
252 if path not in sys.builtin_module_names:
253 # Python never loads a dynamic extension a second time from the
254 # same path, even if the file is changed or missing. Deleting
255 # the entry in sys.modules doesn't help for dynamic extensions,
256 # so we're not even going to try to keep them up to date.
257 info = inspect.getmoduleinfo(sys.modules[path].__file__)
258 if info[3] != imp.C_EXTENSION:
259 cache[path] = sys.modules[path] # prevent module from clearing
260 del sys.modules[path]
261 try:
262 module = __import__(path)
263 except:
264 # Did the error occur before or after the module was found?
265 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000266 if path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000267 # An error occured while executing the imported module.
268 raise ErrorDuringImport(sys.modules[path].__file__, info)
269 elif exc is SyntaxError:
270 # A SyntaxError occurred before we could execute the module.
271 raise ErrorDuringImport(value.filename, info)
272 elif exc is ImportError and \
273 split(lower(str(value)))[:2] == ['no', 'module']:
274 # The module was not found.
275 return None
276 else:
277 # Some other error occurred during the importing process.
278 raise ErrorDuringImport(path, sys.exc_info())
279 for part in split(path, '.')[1:]:
280 try: module = getattr(module, part)
281 except AttributeError: return None
282 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000283
284# ---------------------------------------------------- formatter base class
285
286class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000287 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000288 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000289 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000290 # 'try' clause is to attempt to handle the possibility that inspect
291 # identifies something in a way that pydoc itself has issues handling;
292 # think 'super' and how it is a descriptor (which raises the exception
293 # by lacking a __name__ attribute) and an instance.
294 try:
295 if inspect.ismodule(object): return self.docmodule(*args)
296 if inspect.isclass(object): return self.docclass(*args)
297 if inspect.isroutine(object): return self.docroutine(*args)
298 except AttributeError:
299 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000300 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000301 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000302
303 def fail(self, object, name=None, *args):
304 """Raise an exception for unimplemented types."""
305 message = "don't know how to document object%s of type %s" % (
306 name and ' ' + repr(name), type(object).__name__)
307 raise TypeError, message
308
309 docmodule = docclass = docroutine = docother = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000310
Skip Montanaro4997a692003-09-10 16:47:51 +0000311 def getdocloc(self, object):
312 """Return the location of module docs or None"""
313
314 try:
315 file = inspect.getabsfile(object)
316 except TypeError:
317 file = '(built-in)'
318
319 docloc = os.environ.get("PYTHONDOCS",
320 "http://www.python.org/doc/current/lib")
321 basedir = os.path.join(sys.exec_prefix, "lib",
322 "python"+sys.version[0:3])
323 if (isinstance(object, type(os)) and
324 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
325 'marshal', 'posix', 'signal', 'sys',
326 'thread', 'zipimport') or
327 (file.startswith(basedir) and
328 not file.startswith(os.path.join(basedir, 'site-packages'))))):
Skip Montanarof2134842004-06-07 02:40:05 +0000329 htmlfile = "module-%s.html" % object.__name__
Skip Montanaro4997a692003-09-10 16:47:51 +0000330 if docloc.startswith("http://"):
Skip Montanarof2134842004-06-07 02:40:05 +0000331 docloc = "%s/%s" % (docloc.rstrip("/"), htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000332 else:
Skip Montanarof2134842004-06-07 02:40:05 +0000333 docloc = os.path.join(docloc, htmlfile)
Skip Montanaro4997a692003-09-10 16:47:51 +0000334 else:
335 docloc = None
336 return docloc
337
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000338# -------------------------------------------- HTML documentation generator
339
340class HTMLRepr(Repr):
341 """Class for safely making an HTML representation of a Python object."""
342 def __init__(self):
343 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000344 self.maxlist = self.maxtuple = 20
345 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000346 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000347
348 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000349 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000350
351 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000352 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000353
354 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000355 if hasattr(type(x), '__name__'):
356 methodname = 'repr_' + join(split(type(x).__name__), '_')
357 if hasattr(self, methodname):
358 return getattr(self, methodname)(x, level)
359 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000360
361 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000362 test = cram(x, self.maxstring)
363 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000364 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000365 # Backslashes are only literal in the string and are never
366 # needed to make any special characters, so show a raw string.
367 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000368 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000369 r'<font color="#c040c0">\1</font>',
370 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000371
Skip Montanarodf708782002-03-07 22:58:02 +0000372 repr_str = repr_string
373
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000374 def repr_instance(self, x, level):
375 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000376 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000377 except:
378 return self.escape('<%s instance>' % x.__class__.__name__)
379
380 repr_unicode = repr_string
381
382class HTMLDoc(Doc):
383 """Formatter class for HTML documentation."""
384
385 # ------------------------------------------- HTML formatting utilities
386
387 _repr_instance = HTMLRepr()
388 repr = _repr_instance.repr
389 escape = _repr_instance.escape
390
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000391 def page(self, title, contents):
392 """Format an HTML page."""
393 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000394<!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000395<html><head><title>Python: %s</title>
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000396</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000397%s
398</body></html>''' % (title, contents)
399
400 def heading(self, title, fgcol, bgcol, extras=''):
401 """Format a page heading."""
402 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000403<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000404<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000405<td valign=bottom>&nbsp;<br>
406<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000407><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000408><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000409 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
410
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000411 def section(self, title, fgcol, bgcol, contents, width=6,
412 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000413 """Format a section with a heading."""
414 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000415 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000416 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000417<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000418<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000419<td colspan=3 valign=bottom>&nbsp;<br>
420<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000421 ''' % (bgcol, fgcol, title)
422 if prelude:
423 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000424<tr bgcolor="%s"><td rowspan=2>%s</td>
425<td colspan=2>%s</td></tr>
426<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
427 else:
428 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000429<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000430
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000431 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000432
433 def bigsection(self, title, *args):
434 """Format a section with a big heading."""
435 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000436 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000437
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000438 def preformat(self, text):
439 """Format literal preformatted text."""
440 text = self.escape(expandtabs(text))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000441 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
442 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000443
444 def multicolumn(self, list, format, cols=4):
445 """Format a list of items into a multi-column list."""
446 result = ''
447 rows = (len(list)+cols-1)/cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000448 for col in range(cols):
449 result = result + '<td width="%d%%" valign=top>' % (100/cols)
450 for i in range(rows*col, rows*col+rows):
451 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000452 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000453 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000454 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000455
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000456 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000457
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000458 def namelink(self, name, *dicts):
459 """Make a link for an identifier, given name-to-URL mappings."""
460 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000461 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000462 return '<a href="%s">%s</a>' % (dict[name], name)
463 return name
464
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000465 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000466 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000467 name, module = object.__name__, sys.modules.get(object.__module__)
468 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000469 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000470 module.__name__, name, classname(object, modname))
471 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000472
473 def modulelink(self, object):
474 """Make a link for a module."""
475 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
476
477 def modpkglink(self, (name, path, ispackage, shadowed)):
478 """Make a link for a module or package to display in an index."""
479 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000480 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000481 if path:
482 url = '%s.%s.html' % (path, name)
483 else:
484 url = '%s.html' % name
485 if ispackage:
486 text = '<strong>%s</strong>&nbsp;(package)' % name
487 else:
488 text = name
489 return '<a href="%s">%s</a>' % (url, text)
490
491 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
492 """Mark up some plain text, given a context of symbols to look for.
493 Each context dictionary maps object names to anchor names."""
494 escape = escape or self.escape
495 results = []
496 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000497 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
498 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000499 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000500 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000501 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000502 match = pattern.search(text, here)
503 if not match: break
504 start, end = match.span()
505 results.append(escape(text[here:start]))
506
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000507 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000508 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000509 url = escape(all).replace('"', '&quot;')
510 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000511 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000512 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
513 results.append('<a href="%s">%s</a>' % (url, escape(all)))
514 elif pep:
515 url = 'http://www.python.org/peps/pep-%04d.html' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000516 results.append('<a href="%s">%s</a>' % (url, escape(all)))
517 elif text[end:end+1] == '(':
518 results.append(self.namelink(name, methods, funcs, classes))
519 elif selfdot:
520 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000521 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000522 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000523 here = end
524 results.append(escape(text[here:]))
525 return join(results, '')
526
527 # ---------------------------------------------- type-specific routines
528
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000529 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000530 """Produce HTML for a class tree as given by inspect.getclasstree()."""
531 result = ''
532 for entry in tree:
533 if type(entry) is type(()):
534 c, bases = entry
Tim Peters2306d242001-09-25 03:18:32 +0000535 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000536 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000537 if bases and bases != (parent,):
538 parents = []
539 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000540 parents.append(self.classlink(base, modname))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000541 result = result + '(' + join(parents, ', ') + ')'
Tim Peters2306d242001-09-25 03:18:32 +0000542 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000543 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000544 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000545 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000546 return '<dl>\n%s</dl>\n' % result
547
Tim Peters8dd7ade2001-10-18 19:56:17 +0000548 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000549 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000550 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000551 try:
552 all = object.__all__
553 except AttributeError:
554 all = None
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000555 parts = split(name, '.')
556 links = []
557 for i in range(len(parts)-1):
558 links.append(
559 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
560 (join(parts[:i+1], '.'), parts[i]))
561 linkedname = join(links + parts[-1:], '.')
562 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000563 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000564 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000565 url = path
566 if sys.platform == 'win32':
567 import nturl2path
568 url = nturl2path.pathname2url(path)
569 filelink = '<a href="file:%s">%s</a>' % (url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000570 except TypeError:
571 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000572 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000573 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000574 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000575 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
576 version = strip(version[11:-1])
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000577 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000578 if hasattr(object, '__date__'):
579 info.append(self.escape(str(object.__date__)))
580 if info:
581 head = head + ' (%s)' % join(info, ', ')
Skip Montanaro4997a692003-09-10 16:47:51 +0000582 docloc = self.getdocloc(object)
583 if docloc is not None:
584 docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
585 else:
586 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000587 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000588 head, '#ffffff', '#7799ee',
589 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000590
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000591 modules = inspect.getmembers(object, inspect.ismodule)
592
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000593 classes, cdict = [], {}
594 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000595 # if __all__ exists, believe it. Otherwise use old heuristic.
596 if (all is not None or
597 (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000598 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000599 classes.append((key, value))
600 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000601 for key, value in classes:
602 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000603 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000604 module = sys.modules.get(modname)
605 if modname != name and module and hasattr(module, key):
606 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000607 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000608 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000609 funcs, fdict = [], {}
610 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000611 # if __all__ exists, believe it. Otherwise use old heuristic.
612 if (all is not None or
613 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000614 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000615 funcs.append((key, value))
616 fdict[key] = '#-' + key
617 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000618 data = []
619 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000620 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000621 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000622
623 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
624 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000625 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000626
627 if hasattr(object, '__path__'):
628 modpkgs = []
629 modnames = []
630 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000631 path = os.path.join(object.__path__[0], file)
632 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000633 if modname != '__init__':
634 if modname and modname not in modnames:
635 modpkgs.append((modname, name, 0, 0))
636 modnames.append(modname)
637 elif ispackage(path):
638 modpkgs.append((file, name, 1, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000639 modpkgs.sort()
640 contents = self.multicolumn(modpkgs, self.modpkglink)
641 result = result + self.bigsection(
642 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000643 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000644 contents = self.multicolumn(
645 modules, lambda (key, value), s=self: s.modulelink(value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000646 result = result + self.bigsection(
647 'Modules', '#fffff', '#aa55cc', contents)
648
649 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000650 classlist = map(lambda (key, value): value, classes)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000651 contents = [
652 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000653 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000654 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000655 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000656 'Classes', '#ffffff', '#ee77aa', join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000657 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000658 contents = []
659 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000660 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000661 result = result + self.bigsection(
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000662 'Functions', '#ffffff', '#eeaa77', join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000663 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000664 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000665 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000666 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000667 result = result + self.bigsection(
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000668 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000669 if hasattr(object, '__author__'):
670 contents = self.markup(str(object.__author__), self.preformat)
671 result = result + self.bigsection(
672 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000673 if hasattr(object, '__credits__'):
674 contents = self.markup(str(object.__credits__), self.preformat)
675 result = result + self.bigsection(
676 'Credits', '#ffffff', '#7799ee', contents)
677
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000678 return result
679
Tim Peters8dd7ade2001-10-18 19:56:17 +0000680 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
681 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000682 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000683 realname = object.__name__
684 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000685 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000686
Tim Petersb47879b2001-09-24 04:47:19 +0000687 contents = []
688 push = contents.append
689
Tim Petersfa26f7c2001-09-24 08:05:11 +0000690 # Cute little class to pump out a horizontal rule between sections.
691 class HorizontalRule:
692 def __init__(self):
693 self.needone = 0
694 def maybe(self):
695 if self.needone:
696 push('<hr>\n')
697 self.needone = 1
698 hr = HorizontalRule()
699
Tim Petersc86f6ca2001-09-26 21:31:51 +0000700 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000701 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000702 if len(mro) > 2:
703 hr.maybe()
704 push('<dl><dt>Method resolution order:</dt>\n')
705 for base in mro:
706 push('<dd>%s</dd>\n' % self.classlink(base,
707 object.__module__))
708 push('</dl>\n')
709
Tim Petersb47879b2001-09-24 04:47:19 +0000710 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000711 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000712 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000713 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000714 push(msg)
715 for name, kind, homecls, value in ok:
716 push(self.document(getattr(object, name), name, mod,
717 funcs, classes, mdict, object))
718 push('\n')
719 return attrs
720
Tim Petersfa26f7c2001-09-24 08:05:11 +0000721 def spillproperties(msg, attrs, predicate):
722 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000723 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000724 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000725 push(msg)
726 for name, kind, homecls, value in ok:
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000727 push(self._docproperty(name, value, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000728 return attrs
729
Tim Petersfa26f7c2001-09-24 08:05:11 +0000730 def spilldata(msg, attrs, predicate):
731 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000732 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000733 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000734 push(msg)
735 for name, kind, homecls, value in ok:
736 base = self.docother(getattr(object, name), name, mod)
Martin v. Löwise59e2ba2003-05-03 09:09:02 +0000737 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000738 doc = getattr(value, "__doc__", None)
739 else:
740 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000741 if doc is None:
742 push('<dl><dt>%s</dl>\n' % base)
743 else:
744 doc = self.markup(getdoc(value), self.preformat,
745 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000746 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000747 push('<dl><dt>%s%s</dl>\n' % (base, doc))
748 push('\n')
749 return attrs
750
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000751 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
752 inspect.classify_class_attrs(object))
Tim Petersb47879b2001-09-24 04:47:19 +0000753 mdict = {}
754 for key, kind, homecls, value in attrs:
755 mdict[key] = anchor = '#' + name + '-' + key
756 value = getattr(object, key)
757 try:
758 # The value may not be hashable (e.g., a data attr with
759 # a dict or list value).
760 mdict[value] = anchor
761 except TypeError:
762 pass
763
Tim Petersfa26f7c2001-09-24 08:05:11 +0000764 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000765 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000766 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000767 else:
768 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000769 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
770
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000771 if thisclass is __builtin__.object:
772 attrs = inherited
773 continue
774 elif thisclass is object:
775 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000776 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000777 tag = 'inherited from %s' % self.classlink(thisclass,
778 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000779 tag += ':<br>\n'
780
781 # Sort attrs by name.
Raymond Hettinger6b59f5f2003-10-16 05:53:16 +0000782 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000783
784 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000785 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000786 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000787 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000788 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000789 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000790 lambda t: t[1] == 'static method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000791 attrs = spillproperties('Properties %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000792 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000793 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000794 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000795 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000796 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000797
798 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000799
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000800 if name == realname:
801 title = '<a name="%s">class <strong>%s</strong></a>' % (
802 name, realname)
803 else:
804 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
805 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000806 if bases:
807 parents = []
808 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000809 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000810 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000811 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000812 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000813
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000814 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000815
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000816 def formatvalue(self, object):
817 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000818 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000819
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000820 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000821 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000822 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000823 realname = object.__name__
824 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000825 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000826 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000827 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000828 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000829 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000830 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000831 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000832 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000833 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000834 if object.im_self:
835 note = ' method of %s instance' % self.classlink(
836 object.im_self.__class__, mod)
837 else:
838 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000839 object = object.im_func
840
841 if name == realname:
842 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
843 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000844 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000845 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000846 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000847 cl.__name__ + '-' + realname, realname)
848 skipdocs = 1
849 else:
850 reallink = realname
851 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
852 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000853 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000854 args, varargs, varkw, defaults = inspect.getargspec(object)
855 argspec = inspect.formatargspec(
856 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000857 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000858 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000859 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000860 else:
861 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000862
Tim Peters2306d242001-09-25 03:18:32 +0000863 decl = title + argspec + (note and self.grey(
864 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000865
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000866 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000867 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000868 else:
869 doc = self.markup(
870 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000871 doc = doc and '<dd><tt>%s</tt></dd>' % doc
872 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000873
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000874 def _docproperty(self, name, value, mod):
875 results = []
876 push = results.append
877
878 if name:
879 push('<dl><dt><strong>%s</strong></dt>\n' % name)
880 if value.__doc__ is not None:
881 doc = self.markup(value.__doc__, self.preformat)
882 push('<dd><tt>%s</tt></dd>\n' % doc)
883 for attr, tag in [('fget', '<em>get</em>'),
884 ('fset', '<em>set</em>'),
885 ('fdel', '<em>delete</em>')]:
886 func = getattr(value, attr)
887 if func is not None:
888 base = self.document(func, tag, mod)
889 push('<dd>%s</dd>\n' % base)
890 push('</dl>\n')
891
892 return ''.join(results)
893
894 def docproperty(self, object, name=None, mod=None, cl=None):
895 """Produce html documentation for a property."""
896 return self._docproperty(name, object, mod)
897
Tim Peters8dd7ade2001-10-18 19:56:17 +0000898 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000899 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000900 lhs = name and '<strong>%s</strong> = ' % name or ''
901 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000902
903 def index(self, dir, shadowed=None):
904 """Generate an HTML index for a directory of modules."""
905 modpkgs = []
906 if shadowed is None: shadowed = {}
907 seen = {}
908 files = os.listdir(dir)
909
910 def found(name, ispackage,
911 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
Raymond Hettinger4f759d82002-11-02 02:02:46 +0000912 if name not in seen:
913 modpkgs.append((name, '', ispackage, name in shadowed))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000914 seen[name] = 1
915 shadowed[name] = 1
916
917 # Package spam/__init__.py takes precedence over module spam.py.
918 for file in files:
919 path = os.path.join(dir, file)
920 if ispackage(path): found(file, 1)
921 for file in files:
922 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000923 if os.path.isfile(path):
924 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000925 if modname: found(modname, 0)
926
927 modpkgs.sort()
928 contents = self.multicolumn(modpkgs, self.modpkglink)
929 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
930
931# -------------------------------------------- text documentation generator
932
933class TextRepr(Repr):
934 """Class for safely making a text representation of a Python object."""
935 def __init__(self):
936 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000937 self.maxlist = self.maxtuple = 20
938 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000939 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000940
941 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000942 if hasattr(type(x), '__name__'):
943 methodname = 'repr_' + join(split(type(x).__name__), '_')
944 if hasattr(self, methodname):
945 return getattr(self, methodname)(x, level)
946 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000947
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000948 def repr_string(self, x, level):
949 test = cram(x, self.maxstring)
950 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000951 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000952 # Backslashes are only literal in the string and are never
953 # needed to make any special characters, so show a raw string.
954 return 'r' + testrepr[0] + test + testrepr[0]
955 return testrepr
956
Skip Montanarodf708782002-03-07 22:58:02 +0000957 repr_str = repr_string
958
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000959 def repr_instance(self, x, level):
960 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000961 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000962 except:
963 return '<%s instance>' % x.__class__.__name__
964
965class TextDoc(Doc):
966 """Formatter class for text documentation."""
967
968 # ------------------------------------------- text formatting utilities
969
970 _repr_instance = TextRepr()
971 repr = _repr_instance.repr
972
973 def bold(self, text):
974 """Format a string in bold by overstriking."""
975 return join(map(lambda ch: ch + '\b' + ch, text), '')
976
977 def indent(self, text, prefix=' '):
978 """Indent text by prepending a given prefix to each line."""
979 if not text: return ''
980 lines = split(text, '\n')
981 lines = map(lambda line, prefix=prefix: prefix + line, lines)
982 if lines: lines[-1] = rstrip(lines[-1])
983 return join(lines, '\n')
984
985 def section(self, title, contents):
986 """Format a section with a given heading."""
987 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
988
989 # ---------------------------------------------- type-specific routines
990
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000991 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000992 """Render in text a class tree as returned by inspect.getclasstree()."""
993 result = ''
994 for entry in tree:
995 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000996 c, bases = entry
997 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000998 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000999 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001000 result = result + '(%s)' % join(parents, ', ')
1001 result = result + '\n'
1002 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001003 result = result + self.formattree(
1004 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001005 return result
1006
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001007 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001008 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001009 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001010 synop, desc = splitdoc(getdoc(object))
1011 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001012
1013 try:
Skip Montanaroa5616d22004-06-11 04:46:12 +00001014 all = object.__all__
1015 except AttributeError:
1016 all = None
1017
1018 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001019 file = inspect.getabsfile(object)
1020 except TypeError:
1021 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001022 result = result + self.section('FILE', file)
Skip Montanaro4997a692003-09-10 16:47:51 +00001023
1024 docloc = self.getdocloc(object)
1025 if docloc is not None:
1026 result = result + self.section('MODULE DOCS', docloc)
1027
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001028 if desc:
1029 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001030
1031 classes = []
1032 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001033 # if __all__ exists, believe it. Otherwise use old heuristic.
1034 if (all is not None
1035 or (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001036 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001037 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001038 funcs = []
1039 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001040 # if __all__ exists, believe it. Otherwise use old heuristic.
1041 if (all is not None or
1042 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001043 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001044 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001045 data = []
1046 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001047 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001048 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001049
1050 if hasattr(object, '__path__'):
1051 modpkgs = []
1052 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001053 path = os.path.join(object.__path__[0], file)
1054 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001055 if modname != '__init__':
1056 if modname and modname not in modpkgs:
1057 modpkgs.append(modname)
1058 elif ispackage(path):
1059 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001060 modpkgs.sort()
1061 result = result + self.section(
1062 'PACKAGE CONTENTS', join(modpkgs, '\n'))
1063
1064 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001065 classlist = map(lambda (key, value): value, classes)
1066 contents = [self.formattree(
1067 inspect.getclasstree(classlist, 1), name)]
1068 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001069 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001070 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001071
1072 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001073 contents = []
1074 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001075 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001076 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001077
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001078 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001079 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001080 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001081 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001082 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001083
1084 if hasattr(object, '__version__'):
1085 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001086 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1087 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001088 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001089 if hasattr(object, '__date__'):
1090 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001091 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001092 result = result + self.section('AUTHOR', str(object.__author__))
1093 if hasattr(object, '__credits__'):
1094 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001095 return result
1096
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001097 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001098 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001099 realname = object.__name__
1100 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001101 bases = object.__bases__
1102
Tim Petersc86f6ca2001-09-26 21:31:51 +00001103 def makename(c, m=object.__module__):
1104 return classname(c, m)
1105
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001106 if name == realname:
1107 title = 'class ' + self.bold(realname)
1108 else:
1109 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001110 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001111 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001112 title = title + '(%s)' % join(parents, ', ')
1113
1114 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001115 contents = doc and [doc + '\n'] or []
1116 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001117
Tim Petersc86f6ca2001-09-26 21:31:51 +00001118 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001119 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001120 if len(mro) > 2:
1121 push("Method resolution order:")
1122 for base in mro:
1123 push(' ' + makename(base))
1124 push('')
1125
Tim Petersf4aad8e2001-09-24 22:40:47 +00001126 # Cute little class to pump out a horizontal rule between sections.
1127 class HorizontalRule:
1128 def __init__(self):
1129 self.needone = 0
1130 def maybe(self):
1131 if self.needone:
1132 push('-' * 70)
1133 self.needone = 1
1134 hr = HorizontalRule()
1135
Tim Peters28355492001-09-23 21:29:55 +00001136 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001137 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001138 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001139 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001140 push(msg)
1141 for name, kind, homecls, value in ok:
1142 push(self.document(getattr(object, name),
1143 name, mod, object))
1144 return attrs
1145
Tim Petersfa26f7c2001-09-24 08:05:11 +00001146 def spillproperties(msg, attrs, predicate):
1147 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001148 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001149 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001150 push(msg)
1151 for name, kind, homecls, value in ok:
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001152 push(self._docproperty(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001153 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001154
Tim Petersfa26f7c2001-09-24 08:05:11 +00001155 def spilldata(msg, attrs, predicate):
1156 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001157 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001158 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001159 push(msg)
1160 for name, kind, homecls, value in ok:
Martin v. Löwise59e2ba2003-05-03 09:09:02 +00001161 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +00001162 doc = getattr(value, "__doc__", None)
1163 else:
1164 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001165 push(self.docother(getattr(object, name),
1166 name, mod, 70, doc) + '\n')
1167 return attrs
1168
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001169 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
1170 inspect.classify_class_attrs(object))
Tim Petersfa26f7c2001-09-24 08:05:11 +00001171 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001172 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001173 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001174 else:
1175 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001176 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1177
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001178 if thisclass is __builtin__.object:
1179 attrs = inherited
1180 continue
1181 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001182 tag = "defined here"
1183 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001184 tag = "inherited from %s" % classname(thisclass,
1185 object.__module__)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001186 filter(lambda t: not t[0].startswith('_'), attrs)
Tim Peters28355492001-09-23 21:29:55 +00001187
1188 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001189 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001190
1191 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001192 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001193 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001194 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001195 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001196 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001197 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001198 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001199 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001200 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1201 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001202 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001203 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001204
1205 contents = '\n'.join(contents)
1206 if not contents:
1207 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001208 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1209
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001210 def formatvalue(self, object):
1211 """Format an argument default value as text."""
1212 return '=' + self.repr(object)
1213
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001214 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001215 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001216 realname = object.__name__
1217 name = name or realname
1218 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001219 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001220 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001221 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001222 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001223 if imclass is not cl:
1224 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001225 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001226 if object.im_self:
1227 note = ' method of %s instance' % classname(
1228 object.im_self.__class__, mod)
1229 else:
1230 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001231 object = object.im_func
1232
1233 if name == realname:
1234 title = self.bold(realname)
1235 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001236 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001237 cl.__dict__[realname] is object):
1238 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001239 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001240 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001241 args, varargs, varkw, defaults = inspect.getargspec(object)
1242 argspec = inspect.formatargspec(
1243 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001244 if realname == '<lambda>':
1245 title = 'lambda'
1246 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001247 else:
1248 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001249 decl = title + argspec + note
1250
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001251 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001252 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001253 else:
1254 doc = getdoc(object) or ''
1255 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001256
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001257 def _docproperty(self, name, value, mod):
1258 results = []
1259 push = results.append
1260
1261 if name:
1262 push(name)
1263 need_blank_after_doc = 0
1264 doc = getdoc(value) or ''
1265 if doc:
1266 push(self.indent(doc))
1267 need_blank_after_doc = 1
1268 for attr, tag in [('fget', '<get>'),
1269 ('fset', '<set>'),
1270 ('fdel', '<delete>')]:
1271 func = getattr(value, attr)
1272 if func is not None:
1273 if need_blank_after_doc:
1274 push('')
1275 need_blank_after_doc = 0
1276 base = self.document(func, tag, mod)
1277 push(self.indent(base))
1278
1279 return '\n'.join(results)
1280
1281 def docproperty(self, object, name=None, mod=None, cl=None):
1282 """Produce text documentation for a property."""
1283 return self._docproperty(name, object, mod)
1284
Tim Peters28355492001-09-23 21:29:55 +00001285 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001286 """Produce text documentation for a data object."""
1287 repr = self.repr(object)
1288 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001289 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001290 chop = maxlen - len(line)
1291 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001292 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001293 if doc is not None:
1294 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001295 return line
1296
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001297# --------------------------------------------------------- user interfaces
1298
1299def pager(text):
1300 """The first time this is called, determine what kind of pager to use."""
1301 global pager
1302 pager = getpager()
1303 pager(text)
1304
1305def getpager():
1306 """Decide what method to use for paging through text."""
1307 if type(sys.stdout) is not types.FileType:
1308 return plainpager
1309 if not sys.stdin.isatty() or not sys.stdout.isatty():
1310 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001311 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001312 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001313 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001314 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001315 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1316 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1317 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001318 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001319 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001320 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001321 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001322 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001323 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001324
1325 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001326 (fd, filename) = tempfile.mkstemp()
1327 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001328 try:
1329 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1330 return lambda text: pipepager(text, 'more')
1331 else:
1332 return ttypager
1333 finally:
1334 os.unlink(filename)
1335
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001336def plain(text):
1337 """Remove boldface formatting from text."""
1338 return re.sub('.\b', '', text)
1339
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001340def pipepager(text, cmd):
1341 """Page through text by feeding it to another program."""
1342 pipe = os.popen(cmd, 'w')
1343 try:
1344 pipe.write(text)
1345 pipe.close()
1346 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001347 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001348
1349def tempfilepager(text, cmd):
1350 """Page through text by invoking a program on a temporary file."""
1351 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001352 filename = tempfile.mktemp()
1353 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001354 file.write(text)
1355 file.close()
1356 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001357 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001358 finally:
1359 os.unlink(filename)
1360
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001361def ttypager(text):
1362 """Page through text on a text terminal."""
1363 lines = split(plain(text), '\n')
1364 try:
1365 import tty
1366 fd = sys.stdin.fileno()
1367 old = tty.tcgetattr(fd)
1368 tty.setcbreak(fd)
1369 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001370 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001371 tty = None
1372 getchar = lambda: sys.stdin.readline()[:-1][:1]
1373
1374 try:
1375 r = inc = os.environ.get('LINES', 25) - 1
1376 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1377 while lines[r:]:
1378 sys.stdout.write('-- more --')
1379 sys.stdout.flush()
1380 c = getchar()
1381
1382 if c in ['q', 'Q']:
1383 sys.stdout.write('\r \r')
1384 break
1385 elif c in ['\r', '\n']:
1386 sys.stdout.write('\r \r' + lines[r] + '\n')
1387 r = r + 1
1388 continue
1389 if c in ['b', 'B', '\x1b']:
1390 r = r - inc - inc
1391 if r < 0: r = 0
1392 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1393 r = r + inc
1394
1395 finally:
1396 if tty:
1397 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1398
1399def plainpager(text):
1400 """Simply print unformatted text. This is the ultimate fallback."""
1401 sys.stdout.write(plain(text))
1402
1403def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001404 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001405 if inspect.ismodule(thing):
1406 if thing.__name__ in sys.builtin_module_names:
1407 return 'built-in module ' + thing.__name__
1408 if hasattr(thing, '__path__'):
1409 return 'package ' + thing.__name__
1410 else:
1411 return 'module ' + thing.__name__
1412 if inspect.isbuiltin(thing):
1413 return 'built-in function ' + thing.__name__
1414 if inspect.isclass(thing):
1415 return 'class ' + thing.__name__
1416 if inspect.isfunction(thing):
1417 return 'function ' + thing.__name__
1418 if inspect.ismethod(thing):
1419 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001420 if type(thing) is types.InstanceType:
1421 return 'instance of ' + thing.__class__.__name__
1422 return type(thing).__name__
1423
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001424def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001425 """Locate an object by name or dotted path, importing as necessary."""
Guido van Rossum97dede02003-02-16 01:12:32 +00001426 parts = [part for part in split(path, '.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001427 module, n = None, 0
1428 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001429 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001430 if nextmodule: module, n = nextmodule, n + 1
1431 else: break
1432 if module:
1433 object = module
1434 for part in parts[n:]:
1435 try: object = getattr(object, part)
1436 except AttributeError: return None
1437 return object
1438 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001439 if hasattr(__builtin__, path):
1440 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001441
1442# --------------------------------------- interactive interpreter interface
1443
1444text = TextDoc()
1445html = HTMLDoc()
1446
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001447def resolve(thing, forceload=0):
1448 """Given an object or a path to an object, get the object and its name."""
1449 if isinstance(thing, str):
1450 object = locate(thing, forceload)
1451 if not object:
1452 raise ImportError, 'no Python documentation found for %r' % thing
1453 return object, thing
1454 else:
1455 return thing, getattr(thing, '__name__', None)
1456
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001457def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001458 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001459 try:
1460 object, name = resolve(thing, forceload)
1461 desc = describe(object)
1462 module = inspect.getmodule(object)
1463 if name and '.' in name:
1464 desc += ' in ' + name[:name.rfind('.')]
1465 elif module and module is not object:
1466 desc += ' in module ' + module.__name__
1467 pager(title % desc + '\n\n' + text.document(object, name))
1468 except (ImportError, ErrorDuringImport), value:
1469 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001470
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001471def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001472 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001473 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001474 object, name = resolve(thing, forceload)
1475 page = html.page(describe(object), html.document(object, name))
1476 file = open(name + '.html', 'w')
1477 file.write(page)
1478 file.close()
1479 print 'wrote', name + '.html'
1480 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001481 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001482
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001483def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001484 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001485 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001486 for file in os.listdir(dir):
1487 path = os.path.join(dir, file)
1488 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001489 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001490 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001491 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001492 if modname:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001493 if modname == '__init__':
1494 modname = pkgpath[:-1] # remove trailing period
1495 else:
1496 modname = pkgpath + modname
1497 if modname not in done:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001498 done[modname] = 1
1499 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001500
1501class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001502 keywords = {
1503 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001504 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001505 'break': ('ref/break', 'while for'),
1506 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1507 'continue': ('ref/continue', 'while for'),
1508 'def': ('ref/function', ''),
1509 'del': ('ref/del', 'BASICMETHODS'),
1510 'elif': 'if',
1511 'else': ('ref/if', 'while for'),
1512 'except': 'try',
1513 'exec': ('ref/exec', ''),
1514 'finally': 'try',
1515 'for': ('ref/for', 'break continue while'),
1516 'from': 'import',
1517 'global': ('ref/global', 'NAMESPACES'),
1518 'if': ('ref/if', 'TRUTHVALUE'),
1519 'import': ('ref/import', 'MODULES'),
1520 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1521 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001522 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001523 'not': 'BOOLEAN',
1524 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001525 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001526 'print': ('ref/print', ''),
1527 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001528 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001529 'try': ('ref/try', 'EXCEPTIONS'),
1530 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001531 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001532 }
1533
1534 topics = {
1535 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001536 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001537 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1538 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001539 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001540 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1541 'INTEGER': ('ref/integers', 'int range'),
1542 'FLOAT': ('ref/floating', 'float math'),
1543 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001544 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001545 'MAPPINGS': 'DICTIONARIES',
1546 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1547 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1548 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001549 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001550 'FRAMEOBJECTS': 'TYPES',
1551 'TRACEBACKS': 'TYPES',
1552 'NONE': ('lib/bltin-null-object', ''),
1553 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1554 'FILES': ('lib/bltin-file-objects', ''),
1555 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1556 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1557 'MODULES': ('lib/typesmodules', 'import'),
1558 'PACKAGES': 'import',
1559 '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'),
1560 'OPERATORS': 'EXPRESSIONS',
1561 'PRECEDENCE': 'EXPRESSIONS',
1562 'OBJECTS': ('ref/objects', 'TYPES'),
1563 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001564 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1565 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1566 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1567 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1568 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1569 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1570 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001571 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1572 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1573 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001574 'SCOPING': 'NAMESPACES',
1575 'FRAMES': 'NAMESPACES',
1576 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001577 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1578 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001579 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1580 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001581 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001582 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1583 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001584 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001585 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001586 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001587 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001588 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1589 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001590 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1591 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1592 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1593 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1594 'POWER': ('ref/power', 'EXPRESSIONS'),
1595 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1596 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1597 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1598 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1599 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001600 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001601 'ASSERTION': 'assert',
1602 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001603 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001604 'DELETION': 'del',
1605 'PRINTING': 'print',
1606 'RETURNING': 'return',
1607 'IMPORTING': 'import',
1608 'CONDITIONAL': 'if',
1609 'LOOPING': ('ref/compound', 'for while break continue'),
1610 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001611 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001612 }
1613
1614 def __init__(self, input, output):
1615 self.input = input
1616 self.output = output
1617 self.docdir = None
1618 execdir = os.path.dirname(sys.executable)
1619 homedir = os.environ.get('PYTHONHOME')
1620 for dir in [os.environ.get('PYTHONDOCS'),
1621 homedir and os.path.join(homedir, 'doc'),
1622 os.path.join(execdir, 'doc'),
1623 '/usr/doc/python-docs-' + split(sys.version)[0],
1624 '/usr/doc/python-' + split(sys.version)[0],
1625 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001626 '/usr/doc/python-' + sys.version[:3],
1627 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001628 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1629 self.docdir = dir
1630
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001631 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001632 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001633 self()
1634 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001635 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001636
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001637 def __call__(self, request=None):
1638 if request is not None:
1639 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001640 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001641 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001642 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001643 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001644You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001645If you want to ask for help on a particular object directly from the
1646interpreter, you can type "help(object)". Executing "help('string')"
1647has the same effect as typing a particular string at the help> prompt.
1648''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001649
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001650 def interact(self):
1651 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001652 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001653 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001654 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001655 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001656 except (KeyboardInterrupt, EOFError):
1657 break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001658 request = strip(replace(request, '"', '', "'", ''))
1659 if lower(request) in ['q', 'quit']: break
1660 self.help(request)
1661
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001662 def getline(self, prompt):
1663 """Read one line, using raw_input when available."""
1664 if self.input is sys.stdin:
1665 return raw_input(prompt)
1666 else:
1667 self.output.write(prompt)
1668 self.output.flush()
1669 return self.input.readline()
1670
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001671 def help(self, request):
1672 if type(request) is type(''):
1673 if request == 'help': self.intro()
1674 elif request == 'keywords': self.listkeywords()
1675 elif request == 'topics': self.listtopics()
1676 elif request == 'modules': self.listmodules()
1677 elif request[:8] == 'modules ':
1678 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001679 elif request in self.keywords: self.showtopic(request)
1680 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001681 elif request: doc(request, 'Help on %s:')
1682 elif isinstance(request, Helper): self()
1683 else: doc(request, 'Help on %s:')
1684 self.output.write('\n')
1685
1686 def intro(self):
1687 self.output.write('''
1688Welcome to Python %s! This is the online help utility.
1689
1690If this is your first time using Python, you should definitely check out
1691the tutorial on the Internet at http://www.python.org/doc/tut/.
1692
1693Enter the name of any module, keyword, or topic to get help on writing
1694Python programs and using Python modules. To quit this help utility and
1695return to the interpreter, just type "quit".
1696
1697To get a list of available modules, keywords, or topics, type "modules",
1698"keywords", or "topics". Each module also comes with a one-line summary
1699of what it does; to list the modules whose summaries contain a given word
1700such as "spam", type "modules spam".
1701''' % sys.version[:3])
1702
1703 def list(self, items, columns=4, width=80):
1704 items = items[:]
1705 items.sort()
1706 colw = width / columns
1707 rows = (len(items) + columns - 1) / columns
1708 for row in range(rows):
1709 for col in range(columns):
1710 i = col * rows + row
1711 if i < len(items):
1712 self.output.write(items[i])
1713 if col < columns - 1:
1714 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1715 self.output.write('\n')
1716
1717 def listkeywords(self):
1718 self.output.write('''
1719Here is a list of the Python keywords. Enter any keyword to get more help.
1720
1721''')
1722 self.list(self.keywords.keys())
1723
1724 def listtopics(self):
1725 self.output.write('''
1726Here is a list of available topics. Enter any topic name to get more help.
1727
1728''')
1729 self.list(self.topics.keys())
1730
1731 def showtopic(self, topic):
1732 if not self.docdir:
1733 self.output.write('''
1734Sorry, topic and keyword documentation is not available because the Python
1735HTML documentation files could not be found. If you have installed them,
1736please set the environment variable PYTHONDOCS to indicate their location.
1737''')
1738 return
1739 target = self.topics.get(topic, self.keywords.get(topic))
1740 if not target:
1741 self.output.write('no documentation found for %s\n' % repr(topic))
1742 return
1743 if type(target) is type(''):
1744 return self.showtopic(target)
1745
1746 filename, xrefs = target
1747 filename = self.docdir + '/' + filename + '.html'
1748 try:
1749 file = open(filename)
1750 except:
1751 self.output.write('could not read docs from %s\n' % filename)
1752 return
1753
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001754 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1755 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001756 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1757 file.close()
1758
1759 import htmllib, formatter, StringIO
1760 buffer = StringIO.StringIO()
1761 parser = htmllib.HTMLParser(
1762 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1763 parser.start_table = parser.do_p
1764 parser.end_table = lambda parser=parser: parser.do_p({})
1765 parser.start_tr = parser.do_br
1766 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1767 parser.feed(document)
1768 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1769 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001770 if xrefs:
1771 buffer = StringIO.StringIO()
1772 formatter.DumbWriter(buffer).send_flowing_data(
1773 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1774 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001775
1776 def listmodules(self, key=''):
1777 if key:
1778 self.output.write('''
1779Here is a list of matching modules. Enter any module name to get more help.
1780
1781''')
1782 apropos(key)
1783 else:
1784 self.output.write('''
1785Please wait a moment while I gather a list of all available modules...
1786
1787''')
1788 modules = {}
1789 def callback(path, modname, desc, modules=modules):
1790 if modname and modname[-9:] == '.__init__':
1791 modname = modname[:-9] + ' (package)'
1792 if find(modname, '.') < 0:
1793 modules[modname] = 1
1794 ModuleScanner().run(callback)
1795 self.list(modules.keys())
1796 self.output.write('''
1797Enter any module name to get more help. Or, type "modules spam" to search
1798for modules whose descriptions contain the word "spam".
1799''')
1800
1801help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001802
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001803class Scanner:
1804 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001805 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001806 self.roots = roots[:]
1807 self.state = []
1808 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001809 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001810
1811 def next(self):
1812 if not self.state:
1813 if not self.roots:
1814 return None
1815 root = self.roots.pop(0)
1816 self.state = [(root, self.children(root))]
1817 node, children = self.state[-1]
1818 if not children:
1819 self.state.pop()
1820 return self.next()
1821 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001822 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001823 self.state.append((child, self.children(child)))
1824 return child
1825
1826class ModuleScanner(Scanner):
1827 """An interruptible scanner that searches module synopses."""
1828 def __init__(self):
1829 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001830 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001831 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001832
1833 def submodules(self, (dir, package)):
1834 children = []
1835 for file in os.listdir(dir):
1836 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001837 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001838 children.append((path, package + (package and '.') + file))
1839 else:
1840 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001841 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001842 return children
1843
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001844 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001845 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001846 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001847 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001848 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001849 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001850
Ka-Ping Yee66246962001-04-12 11:59:50 +00001851 def run(self, callback, key=None, completer=None):
1852 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001853 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001854 seen = {}
1855
1856 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001857 if modname != '__main__':
1858 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001859 if key is None:
1860 callback(None, modname, '')
1861 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001862 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001863 if find(lower(modname + ' - ' + desc), key) >= 0:
1864 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001865
1866 while not self.quit:
1867 node = self.next()
1868 if not node: break
1869 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001870 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001871 if os.path.isfile(path) and modname:
1872 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001873 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001874 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001875 if key is None:
1876 callback(path, modname, '')
1877 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001878 desc = synopsis(path) or ''
1879 if find(lower(modname + ' - ' + desc), key) >= 0:
1880 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001881 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001882
1883def apropos(key):
1884 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001885 def callback(path, modname, desc):
1886 if modname[-9:] == '.__init__':
1887 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001888 print modname, desc and '- ' + desc
1889 try: import warnings
1890 except ImportError: pass
1891 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001892 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001893
1894# --------------------------------------------------- web browser interface
1895
Ka-Ping Yee66246962001-04-12 11:59:50 +00001896def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001897 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001898
1899 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1900 class Message(mimetools.Message):
1901 def __init__(self, fp, seekable=1):
1902 Message = self.__class__
1903 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1904 self.encodingheader = self.getheader('content-transfer-encoding')
1905 self.typeheader = self.getheader('content-type')
1906 self.parsetype()
1907 self.parseplist()
1908
1909 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1910 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001911 try:
1912 self.send_response(200)
1913 self.send_header('Content-Type', 'text/html')
1914 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001915 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001916 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001917
1918 def do_GET(self):
1919 path = self.path
1920 if path[-5:] == '.html': path = path[:-5]
1921 if path[:1] == '/': path = path[1:]
1922 if path and path != '.':
1923 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001924 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001925 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001926 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001927 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001928 if obj:
1929 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001930 else:
1931 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001932'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001933 else:
1934 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001935'<big><big><strong>Python: Index of Modules</strong></big></big>',
1936'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001937 def bltinlink(name):
1938 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001939 names = filter(lambda x: x != '__main__',
1940 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001941 contents = html.multicolumn(names, bltinlink)
1942 indices = ['<p>' + html.bigsection(
1943 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1944
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001945 seen = {}
1946 for dir in pathdirs():
1947 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001948 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001949<font color="#909090" face="helvetica, arial"><strong>
1950pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001951 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001952
1953 def log_message(self, *args): pass
1954
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001955 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001956 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001957 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001958 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001959 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001960 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001961 self.base.__init__(self, self.address, self.handler)
1962
1963 def serve_until_quit(self):
1964 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001965 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001966 while not self.quit:
1967 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1968 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001969
1970 def server_activate(self):
1971 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001972 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001973
1974 DocServer.base = BaseHTTPServer.HTTPServer
1975 DocServer.handler = DocHandler
1976 DocHandler.MessageClass = Message
1977 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001978 try:
1979 DocServer(port, callback).serve_until_quit()
1980 except (KeyboardInterrupt, select.error):
1981 pass
1982 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001983 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001984
1985# ----------------------------------------------------- graphical interface
1986
1987def gui():
1988 """Graphical interface (starts web server and pops up a control window)."""
1989 class GUI:
1990 def __init__(self, window, port=7464):
1991 self.window = window
1992 self.server = None
1993 self.scanner = None
1994
1995 import Tkinter
1996 self.server_frm = Tkinter.Frame(window)
1997 self.title_lbl = Tkinter.Label(self.server_frm,
1998 text='Starting server...\n ')
1999 self.open_btn = Tkinter.Button(self.server_frm,
2000 text='open browser', command=self.open, state='disabled')
2001 self.quit_btn = Tkinter.Button(self.server_frm,
2002 text='quit serving', command=self.quit, state='disabled')
2003
2004 self.search_frm = Tkinter.Frame(window)
2005 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
2006 self.search_ent = Tkinter.Entry(self.search_frm)
2007 self.search_ent.bind('<Return>', self.search)
2008 self.stop_btn = Tkinter.Button(self.search_frm,
2009 text='stop', pady=0, command=self.stop, state='disabled')
2010 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002011 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002012 self.stop_btn.pack(side='right')
2013
2014 self.window.title('pydoc')
2015 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2016 self.title_lbl.pack(side='top', fill='x')
2017 self.open_btn.pack(side='left', fill='x', expand=1)
2018 self.quit_btn.pack(side='right', fill='x', expand=1)
2019 self.server_frm.pack(side='top', fill='x')
2020
2021 self.search_lbl.pack(side='left')
2022 self.search_ent.pack(side='right', fill='x', expand=1)
2023 self.search_frm.pack(side='top', fill='x')
2024 self.search_ent.focus_set()
2025
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002026 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002027 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002028 self.result_lst.bind('<Button-1>', self.select)
2029 self.result_lst.bind('<Double-Button-1>', self.goto)
2030 self.result_scr = Tkinter.Scrollbar(window,
2031 orient='vertical', command=self.result_lst.yview)
2032 self.result_lst.config(yscrollcommand=self.result_scr.set)
2033
2034 self.result_frm = Tkinter.Frame(window)
2035 self.goto_btn = Tkinter.Button(self.result_frm,
2036 text='go to selected', command=self.goto)
2037 self.hide_btn = Tkinter.Button(self.result_frm,
2038 text='hide results', command=self.hide)
2039 self.goto_btn.pack(side='left', fill='x', expand=1)
2040 self.hide_btn.pack(side='right', fill='x', expand=1)
2041
2042 self.window.update()
2043 self.minwidth = self.window.winfo_width()
2044 self.minheight = self.window.winfo_height()
2045 self.bigminheight = (self.server_frm.winfo_reqheight() +
2046 self.search_frm.winfo_reqheight() +
2047 self.result_lst.winfo_reqheight() +
2048 self.result_frm.winfo_reqheight())
2049 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2050 self.expanded = 0
2051 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2052 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002053 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002054
2055 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002056 threading.Thread(
2057 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002058
2059 def ready(self, server):
2060 self.server = server
2061 self.title_lbl.config(
2062 text='Python documentation server at\n' + server.url)
2063 self.open_btn.config(state='normal')
2064 self.quit_btn.config(state='normal')
2065
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002066 def open(self, event=None, url=None):
2067 url = url or self.server.url
2068 try:
2069 import webbrowser
2070 webbrowser.open(url)
2071 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002072 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002073 os.system('start "%s"' % url)
2074 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002075 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002076 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002077 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002078 else:
2079 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2080 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002081
2082 def quit(self, event=None):
2083 if self.server:
2084 self.server.quit = 1
2085 self.window.quit()
2086
2087 def search(self, event=None):
2088 key = self.search_ent.get()
2089 self.stop_btn.pack(side='right')
2090 self.stop_btn.config(state='normal')
2091 self.search_lbl.config(text='Searching for "%s"...' % key)
2092 self.search_ent.forget()
2093 self.search_lbl.pack(side='left')
2094 self.result_lst.delete(0, 'end')
2095 self.goto_btn.config(state='disabled')
2096 self.expand()
2097
2098 import threading
2099 if self.scanner:
2100 self.scanner.quit = 1
2101 self.scanner = ModuleScanner()
2102 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002103 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002104
2105 def update(self, path, modname, desc):
2106 if modname[-9:] == '.__init__':
2107 modname = modname[:-9] + ' (package)'
2108 self.result_lst.insert('end',
2109 modname + ' - ' + (desc or '(no description)'))
2110
2111 def stop(self, event=None):
2112 if self.scanner:
2113 self.scanner.quit = 1
2114 self.scanner = None
2115
2116 def done(self):
2117 self.scanner = None
2118 self.search_lbl.config(text='Search for')
2119 self.search_lbl.pack(side='left')
2120 self.search_ent.pack(side='right', fill='x', expand=1)
2121 if sys.platform != 'win32': self.stop_btn.forget()
2122 self.stop_btn.config(state='disabled')
2123
2124 def select(self, event=None):
2125 self.goto_btn.config(state='normal')
2126
2127 def goto(self, event=None):
2128 selection = self.result_lst.curselection()
2129 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002130 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002131 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002132
2133 def collapse(self):
2134 if not self.expanded: return
2135 self.result_frm.forget()
2136 self.result_scr.forget()
2137 self.result_lst.forget()
2138 self.bigwidth = self.window.winfo_width()
2139 self.bigheight = self.window.winfo_height()
2140 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2141 self.window.wm_minsize(self.minwidth, self.minheight)
2142 self.expanded = 0
2143
2144 def expand(self):
2145 if self.expanded: return
2146 self.result_frm.pack(side='bottom', fill='x')
2147 self.result_scr.pack(side='right', fill='y')
2148 self.result_lst.pack(side='top', fill='both', expand=1)
2149 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2150 self.window.wm_minsize(self.minwidth, self.bigminheight)
2151 self.expanded = 1
2152
2153 def hide(self, event=None):
2154 self.stop()
2155 self.collapse()
2156
2157 import Tkinter
2158 try:
Martin v. Löwise09bd932004-08-22 16:13:26 +00002159 root = Tkinter.Tk()
2160 # Tk will crash if pythonw.exe has an XP .manifest
2161 # file and the root has is not destroyed explicitly.
2162 # If the problem is ever fixed in Tk, the explicit
2163 # destroy can go.
2164 try:
2165 gui = GUI(root)
2166 root.mainloop()
2167 finally:
2168 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002169 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002170 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002171
2172# -------------------------------------------------- command-line interface
2173
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002174def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002175 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002176
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002177def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002178 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002179 import getopt
2180 class BadUsage: pass
2181
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002182 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002183 scriptdir = os.path.dirname(sys.argv[0])
2184 if scriptdir in sys.path:
2185 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002186 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002187
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002188 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002189 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002190 writing = 0
2191
2192 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002193 if opt == '-g':
2194 gui()
2195 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002196 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002197 apropos(val)
2198 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002199 if opt == '-p':
2200 try:
2201 port = int(val)
2202 except ValueError:
2203 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002204 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002205 print 'pydoc server ready at %s' % server.url
2206 def stopped():
2207 print 'pydoc server stopped'
2208 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002209 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002210 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002211 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002212
2213 if not args: raise BadUsage
2214 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002215 if ispath(arg) and not os.path.exists(arg):
2216 print 'file %r does not exist' % arg
2217 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002218 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002219 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002220 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002221 if writing:
2222 if ispath(arg) and os.path.isdir(arg):
2223 writedocs(arg)
2224 else:
2225 writedoc(arg)
2226 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002227 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002228 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002229 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002230
2231 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002232 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002233 print """pydoc - the Python documentation tool
2234
2235%s <name> ...
2236 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002237 Python keyword, topic, function, module, or package, or a dotted
2238 reference to a class or function within a module or module in a
2239 package. If <name> contains a '%s', it is used as the path to a
2240 Python source file to document. If name is 'keywords', 'topics',
2241 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002242
2243%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002244 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002245
2246%s -p <port>
2247 Start an HTTP server on the given port on the local machine.
2248
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002249%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002250 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002251
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002252%s -w <name> ...
2253 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002254 directory. If <name> contains a '%s', it is treated as a filename; if
2255 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002256""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002257
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002258if __name__ == '__main__': cli()