blob: daec8ab8191e152bab909c11a0154d2a3b179add [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öwisac37f3d2004-08-22 16:08:04 +000040__credits__ = u"""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.
44
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000045Mynd you, møøse bites Kan be pretty nasti..."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000046
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000047# Known bugs that can't be fixed here:
48# - imp.load_module() cannot be prevented from clobbering existing
49# loaded modules, so calling synopsis() on a binary module file
50# changes the contents of any existing module with the same name.
51# - If the __file__ attribute on a module is a relative path and
52# the current directory is changed with os.chdir(), an incorrect
53# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000054
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +000055import sys, imp, os, re, types, inspect, __builtin__
Ka-Ping Yeedd175342001-02-27 14:43:46 +000056from repr import Repr
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000057from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
Raymond Hettinger756b3f32004-01-29 06:37:52 +000058from collections import deque
Ka-Ping Yeedd175342001-02-27 14:43:46 +000059
60# --------------------------------------------------------- common routines
61
Ka-Ping Yeedd175342001-02-27 14:43:46 +000062def pathdirs():
63 """Convert sys.path into a list of absolute, existing, unique paths."""
64 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000065 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000066 for dir in sys.path:
67 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000068 normdir = os.path.normcase(dir)
69 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000070 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000071 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000072 return dirs
73
74def getdoc(object):
75 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000076 result = inspect.getdoc(object) or inspect.getcomments(object)
Ka-Ping Yee239432a2001-03-02 02:45:08 +000077 return result and re.sub('^ *\n', '', rstrip(result)) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000078
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000079def splitdoc(doc):
80 """Split a doc string into a synopsis line (if any) and the rest."""
81 lines = split(strip(doc), '\n')
82 if len(lines) == 1:
83 return lines[0], ''
84 elif len(lines) >= 2 and not rstrip(lines[1]):
85 return lines[0], join(lines[2:], '\n')
86 return '', join(lines, '\n')
87
Ka-Ping Yeedd175342001-02-27 14:43:46 +000088def classname(object, modname):
89 """Get a class name and qualify it with a module name if necessary."""
90 name = object.__name__
91 if object.__module__ != modname:
92 name = object.__module__ + '.' + name
93 return name
94
Ka-Ping Yeedec96e92001-04-13 09:55:49 +000095def isdata(object):
96 """Check if an object is of a type that probably means it's data."""
97 return not (inspect.ismodule(object) or inspect.isclass(object) or
98 inspect.isroutine(object) or inspect.isframe(object) or
99 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000100
101def replace(text, *pairs):
102 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000103 while pairs:
104 text = join(split(text, pairs[0]), pairs[1])
105 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000106 return text
107
108def cram(text, maxlen):
109 """Omit part of a string if needed to make it fit in a maximum length."""
110 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000111 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000112 post = max(0, maxlen-3-pre)
113 return text[:pre] + '...' + text[len(text)-post:]
114 return text
115
Brett Cannon84601f12004-06-19 01:22:48 +0000116_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000117def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000118 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000119 # The behaviour of %p is implementation-dependent in terms of case.
120 if _re_stripid.search(repr(Exception)):
121 return _re_stripid.sub(r'\1', text)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000122 return text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000123
Brett Cannonc6c1f472004-06-19 01:02:51 +0000124def _is_some_method(obj):
125 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000126
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000127def allmethods(cl):
128 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000129 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000130 methods[key] = 1
131 for base in cl.__bases__:
132 methods.update(allmethods(base)) # all your base are belong to us
133 for key in methods.keys():
134 methods[key] = getattr(cl, key)
135 return methods
136
Tim Petersfa26f7c2001-09-24 08:05:11 +0000137def _split_list(s, predicate):
138 """Split sequence s via predicate, and return pair ([true], [false]).
139
140 The return value is a 2-tuple of lists,
141 ([x for x in s if predicate(x)],
142 [x for x in s if not predicate(x)])
143 """
144
Tim Peters28355492001-09-23 21:29:55 +0000145 yes = []
146 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000147 for x in s:
148 if predicate(x):
149 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000150 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000151 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000152 return yes, no
153
Skip Montanaroa5616d22004-06-11 04:46:12 +0000154def visiblename(name, all=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000155 """Decide whether to show documentation on a variable."""
156 # Certain special names are redundant.
157 if name in ['__builtins__', '__doc__', '__file__', '__path__',
158 '__module__', '__name__']: return 0
159 # Private names are hidden, but special names are displayed.
160 if name.startswith('__') and name.endswith('__'): return 1
Skip Montanaroa5616d22004-06-11 04:46:12 +0000161 if all is not None:
162 # only document that which the programmer exported in __all__
163 return name in all
164 else:
165 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000166
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000167# ----------------------------------------------------- module manipulation
168
169def ispackage(path):
170 """Guess whether a path refers to a package directory."""
171 if os.path.isdir(path):
172 for ext in ['.py', '.pyc', '.pyo']:
173 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000174 return True
175 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000176
177def synopsis(filename, cache={}):
178 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000179 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000180 lastupdate, result = cache.get(filename, (0, None))
181 if lastupdate < mtime:
182 info = inspect.getmoduleinfo(filename)
183 file = open(filename)
184 if info and 'b' in info[2]: # binary modules have to be imported
185 try: module = imp.load_module('__temp__', file, filename, info[1:])
186 except: return None
187 result = split(module.__doc__ or '', '\n')[0]
188 del sys.modules['__temp__']
189 else: # text modules can be directly examined
190 line = file.readline()
191 while line[:1] == '#' or not strip(line):
192 line = file.readline()
193 if not line: break
194 line = strip(line)
195 if line[:4] == 'r"""': line = line[1:]
196 if line[:3] == '"""':
197 line = line[3:]
198 if line[-1:] == '\\': line = line[:-1]
199 while not strip(line):
200 line = file.readline()
201 if not line: break
202 result = strip(split(line, '"""')[0])
203 else: result = None
204 file.close()
205 cache[filename] = (mtime, result)
206 return result
207
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000208class ErrorDuringImport(Exception):
209 """Errors that occurred while trying to import something to document it."""
210 def __init__(self, filename, (exc, value, tb)):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000211 self.filename = filename
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000212 self.exc = exc
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000213 self.value = value
214 self.tb = tb
215
216 def __str__(self):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000217 exc = self.exc
218 if type(exc) is types.ClassType:
219 exc = exc.__name__
220 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000221
222def importfile(path):
223 """Import a Python source file or compiled file given its path."""
224 magic = imp.get_magic()
225 file = open(path, 'r')
226 if file.read(len(magic)) == magic:
227 kind = imp.PY_COMPILED
228 else:
229 kind = imp.PY_SOURCE
230 file.close()
231 filename = os.path.basename(path)
232 name, ext = os.path.splitext(filename)
233 file = open(path, 'r')
234 try:
235 module = imp.load_module(name, file, path, (ext, 'r', kind))
236 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000237 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000238 file.close()
239 return module
240
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000241def safeimport(path, forceload=0, cache={}):
242 """Import a module; handle errors; return None if the module isn't found.
243
244 If the module *is* found but an exception occurs, it's wrapped in an
245 ErrorDuringImport exception and reraised. Unlike __import__, if a
246 package path is specified, the module at the end of the path is returned,
247 not the package at the beginning. If the optional 'forceload' argument
248 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Raymond Hettinger54f02222002-06-01 14:18:47 +0000249 if forceload and path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000250 # This is the only way to be sure. Checking the mtime of the file
251 # isn't good enough (e.g. what if the module contains a class that
252 # inherits from another module that has changed?).
253 if path not in sys.builtin_module_names:
254 # Python never loads a dynamic extension a second time from the
255 # same path, even if the file is changed or missing. Deleting
256 # the entry in sys.modules doesn't help for dynamic extensions,
257 # so we're not even going to try to keep them up to date.
258 info = inspect.getmoduleinfo(sys.modules[path].__file__)
259 if info[3] != imp.C_EXTENSION:
260 cache[path] = sys.modules[path] # prevent module from clearing
261 del sys.modules[path]
262 try:
263 module = __import__(path)
264 except:
265 # Did the error occur before or after the module was found?
266 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000267 if path in sys.modules:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000268 # An error occured while executing the imported module.
269 raise ErrorDuringImport(sys.modules[path].__file__, info)
270 elif exc is SyntaxError:
271 # A SyntaxError occurred before we could execute the module.
272 raise ErrorDuringImport(value.filename, info)
273 elif exc is ImportError and \
274 split(lower(str(value)))[:2] == ['no', 'module']:
275 # The module was not found.
276 return None
277 else:
278 # Some other error occurred during the importing process.
279 raise ErrorDuringImport(path, sys.exc_info())
280 for part in split(path, '.')[1:]:
281 try: module = getattr(module, part)
282 except AttributeError: return None
283 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000284
285# ---------------------------------------------------- formatter base class
286
287class Doc:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000288 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000289 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000290 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000291 # 'try' clause is to attempt to handle the possibility that inspect
292 # identifies something in a way that pydoc itself has issues handling;
293 # think 'super' and how it is a descriptor (which raises the exception
294 # by lacking a __name__ attribute) and an instance.
295 try:
296 if inspect.ismodule(object): return self.docmodule(*args)
297 if inspect.isclass(object): return self.docclass(*args)
298 if inspect.isroutine(object): return self.docroutine(*args)
299 except AttributeError:
300 pass
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:
Tim Peters3e767d12001-09-25 00:01:06 +0000727 push('<dl><dt><strong>%s</strong></dt>\n' % name)
728 if value.__doc__ is not None:
729 doc = self.markup(value.__doc__, self.preformat,
730 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000731 push('<dd><tt>%s</tt></dd>\n' % doc)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000732 for attr, tag in [('fget', '<em>get</em>'),
733 ('fset', '<em>set</em>'),
734 ('fdel', '<em>delete</em>')]:
Tim Peters3e767d12001-09-25 00:01:06 +0000735 func = getattr(value, attr)
736 if func is not None:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000737 base = self.document(func, tag, mod,
Tim Peters3e767d12001-09-25 00:01:06 +0000738 funcs, classes, mdict, object)
739 push('<dd>%s</dd>\n' % base)
740 push('</dl>\n')
Tim Petersb47879b2001-09-24 04:47:19 +0000741 return attrs
742
Tim Petersfa26f7c2001-09-24 08:05:11 +0000743 def spilldata(msg, attrs, predicate):
744 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000745 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000746 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000747 push(msg)
748 for name, kind, homecls, value in ok:
749 base = self.docother(getattr(object, name), name, mod)
Martin v. Löwise59e2ba2003-05-03 09:09:02 +0000750 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000751 doc = getattr(value, "__doc__", None)
752 else:
753 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000754 if doc is None:
755 push('<dl><dt>%s</dl>\n' % base)
756 else:
757 doc = self.markup(getdoc(value), self.preformat,
758 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000759 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000760 push('<dl><dt>%s%s</dl>\n' % (base, doc))
761 push('\n')
762 return attrs
763
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000764 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
765 inspect.classify_class_attrs(object))
Tim Petersb47879b2001-09-24 04:47:19 +0000766 mdict = {}
767 for key, kind, homecls, value in attrs:
768 mdict[key] = anchor = '#' + name + '-' + key
769 value = getattr(object, key)
770 try:
771 # The value may not be hashable (e.g., a data attr with
772 # a dict or list value).
773 mdict[value] = anchor
774 except TypeError:
775 pass
776
Tim Petersfa26f7c2001-09-24 08:05:11 +0000777 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000778 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000779 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000780 else:
781 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000782 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
783
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000784 if thisclass is __builtin__.object:
785 attrs = inherited
786 continue
787 elif thisclass is object:
788 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000789 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000790 tag = 'inherited from %s' % self.classlink(thisclass,
791 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000792 tag += ':<br>\n'
793
794 # Sort attrs by name.
Raymond Hettinger6b59f5f2003-10-16 05:53:16 +0000795 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000796
797 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000798 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000799 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000800 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000801 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000802 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000803 lambda t: t[1] == 'static method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000804 attrs = spillproperties('Properties %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000805 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000806 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000807 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000808 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000809 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000810
811 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000812
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000813 if name == realname:
814 title = '<a name="%s">class <strong>%s</strong></a>' % (
815 name, realname)
816 else:
817 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
818 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000819 if bases:
820 parents = []
821 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000822 parents.append(self.classlink(base, object.__module__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000823 title = title + '(%s)' % join(parents, ', ')
Tim Peters2306d242001-09-25 03:18:32 +0000824 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000825 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000826
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000827 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000828
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000829 def formatvalue(self, object):
830 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000831 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000832
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000833 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000834 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000835 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000836 realname = object.__name__
837 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000838 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000839 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000840 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000841 if inspect.ismethod(object):
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +0000842 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000843 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000844 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000845 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000846 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000847 if object.im_self:
848 note = ' method of %s instance' % self.classlink(
849 object.im_self.__class__, mod)
850 else:
851 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000852 object = object.im_func
853
854 if name == realname:
855 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
856 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000857 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000858 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000859 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000860 cl.__name__ + '-' + realname, realname)
861 skipdocs = 1
862 else:
863 reallink = realname
864 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
865 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000866 if inspect.isfunction(object):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000867 args, varargs, varkw, defaults = inspect.getargspec(object)
868 argspec = inspect.formatargspec(
869 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000870 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000871 title = '<strong>%s</strong> <em>lambda</em> ' % name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000872 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000873 else:
874 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000875
Tim Peters2306d242001-09-25 03:18:32 +0000876 decl = title + argspec + (note and self.grey(
877 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000878
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000879 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000880 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000881 else:
882 doc = self.markup(
883 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000884 doc = doc and '<dd><tt>%s</tt></dd>' % doc
885 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000886
Tim Peters8dd7ade2001-10-18 19:56:17 +0000887 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000888 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000889 lhs = name and '<strong>%s</strong> = ' % name or ''
890 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000891
892 def index(self, dir, shadowed=None):
893 """Generate an HTML index for a directory of modules."""
894 modpkgs = []
895 if shadowed is None: shadowed = {}
896 seen = {}
897 files = os.listdir(dir)
898
899 def found(name, ispackage,
900 modpkgs=modpkgs, shadowed=shadowed, seen=seen):
Raymond Hettinger4f759d82002-11-02 02:02:46 +0000901 if name not in seen:
902 modpkgs.append((name, '', ispackage, name in shadowed))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000903 seen[name] = 1
904 shadowed[name] = 1
905
906 # Package spam/__init__.py takes precedence over module spam.py.
907 for file in files:
908 path = os.path.join(dir, file)
909 if ispackage(path): found(file, 1)
910 for file in files:
911 path = os.path.join(dir, file)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000912 if os.path.isfile(path):
913 modname = inspect.getmodulename(file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000914 if modname: found(modname, 0)
915
916 modpkgs.sort()
917 contents = self.multicolumn(modpkgs, self.modpkglink)
918 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
919
920# -------------------------------------------- text documentation generator
921
922class TextRepr(Repr):
923 """Class for safely making a text representation of a Python object."""
924 def __init__(self):
925 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000926 self.maxlist = self.maxtuple = 20
927 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000928 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000929
930 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000931 if hasattr(type(x), '__name__'):
932 methodname = 'repr_' + join(split(type(x).__name__), '_')
933 if hasattr(self, methodname):
934 return getattr(self, methodname)(x, level)
935 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000936
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000937 def repr_string(self, x, level):
938 test = cram(x, self.maxstring)
939 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000940 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000941 # Backslashes are only literal in the string and are never
942 # needed to make any special characters, so show a raw string.
943 return 'r' + testrepr[0] + test + testrepr[0]
944 return testrepr
945
Skip Montanarodf708782002-03-07 22:58:02 +0000946 repr_str = repr_string
947
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000948 def repr_instance(self, x, level):
949 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000950 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000951 except:
952 return '<%s instance>' % x.__class__.__name__
953
954class TextDoc(Doc):
955 """Formatter class for text documentation."""
956
957 # ------------------------------------------- text formatting utilities
958
959 _repr_instance = TextRepr()
960 repr = _repr_instance.repr
961
962 def bold(self, text):
963 """Format a string in bold by overstriking."""
964 return join(map(lambda ch: ch + '\b' + ch, text), '')
965
966 def indent(self, text, prefix=' '):
967 """Indent text by prepending a given prefix to each line."""
968 if not text: return ''
969 lines = split(text, '\n')
970 lines = map(lambda line, prefix=prefix: prefix + line, lines)
971 if lines: lines[-1] = rstrip(lines[-1])
972 return join(lines, '\n')
973
974 def section(self, title, contents):
975 """Format a section with a given heading."""
976 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
977
978 # ---------------------------------------------- type-specific routines
979
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000980 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000981 """Render in text a class tree as returned by inspect.getclasstree()."""
982 result = ''
983 for entry in tree:
984 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000985 c, bases = entry
986 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000987 if bases and bases != (parent,):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000988 parents = map(lambda c, m=modname: classname(c, m), bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000989 result = result + '(%s)' % join(parents, ', ')
990 result = result + '\n'
991 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000992 result = result + self.formattree(
993 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000994 return result
995
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000996 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000997 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000998 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000999 synop, desc = splitdoc(getdoc(object))
1000 result = self.section('NAME', name + (synop and ' - ' + synop))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001001
1002 try:
Skip Montanaroa5616d22004-06-11 04:46:12 +00001003 all = object.__all__
1004 except AttributeError:
1005 all = None
1006
1007 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001008 file = inspect.getabsfile(object)
1009 except TypeError:
1010 file = '(built-in)'
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001011 result = result + self.section('FILE', file)
Skip Montanaro4997a692003-09-10 16:47:51 +00001012
1013 docloc = self.getdocloc(object)
1014 if docloc is not None:
1015 result = result + self.section('MODULE DOCS', docloc)
1016
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001017 if desc:
1018 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001019
1020 classes = []
1021 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001022 # if __all__ exists, believe it. Otherwise use old heuristic.
1023 if (all is not None
1024 or (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001025 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001026 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001027 funcs = []
1028 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001029 # if __all__ exists, believe it. Otherwise use old heuristic.
1030 if (all is not None or
1031 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001032 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001033 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001034 data = []
1035 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001036 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001037 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001038
1039 if hasattr(object, '__path__'):
1040 modpkgs = []
1041 for file in os.listdir(object.__path__[0]):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001042 path = os.path.join(object.__path__[0], file)
1043 modname = inspect.getmodulename(file)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001044 if modname != '__init__':
1045 if modname and modname not in modpkgs:
1046 modpkgs.append(modname)
1047 elif ispackage(path):
1048 modpkgs.append(file + ' (package)')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001049 modpkgs.sort()
1050 result = result + self.section(
1051 'PACKAGE CONTENTS', join(modpkgs, '\n'))
1052
1053 if classes:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001054 classlist = map(lambda (key, value): value, classes)
1055 contents = [self.formattree(
1056 inspect.getclasstree(classlist, 1), name)]
1057 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001058 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001059 result = result + self.section('CLASSES', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001060
1061 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001062 contents = []
1063 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001064 contents.append(self.document(value, key, name))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001065 result = result + self.section('FUNCTIONS', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001066
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001067 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001068 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001069 for key, value in data:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001070 contents.append(self.docother(value, key, name, 70))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001071 result = result + self.section('DATA', join(contents, '\n'))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001072
1073 if hasattr(object, '__version__'):
1074 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001075 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1076 version = strip(version[11:-1])
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001077 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001078 if hasattr(object, '__date__'):
1079 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001080 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001081 result = result + self.section('AUTHOR', str(object.__author__))
1082 if hasattr(object, '__credits__'):
1083 result = result + self.section('CREDITS', str(object.__credits__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001084 return result
1085
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001086 def docclass(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001087 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001088 realname = object.__name__
1089 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001090 bases = object.__bases__
1091
Tim Petersc86f6ca2001-09-26 21:31:51 +00001092 def makename(c, m=object.__module__):
1093 return classname(c, m)
1094
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001095 if name == realname:
1096 title = 'class ' + self.bold(realname)
1097 else:
1098 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001099 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001100 parents = map(makename, bases)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001101 title = title + '(%s)' % join(parents, ', ')
1102
1103 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001104 contents = doc and [doc + '\n'] or []
1105 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001106
Tim Petersc86f6ca2001-09-26 21:31:51 +00001107 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001108 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001109 if len(mro) > 2:
1110 push("Method resolution order:")
1111 for base in mro:
1112 push(' ' + makename(base))
1113 push('')
1114
Tim Petersf4aad8e2001-09-24 22:40:47 +00001115 # Cute little class to pump out a horizontal rule between sections.
1116 class HorizontalRule:
1117 def __init__(self):
1118 self.needone = 0
1119 def maybe(self):
1120 if self.needone:
1121 push('-' * 70)
1122 self.needone = 1
1123 hr = HorizontalRule()
1124
Tim Peters28355492001-09-23 21:29:55 +00001125 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001126 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001127 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001128 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001129 push(msg)
1130 for name, kind, homecls, value in ok:
1131 push(self.document(getattr(object, name),
1132 name, mod, object))
1133 return attrs
1134
Tim Petersfa26f7c2001-09-24 08:05:11 +00001135 def spillproperties(msg, attrs, predicate):
1136 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001137 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001138 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001139 push(msg)
1140 for name, kind, homecls, value in ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001141 push(name)
1142 need_blank_after_doc = 0
1143 doc = getdoc(value) or ''
1144 if doc:
1145 push(self.indent(doc))
1146 need_blank_after_doc = 1
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001147 for attr, tag in [('fget', '<get>'),
1148 ('fset', '<set>'),
1149 ('fdel', '<delete>')]:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001150 func = getattr(value, attr)
1151 if func is not None:
1152 if need_blank_after_doc:
1153 push('')
1154 need_blank_after_doc = 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001155 base = self.document(func, tag, mod)
Tim Petersf4aad8e2001-09-24 22:40:47 +00001156 push(self.indent(base))
Tim Peters28355492001-09-23 21:29:55 +00001157 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001158
Tim Petersfa26f7c2001-09-24 08:05:11 +00001159 def spilldata(msg, attrs, predicate):
1160 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001161 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001162 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001163 push(msg)
1164 for name, kind, homecls, value in ok:
Martin v. Löwise59e2ba2003-05-03 09:09:02 +00001165 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +00001166 doc = getattr(value, "__doc__", None)
1167 else:
1168 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001169 push(self.docother(getattr(object, name),
1170 name, mod, 70, doc) + '\n')
1171 return attrs
1172
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001173 attrs = filter(lambda (name, kind, cls, value): visiblename(name),
1174 inspect.classify_class_attrs(object))
Tim Petersfa26f7c2001-09-24 08:05:11 +00001175 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001176 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001177 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001178 else:
1179 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001180 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1181
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001182 if thisclass is __builtin__.object:
1183 attrs = inherited
1184 continue
1185 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001186 tag = "defined here"
1187 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001188 tag = "inherited from %s" % classname(thisclass,
1189 object.__module__)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001190 filter(lambda t: not t[0].startswith('_'), attrs)
Tim Peters28355492001-09-23 21:29:55 +00001191
1192 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001193 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001194
1195 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001196 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001197 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001198 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001199 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001200 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001201 lambda t: t[1] == 'static method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001202 attrs = spillproperties("Properties %s:\n" % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +00001203 lambda t: t[1] == 'property')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001204 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1205 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001206 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001207 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001208
1209 contents = '\n'.join(contents)
1210 if not contents:
1211 return title + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001212 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1213
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001214 def formatvalue(self, object):
1215 """Format an argument default value as text."""
1216 return '=' + self.repr(object)
1217
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001218 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001219 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001220 realname = object.__name__
1221 name = name or realname
1222 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001223 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001224 if inspect.ismethod(object):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001225 imclass = object.im_class
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001226 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001227 if imclass is not cl:
1228 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001229 else:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001230 if object.im_self:
1231 note = ' method of %s instance' % classname(
1232 object.im_self.__class__, mod)
1233 else:
1234 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001235 object = object.im_func
1236
1237 if name == realname:
1238 title = self.bold(realname)
1239 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001240 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001241 cl.__dict__[realname] is object):
1242 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001243 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001244 if inspect.isfunction(object):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001245 args, varargs, varkw, defaults = inspect.getargspec(object)
1246 argspec = inspect.formatargspec(
1247 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001248 if realname == '<lambda>':
1249 title = 'lambda'
1250 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001251 else:
1252 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001253 decl = title + argspec + note
1254
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001255 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001256 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001257 else:
1258 doc = getdoc(object) or ''
1259 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001260
Tim Peters28355492001-09-23 21:29:55 +00001261 def docother(self, object, name=None, mod=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001262 """Produce text documentation for a data object."""
1263 repr = self.repr(object)
1264 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001265 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001266 chop = maxlen - len(line)
1267 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001268 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001269 if doc is not None:
1270 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001271 return line
1272
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001273# --------------------------------------------------------- user interfaces
1274
1275def pager(text):
1276 """The first time this is called, determine what kind of pager to use."""
1277 global pager
1278 pager = getpager()
1279 pager(text)
1280
1281def getpager():
1282 """Decide what method to use for paging through text."""
1283 if type(sys.stdout) is not types.FileType:
1284 return plainpager
1285 if not sys.stdin.isatty() or not sys.stdout.isatty():
1286 return plainpager
Fred Drake0a66fcb2001-07-23 19:44:30 +00001287 if os.environ.get('TERM') in ['dumb', 'emacs']:
Fred Drake5e9eb982001-07-23 19:48:10 +00001288 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001289 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001290 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001291 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1292 elif os.environ.get('TERM') in ['dumb', 'emacs']:
1293 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001294 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001295 return lambda text: pipepager(text, os.environ['PAGER'])
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001296 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001297 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001298 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001299 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001300
1301 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001302 (fd, filename) = tempfile.mkstemp()
1303 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001304 try:
1305 if hasattr(os, 'system') and os.system('more %s' % filename) == 0:
1306 return lambda text: pipepager(text, 'more')
1307 else:
1308 return ttypager
1309 finally:
1310 os.unlink(filename)
1311
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001312def plain(text):
1313 """Remove boldface formatting from text."""
1314 return re.sub('.\b', '', text)
1315
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001316def pipepager(text, cmd):
1317 """Page through text by feeding it to another program."""
1318 pipe = os.popen(cmd, 'w')
1319 try:
1320 pipe.write(text)
1321 pipe.close()
1322 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001323 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001324
1325def tempfilepager(text, cmd):
1326 """Page through text by invoking a program on a temporary file."""
1327 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001328 filename = tempfile.mktemp()
1329 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001330 file.write(text)
1331 file.close()
1332 try:
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001333 os.system(cmd + ' ' + filename)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001334 finally:
1335 os.unlink(filename)
1336
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001337def ttypager(text):
1338 """Page through text on a text terminal."""
1339 lines = split(plain(text), '\n')
1340 try:
1341 import tty
1342 fd = sys.stdin.fileno()
1343 old = tty.tcgetattr(fd)
1344 tty.setcbreak(fd)
1345 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001346 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001347 tty = None
1348 getchar = lambda: sys.stdin.readline()[:-1][:1]
1349
1350 try:
1351 r = inc = os.environ.get('LINES', 25) - 1
1352 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1353 while lines[r:]:
1354 sys.stdout.write('-- more --')
1355 sys.stdout.flush()
1356 c = getchar()
1357
1358 if c in ['q', 'Q']:
1359 sys.stdout.write('\r \r')
1360 break
1361 elif c in ['\r', '\n']:
1362 sys.stdout.write('\r \r' + lines[r] + '\n')
1363 r = r + 1
1364 continue
1365 if c in ['b', 'B', '\x1b']:
1366 r = r - inc - inc
1367 if r < 0: r = 0
1368 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1369 r = r + inc
1370
1371 finally:
1372 if tty:
1373 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1374
1375def plainpager(text):
1376 """Simply print unformatted text. This is the ultimate fallback."""
1377 sys.stdout.write(plain(text))
1378
1379def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001380 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001381 if inspect.ismodule(thing):
1382 if thing.__name__ in sys.builtin_module_names:
1383 return 'built-in module ' + thing.__name__
1384 if hasattr(thing, '__path__'):
1385 return 'package ' + thing.__name__
1386 else:
1387 return 'module ' + thing.__name__
1388 if inspect.isbuiltin(thing):
1389 return 'built-in function ' + thing.__name__
1390 if inspect.isclass(thing):
1391 return 'class ' + thing.__name__
1392 if inspect.isfunction(thing):
1393 return 'function ' + thing.__name__
1394 if inspect.ismethod(thing):
1395 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001396 if type(thing) is types.InstanceType:
1397 return 'instance of ' + thing.__class__.__name__
1398 return type(thing).__name__
1399
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001400def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001401 """Locate an object by name or dotted path, importing as necessary."""
Guido van Rossum97dede02003-02-16 01:12:32 +00001402 parts = [part for part in split(path, '.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001403 module, n = None, 0
1404 while n < len(parts):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001405 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001406 if nextmodule: module, n = nextmodule, n + 1
1407 else: break
1408 if module:
1409 object = module
1410 for part in parts[n:]:
1411 try: object = getattr(object, part)
1412 except AttributeError: return None
1413 return object
1414 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001415 if hasattr(__builtin__, path):
1416 return getattr(__builtin__, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001417
1418# --------------------------------------- interactive interpreter interface
1419
1420text = TextDoc()
1421html = HTMLDoc()
1422
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001423def resolve(thing, forceload=0):
1424 """Given an object or a path to an object, get the object and its name."""
1425 if isinstance(thing, str):
1426 object = locate(thing, forceload)
1427 if not object:
1428 raise ImportError, 'no Python documentation found for %r' % thing
1429 return object, thing
1430 else:
1431 return thing, getattr(thing, '__name__', None)
1432
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001433def doc(thing, title='Python Library Documentation: %s', forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001434 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001435 try:
1436 object, name = resolve(thing, forceload)
1437 desc = describe(object)
1438 module = inspect.getmodule(object)
1439 if name and '.' in name:
1440 desc += ' in ' + name[:name.rfind('.')]
1441 elif module and module is not object:
1442 desc += ' in module ' + module.__name__
1443 pager(title % desc + '\n\n' + text.document(object, name))
1444 except (ImportError, ErrorDuringImport), value:
1445 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001446
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001447def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001448 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001449 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001450 object, name = resolve(thing, forceload)
1451 page = html.page(describe(object), html.document(object, name))
1452 file = open(name + '.html', 'w')
1453 file.write(page)
1454 file.close()
1455 print 'wrote', name + '.html'
1456 except (ImportError, ErrorDuringImport), value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001457 print value
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001458
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001459def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001460 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001461 if done is None: done = {}
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001462 for file in os.listdir(dir):
1463 path = os.path.join(dir, file)
1464 if ispackage(path):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001465 writedocs(path, pkgpath + file + '.', done)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001466 elif os.path.isfile(path):
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001467 modname = inspect.getmodulename(path)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001468 if modname:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001469 if modname == '__init__':
1470 modname = pkgpath[:-1] # remove trailing period
1471 else:
1472 modname = pkgpath + modname
1473 if modname not in done:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001474 done[modname] = 1
1475 writedoc(modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001476
1477class Helper:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001478 keywords = {
1479 'and': 'BOOLEAN',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001480 'assert': ('ref/assert', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001481 'break': ('ref/break', 'while for'),
1482 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1483 'continue': ('ref/continue', 'while for'),
1484 'def': ('ref/function', ''),
1485 'del': ('ref/del', 'BASICMETHODS'),
1486 'elif': 'if',
1487 'else': ('ref/if', 'while for'),
1488 'except': 'try',
1489 'exec': ('ref/exec', ''),
1490 'finally': 'try',
1491 'for': ('ref/for', 'break continue while'),
1492 'from': 'import',
1493 'global': ('ref/global', 'NAMESPACES'),
1494 'if': ('ref/if', 'TRUTHVALUE'),
1495 'import': ('ref/import', 'MODULES'),
1496 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1497 'is': 'COMPARISON',
Neal Norwitz742dde42003-03-30 20:31:34 +00001498 'lambda': ('ref/lambdas', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001499 'not': 'BOOLEAN',
1500 'or': 'BOOLEAN',
Neal Norwitz742dde42003-03-30 20:31:34 +00001501 'pass': ('ref/pass', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001502 'print': ('ref/print', ''),
1503 'raise': ('ref/raise', 'EXCEPTIONS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001504 'return': ('ref/return', 'FUNCTIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001505 'try': ('ref/try', 'EXCEPTIONS'),
1506 'while': ('ref/while', 'break continue if TRUTHVALUE'),
Tim Petersfb05c4e2002-10-30 05:21:00 +00001507 'yield': ('ref/yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001508 }
1509
1510 topics = {
1511 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001512 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001513 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1514 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001515 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001516 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1517 'INTEGER': ('ref/integers', 'int range'),
1518 'FLOAT': ('ref/floating', 'float math'),
1519 'COMPLEX': ('ref/imaginary', 'complex cmath'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001520 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001521 'MAPPINGS': 'DICTIONARIES',
1522 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1523 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1524 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001525 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001526 'FRAMEOBJECTS': 'TYPES',
1527 'TRACEBACKS': 'TYPES',
1528 'NONE': ('lib/bltin-null-object', ''),
1529 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1530 'FILES': ('lib/bltin-file-objects', ''),
1531 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1532 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1533 'MODULES': ('lib/typesmodules', 'import'),
1534 'PACKAGES': 'import',
1535 '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'),
1536 'OPERATORS': 'EXPRESSIONS',
1537 'PRECEDENCE': 'EXPRESSIONS',
1538 'OBJECTS': ('ref/objects', 'TYPES'),
1539 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001540 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1541 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1542 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1543 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1544 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1545 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1546 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001547 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1548 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1549 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001550 'SCOPING': 'NAMESPACES',
1551 'FRAMES': 'NAMESPACES',
1552 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
Neal Norwitz54f871e2003-05-26 13:49:54 +00001553 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1554 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001555 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1556 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001557 'PRIVATENAMES': ('ref/atom-identifiers', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001558 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1559 'TUPLES': 'SEQUENCES',
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001560 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001561 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001562 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001563 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001564 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1565 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001566 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1567 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1568 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1569 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1570 'POWER': ('ref/power', 'EXPRESSIONS'),
1571 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1572 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1573 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1574 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1575 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
Neal Norwitzf98159c2003-02-07 20:49:40 +00001576 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001577 'ASSERTION': 'assert',
1578 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001579 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001580 'DELETION': 'del',
1581 'PRINTING': 'print',
1582 'RETURNING': 'return',
1583 'IMPORTING': 'import',
1584 'CONDITIONAL': 'if',
1585 'LOOPING': ('ref/compound', 'for while break continue'),
1586 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001587 'DEBUGGING': ('lib/module-pdb', 'pdb'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001588 }
1589
1590 def __init__(self, input, output):
1591 self.input = input
1592 self.output = output
1593 self.docdir = None
1594 execdir = os.path.dirname(sys.executable)
1595 homedir = os.environ.get('PYTHONHOME')
1596 for dir in [os.environ.get('PYTHONDOCS'),
1597 homedir and os.path.join(homedir, 'doc'),
1598 os.path.join(execdir, 'doc'),
1599 '/usr/doc/python-docs-' + split(sys.version)[0],
1600 '/usr/doc/python-' + split(sys.version)[0],
1601 '/usr/doc/python-docs-' + sys.version[:3],
Jack Jansenb2628b02002-08-23 08:40:42 +00001602 '/usr/doc/python-' + sys.version[:3],
1603 os.path.join(sys.prefix, 'Resources/English.lproj/Documentation')]:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001604 if dir and os.path.isdir(os.path.join(dir, 'lib')):
1605 self.docdir = dir
1606
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001607 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001608 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001609 self()
1610 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001611 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001612
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001613 def __call__(self, request=None):
1614 if request is not None:
1615 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001616 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001617 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001618 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001619 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001620You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001621If you want to ask for help on a particular object directly from the
1622interpreter, you can type "help(object)". Executing "help('string')"
1623has the same effect as typing a particular string at the help> prompt.
1624''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001625
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001626 def interact(self):
1627 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001628 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001629 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001630 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001631 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001632 except (KeyboardInterrupt, EOFError):
1633 break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001634 request = strip(replace(request, '"', '', "'", ''))
1635 if lower(request) in ['q', 'quit']: break
1636 self.help(request)
1637
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001638 def getline(self, prompt):
1639 """Read one line, using raw_input when available."""
1640 if self.input is sys.stdin:
1641 return raw_input(prompt)
1642 else:
1643 self.output.write(prompt)
1644 self.output.flush()
1645 return self.input.readline()
1646
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001647 def help(self, request):
1648 if type(request) is type(''):
1649 if request == 'help': self.intro()
1650 elif request == 'keywords': self.listkeywords()
1651 elif request == 'topics': self.listtopics()
1652 elif request == 'modules': self.listmodules()
1653 elif request[:8] == 'modules ':
1654 self.listmodules(split(request)[1])
Raymond Hettinger54f02222002-06-01 14:18:47 +00001655 elif request in self.keywords: self.showtopic(request)
1656 elif request in self.topics: self.showtopic(request)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001657 elif request: doc(request, 'Help on %s:')
1658 elif isinstance(request, Helper): self()
1659 else: doc(request, 'Help on %s:')
1660 self.output.write('\n')
1661
1662 def intro(self):
1663 self.output.write('''
1664Welcome to Python %s! This is the online help utility.
1665
1666If this is your first time using Python, you should definitely check out
1667the tutorial on the Internet at http://www.python.org/doc/tut/.
1668
1669Enter the name of any module, keyword, or topic to get help on writing
1670Python programs and using Python modules. To quit this help utility and
1671return to the interpreter, just type "quit".
1672
1673To get a list of available modules, keywords, or topics, type "modules",
1674"keywords", or "topics". Each module also comes with a one-line summary
1675of what it does; to list the modules whose summaries contain a given word
1676such as "spam", type "modules spam".
1677''' % sys.version[:3])
1678
1679 def list(self, items, columns=4, width=80):
1680 items = items[:]
1681 items.sort()
1682 colw = width / columns
1683 rows = (len(items) + columns - 1) / columns
1684 for row in range(rows):
1685 for col in range(columns):
1686 i = col * rows + row
1687 if i < len(items):
1688 self.output.write(items[i])
1689 if col < columns - 1:
1690 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1691 self.output.write('\n')
1692
1693 def listkeywords(self):
1694 self.output.write('''
1695Here is a list of the Python keywords. Enter any keyword to get more help.
1696
1697''')
1698 self.list(self.keywords.keys())
1699
1700 def listtopics(self):
1701 self.output.write('''
1702Here is a list of available topics. Enter any topic name to get more help.
1703
1704''')
1705 self.list(self.topics.keys())
1706
1707 def showtopic(self, topic):
1708 if not self.docdir:
1709 self.output.write('''
1710Sorry, topic and keyword documentation is not available because the Python
1711HTML documentation files could not be found. If you have installed them,
1712please set the environment variable PYTHONDOCS to indicate their location.
1713''')
1714 return
1715 target = self.topics.get(topic, self.keywords.get(topic))
1716 if not target:
1717 self.output.write('no documentation found for %s\n' % repr(topic))
1718 return
1719 if type(target) is type(''):
1720 return self.showtopic(target)
1721
1722 filename, xrefs = target
1723 filename = self.docdir + '/' + filename + '.html'
1724 try:
1725 file = open(filename)
1726 except:
1727 self.output.write('could not read docs from %s\n' % filename)
1728 return
1729
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001730 divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
1731 addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001732 document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
1733 file.close()
1734
1735 import htmllib, formatter, StringIO
1736 buffer = StringIO.StringIO()
1737 parser = htmllib.HTMLParser(
1738 formatter.AbstractFormatter(formatter.DumbWriter(buffer)))
1739 parser.start_table = parser.do_p
1740 parser.end_table = lambda parser=parser: parser.do_p({})
1741 parser.start_tr = parser.do_br
1742 parser.start_td = parser.start_th = lambda a, b=buffer: b.write('\t')
1743 parser.feed(document)
1744 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1745 pager(' ' + strip(buffer) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001746 if xrefs:
1747 buffer = StringIO.StringIO()
1748 formatter.DumbWriter(buffer).send_flowing_data(
1749 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1750 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001751
1752 def listmodules(self, key=''):
1753 if key:
1754 self.output.write('''
1755Here is a list of matching modules. Enter any module name to get more help.
1756
1757''')
1758 apropos(key)
1759 else:
1760 self.output.write('''
1761Please wait a moment while I gather a list of all available modules...
1762
1763''')
1764 modules = {}
1765 def callback(path, modname, desc, modules=modules):
1766 if modname and modname[-9:] == '.__init__':
1767 modname = modname[:-9] + ' (package)'
1768 if find(modname, '.') < 0:
1769 modules[modname] = 1
1770 ModuleScanner().run(callback)
1771 self.list(modules.keys())
1772 self.output.write('''
1773Enter any module name to get more help. Or, type "modules spam" to search
1774for modules whose descriptions contain the word "spam".
1775''')
1776
1777help = Helper(sys.stdin, sys.stdout)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001778
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001779class Scanner:
1780 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001781 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001782 self.roots = roots[:]
1783 self.state = []
1784 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001785 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001786
1787 def next(self):
1788 if not self.state:
1789 if not self.roots:
1790 return None
1791 root = self.roots.pop(0)
1792 self.state = [(root, self.children(root))]
1793 node, children = self.state[-1]
1794 if not children:
1795 self.state.pop()
1796 return self.next()
1797 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001798 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001799 self.state.append((child, self.children(child)))
1800 return child
1801
1802class ModuleScanner(Scanner):
1803 """An interruptible scanner that searches module synopses."""
1804 def __init__(self):
1805 roots = map(lambda dir: (dir, ''), pathdirs())
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001806 Scanner.__init__(self, roots, self.submodules, self.isnewpackage)
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001807 self.inodes = map(lambda (dir, pkg): os.stat(dir).st_ino, roots)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001808
1809 def submodules(self, (dir, package)):
1810 children = []
1811 for file in os.listdir(dir):
1812 path = os.path.join(dir, file)
Tim Peters30edd232001-03-16 08:29:48 +00001813 if ispackage(path):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001814 children.append((path, package + (package and '.') + file))
1815 else:
1816 children.append((path, package))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001817 children.sort() # so that spam.py comes before spam.pyc or spam.pyo
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001818 return children
1819
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001820 def isnewpackage(self, (dir, package)):
Raymond Hettinger32200ae2002-06-01 19:51:15 +00001821 inode = os.path.exists(dir) and os.stat(dir).st_ino
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001822 if not (os.path.islink(dir) and inode in self.inodes):
Ka-Ping Yee6191a232001-04-13 15:00:27 +00001823 self.inodes.append(inode) # detect circular symbolic links
Ka-Ping Yeeeca15c12001-04-13 13:53:07 +00001824 return ispackage(dir)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001825 return False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001826
Ka-Ping Yee66246962001-04-12 11:59:50 +00001827 def run(self, callback, key=None, completer=None):
1828 if key: key = lower(key)
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001829 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001830 seen = {}
1831
1832 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001833 if modname != '__main__':
1834 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001835 if key is None:
1836 callback(None, modname, '')
1837 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001838 desc = split(__import__(modname).__doc__ or '', '\n')[0]
Ka-Ping Yee66246962001-04-12 11:59:50 +00001839 if find(lower(modname + ' - ' + desc), key) >= 0:
1840 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001841
1842 while not self.quit:
1843 node = self.next()
1844 if not node: break
1845 path, package = node
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001846 modname = inspect.getmodulename(path)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001847 if os.path.isfile(path) and modname:
1848 modname = package + (package and '.') + modname
Raymond Hettinger54f02222002-06-01 14:18:47 +00001849 if not modname in seen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001850 seen[modname] = 1 # if we see spam.py, skip spam.pyc
Ka-Ping Yee66246962001-04-12 11:59:50 +00001851 if key is None:
1852 callback(path, modname, '')
1853 else:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001854 desc = synopsis(path) or ''
1855 if find(lower(modname + ' - ' + desc), key) >= 0:
1856 callback(path, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001857 if completer: completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001858
1859def apropos(key):
1860 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001861 def callback(path, modname, desc):
1862 if modname[-9:] == '.__init__':
1863 modname = modname[:-9] + ' (package)'
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001864 print modname, desc and '- ' + desc
1865 try: import warnings
1866 except ImportError: pass
1867 else: warnings.filterwarnings('ignore') # ignore problems during import
Ka-Ping Yee66246962001-04-12 11:59:50 +00001868 ModuleScanner().run(callback, key)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001869
1870# --------------------------------------------------- web browser interface
1871
Ka-Ping Yee66246962001-04-12 11:59:50 +00001872def serve(port, callback=None, completer=None):
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001873 import BaseHTTPServer, mimetools, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001874
1875 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1876 class Message(mimetools.Message):
1877 def __init__(self, fp, seekable=1):
1878 Message = self.__class__
1879 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1880 self.encodingheader = self.getheader('content-transfer-encoding')
1881 self.typeheader = self.getheader('content-type')
1882 self.parsetype()
1883 self.parseplist()
1884
1885 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1886 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001887 try:
1888 self.send_response(200)
1889 self.send_header('Content-Type', 'text/html')
1890 self.end_headers()
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001891 self.wfile.write(html.page(title, contents))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001892 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001893
1894 def do_GET(self):
1895 path = self.path
1896 if path[-5:] == '.html': path = path[:-5]
1897 if path[:1] == '/': path = path[1:]
1898 if path and path != '.':
1899 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001900 obj = locate(path, forceload=1)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001901 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001902 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001903 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001904 if obj:
1905 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001906 else:
1907 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001908'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001909 else:
1910 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001911'<big><big><strong>Python: Index of Modules</strong></big></big>',
1912'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001913 def bltinlink(name):
1914 return '<a href="%s.html">%s</a>' % (name, name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001915 names = filter(lambda x: x != '__main__',
1916 sys.builtin_module_names)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001917 contents = html.multicolumn(names, bltinlink)
1918 indices = ['<p>' + html.bigsection(
1919 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
1920
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001921 seen = {}
1922 for dir in pathdirs():
1923 indices.append(html.index(dir, seen))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001924 contents = heading + join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00001925<font color="#909090" face="helvetica, arial"><strong>
1926pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001927 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001928
1929 def log_message(self, *args): pass
1930
Ka-Ping Yeefd540692001-04-12 12:54:36 +00001931 class DocServer(BaseHTTPServer.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001932 def __init__(self, port, callback):
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001933 host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001934 self.address = ('', port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00001935 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001936 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001937 self.base.__init__(self, self.address, self.handler)
1938
1939 def serve_until_quit(self):
1940 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001941 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001942 while not self.quit:
1943 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
1944 if rd: self.handle_request()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001945
1946 def server_activate(self):
1947 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001948 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001949
1950 DocServer.base = BaseHTTPServer.HTTPServer
1951 DocServer.handler = DocHandler
1952 DocHandler.MessageClass = Message
1953 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001954 try:
1955 DocServer(port, callback).serve_until_quit()
1956 except (KeyboardInterrupt, select.error):
1957 pass
1958 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001959 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001960
1961# ----------------------------------------------------- graphical interface
1962
1963def gui():
1964 """Graphical interface (starts web server and pops up a control window)."""
1965 class GUI:
1966 def __init__(self, window, port=7464):
1967 self.window = window
1968 self.server = None
1969 self.scanner = None
1970
1971 import Tkinter
1972 self.server_frm = Tkinter.Frame(window)
1973 self.title_lbl = Tkinter.Label(self.server_frm,
1974 text='Starting server...\n ')
1975 self.open_btn = Tkinter.Button(self.server_frm,
1976 text='open browser', command=self.open, state='disabled')
1977 self.quit_btn = Tkinter.Button(self.server_frm,
1978 text='quit serving', command=self.quit, state='disabled')
1979
1980 self.search_frm = Tkinter.Frame(window)
1981 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
1982 self.search_ent = Tkinter.Entry(self.search_frm)
1983 self.search_ent.bind('<Return>', self.search)
1984 self.stop_btn = Tkinter.Button(self.search_frm,
1985 text='stop', pady=0, command=self.stop, state='disabled')
1986 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00001987 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001988 self.stop_btn.pack(side='right')
1989
1990 self.window.title('pydoc')
1991 self.window.protocol('WM_DELETE_WINDOW', self.quit)
1992 self.title_lbl.pack(side='top', fill='x')
1993 self.open_btn.pack(side='left', fill='x', expand=1)
1994 self.quit_btn.pack(side='right', fill='x', expand=1)
1995 self.server_frm.pack(side='top', fill='x')
1996
1997 self.search_lbl.pack(side='left')
1998 self.search_ent.pack(side='right', fill='x', expand=1)
1999 self.search_frm.pack(side='top', fill='x')
2000 self.search_ent.focus_set()
2001
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002002 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002003 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002004 self.result_lst.bind('<Button-1>', self.select)
2005 self.result_lst.bind('<Double-Button-1>', self.goto)
2006 self.result_scr = Tkinter.Scrollbar(window,
2007 orient='vertical', command=self.result_lst.yview)
2008 self.result_lst.config(yscrollcommand=self.result_scr.set)
2009
2010 self.result_frm = Tkinter.Frame(window)
2011 self.goto_btn = Tkinter.Button(self.result_frm,
2012 text='go to selected', command=self.goto)
2013 self.hide_btn = Tkinter.Button(self.result_frm,
2014 text='hide results', command=self.hide)
2015 self.goto_btn.pack(side='left', fill='x', expand=1)
2016 self.hide_btn.pack(side='right', fill='x', expand=1)
2017
2018 self.window.update()
2019 self.minwidth = self.window.winfo_width()
2020 self.minheight = self.window.winfo_height()
2021 self.bigminheight = (self.server_frm.winfo_reqheight() +
2022 self.search_frm.winfo_reqheight() +
2023 self.result_lst.winfo_reqheight() +
2024 self.result_frm.winfo_reqheight())
2025 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2026 self.expanded = 0
2027 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2028 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002029 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002030
2031 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002032 threading.Thread(
2033 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002034
2035 def ready(self, server):
2036 self.server = server
2037 self.title_lbl.config(
2038 text='Python documentation server at\n' + server.url)
2039 self.open_btn.config(state='normal')
2040 self.quit_btn.config(state='normal')
2041
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002042 def open(self, event=None, url=None):
2043 url = url or self.server.url
2044 try:
2045 import webbrowser
2046 webbrowser.open(url)
2047 except ImportError: # pre-webbrowser.py compatibility
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002048 if sys.platform == 'win32':
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002049 os.system('start "%s"' % url)
2050 elif sys.platform == 'mac':
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002051 try: import ic
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002052 except ImportError: pass
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002053 else: ic.launchurl(url)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002054 else:
2055 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2056 if rc: os.system('netscape "%s" &' % url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002057
2058 def quit(self, event=None):
2059 if self.server:
2060 self.server.quit = 1
2061 self.window.quit()
2062
2063 def search(self, event=None):
2064 key = self.search_ent.get()
2065 self.stop_btn.pack(side='right')
2066 self.stop_btn.config(state='normal')
2067 self.search_lbl.config(text='Searching for "%s"...' % key)
2068 self.search_ent.forget()
2069 self.search_lbl.pack(side='left')
2070 self.result_lst.delete(0, 'end')
2071 self.goto_btn.config(state='disabled')
2072 self.expand()
2073
2074 import threading
2075 if self.scanner:
2076 self.scanner.quit = 1
2077 self.scanner = ModuleScanner()
2078 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002079 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002080
2081 def update(self, path, modname, desc):
2082 if modname[-9:] == '.__init__':
2083 modname = modname[:-9] + ' (package)'
2084 self.result_lst.insert('end',
2085 modname + ' - ' + (desc or '(no description)'))
2086
2087 def stop(self, event=None):
2088 if self.scanner:
2089 self.scanner.quit = 1
2090 self.scanner = None
2091
2092 def done(self):
2093 self.scanner = None
2094 self.search_lbl.config(text='Search for')
2095 self.search_lbl.pack(side='left')
2096 self.search_ent.pack(side='right', fill='x', expand=1)
2097 if sys.platform != 'win32': self.stop_btn.forget()
2098 self.stop_btn.config(state='disabled')
2099
2100 def select(self, event=None):
2101 self.goto_btn.config(state='normal')
2102
2103 def goto(self, event=None):
2104 selection = self.result_lst.curselection()
2105 if selection:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002106 modname = split(self.result_lst.get(selection[0]))[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002107 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002108
2109 def collapse(self):
2110 if not self.expanded: return
2111 self.result_frm.forget()
2112 self.result_scr.forget()
2113 self.result_lst.forget()
2114 self.bigwidth = self.window.winfo_width()
2115 self.bigheight = self.window.winfo_height()
2116 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2117 self.window.wm_minsize(self.minwidth, self.minheight)
2118 self.expanded = 0
2119
2120 def expand(self):
2121 if self.expanded: return
2122 self.result_frm.pack(side='bottom', fill='x')
2123 self.result_scr.pack(side='right', fill='y')
2124 self.result_lst.pack(side='top', fill='both', expand=1)
2125 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2126 self.window.wm_minsize(self.minwidth, self.bigminheight)
2127 self.expanded = 1
2128
2129 def hide(self, event=None):
2130 self.stop()
2131 self.collapse()
2132
2133 import Tkinter
2134 try:
Martin v. Löwise09bd932004-08-22 16:13:26 +00002135 root = Tkinter.Tk()
2136 # Tk will crash if pythonw.exe has an XP .manifest
2137 # file and the root has is not destroyed explicitly.
2138 # If the problem is ever fixed in Tk, the explicit
2139 # destroy can go.
2140 try:
2141 gui = GUI(root)
2142 root.mainloop()
2143 finally:
2144 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002145 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002146 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002147
2148# -------------------------------------------------- command-line interface
2149
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002150def ispath(x):
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002151 return isinstance(x, str) and find(x, os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002152
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002153def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002154 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002155 import getopt
2156 class BadUsage: pass
2157
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002158 # Scripts don't get the current directory in their path by default.
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +00002159 scriptdir = os.path.dirname(sys.argv[0])
2160 if scriptdir in sys.path:
2161 sys.path.remove(scriptdir)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002162 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002163
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002164 try:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002165 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002166 writing = 0
2167
2168 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002169 if opt == '-g':
2170 gui()
2171 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002172 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002173 apropos(val)
2174 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002175 if opt == '-p':
2176 try:
2177 port = int(val)
2178 except ValueError:
2179 raise BadUsage
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002180 def ready(server):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002181 print 'pydoc server ready at %s' % server.url
2182 def stopped():
2183 print 'pydoc server stopped'
2184 serve(port, ready, stopped)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002185 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002186 if opt == '-w':
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002187 writing = 1
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002188
2189 if not args: raise BadUsage
2190 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002191 if ispath(arg) and not os.path.exists(arg):
2192 print 'file %r does not exist' % arg
2193 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002194 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002195 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002196 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002197 if writing:
2198 if ispath(arg) and os.path.isdir(arg):
2199 writedocs(arg)
2200 else:
2201 writedoc(arg)
2202 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002203 help.help(arg)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002204 except ErrorDuringImport, value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002205 print value
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002206
2207 except (getopt.error, BadUsage):
Martin v. Löwisf9b08b82003-10-31 13:05:21 +00002208 cmd = os.path.basename(sys.argv[0])
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002209 print """pydoc - the Python documentation tool
2210
2211%s <name> ...
2212 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002213 Python keyword, topic, function, module, or package, or a dotted
2214 reference to a class or function within a module or module in a
2215 package. If <name> contains a '%s', it is used as the path to a
2216 Python source file to document. If name is 'keywords', 'topics',
2217 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002218
2219%s -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002220 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002221
2222%s -p <port>
2223 Start an HTTP server on the given port on the local machine.
2224
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002225%s -g
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002226 Pop up a graphical interface for finding and serving documentation.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002227
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002228%s -w <name> ...
2229 Write out the HTML documentation for a module to a file in the current
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002230 directory. If <name> contains a '%s', it is treated as a filename; if
2231 it names a directory, documentation is written for all the contents.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002232""" % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002233
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002234if __name__ == '__main__': cli()