blob: 9d3cdd5c9b03a81e392b8148dc683a1c7f0a271e [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#!/usr/bin/env python3
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002"""Generate Python documentation in HTML or text for interactive use.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00003
Ka-Ping Yeedd175342001-02-27 14:43:46 +00004In the Python interpreter, do "from pydoc import help" to provide online
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00005help. Calling help(thing) on a Python object documents the object.
6
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00007Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00008
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00009Run "pydoc <name>" to show documentation on something. <name> may be
10the name of a function, module, package, or a dotted reference to a
11class or function within a module or module in a package. If the
12argument contains a path segment delimiter (e.g. slash on Unix,
13backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000014
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000015Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
16of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000017
Nick Coghlan7bb30b72010-12-03 09:29:11 +000018Run "pydoc -p <port>" to start an HTTP server on the given port on the
19local machine. Port number 0 can be used to get an arbitrary unused port.
20
21Run "pydoc -b" to start an HTTP server on an arbitrary unused port and
22open a Web browser to interactively browse documentation. The -p option
23can be used with the -b option to explicitly specify the server port.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000024
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000025For platforms without a command line, "pydoc -g" starts the HTTP server
Nick Coghlan7bb30b72010-12-03 09:29:11 +000026and also pops up a little window for controlling it. This option is
27deprecated, since the server can now be controlled directly from HTTP
28clients.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000029
30Run "pydoc -w <name>" to write out the HTML documentation for a module
31to a file named "<name>.html".
Skip Montanaro4997a692003-09-10 16:47:51 +000032
33Module docs for core modules are assumed to be in
34
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000035 http://docs.python.org/X.Y/library/
Skip Montanaro4997a692003-09-10 16:47:51 +000036
37This can be overridden by setting the PYTHONDOCS environment variable
38to a different URL or to a local directory containing the Library
39Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000040"""
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000041__all__ = ['help']
Ka-Ping Yeedd175342001-02-27 14:43:46 +000042__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000043__date__ = "26 February 2001"
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000044
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000045__version__ = "$Revision$"
Martin v. Löwis6fe8f192004-11-14 10:21:04 +000046__credits__ = """Guido van Rossum, for an excellent programming language.
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000047Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000048Paul Prescod, for all his work on onlinehelp.
49Richard Chamberlain, for the first implementation of textdoc.
Raymond Hettingered2dbe32005-01-01 07:51:01 +000050"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000051
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000052# Known bugs that can't be fixed here:
53# - imp.load_module() cannot be prevented from clobbering existing
54# loaded modules, so calling synopsis() on a binary module file
55# changes the contents of any existing module with the same name.
56# - If the __file__ attribute on a module is a relative path and
57# the current directory is changed with os.chdir(), an incorrect
58# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000059
Nick Coghlan7bb30b72010-12-03 09:29:11 +000060import os
61import sys
62import builtins
63import imp
64import io
65import inspect
66import pkgutil
67import platform
68import re
69import time
70import warnings
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000071from collections import deque
Nick Coghlan7bb30b72010-12-03 09:29:11 +000072from reprlib import Repr
Georg Brandld2f38572011-01-30 08:37:19 +000073from traceback import extract_tb, format_exception_only
Nick Coghlan7bb30b72010-12-03 09:29:11 +000074
75
Ka-Ping Yeedd175342001-02-27 14:43:46 +000076# --------------------------------------------------------- common routines
77
Ka-Ping Yeedd175342001-02-27 14:43:46 +000078def pathdirs():
79 """Convert sys.path into a list of absolute, existing, unique paths."""
80 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000081 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000082 for dir in sys.path:
83 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000084 normdir = os.path.normcase(dir)
85 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000086 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000087 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000088 return dirs
89
90def getdoc(object):
91 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000092 result = inspect.getdoc(object) or inspect.getcomments(object)
Neal Norwitz9d72bb42007-04-17 08:48:32 +000093 return result and re.sub('^ *\n', '', result.rstrip()) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000094
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000095def splitdoc(doc):
96 """Split a doc string into a synopsis line (if any) and the rest."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +000097 lines = doc.strip().split('\n')
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000098 if len(lines) == 1:
99 return lines[0], ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000100 elif len(lines) >= 2 and not lines[1].rstrip():
101 return lines[0], '\n'.join(lines[2:])
102 return '', '\n'.join(lines)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000103
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000104def classname(object, modname):
105 """Get a class name and qualify it with a module name if necessary."""
106 name = object.__name__
107 if object.__module__ != modname:
108 name = object.__module__ + '.' + name
109 return name
110
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000111def isdata(object):
Georg Brandl94432422005-07-22 21:52:25 +0000112 """Check if an object is of a type that probably means it's data."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000113 return not (inspect.ismodule(object) or inspect.isclass(object) or
114 inspect.isroutine(object) or inspect.isframe(object) or
115 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000116
117def replace(text, *pairs):
118 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000119 while pairs:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000120 text = pairs[1].join(text.split(pairs[0]))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000121 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000122 return text
123
124def cram(text, maxlen):
125 """Omit part of a string if needed to make it fit in a maximum length."""
126 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000127 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000128 post = max(0, maxlen-3-pre)
129 return text[:pre] + '...' + text[len(text)-post:]
130 return text
131
Brett Cannon84601f12004-06-19 01:22:48 +0000132_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000133def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000134 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000135 # The behaviour of %p is implementation-dependent in terms of case.
Ezio Melotti412c95a2010-02-16 23:31:04 +0000136 return _re_stripid.sub(r'\1', text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000137
Brett Cannonc6c1f472004-06-19 01:02:51 +0000138def _is_some_method(obj):
139 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000140
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000141def allmethods(cl):
142 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000143 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000144 methods[key] = 1
145 for base in cl.__bases__:
146 methods.update(allmethods(base)) # all your base are belong to us
147 for key in methods.keys():
148 methods[key] = getattr(cl, key)
149 return methods
150
Tim Petersfa26f7c2001-09-24 08:05:11 +0000151def _split_list(s, predicate):
152 """Split sequence s via predicate, and return pair ([true], [false]).
153
154 The return value is a 2-tuple of lists,
155 ([x for x in s if predicate(x)],
156 [x for x in s if not predicate(x)])
157 """
158
Tim Peters28355492001-09-23 21:29:55 +0000159 yes = []
160 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000161 for x in s:
162 if predicate(x):
163 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000164 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000165 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000166 return yes, no
167
Skip Montanaroa5616d22004-06-11 04:46:12 +0000168def visiblename(name, all=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000169 """Decide whether to show documentation on a variable."""
170 # Certain special names are redundant.
Benjamin Peterson41181742008-07-02 20:22:54 +0000171 _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__',
Barry Warsaw28a691b2010-04-17 00:19:56 +0000172 '__module__', '__name__', '__slots__', '__package__',
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000173 '__cached__', '__author__', '__credits__', '__date__',
174 '__version__')
Benjamin Peterson41181742008-07-02 20:22:54 +0000175 if name in _hidden_names: return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000176 # Private names are hidden, but special names are displayed.
177 if name.startswith('__') and name.endswith('__'): return 1
Skip Montanaroa5616d22004-06-11 04:46:12 +0000178 if all is not None:
179 # only document that which the programmer exported in __all__
180 return name in all
181 else:
182 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000183
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000184def classify_class_attrs(object):
185 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000186 results = []
187 for (name, kind, cls, value) in inspect.classify_class_attrs(object):
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000188 if inspect.isdatadescriptor(value):
189 kind = 'data descriptor'
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000190 results.append((name, kind, cls, value))
191 return results
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000192
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000193# ----------------------------------------------------- module manipulation
194
195def ispackage(path):
196 """Guess whether a path refers to a package directory."""
197 if os.path.isdir(path):
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000198 for ext in ('.py', '.pyc', '.pyo'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000199 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000200 return True
201 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000202
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000203def source_synopsis(file):
204 line = file.readline()
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000205 while line[:1] == '#' or not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000206 line = file.readline()
207 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000208 line = line.strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000209 if line[:4] == 'r"""': line = line[1:]
210 if line[:3] == '"""':
211 line = line[3:]
212 if line[-1:] == '\\': line = line[:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000213 while not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000214 line = file.readline()
215 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000216 result = line.split('"""')[0].strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000217 else: result = None
218 return result
219
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000220def synopsis(filename, cache={}):
221 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000222 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000223 lastupdate, result = cache.get(filename, (0, None))
224 if lastupdate < mtime:
225 info = inspect.getmoduleinfo(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000226 try:
227 file = open(filename)
228 except IOError:
229 # module can't be opened, so skip it
230 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000231 if info and 'b' in info[2]: # binary modules have to be imported
232 try: module = imp.load_module('__temp__', file, filename, info[1:])
233 except: return None
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000234 result = (module.__doc__ or '').splitlines()[0]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000235 del sys.modules['__temp__']
236 else: # text modules can be directly examined
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000237 result = source_synopsis(file)
238 file.close()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000239 cache[filename] = (mtime, result)
240 return result
241
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000242class ErrorDuringImport(Exception):
243 """Errors that occurred while trying to import something to document it."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000244 def __init__(self, filename, exc_info):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000245 self.filename = filename
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000246 self.exc, self.value, self.tb = exc_info
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000247
248 def __str__(self):
Guido van Rossuma01a8b62007-05-27 09:20:14 +0000249 exc = self.exc.__name__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000250 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000251
252def importfile(path):
253 """Import a Python source file or compiled file given its path."""
254 magic = imp.get_magic()
255 file = open(path, 'r')
256 if file.read(len(magic)) == magic:
257 kind = imp.PY_COMPILED
258 else:
259 kind = imp.PY_SOURCE
260 file.close()
261 filename = os.path.basename(path)
262 name, ext = os.path.splitext(filename)
263 file = open(path, 'r')
264 try:
265 module = imp.load_module(name, file, path, (ext, 'r', kind))
266 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000267 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000268 file.close()
269 return module
270
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000271def safeimport(path, forceload=0, cache={}):
272 """Import a module; handle errors; return None if the module isn't found.
273
274 If the module *is* found but an exception occurs, it's wrapped in an
275 ErrorDuringImport exception and reraised. Unlike __import__, if a
276 package path is specified, the module at the end of the path is returned,
277 not the package at the beginning. If the optional 'forceload' argument
278 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000279 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000280 # If forceload is 1 and the module has been previously loaded from
281 # disk, we always have to reload the module. Checking the file's
282 # mtime isn't good enough (e.g. the module could contain a class
283 # that inherits from another module that has changed).
284 if forceload and path in sys.modules:
285 if path not in sys.builtin_module_names:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000286 # Remove the module from sys.modules and re-import to try
287 # and avoid problems with partially loaded modules.
288 # Also remove any submodules because they won't appear
289 # in the newly loaded module's namespace if they're already
290 # in sys.modules.
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000291 subs = [m for m in sys.modules if m.startswith(path + '.')]
292 for key in [path] + subs:
293 # Prevent garbage collection.
294 cache[key] = sys.modules[key]
295 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000296 module = __import__(path)
297 except:
298 # Did the error occur before or after the module was found?
299 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000300 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000301 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000302 raise ErrorDuringImport(sys.modules[path].__file__, info)
303 elif exc is SyntaxError:
304 # A SyntaxError occurred before we could execute the module.
305 raise ErrorDuringImport(value.filename, info)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000306 elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport':
Benjamin Peterson0289b152009-06-28 17:22:03 +0000307 # The import error occurred directly in this function,
308 # which means there is no such module in the path.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000309 return None
310 else:
311 # Some other error occurred during the importing process.
312 raise ErrorDuringImport(path, sys.exc_info())
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000313 for part in path.split('.')[1:]:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000314 try: module = getattr(module, part)
315 except AttributeError: return None
316 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000317
318# ---------------------------------------------------- formatter base class
319
320class Doc:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000321
322 PYTHONDOCS = os.environ.get("PYTHONDOCS",
323 "http://docs.python.org/%d.%d/library"
324 % sys.version_info[:2])
325
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000326 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000327 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000328 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000329 # 'try' clause is to attempt to handle the possibility that inspect
330 # identifies something in a way that pydoc itself has issues handling;
331 # think 'super' and how it is a descriptor (which raises the exception
332 # by lacking a __name__ attribute) and an instance.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000333 if inspect.isgetsetdescriptor(object): return self.docdata(*args)
334 if inspect.ismemberdescriptor(object): return self.docdata(*args)
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000335 try:
336 if inspect.ismodule(object): return self.docmodule(*args)
337 if inspect.isclass(object): return self.docclass(*args)
338 if inspect.isroutine(object): return self.docroutine(*args)
339 except AttributeError:
340 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000341 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000342 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000343
344 def fail(self, object, name=None, *args):
345 """Raise an exception for unimplemented types."""
346 message = "don't know how to document object%s of type %s" % (
347 name and ' ' + repr(name), type(object).__name__)
Collin Winterce36ad82007-08-30 01:19:48 +0000348 raise TypeError(message)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000349
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000350 docmodule = docclass = docroutine = docother = docproperty = docdata = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000351
Skip Montanaro4997a692003-09-10 16:47:51 +0000352 def getdocloc(self, object):
353 """Return the location of module docs or None"""
354
355 try:
356 file = inspect.getabsfile(object)
357 except TypeError:
358 file = '(built-in)'
359
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000360 docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
361
Skip Montanaro4997a692003-09-10 16:47:51 +0000362 basedir = os.path.join(sys.exec_prefix, "lib",
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000363 "python%d.%d" % sys.version_info[:2])
Skip Montanaro4997a692003-09-10 16:47:51 +0000364 if (isinstance(object, type(os)) and
365 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
366 'marshal', 'posix', 'signal', 'sys',
Georg Brandl2067bfd2008-05-25 13:05:15 +0000367 '_thread', 'zipimport') or
Skip Montanaro4997a692003-09-10 16:47:51 +0000368 (file.startswith(basedir) and
Brian Curtin49c284c2010-03-31 03:19:28 +0000369 not file.startswith(os.path.join(basedir, 'site-packages')))) and
Brian Curtinedef05b2010-04-01 04:05:25 +0000370 object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
Skip Montanaro4997a692003-09-10 16:47:51 +0000371 if docloc.startswith("http://"):
Georg Brandl86def6c2008-01-21 20:36:10 +0000372 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__)
Skip Montanaro4997a692003-09-10 16:47:51 +0000373 else:
Georg Brandl86def6c2008-01-21 20:36:10 +0000374 docloc = os.path.join(docloc, object.__name__ + ".html")
Skip Montanaro4997a692003-09-10 16:47:51 +0000375 else:
376 docloc = None
377 return docloc
378
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000379# -------------------------------------------- HTML documentation generator
380
381class HTMLRepr(Repr):
382 """Class for safely making an HTML representation of a Python object."""
383 def __init__(self):
384 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000385 self.maxlist = self.maxtuple = 20
386 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000387 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000388
389 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000390 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000391
392 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000393 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000394
395 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000396 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000397 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000398 if hasattr(self, methodname):
399 return getattr(self, methodname)(x, level)
400 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000401
402 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000403 test = cram(x, self.maxstring)
404 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000405 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000406 # Backslashes are only literal in the string and are never
407 # needed to make any special characters, so show a raw string.
408 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000409 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000410 r'<font color="#c040c0">\1</font>',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000411 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000412
Skip Montanarodf708782002-03-07 22:58:02 +0000413 repr_str = repr_string
414
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000415 def repr_instance(self, x, level):
416 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000417 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000418 except:
419 return self.escape('<%s instance>' % x.__class__.__name__)
420
421 repr_unicode = repr_string
422
423class HTMLDoc(Doc):
424 """Formatter class for HTML documentation."""
425
426 # ------------------------------------------- HTML formatting utilities
427
428 _repr_instance = HTMLRepr()
429 repr = _repr_instance.repr
430 escape = _repr_instance.escape
431
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000432 def page(self, title, contents):
433 """Format an HTML page."""
Georg Brandl388faac2009-04-10 08:31:48 +0000434 return '''\
Georg Brandle6066942009-04-10 08:28:28 +0000435<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000436<html><head><title>Python: %s</title>
Georg Brandl388faac2009-04-10 08:31:48 +0000437<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000438</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000439%s
440</body></html>''' % (title, contents)
441
442 def heading(self, title, fgcol, bgcol, extras=''):
443 """Format a page heading."""
444 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000445<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000446<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000447<td valign=bottom>&nbsp;<br>
448<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000449><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000450><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000451 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
452
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000453 def section(self, title, fgcol, bgcol, contents, width=6,
454 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000455 """Format a section with a heading."""
456 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000457 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000458 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000459<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000460<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000461<td colspan=3 valign=bottom>&nbsp;<br>
462<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000463 ''' % (bgcol, fgcol, title)
464 if prelude:
465 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000466<tr bgcolor="%s"><td rowspan=2>%s</td>
467<td colspan=2>%s</td></tr>
468<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
469 else:
470 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000471<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000472
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000473 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000474
475 def bigsection(self, title, *args):
476 """Format a section with a big heading."""
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000477 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000478 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000479
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000480 def preformat(self, text):
481 """Format literal preformatted text."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000482 text = self.escape(text.expandtabs())
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000483 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
484 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000485
486 def multicolumn(self, list, format, cols=4):
487 """Format a list of items into a multi-column list."""
488 result = ''
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000489 rows = (len(list)+cols-1)//cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000490 for col in range(cols):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000491 result = result + '<td width="%d%%" valign=top>' % (100//cols)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000492 for i in range(rows*col, rows*col+rows):
493 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000494 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000495 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000496 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000497
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000498 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000499
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000500 def namelink(self, name, *dicts):
501 """Make a link for an identifier, given name-to-URL mappings."""
502 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000503 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000504 return '<a href="%s">%s</a>' % (dict[name], name)
505 return name
506
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000507 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000508 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000509 name, module = object.__name__, sys.modules.get(object.__module__)
510 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000511 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000512 module.__name__, name, classname(object, modname))
513 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000514
515 def modulelink(self, object):
516 """Make a link for a module."""
517 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
518
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000519 def modpkglink(self, modpkginfo):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000520 """Make a link for a module or package to display in an index."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000521 name, path, ispackage, shadowed = modpkginfo
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000522 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000523 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000524 if path:
525 url = '%s.%s.html' % (path, name)
526 else:
527 url = '%s.html' % name
528 if ispackage:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000529 text = '<strong>%s</strong>&nbsp;(package)' % name
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000530 else:
531 text = name
532 return '<a href="%s">%s</a>' % (url, text)
533
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000534 def filelink(self, url, path):
535 """Make a link to source file."""
536 return '<a href="file:%s">%s</a>' % (url, path)
537
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000538 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
539 """Mark up some plain text, given a context of symbols to look for.
540 Each context dictionary maps object names to anchor names."""
541 escape = escape or self.escape
542 results = []
543 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000544 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
545 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000546 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000547 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000548 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000549 match = pattern.search(text, here)
550 if not match: break
551 start, end = match.span()
552 results.append(escape(text[here:start]))
553
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000554 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000555 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000556 url = escape(all).replace('"', '&quot;')
557 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000558 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000559 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
560 results.append('<a href="%s">%s</a>' % (url, escape(all)))
561 elif pep:
Christian Heimes2202f872008-02-06 14:31:34 +0000562 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000563 results.append('<a href="%s">%s</a>' % (url, escape(all)))
564 elif text[end:end+1] == '(':
565 results.append(self.namelink(name, methods, funcs, classes))
566 elif selfdot:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000567 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000568 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000569 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000570 here = end
571 results.append(escape(text[here:]))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000572 return ''.join(results)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000573
574 # ---------------------------------------------- type-specific routines
575
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000576 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000577 """Produce HTML for a class tree as given by inspect.getclasstree()."""
578 result = ''
579 for entry in tree:
580 if type(entry) is type(()):
581 c, bases = entry
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000582 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000583 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000584 if bases and bases != (parent,):
585 parents = []
586 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000587 parents.append(self.classlink(base, modname))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000588 result = result + '(' + ', '.join(parents) + ')'
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000589 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000590 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000591 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000592 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000593 return '<dl>\n%s</dl>\n' % result
594
Tim Peters8dd7ade2001-10-18 19:56:17 +0000595 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000596 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000597 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000598 try:
599 all = object.__all__
600 except AttributeError:
601 all = None
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000602 parts = name.split('.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000603 links = []
604 for i in range(len(parts)-1):
605 links.append(
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000606 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000607 ('.'.join(parts[:i+1]), parts[i]))
608 linkedname = '.'.join(links + parts[-1:])
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000609 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000610 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000611 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000612 url = path
613 if sys.platform == 'win32':
614 import nturl2path
615 url = nturl2path.pathname2url(path)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000616 filelink = self.filelink(url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000617 except TypeError:
618 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000619 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000620 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000621 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000622 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000623 version = version[11:-1].strip()
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000624 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000625 if hasattr(object, '__date__'):
626 info.append(self.escape(str(object.__date__)))
627 if info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000628 head = head + ' (%s)' % ', '.join(info)
Skip Montanaro4997a692003-09-10 16:47:51 +0000629 docloc = self.getdocloc(object)
630 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000631 docloc = '<br><a href="%(docloc)s">Module Reference</a>' % locals()
Skip Montanaro4997a692003-09-10 16:47:51 +0000632 else:
633 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000634 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000635 head, '#ffffff', '#7799ee',
636 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000637
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000638 modules = inspect.getmembers(object, inspect.ismodule)
639
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000640 classes, cdict = [], {}
641 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000642 # if __all__ exists, believe it. Otherwise use old heuristic.
643 if (all is not None or
644 (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000645 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000646 classes.append((key, value))
647 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000648 for key, value in classes:
649 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000650 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000651 module = sys.modules.get(modname)
652 if modname != name and module and hasattr(module, key):
653 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000654 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000655 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000656 funcs, fdict = [], {}
657 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000658 # if __all__ exists, believe it. Otherwise use old heuristic.
659 if (all is not None or
660 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000661 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000662 funcs.append((key, value))
663 fdict[key] = '#-' + key
664 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000665 data = []
666 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +0000667 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000668 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000669
670 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
671 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000672 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000673
674 if hasattr(object, '__path__'):
675 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000676 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
677 modpkgs.append((modname, name, ispkg, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000678 modpkgs.sort()
679 contents = self.multicolumn(modpkgs, self.modpkglink)
680 result = result + self.bigsection(
681 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000682 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000683 contents = self.multicolumn(
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000684 modules, lambda t: self.modulelink(t[1]))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000685 result = result + self.bigsection(
Christian Heimes7131fd92008-02-19 14:21:46 +0000686 'Modules', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000687
688 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000689 classlist = [value for (key, value) in classes]
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000690 contents = [
691 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000692 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000693 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000694 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000695 'Classes', '#ffffff', '#ee77aa', ' '.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000696 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000697 contents = []
698 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000699 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000700 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000701 'Functions', '#ffffff', '#eeaa77', ' '.join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000702 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000703 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000704 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000705 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000706 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000707 'Data', '#ffffff', '#55aa55', '<br>\n'.join(contents))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000708 if hasattr(object, '__author__'):
709 contents = self.markup(str(object.__author__), self.preformat)
710 result = result + self.bigsection(
711 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000712 if hasattr(object, '__credits__'):
713 contents = self.markup(str(object.__credits__), self.preformat)
714 result = result + self.bigsection(
715 'Credits', '#ffffff', '#7799ee', contents)
716
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000717 return result
718
Tim Peters8dd7ade2001-10-18 19:56:17 +0000719 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
720 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000721 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000722 realname = object.__name__
723 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000724 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000725
Tim Petersb47879b2001-09-24 04:47:19 +0000726 contents = []
727 push = contents.append
728
Tim Petersfa26f7c2001-09-24 08:05:11 +0000729 # Cute little class to pump out a horizontal rule between sections.
730 class HorizontalRule:
731 def __init__(self):
732 self.needone = 0
733 def maybe(self):
734 if self.needone:
735 push('<hr>\n')
736 self.needone = 1
737 hr = HorizontalRule()
738
Tim Petersc86f6ca2001-09-26 21:31:51 +0000739 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000740 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000741 if len(mro) > 2:
742 hr.maybe()
743 push('<dl><dt>Method resolution order:</dt>\n')
744 for base in mro:
745 push('<dd>%s</dd>\n' % self.classlink(base,
746 object.__module__))
747 push('</dl>\n')
748
Tim Petersb47879b2001-09-24 04:47:19 +0000749 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000750 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000751 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000752 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000753 push(msg)
754 for name, kind, homecls, value in ok:
755 push(self.document(getattr(object, name), name, mod,
756 funcs, classes, mdict, object))
757 push('\n')
758 return attrs
759
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000760 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000761 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000762 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000763 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000764 push(msg)
765 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000766 push(self._docdescriptor(name, value, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000767 return attrs
768
Tim Petersfa26f7c2001-09-24 08:05:11 +0000769 def spilldata(msg, attrs, predicate):
770 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000771 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000772 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000773 push(msg)
774 for name, kind, homecls, value in ok:
775 base = self.docother(getattr(object, name), name, mod)
Guido van Rossumd59da4b2007-05-22 18:11:13 +0000776 if hasattr(value, '__call__') or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000777 doc = getattr(value, "__doc__", None)
778 else:
779 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000780 if doc is None:
781 push('<dl><dt>%s</dl>\n' % base)
782 else:
783 doc = self.markup(getdoc(value), self.preformat,
784 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000785 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000786 push('<dl><dt>%s%s</dl>\n' % (base, doc))
787 push('\n')
788 return attrs
789
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000790 attrs = [(name, kind, cls, value)
791 for name, kind, cls, value in classify_class_attrs(object)
792 if visiblename(name)]
793
Tim Petersb47879b2001-09-24 04:47:19 +0000794 mdict = {}
795 for key, kind, homecls, value in attrs:
796 mdict[key] = anchor = '#' + name + '-' + key
797 value = getattr(object, key)
798 try:
799 # The value may not be hashable (e.g., a data attr with
800 # a dict or list value).
801 mdict[value] = anchor
802 except TypeError:
803 pass
804
Tim Petersfa26f7c2001-09-24 08:05:11 +0000805 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000806 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000807 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000808 else:
809 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000810 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
811
Georg Brandl1a3284e2007-12-02 09:40:06 +0000812 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000813 attrs = inherited
814 continue
815 elif thisclass is object:
816 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000817 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000818 tag = 'inherited from %s' % self.classlink(thisclass,
819 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000820 tag += ':<br>\n'
821
822 # Sort attrs by name.
Raymond Hettingerd4cb56d2008-01-30 02:55:10 +0000823 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000824
825 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000826 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000827 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000828 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000829 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000830 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000831 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000832 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
833 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000834 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000835 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000836 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000837 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000838
839 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000840
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000841 if name == realname:
842 title = '<a name="%s">class <strong>%s</strong></a>' % (
843 name, realname)
844 else:
845 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
846 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000847 if bases:
848 parents = []
849 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000850 parents.append(self.classlink(base, object.__module__))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000851 title = title + '(%s)' % ', '.join(parents)
Tim Peters2306d242001-09-25 03:18:32 +0000852 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000853 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000854
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000855 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000856
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000857 def formatvalue(self, object):
858 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000859 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000860
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000861 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000862 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000863 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000864 realname = object.__name__
865 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000866 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000867 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000868 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000869 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +0000870 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000871 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000872 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000873 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000874 else:
Christian Heimesff737952007-11-27 10:40:20 +0000875 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000876 note = ' method of %s instance' % self.classlink(
Christian Heimesff737952007-11-27 10:40:20 +0000877 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000878 else:
879 note = ' unbound %s method' % self.classlink(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +0000880 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000881
882 if name == realname:
883 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
884 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000885 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000886 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000887 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000888 cl.__name__ + '-' + realname, realname)
889 skipdocs = 1
890 else:
891 reallink = realname
892 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
893 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000894 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +0000895 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann = \
896 inspect.getfullargspec(object)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000897 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +0000898 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann,
899 formatvalue=self.formatvalue,
900 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000901 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000902 title = '<strong>%s</strong> <em>lambda</em> ' % name
Guido van Rossum2e65f892007-02-28 22:03:49 +0000903 # XXX lambda's won't usually have func_annotations['return']
904 # since the syntax doesn't support but it is possible.
905 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000906 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000907 else:
908 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000909
Tim Peters2306d242001-09-25 03:18:32 +0000910 decl = title + argspec + (note and self.grey(
911 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000912
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000913 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000914 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000915 else:
916 doc = self.markup(
917 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000918 doc = doc and '<dd><tt>%s</tt></dd>' % doc
919 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000920
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000921 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000922 results = []
923 push = results.append
924
925 if name:
926 push('<dl><dt><strong>%s</strong></dt>\n' % name)
927 if value.__doc__ is not None:
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +0000928 doc = self.markup(getdoc(value), self.preformat)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000929 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000930 push('</dl>\n')
931
932 return ''.join(results)
933
934 def docproperty(self, object, name=None, mod=None, cl=None):
935 """Produce html documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000936 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000937
Tim Peters8dd7ade2001-10-18 19:56:17 +0000938 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000939 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000940 lhs = name and '<strong>%s</strong> = ' % name or ''
941 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000942
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000943 def docdata(self, object, name=None, mod=None, cl=None):
944 """Produce html documentation for a data descriptor."""
945 return self._docdescriptor(name, object, mod)
946
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000947 def index(self, dir, shadowed=None):
948 """Generate an HTML index for a directory of modules."""
949 modpkgs = []
950 if shadowed is None: shadowed = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000951 for importer, name, ispkg in pkgutil.iter_modules([dir]):
952 modpkgs.append((name, '', ispkg, name in shadowed))
953 shadowed[name] = 1
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000954
955 modpkgs.sort()
956 contents = self.multicolumn(modpkgs, self.modpkglink)
957 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
958
959# -------------------------------------------- text documentation generator
960
961class TextRepr(Repr):
962 """Class for safely making a text representation of a Python object."""
963 def __init__(self):
964 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000965 self.maxlist = self.maxtuple = 20
966 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000967 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000968
969 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000970 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000971 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000972 if hasattr(self, methodname):
973 return getattr(self, methodname)(x, level)
974 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000975
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000976 def repr_string(self, x, level):
977 test = cram(x, self.maxstring)
978 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000979 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000980 # Backslashes are only literal in the string and are never
981 # needed to make any special characters, so show a raw string.
982 return 'r' + testrepr[0] + test + testrepr[0]
983 return testrepr
984
Skip Montanarodf708782002-03-07 22:58:02 +0000985 repr_str = repr_string
986
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000987 def repr_instance(self, x, level):
988 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000989 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000990 except:
991 return '<%s instance>' % x.__class__.__name__
992
993class TextDoc(Doc):
994 """Formatter class for text documentation."""
995
996 # ------------------------------------------- text formatting utilities
997
998 _repr_instance = TextRepr()
999 repr = _repr_instance.repr
1000
1001 def bold(self, text):
1002 """Format a string in bold by overstriking."""
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001003 return ''.join(ch + '\b' + ch for ch in text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001004
1005 def indent(self, text, prefix=' '):
1006 """Indent text by prepending a given prefix to each line."""
1007 if not text: return ''
Collin Winter72e110c2007-07-17 00:27:30 +00001008 lines = [prefix + line for line in text.split('\n')]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001009 if lines: lines[-1] = lines[-1].rstrip()
1010 return '\n'.join(lines)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001011
1012 def section(self, title, contents):
1013 """Format a section with a given heading."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001014 clean_contents = self.indent(contents).rstrip()
1015 return self.bold(title) + '\n' + clean_contents + '\n\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001016
1017 # ---------------------------------------------- type-specific routines
1018
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001019 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001020 """Render in text a class tree as returned by inspect.getclasstree()."""
1021 result = ''
1022 for entry in tree:
1023 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001024 c, bases = entry
1025 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001026 if bases and bases != (parent,):
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001027 parents = (classname(c, modname) for c in bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001028 result = result + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001029 result = result + '\n'
1030 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001031 result = result + self.formattree(
1032 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001033 return result
1034
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001035 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001036 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001037 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001038 synop, desc = splitdoc(getdoc(object))
1039 result = self.section('NAME', name + (synop and ' - ' + synop))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001040 all = getattr(object, '__all__', None)
Skip Montanaro4997a692003-09-10 16:47:51 +00001041 docloc = self.getdocloc(object)
1042 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001043 result = result + self.section('MODULE REFERENCE', docloc + """
1044
1045The following documentation is automatically generated from the Python source
1046files. It may be incomplete, incorrect or include features that are considered
1047implementation detail and may vary between Python implementations. When in
1048doubt, consult the module reference at the location listed above.
1049""")
Skip Montanaro4997a692003-09-10 16:47:51 +00001050
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001051 if desc:
1052 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001053
1054 classes = []
1055 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001056 # if __all__ exists, believe it. Otherwise use old heuristic.
1057 if (all is not None
1058 or (inspect.getmodule(value) or object) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001059 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001060 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001061 funcs = []
1062 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001063 # if __all__ exists, believe it. Otherwise use old heuristic.
1064 if (all is not None or
1065 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001066 if visiblename(key, all):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001067 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001068 data = []
1069 for key, value in inspect.getmembers(object, isdata):
Skip Montanaroa5616d22004-06-11 04:46:12 +00001070 if visiblename(key, all):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001071 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001072
Christian Heimes1af737c2008-01-23 08:24:23 +00001073 modpkgs = []
1074 modpkgs_names = set()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001075 if hasattr(object, '__path__'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001076 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
Christian Heimes1af737c2008-01-23 08:24:23 +00001077 modpkgs_names.add(modname)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001078 if ispkg:
1079 modpkgs.append(modname + ' (package)')
1080 else:
1081 modpkgs.append(modname)
1082
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001083 modpkgs.sort()
1084 result = result + self.section(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001085 'PACKAGE CONTENTS', '\n'.join(modpkgs))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001086
Christian Heimes1af737c2008-01-23 08:24:23 +00001087 # Detect submodules as sometimes created by C extensions
1088 submodules = []
1089 for key, value in inspect.getmembers(object, inspect.ismodule):
1090 if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1091 submodules.append(key)
1092 if submodules:
1093 submodules.sort()
1094 result = result + self.section(
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001095 'SUBMODULES', '\n'.join(submodules))
Christian Heimes1af737c2008-01-23 08:24:23 +00001096
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001097 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001098 classlist = [value for key, value in classes]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001099 contents = [self.formattree(
1100 inspect.getclasstree(classlist, 1), name)]
1101 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001102 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001103 result = result + self.section('CLASSES', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001104
1105 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001106 contents = []
1107 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001108 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001109 result = result + self.section('FUNCTIONS', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001110
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001111 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001112 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001113 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001114 contents.append(self.docother(value, key, name, maxlen=70))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001115 result = result + self.section('DATA', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001116
1117 if hasattr(object, '__version__'):
1118 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001119 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001120 version = version[11:-1].strip()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001121 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001122 if hasattr(object, '__date__'):
1123 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001124 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001125 result = result + self.section('AUTHOR', str(object.__author__))
1126 if hasattr(object, '__credits__'):
1127 result = result + self.section('CREDITS', str(object.__credits__))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001128 try:
1129 file = inspect.getabsfile(object)
1130 except TypeError:
1131 file = '(built-in)'
1132 result = result + self.section('FILE', file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001133 return result
1134
Georg Brandl9bd45f992010-12-03 09:58:38 +00001135 def docclass(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001136 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001137 realname = object.__name__
1138 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001139 bases = object.__bases__
1140
Tim Petersc86f6ca2001-09-26 21:31:51 +00001141 def makename(c, m=object.__module__):
1142 return classname(c, m)
1143
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001144 if name == realname:
1145 title = 'class ' + self.bold(realname)
1146 else:
1147 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001148 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001149 parents = map(makename, bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001150 title = title + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001151
1152 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001153 contents = doc and [doc + '\n'] or []
1154 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001155
Tim Petersc86f6ca2001-09-26 21:31:51 +00001156 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001157 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001158 if len(mro) > 2:
1159 push("Method resolution order:")
1160 for base in mro:
1161 push(' ' + makename(base))
1162 push('')
1163
Tim Petersf4aad8e2001-09-24 22:40:47 +00001164 # Cute little class to pump out a horizontal rule between sections.
1165 class HorizontalRule:
1166 def __init__(self):
1167 self.needone = 0
1168 def maybe(self):
1169 if self.needone:
1170 push('-' * 70)
1171 self.needone = 1
1172 hr = HorizontalRule()
1173
Tim Peters28355492001-09-23 21:29:55 +00001174 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001175 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001176 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001177 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001178 push(msg)
1179 for name, kind, homecls, value in ok:
1180 push(self.document(getattr(object, name),
1181 name, mod, object))
1182 return attrs
1183
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001184 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001185 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001186 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001187 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001188 push(msg)
1189 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001190 push(self._docdescriptor(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001191 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001192
Tim Petersfa26f7c2001-09-24 08:05:11 +00001193 def spilldata(msg, attrs, predicate):
1194 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001195 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001196 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001197 push(msg)
1198 for name, kind, homecls, value in ok:
Guido van Rossumd59da4b2007-05-22 18:11:13 +00001199 if hasattr(value, '__call__') or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001200 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001201 else:
1202 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001203 push(self.docother(getattr(object, name),
Georg Brandl8b813db2005-10-01 16:32:31 +00001204 name, mod, maxlen=70, doc=doc) + '\n')
Tim Peters28355492001-09-23 21:29:55 +00001205 return attrs
1206
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001207 attrs = [(name, kind, cls, value)
1208 for name, kind, cls, value in classify_class_attrs(object)
1209 if visiblename(name)]
1210
Tim Petersfa26f7c2001-09-24 08:05:11 +00001211 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001212 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001213 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001214 else:
1215 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001216 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1217
Georg Brandl1a3284e2007-12-02 09:40:06 +00001218 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001219 attrs = inherited
1220 continue
1221 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001222 tag = "defined here"
1223 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001224 tag = "inherited from %s" % classname(thisclass,
1225 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001226
1227 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001228 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001229
1230 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001231 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001232 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001233 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001234 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001235 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001236 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001237 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1238 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001239 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1240 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001241 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001242 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001243
1244 contents = '\n'.join(contents)
1245 if not contents:
1246 return title + '\n'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001247 return title + '\n' + self.indent(contents.rstrip(), ' | ') + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001248
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001249 def formatvalue(self, object):
1250 """Format an argument default value as text."""
1251 return '=' + self.repr(object)
1252
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001253 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001254 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001255 realname = object.__name__
1256 name = name or realname
1257 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001258 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001259 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +00001260 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001261 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001262 if imclass is not cl:
1263 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001264 else:
Christian Heimesff737952007-11-27 10:40:20 +00001265 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001266 note = ' method of %s instance' % classname(
Christian Heimesff737952007-11-27 10:40:20 +00001267 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001268 else:
1269 note = ' unbound %s method' % classname(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +00001270 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001271
1272 if name == realname:
1273 title = self.bold(realname)
1274 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001275 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001276 cl.__dict__[realname] is object):
1277 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001278 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001279 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +00001280 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann = \
1281 inspect.getfullargspec(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001282 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +00001283 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann,
1284 formatvalue=self.formatvalue,
1285 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001286 if realname == '<lambda>':
Georg Brandl501dd0d2006-02-17 09:45:40 +00001287 title = self.bold(name) + ' lambda '
Guido van Rossum2e65f892007-02-28 22:03:49 +00001288 # XXX lambda's won't usually have func_annotations['return']
1289 # since the syntax doesn't support but it is possible.
1290 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001291 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001292 else:
1293 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001294 decl = title + argspec + note
1295
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001296 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001297 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001298 else:
1299 doc = getdoc(object) or ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001300 return decl + '\n' + (doc and self.indent(doc).rstrip() + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001301
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001302 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001303 results = []
1304 push = results.append
1305
1306 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001307 push(self.bold(name))
1308 push('\n')
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001309 doc = getdoc(value) or ''
1310 if doc:
1311 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001312 push('\n')
1313 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001314
1315 def docproperty(self, object, name=None, mod=None, cl=None):
1316 """Produce text documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001317 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001318
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001319 def docdata(self, object, name=None, mod=None, cl=None):
1320 """Produce text documentation for a data descriptor."""
1321 return self._docdescriptor(name, object, mod)
1322
Georg Brandl8b813db2005-10-01 16:32:31 +00001323 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001324 """Produce text documentation for a data object."""
1325 repr = self.repr(object)
1326 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001327 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001328 chop = maxlen - len(line)
1329 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001330 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001331 if doc is not None:
1332 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001333 return line
1334
Georg Brandld80d5f42010-12-03 07:47:22 +00001335class _PlainTextDoc(TextDoc):
1336 """Subclass of TextDoc which overrides string styling"""
1337 def bold(self, text):
1338 return text
1339
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001340# --------------------------------------------------------- user interfaces
1341
1342def pager(text):
1343 """The first time this is called, determine what kind of pager to use."""
1344 global pager
1345 pager = getpager()
1346 pager(text)
1347
1348def getpager():
1349 """Decide what method to use for paging through text."""
Guido van Rossuma01a8b62007-05-27 09:20:14 +00001350 if not hasattr(sys.stdout, "isatty"):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001351 return plainpager
1352 if not sys.stdin.isatty() or not sys.stdout.isatty():
1353 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001354 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001355 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001356 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001357 elif os.environ.get('TERM') in ('dumb', 'emacs'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001358 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001359 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001360 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001361 if os.environ.get('TERM') in ('dumb', 'emacs'):
1362 return plainpager
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001363 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001364 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001365 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001366 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001367
1368 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001369 (fd, filename) = tempfile.mkstemp()
1370 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001371 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001372 if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001373 return lambda text: pipepager(text, 'more')
1374 else:
1375 return ttypager
1376 finally:
1377 os.unlink(filename)
1378
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001379def plain(text):
1380 """Remove boldface formatting from text."""
1381 return re.sub('.\b', '', text)
1382
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001383def pipepager(text, cmd):
1384 """Page through text by feeding it to another program."""
1385 pipe = os.popen(cmd, 'w')
1386 try:
1387 pipe.write(text)
1388 pipe.close()
1389 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001390 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001391
1392def tempfilepager(text, cmd):
1393 """Page through text by invoking a program on a temporary file."""
1394 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001395 filename = tempfile.mktemp()
1396 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001397 file.write(text)
1398 file.close()
1399 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001400 os.system(cmd + ' "' + filename + '"')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001401 finally:
1402 os.unlink(filename)
1403
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001404def ttypager(text):
1405 """Page through text on a text terminal."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001406 lines = plain(text).split('\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001407 try:
1408 import tty
1409 fd = sys.stdin.fileno()
1410 old = tty.tcgetattr(fd)
1411 tty.setcbreak(fd)
1412 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001413 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001414 tty = None
1415 getchar = lambda: sys.stdin.readline()[:-1][:1]
1416
1417 try:
1418 r = inc = os.environ.get('LINES', 25) - 1
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001419 sys.stdout.write('\n'.join(lines[:inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001420 while lines[r:]:
1421 sys.stdout.write('-- more --')
1422 sys.stdout.flush()
1423 c = getchar()
1424
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001425 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001426 sys.stdout.write('\r \r')
1427 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001428 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001429 sys.stdout.write('\r \r' + lines[r] + '\n')
1430 r = r + 1
1431 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001432 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001433 r = r - inc - inc
1434 if r < 0: r = 0
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001435 sys.stdout.write('\n' + '\n'.join(lines[r:r+inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001436 r = r + inc
1437
1438 finally:
1439 if tty:
1440 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1441
1442def plainpager(text):
1443 """Simply print unformatted text. This is the ultimate fallback."""
1444 sys.stdout.write(plain(text))
1445
1446def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001447 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001448 if inspect.ismodule(thing):
1449 if thing.__name__ in sys.builtin_module_names:
1450 return 'built-in module ' + thing.__name__
1451 if hasattr(thing, '__path__'):
1452 return 'package ' + thing.__name__
1453 else:
1454 return 'module ' + thing.__name__
1455 if inspect.isbuiltin(thing):
1456 return 'built-in function ' + thing.__name__
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001457 if inspect.isgetsetdescriptor(thing):
1458 return 'getset descriptor %s.%s.%s' % (
1459 thing.__objclass__.__module__, thing.__objclass__.__name__,
1460 thing.__name__)
1461 if inspect.ismemberdescriptor(thing):
1462 return 'member descriptor %s.%s.%s' % (
1463 thing.__objclass__.__module__, thing.__objclass__.__name__,
1464 thing.__name__)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001465 if inspect.isclass(thing):
1466 return 'class ' + thing.__name__
1467 if inspect.isfunction(thing):
1468 return 'function ' + thing.__name__
1469 if inspect.ismethod(thing):
1470 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001471 return type(thing).__name__
1472
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001473def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001474 """Locate an object by name or dotted path, importing as necessary."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001475 parts = [part for part in path.split('.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001476 module, n = None, 0
1477 while n < len(parts):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001478 nextmodule = safeimport('.'.join(parts[:n+1]), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001479 if nextmodule: module, n = nextmodule, n + 1
1480 else: break
1481 if module:
1482 object = module
1483 for part in parts[n:]:
1484 try: object = getattr(object, part)
1485 except AttributeError: return None
1486 return object
1487 else:
Georg Brandl1a3284e2007-12-02 09:40:06 +00001488 if hasattr(builtins, path):
1489 return getattr(builtins, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001490
1491# --------------------------------------- interactive interpreter interface
1492
1493text = TextDoc()
Georg Brandld80d5f42010-12-03 07:47:22 +00001494plaintext = _PlainTextDoc()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001495html = HTMLDoc()
1496
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001497def resolve(thing, forceload=0):
1498 """Given an object or a path to an object, get the object and its name."""
1499 if isinstance(thing, str):
1500 object = locate(thing, forceload)
1501 if not object:
Collin Winterce36ad82007-08-30 01:19:48 +00001502 raise ImportError('no Python documentation found for %r' % thing)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001503 return object, thing
1504 else:
1505 return thing, getattr(thing, '__name__', None)
1506
Georg Brandld80d5f42010-12-03 07:47:22 +00001507def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
1508 renderer=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001509 """Render text documentation, given an object or a path to an object."""
Georg Brandld80d5f42010-12-03 07:47:22 +00001510 if renderer is None:
1511 renderer = text
Guido van Rossumd8faa362007-04-27 19:54:29 +00001512 object, name = resolve(thing, forceload)
1513 desc = describe(object)
1514 module = inspect.getmodule(object)
1515 if name and '.' in name:
1516 desc += ' in ' + name[:name.rfind('.')]
1517 elif module and module is not object:
1518 desc += ' in module ' + module.__name__
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001519
1520 if not (inspect.ismodule(object) or
Guido van Rossumd8faa362007-04-27 19:54:29 +00001521 inspect.isclass(object) or
1522 inspect.isroutine(object) or
1523 inspect.isgetsetdescriptor(object) or
1524 inspect.ismemberdescriptor(object) or
1525 isinstance(object, property)):
1526 # If the passed object is a piece of data or an instance,
1527 # document its available methods instead of its value.
1528 object = type(object)
1529 desc += ' object'
Georg Brandld80d5f42010-12-03 07:47:22 +00001530 return title % desc + '\n\n' + renderer.document(object, name)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001531
Georg Brandld80d5f42010-12-03 07:47:22 +00001532def doc(thing, title='Python Library Documentation: %s', forceload=0,
1533 output=None):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001534 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001535 try:
Georg Brandld80d5f42010-12-03 07:47:22 +00001536 if output is None:
1537 pager(render_doc(thing, title, forceload))
1538 else:
1539 output.write(render_doc(thing, title, forceload, plaintext))
Guido van Rossumb940e112007-01-10 16:19:56 +00001540 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001541 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001542
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001543def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001544 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001545 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001546 object, name = resolve(thing, forceload)
1547 page = html.page(describe(object), html.document(object, name))
Georg Brandl388faac2009-04-10 08:31:48 +00001548 file = open(name + '.html', 'w', encoding='utf-8')
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001549 file.write(page)
1550 file.close()
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001551 print('wrote', name + '.html')
Guido van Rossumb940e112007-01-10 16:19:56 +00001552 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001553 print(value)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001554
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001555def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001556 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001557 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001558 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1559 writedoc(modname)
1560 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001561
1562class Helper:
Georg Brandl6b38daa2008-06-01 21:05:17 +00001563
1564 # These dictionaries map a topic name to either an alias, or a tuple
1565 # (label, seealso-items). The "label" is the label of the corresponding
1566 # section in the .rst file under Doc/ and an index into the dictionary
Georg Brandl5617db82009-04-27 16:28:57 +00001567 # in pydoc_data/topics.py.
Georg Brandl6b38daa2008-06-01 21:05:17 +00001568 #
1569 # CAUTION: if you change one of these dictionaries, be sure to adapt the
1570 # list of needed labels in Doc/tools/sphinxext/pyspecific.py and
Georg Brandl5617db82009-04-27 16:28:57 +00001571 # regenerate the pydoc_data/topics.py file by running
Georg Brandl6b38daa2008-06-01 21:05:17 +00001572 # make pydoc-topics
1573 # in Doc/ and copying the output file into the Lib/ directory.
1574
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001575 keywords = {
1576 'and': 'BOOLEAN',
Guido van Rossumd8faa362007-04-27 19:54:29 +00001577 'as': 'with',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001578 'assert': ('assert', ''),
1579 'break': ('break', 'while for'),
1580 'class': ('class', 'CLASSES SPECIALMETHODS'),
1581 'continue': ('continue', 'while for'),
1582 'def': ('function', ''),
1583 'del': ('del', 'BASICMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001584 'elif': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001585 'else': ('else', 'while for'),
Georg Brandl0d855392008-08-30 19:53:05 +00001586 'except': 'try',
1587 'finally': 'try',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001588 'for': ('for', 'break continue while'),
Georg Brandl0d855392008-08-30 19:53:05 +00001589 'from': 'import',
Georg Brandl74abf6f2010-11-20 19:54:36 +00001590 'global': ('global', 'nonlocal NAMESPACES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001591 'if': ('if', 'TRUTHVALUE'),
1592 'import': ('import', 'MODULES'),
Georg Brandl395ed242009-09-04 08:07:32 +00001593 'in': ('in', 'SEQUENCEMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001594 'is': 'COMPARISON',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001595 'lambda': ('lambda', 'FUNCTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001596 'nonlocal': ('nonlocal', 'global NAMESPACES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001597 'not': 'BOOLEAN',
1598 'or': 'BOOLEAN',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001599 'pass': ('pass', ''),
1600 'raise': ('raise', 'EXCEPTIONS'),
1601 'return': ('return', 'FUNCTIONS'),
1602 'try': ('try', 'EXCEPTIONS'),
1603 'while': ('while', 'break continue if TRUTHVALUE'),
1604 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1605 'yield': ('yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001606 }
Georg Brandldb7b6b92009-01-01 15:53:14 +00001607 # Either add symbols to this dictionary or to the symbols dictionary
1608 # directly: Whichever is easier. They are merged later.
1609 _symbols_inverse = {
1610 'STRINGS' : ("'", "'''", "r'", "b'", '"""', '"', 'r"', 'b"'),
1611 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1612 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1613 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1614 'UNARY' : ('-', '~'),
1615 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1616 '^=', '<<=', '>>=', '**=', '//='),
1617 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1618 'COMPLEX' : ('j', 'J')
1619 }
1620 symbols = {
1621 '%': 'OPERATORS FORMATTING',
1622 '**': 'POWER',
1623 ',': 'TUPLES LISTS FUNCTIONS',
1624 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1625 '...': 'ELLIPSIS',
1626 ':': 'SLICINGS DICTIONARYLITERALS',
1627 '@': 'def class',
1628 '\\': 'STRINGS',
1629 '_': 'PRIVATENAMES',
1630 '__': 'PRIVATENAMES SPECIALMETHODS',
1631 '`': 'BACKQUOTES',
1632 '(': 'TUPLES FUNCTIONS CALLS',
1633 ')': 'TUPLES FUNCTIONS CALLS',
1634 '[': 'LISTS SUBSCRIPTS SLICINGS',
1635 ']': 'LISTS SUBSCRIPTS SLICINGS'
1636 }
1637 for topic, symbols_ in _symbols_inverse.items():
1638 for symbol in symbols_:
1639 topics = symbols.get(symbol, topic)
1640 if topic not in topics:
1641 topics = topics + ' ' + topic
1642 symbols[symbol] = topics
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001643
1644 topics = {
Georg Brandl6b38daa2008-06-01 21:05:17 +00001645 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1646 'FUNCTIONS CLASSES MODULES FILES inspect'),
1647 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
1648 'FORMATTING TYPES'),
1649 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1650 'FORMATTING': ('formatstrings', 'OPERATORS'),
1651 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1652 'FORMATTING TYPES'),
1653 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1654 'INTEGER': ('integers', 'int range'),
1655 'FLOAT': ('floating', 'float math'),
1656 'COMPLEX': ('imaginary', 'complex cmath'),
1657 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001658 'MAPPINGS': 'DICTIONARIES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001659 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1660 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1661 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1662 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001663 'FRAMEOBJECTS': 'TYPES',
1664 'TRACEBACKS': 'TYPES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001665 'NONE': ('bltin-null-object', ''),
1666 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
1667 'FILES': ('bltin-file-objects', ''),
1668 'SPECIALATTRIBUTES': ('specialattrs', ''),
1669 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1670 'MODULES': ('typesmodules', 'import'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001671 'PACKAGES': 'import',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001672 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1673 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1674 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1675 'LISTS DICTIONARIES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001676 'OPERATORS': 'EXPRESSIONS',
1677 'PRECEDENCE': 'EXPRESSIONS',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001678 'OBJECTS': ('objects', 'TYPES'),
1679 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
Georg Brandl395ed242009-09-04 08:07:32 +00001680 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
1681 'NUMBERMETHODS CLASSES'),
Mark Dickinsona56c4672009-01-27 18:17:45 +00001682 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001683 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1684 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001685 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
Georg Brandl6b38daa2008-06-01 21:05:17 +00001686 'SPECIALMETHODS'),
1687 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1688 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1689 'SPECIALMETHODS'),
1690 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001691 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001692 'DYNAMICFEATURES': ('dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001693 'SCOPING': 'NAMESPACES',
1694 'FRAMES': 'NAMESPACES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001695 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1696 'CONVERSIONS': ('conversions', ''),
1697 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1698 'SPECIALIDENTIFIERS': ('id-classes', ''),
1699 'PRIVATENAMES': ('atom-identifiers', ''),
1700 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
1701 'LISTLITERALS DICTIONARYLITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001702 'TUPLES': 'SEQUENCES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001703 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1704 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1705 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1706 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1707 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1708 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001709 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
1710 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001711 'CALLS': ('calls', 'EXPRESSIONS'),
1712 'POWER': ('power', 'EXPRESSIONS'),
1713 'UNARY': ('unary', 'EXPRESSIONS'),
1714 'BINARY': ('binary', 'EXPRESSIONS'),
1715 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1716 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1717 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1718 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001719 'ASSERTION': 'assert',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001720 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1721 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001722 'DELETION': 'del',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001723 'RETURNING': 'return',
1724 'IMPORTING': 'import',
1725 'CONDITIONAL': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001726 'LOOPING': ('compound', 'for while break continue'),
1727 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1728 'DEBUGGING': ('debugger', 'pdb'),
1729 'CONTEXTMANAGERS': ('context-managers', 'with'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001730 }
1731
Georg Brandl78aa3962010-07-31 21:51:48 +00001732 def __init__(self, input=None, output=None):
1733 self._input = input
1734 self._output = output
1735
Georg Brandl76ae3972010-08-01 06:32:55 +00001736 input = property(lambda self: self._input or sys.stdin)
1737 output = property(lambda self: self._output or sys.stdout)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001738
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001739 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001740 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001741 self()
1742 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001743 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001744
Alexander Belopolsky2e733c92010-07-04 17:00:20 +00001745 _GoInteractive = object()
1746 def __call__(self, request=_GoInteractive):
1747 if request is not self._GoInteractive:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001748 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001749 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001750 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001751 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001752 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001753You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001754If you want to ask for help on a particular object directly from the
1755interpreter, you can type "help(object)". Executing "help('string')"
1756has the same effect as typing a particular string at the help> prompt.
1757''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001758
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001759 def interact(self):
1760 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001761 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001762 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001763 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001764 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001765 except (KeyboardInterrupt, EOFError):
1766 break
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001767 request = replace(request, '"', '', "'", '').strip()
1768 if request.lower() in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001769 self.help(request)
1770
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001771 def getline(self, prompt):
Guido van Rossum7c086c02008-01-02 03:52:38 +00001772 """Read one line, using input() when appropriate."""
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001773 if self.input is sys.stdin:
Guido van Rossum7c086c02008-01-02 03:52:38 +00001774 return input(prompt)
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001775 else:
1776 self.output.write(prompt)
1777 self.output.flush()
1778 return self.input.readline()
1779
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001780 def help(self, request):
1781 if type(request) is type(''):
R. David Murray1f1b9d32009-05-27 20:56:59 +00001782 request = request.strip()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001783 if request == 'help': self.intro()
1784 elif request == 'keywords': self.listkeywords()
Georg Brandldb7b6b92009-01-01 15:53:14 +00001785 elif request == 'symbols': self.listsymbols()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001786 elif request == 'topics': self.listtopics()
1787 elif request == 'modules': self.listmodules()
1788 elif request[:8] == 'modules ':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001789 self.listmodules(request.split()[1])
Georg Brandldb7b6b92009-01-01 15:53:14 +00001790 elif request in self.symbols: self.showsymbol(request)
Raymond Hettinger54f02222002-06-01 14:18:47 +00001791 elif request in self.keywords: self.showtopic(request)
1792 elif request in self.topics: self.showtopic(request)
Georg Brandld80d5f42010-12-03 07:47:22 +00001793 elif request: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001794 elif isinstance(request, Helper): self()
Georg Brandld80d5f42010-12-03 07:47:22 +00001795 else: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001796 self.output.write('\n')
1797
1798 def intro(self):
1799 self.output.write('''
1800Welcome to Python %s! This is the online help utility.
1801
1802If this is your first time using Python, you should definitely check out
Georg Brandl86def6c2008-01-21 20:36:10 +00001803the tutorial on the Internet at http://docs.python.org/tutorial/.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001804
1805Enter the name of any module, keyword, or topic to get help on writing
1806Python programs and using Python modules. To quit this help utility and
1807return to the interpreter, just type "quit".
1808
1809To get a list of available modules, keywords, or topics, type "modules",
1810"keywords", or "topics". Each module also comes with a one-line summary
1811of what it does; to list the modules whose summaries contain a given word
1812such as "spam", type "modules spam".
1813''' % sys.version[:3])
1814
1815 def list(self, items, columns=4, width=80):
Guido van Rossum486364b2007-06-30 05:01:58 +00001816 items = list(sorted(items))
1817 colw = width // columns
1818 rows = (len(items) + columns - 1) // columns
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001819 for row in range(rows):
1820 for col in range(columns):
1821 i = col * rows + row
1822 if i < len(items):
1823 self.output.write(items[i])
1824 if col < columns - 1:
Guido van Rossum486364b2007-06-30 05:01:58 +00001825 self.output.write(' ' + ' ' * (colw - 1 - len(items[i])))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001826 self.output.write('\n')
1827
1828 def listkeywords(self):
1829 self.output.write('''
1830Here is a list of the Python keywords. Enter any keyword to get more help.
1831
1832''')
1833 self.list(self.keywords.keys())
1834
Georg Brandldb7b6b92009-01-01 15:53:14 +00001835 def listsymbols(self):
1836 self.output.write('''
1837Here is a list of the punctuation symbols which Python assigns special meaning
1838to. Enter any symbol to get more help.
1839
1840''')
1841 self.list(self.symbols.keys())
1842
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001843 def listtopics(self):
1844 self.output.write('''
1845Here is a list of available topics. Enter any topic name to get more help.
1846
1847''')
1848 self.list(self.topics.keys())
1849
Georg Brandldb7b6b92009-01-01 15:53:14 +00001850 def showtopic(self, topic, more_xrefs=''):
Georg Brandl6b38daa2008-06-01 21:05:17 +00001851 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001852 import pydoc_data.topics
Georg Brandl6b38daa2008-06-01 21:05:17 +00001853 except ImportError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001854 self.output.write('''
Georg Brandl6b38daa2008-06-01 21:05:17 +00001855Sorry, topic and keyword documentation is not available because the
Georg Brandl5617db82009-04-27 16:28:57 +00001856module "pydoc_data.topics" could not be found.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001857''')
1858 return
1859 target = self.topics.get(topic, self.keywords.get(topic))
1860 if not target:
1861 self.output.write('no documentation found for %s\n' % repr(topic))
1862 return
1863 if type(target) is type(''):
Georg Brandldb7b6b92009-01-01 15:53:14 +00001864 return self.showtopic(target, more_xrefs)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001865
Georg Brandl6b38daa2008-06-01 21:05:17 +00001866 label, xrefs = target
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001867 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001868 doc = pydoc_data.topics.topics[label]
Georg Brandl6b38daa2008-06-01 21:05:17 +00001869 except KeyError:
1870 self.output.write('no documentation found for %s\n' % repr(topic))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001871 return
Georg Brandl6b38daa2008-06-01 21:05:17 +00001872 pager(doc.strip() + '\n')
Georg Brandldb7b6b92009-01-01 15:53:14 +00001873 if more_xrefs:
1874 xrefs = (xrefs or '') + ' ' + more_xrefs
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001875 if xrefs:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001876 import formatter
Guido van Rossum34d19282007-08-09 01:03:29 +00001877 buffer = io.StringIO()
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001878 formatter.DumbWriter(buffer).send_flowing_data(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001879 'Related help topics: ' + ', '.join(xrefs.split()) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001880 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001881
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001882 def _gettopic(self, topic, more_xrefs=''):
1883 """Return unbuffered tuple of (topic, xrefs).
1884
Georg Brandld2f38572011-01-30 08:37:19 +00001885 If an error occurs here, the exception is caught and displayed by
1886 the url handler.
1887
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001888 This function duplicates the showtopic method but returns its
1889 result directly so it can be formatted for display in an html page.
1890 """
1891 try:
1892 import pydoc_data.topics
1893 except ImportError:
1894 return('''
1895Sorry, topic and keyword documentation is not available because the
1896module "pydoc_data.topics" could not be found.
1897''' , '')
1898 target = self.topics.get(topic, self.keywords.get(topic))
1899 if not target:
Georg Brandld2f38572011-01-30 08:37:19 +00001900 raise ValueError('could not find topic')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001901 if isinstance(target, str):
1902 return self._gettopic(target, more_xrefs)
1903 label, xrefs = target
Georg Brandld2f38572011-01-30 08:37:19 +00001904 doc = pydoc_data.topics.topics[label]
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001905 if more_xrefs:
1906 xrefs = (xrefs or '') + ' ' + more_xrefs
1907 return doc, xrefs
1908
Georg Brandldb7b6b92009-01-01 15:53:14 +00001909 def showsymbol(self, symbol):
1910 target = self.symbols[symbol]
1911 topic, _, xrefs = target.partition(' ')
1912 self.showtopic(topic, xrefs)
1913
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001914 def listmodules(self, key=''):
1915 if key:
1916 self.output.write('''
1917Here is a list of matching modules. Enter any module name to get more help.
1918
1919''')
1920 apropos(key)
1921 else:
1922 self.output.write('''
1923Please wait a moment while I gather a list of all available modules...
1924
1925''')
1926 modules = {}
1927 def callback(path, modname, desc, modules=modules):
1928 if modname and modname[-9:] == '.__init__':
1929 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001930 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001931 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001932 def onerror(modname):
1933 callback(None, modname, None)
1934 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001935 self.list(modules.keys())
1936 self.output.write('''
1937Enter any module name to get more help. Or, type "modules spam" to search
1938for modules whose descriptions contain the word "spam".
1939''')
1940
Georg Brandl78aa3962010-07-31 21:51:48 +00001941help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001942
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001943class Scanner:
1944 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001945 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001946 self.roots = roots[:]
1947 self.state = []
1948 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001949 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001950
1951 def next(self):
1952 if not self.state:
1953 if not self.roots:
1954 return None
1955 root = self.roots.pop(0)
1956 self.state = [(root, self.children(root))]
1957 node, children = self.state[-1]
1958 if not children:
1959 self.state.pop()
1960 return self.next()
1961 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001962 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001963 self.state.append((child, self.children(child)))
1964 return child
1965
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001966
1967class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001968 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001969
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001970 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001971 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001972 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001973 seen = {}
1974
1975 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001976 if modname != '__main__':
1977 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001978 if key is None:
1979 callback(None, modname, '')
1980 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001981 name = __import__(modname).__doc__ or ''
1982 desc = name.split('\n')[0]
1983 name = modname + ' - ' + desc
1984 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001985 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001986
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001987 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001988 if self.quit:
1989 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001990
1991 # XXX Skipping this file is a workaround for a bug
1992 # that causes python to crash with a segfault.
1993 # http://bugs.python.org/issue9319
1994 #
1995 # TODO Remove this once the bug is fixed.
1996 if modname in {'test.badsyntax_pep3120', 'badsyntax_pep3120'}:
1997 continue
1998
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001999 if key is None:
2000 callback(None, modname, '')
2001 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002002 try:
2003 loader = importer.find_module(modname)
2004 except SyntaxError:
2005 # raised by tests for bad coding cookies or BOM
2006 continue
2007 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002008 try:
2009 source = loader.get_source(modname)
2010 except UnicodeDecodeError:
2011 if onerror:
2012 onerror(modname)
2013 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002014 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002015 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002016 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002017 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002018 path = None
2019 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002020 try:
2021 module = loader.load_module(modname)
2022 except ImportError:
2023 if onerror:
2024 onerror(modname)
2025 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002026 desc = (module.__doc__ or '').splitlines()[0]
2027 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002028 name = modname + ' - ' + desc
2029 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002030 callback(path, modname, desc)
2031
2032 if completer:
2033 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002034
2035def apropos(key):
2036 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002037 def callback(path, modname, desc):
2038 if modname[-9:] == '.__init__':
2039 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002040 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002041 def onerror(modname):
2042 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002043 with warnings.catch_warnings():
2044 warnings.filterwarnings('ignore') # ignore problems during import
2045 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002046
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002047# --------------------------------------------------- Web browser interface
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002048
Ka-Ping Yee66246962001-04-12 11:59:50 +00002049def serve(port, callback=None, completer=None):
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002050 import http.server, email.message, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002051
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002052 msg = 'the pydoc.serve() function is deprecated'
2053 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2054
Georg Brandl24420152008-05-26 16:32:26 +00002055 class DocHandler(http.server.BaseHTTPRequestHandler):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002056 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002057 try:
2058 self.send_response(200)
Georg Brandl825fc8b2008-01-19 20:44:32 +00002059 self.send_header('Content-Type', 'text/html; charset=UTF-8')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002060 self.end_headers()
Georg Brandl825fc8b2008-01-19 20:44:32 +00002061 self.wfile.write(html.page(title, contents).encode('utf-8'))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002062 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002063
2064 def do_GET(self):
2065 path = self.path
2066 if path[-5:] == '.html': path = path[:-5]
2067 if path[:1] == '/': path = path[1:]
2068 if path and path != '.':
2069 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002070 obj = locate(path, forceload=1)
Guido van Rossumb940e112007-01-10 16:19:56 +00002071 except ErrorDuringImport as value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002072 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002073 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002074 if obj:
2075 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002076 else:
2077 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002078'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002079 else:
2080 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002081'<big><big><strong>Python: Index of Modules</strong></big></big>',
2082'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002083 def bltinlink(name):
2084 return '<a href="%s.html">%s</a>' % (name, name)
Georg Brandl661b0a12008-01-27 18:16:00 +00002085 names = [x for x in sys.builtin_module_names if x != '__main__']
2086 contents = html.multicolumn(names, bltinlink)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002087 indices = ['<p>' + html.bigsection(
2088 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2089
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002090 seen = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002091 for dir in sys.path:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002092 indices.append(html.index(dir, seen))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002093 contents = heading + ' '.join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00002094<font color="#909090" face="helvetica, arial"><strong>
2095pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002096 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002097
2098 def log_message(self, *args): pass
2099
Georg Brandl24420152008-05-26 16:32:26 +00002100 class DocServer(http.server.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002101 def __init__(self, port, callback):
Ronald Oussoren94f25282010-05-05 19:11:21 +00002102 host = 'localhost'
Senthil Kumaran7ff59132010-08-18 19:32:21 +00002103 self.address = (host, port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00002104 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002105 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002106 self.base.__init__(self, self.address, self.handler)
2107
2108 def serve_until_quit(self):
2109 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002110 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002111 while not self.quit:
2112 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2113 if rd: self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002114 self.server_close()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002115
2116 def server_activate(self):
2117 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002118 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002119
Georg Brandl24420152008-05-26 16:32:26 +00002120 DocServer.base = http.server.HTTPServer
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002121 DocServer.handler = DocHandler
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002122 DocHandler.MessageClass = email.message.Message
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002123 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002124 try:
2125 DocServer(port, callback).serve_until_quit()
2126 except (KeyboardInterrupt, select.error):
2127 pass
2128 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002129 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002130
2131# ----------------------------------------------------- graphical interface
2132
2133def gui():
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002134 """Graphical interface (starts Web server and pops up a control window)."""
2135
2136 msg = ('the pydoc.gui() function and "pydoc -g" option are deprecated\n',
2137 'use "pydoc.browse() function and "pydoc -b" option instead.')
2138 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2139
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002140 class GUI:
2141 def __init__(self, window, port=7464):
2142 self.window = window
2143 self.server = None
2144 self.scanner = None
2145
Georg Brandl14fc4272008-05-17 18:39:55 +00002146 import tkinter
2147 self.server_frm = tkinter.Frame(window)
2148 self.title_lbl = tkinter.Label(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002149 text='Starting server...\n ')
Georg Brandl14fc4272008-05-17 18:39:55 +00002150 self.open_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002151 text='open browser', command=self.open, state='disabled')
Georg Brandl14fc4272008-05-17 18:39:55 +00002152 self.quit_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002153 text='quit serving', command=self.quit, state='disabled')
2154
Georg Brandl14fc4272008-05-17 18:39:55 +00002155 self.search_frm = tkinter.Frame(window)
2156 self.search_lbl = tkinter.Label(self.search_frm, text='Search for')
2157 self.search_ent = tkinter.Entry(self.search_frm)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002158 self.search_ent.bind('<Return>', self.search)
Georg Brandl14fc4272008-05-17 18:39:55 +00002159 self.stop_btn = tkinter.Button(self.search_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002160 text='stop', pady=0, command=self.stop, state='disabled')
2161 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002162 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002163 self.stop_btn.pack(side='right')
2164
2165 self.window.title('pydoc')
2166 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2167 self.title_lbl.pack(side='top', fill='x')
2168 self.open_btn.pack(side='left', fill='x', expand=1)
2169 self.quit_btn.pack(side='right', fill='x', expand=1)
2170 self.server_frm.pack(side='top', fill='x')
2171
2172 self.search_lbl.pack(side='left')
2173 self.search_ent.pack(side='right', fill='x', expand=1)
2174 self.search_frm.pack(side='top', fill='x')
2175 self.search_ent.focus_set()
2176
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002177 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Georg Brandl14fc4272008-05-17 18:39:55 +00002178 self.result_lst = tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002179 self.result_lst.bind('<Button-1>', self.select)
2180 self.result_lst.bind('<Double-Button-1>', self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002181 self.result_scr = tkinter.Scrollbar(window,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002182 orient='vertical', command=self.result_lst.yview)
2183 self.result_lst.config(yscrollcommand=self.result_scr.set)
2184
Georg Brandl14fc4272008-05-17 18:39:55 +00002185 self.result_frm = tkinter.Frame(window)
2186 self.goto_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002187 text='go to selected', command=self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002188 self.hide_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002189 text='hide results', command=self.hide)
2190 self.goto_btn.pack(side='left', fill='x', expand=1)
2191 self.hide_btn.pack(side='right', fill='x', expand=1)
2192
2193 self.window.update()
2194 self.minwidth = self.window.winfo_width()
2195 self.minheight = self.window.winfo_height()
2196 self.bigminheight = (self.server_frm.winfo_reqheight() +
2197 self.search_frm.winfo_reqheight() +
2198 self.result_lst.winfo_reqheight() +
2199 self.result_frm.winfo_reqheight())
2200 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2201 self.expanded = 0
2202 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2203 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002204 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002205
2206 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002207 threading.Thread(
2208 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002209
2210 def ready(self, server):
2211 self.server = server
2212 self.title_lbl.config(
2213 text='Python documentation server at\n' + server.url)
2214 self.open_btn.config(state='normal')
2215 self.quit_btn.config(state='normal')
2216
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002217 def open(self, event=None, url=None):
2218 url = url or self.server.url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002219 import webbrowser
2220 webbrowser.open(url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002221
2222 def quit(self, event=None):
2223 if self.server:
2224 self.server.quit = 1
2225 self.window.quit()
2226
2227 def search(self, event=None):
2228 key = self.search_ent.get()
2229 self.stop_btn.pack(side='right')
2230 self.stop_btn.config(state='normal')
2231 self.search_lbl.config(text='Searching for "%s"...' % key)
2232 self.search_ent.forget()
2233 self.search_lbl.pack(side='left')
2234 self.result_lst.delete(0, 'end')
2235 self.goto_btn.config(state='disabled')
2236 self.expand()
2237
2238 import threading
2239 if self.scanner:
2240 self.scanner.quit = 1
2241 self.scanner = ModuleScanner()
2242 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002243 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002244
2245 def update(self, path, modname, desc):
2246 if modname[-9:] == '.__init__':
2247 modname = modname[:-9] + ' (package)'
2248 self.result_lst.insert('end',
2249 modname + ' - ' + (desc or '(no description)'))
2250
2251 def stop(self, event=None):
2252 if self.scanner:
2253 self.scanner.quit = 1
2254 self.scanner = None
2255
2256 def done(self):
2257 self.scanner = None
2258 self.search_lbl.config(text='Search for')
2259 self.search_lbl.pack(side='left')
2260 self.search_ent.pack(side='right', fill='x', expand=1)
2261 if sys.platform != 'win32': self.stop_btn.forget()
2262 self.stop_btn.config(state='disabled')
2263
2264 def select(self, event=None):
2265 self.goto_btn.config(state='normal')
2266
2267 def goto(self, event=None):
2268 selection = self.result_lst.curselection()
2269 if selection:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002270 modname = self.result_lst.get(selection[0]).split()[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002271 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002272
2273 def collapse(self):
2274 if not self.expanded: return
2275 self.result_frm.forget()
2276 self.result_scr.forget()
2277 self.result_lst.forget()
2278 self.bigwidth = self.window.winfo_width()
2279 self.bigheight = self.window.winfo_height()
2280 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2281 self.window.wm_minsize(self.minwidth, self.minheight)
2282 self.expanded = 0
2283
2284 def expand(self):
2285 if self.expanded: return
2286 self.result_frm.pack(side='bottom', fill='x')
2287 self.result_scr.pack(side='right', fill='y')
2288 self.result_lst.pack(side='top', fill='both', expand=1)
2289 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2290 self.window.wm_minsize(self.minwidth, self.bigminheight)
2291 self.expanded = 1
2292
2293 def hide(self, event=None):
2294 self.stop()
2295 self.collapse()
2296
Georg Brandl14fc4272008-05-17 18:39:55 +00002297 import tkinter
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002298 try:
Georg Brandl14fc4272008-05-17 18:39:55 +00002299 root = tkinter.Tk()
Martin v. Löwise09bd932004-08-22 16:13:26 +00002300 # Tk will crash if pythonw.exe has an XP .manifest
2301 # file and the root has is not destroyed explicitly.
2302 # If the problem is ever fixed in Tk, the explicit
2303 # destroy can go.
2304 try:
2305 gui = GUI(root)
2306 root.mainloop()
2307 finally:
2308 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002309 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002310 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002311
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002312
2313# --------------------------------------- enhanced Web browser interface
2314
2315def _start_server(urlhandler, port):
2316 """Start an HTTP server thread on a specific port.
2317
2318 Start an HTML/text server thread, so HTML or text documents can be
2319 browsed dynamically and interactively with a Web browser. Example use:
2320
2321 >>> import time
2322 >>> import pydoc
2323
2324 Define a URL handler. To determine what the client is asking
2325 for, check the URL and content_type.
2326
2327 Then get or generate some text or HTML code and return it.
2328
2329 >>> def my_url_handler(url, content_type):
2330 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2331 ... return text
2332
2333 Start server thread on port 0.
2334 If you use port 0, the server will pick a random port number.
2335 You can then use serverthread.port to get the port number.
2336
2337 >>> port = 0
2338 >>> serverthread = pydoc._start_server(my_url_handler, port)
2339
2340 Check that the server is really started. If it is, open browser
2341 and get first page. Use serverthread.url as the starting page.
2342
2343 >>> if serverthread.serving:
2344 ... import webbrowser
2345
2346 The next two lines are commented out so a browser doesn't open if
2347 doctest is run on this module.
2348
2349 #... webbrowser.open(serverthread.url)
2350 #True
2351
2352 Let the server do its thing. We just need to monitor its status.
2353 Use time.sleep so the loop doesn't hog the CPU.
2354
2355 >>> starttime = time.time()
2356 >>> timeout = 1 #seconds
2357
2358 This is a short timeout for testing purposes.
2359
2360 >>> while serverthread.serving:
2361 ... time.sleep(.01)
2362 ... if serverthread.serving and time.time() - starttime > timeout:
2363 ... serverthread.stop()
2364 ... break
2365
2366 Print any errors that may have occurred.
2367
2368 >>> print(serverthread.error)
2369 None
2370 """
2371 import http.server
2372 import email.message
2373 import select
2374 import threading
2375
2376 class DocHandler(http.server.BaseHTTPRequestHandler):
2377
2378 def do_GET(self):
2379 """Process a request from an HTML browser.
2380
2381 The URL received is in self.path.
2382 Get an HTML page from self.urlhandler and send it.
2383 """
2384 if self.path.endswith('.css'):
2385 content_type = 'text/css'
2386 else:
2387 content_type = 'text/html'
2388 self.send_response(200)
Georg Brandld2f38572011-01-30 08:37:19 +00002389 self.send_header('Content-Type', '%s; charset=UTF-8' % content_type)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002390 self.end_headers()
2391 self.wfile.write(self.urlhandler(
2392 self.path, content_type).encode('utf-8'))
2393
2394 def log_message(self, *args):
2395 # Don't log messages.
2396 pass
2397
2398 class DocServer(http.server.HTTPServer):
2399
2400 def __init__(self, port, callback):
2401 self.host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
2402 self.address = ('', port)
2403 self.callback = callback
2404 self.base.__init__(self, self.address, self.handler)
2405 self.quit = False
2406
2407 def serve_until_quit(self):
2408 while not self.quit:
2409 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2410 if rd:
2411 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002412 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002413
2414 def server_activate(self):
2415 self.base.server_activate(self)
2416 if self.callback:
2417 self.callback(self)
2418
2419 class ServerThread(threading.Thread):
2420
2421 def __init__(self, urlhandler, port):
2422 self.urlhandler = urlhandler
2423 self.port = int(port)
2424 threading.Thread.__init__(self)
2425 self.serving = False
2426 self.error = None
2427
2428 def run(self):
2429 """Start the server."""
2430 try:
2431 DocServer.base = http.server.HTTPServer
2432 DocServer.handler = DocHandler
2433 DocHandler.MessageClass = email.message.Message
2434 DocHandler.urlhandler = staticmethod(self.urlhandler)
2435 docsvr = DocServer(self.port, self.ready)
2436 self.docserver = docsvr
2437 docsvr.serve_until_quit()
2438 except Exception as e:
2439 self.error = e
2440
2441 def ready(self, server):
2442 self.serving = True
2443 self.host = server.host
2444 self.port = server.server_port
2445 self.url = 'http://%s:%d/' % (self.host, self.port)
2446
2447 def stop(self):
2448 """Stop the server and this thread nicely"""
2449 self.docserver.quit = True
2450 self.serving = False
2451 self.url = None
2452
2453 thread = ServerThread(urlhandler, port)
2454 thread.start()
2455 # Wait until thread.serving is True to make sure we are
2456 # really up before returning.
2457 while not thread.error and not thread.serving:
2458 time.sleep(.01)
2459 return thread
2460
2461
2462def _url_handler(url, content_type="text/html"):
2463 """The pydoc url handler for use with the pydoc server.
2464
2465 If the content_type is 'text/css', the _pydoc.css style
2466 sheet is read and returned if it exits.
2467
2468 If the content_type is 'text/html', then the result of
2469 get_html_page(url) is returned.
2470 """
2471 class _HTMLDoc(HTMLDoc):
2472
2473 def page(self, title, contents):
2474 """Format an HTML page."""
2475 css_path = "pydoc_data/_pydoc.css"
2476 css_link = (
2477 '<link rel="stylesheet" type="text/css" href="%s">' %
2478 css_path)
2479 return '''\
2480<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Georg Brandld2f38572011-01-30 08:37:19 +00002481<html><head><title>Pydoc: %s</title>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002482<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Georg Brandld2f38572011-01-30 08:37:19 +00002483%s</head><body bgcolor="#f0f0f8">%s<div style="clear:both;padding-top:.5em;">%s</div>
2484</body></html>''' % (title, css_link, html_navbar(), contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002485
2486 def filelink(self, url, path):
2487 return '<a href="getfile?key=%s">%s</a>' % (url, path)
2488
2489
2490 html = _HTMLDoc()
2491
2492 def html_navbar():
Georg Brandld2f38572011-01-30 08:37:19 +00002493 version = html.escape("%s [%s, %s]" % (platform.python_version(),
2494 platform.python_build()[0],
2495 platform.python_compiler()))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002496 return """
2497 <div style='float:left'>
Georg Brandld2f38572011-01-30 08:37:19 +00002498 Python %s<br>%s
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002499 </div>
2500 <div style='float:right'>
2501 <div style='text-align:center'>
2502 <a href="index.html">Module Index</a>
2503 : <a href="topics.html">Topics</a>
2504 : <a href="keywords.html">Keywords</a>
2505 </div>
2506 <div>
Georg Brandld2f38572011-01-30 08:37:19 +00002507 <form action="get" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002508 <input type=text name=key size=15>
2509 <input type=submit value="Get">
Georg Brandld2f38572011-01-30 08:37:19 +00002510 </form>&nbsp;
2511 <form action="search" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002512 <input type=text name=key size=15>
2513 <input type=submit value="Search">
2514 </form>
2515 </div>
2516 </div>
Georg Brandld2f38572011-01-30 08:37:19 +00002517 """ % (version, html.escape(platform.platform(terse=True)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002518
2519 def html_index():
2520 """Module Index page."""
2521
2522 def bltinlink(name):
2523 return '<a href="%s.html">%s</a>' % (name, name)
2524
2525 heading = html.heading(
2526 '<big><big><strong>Index of Modules</strong></big></big>',
2527 '#ffffff', '#7799ee')
2528 names = [name for name in sys.builtin_module_names
2529 if name != '__main__']
2530 contents = html.multicolumn(names, bltinlink)
2531 contents = [heading, '<p>' + html.bigsection(
2532 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2533
2534 seen = {}
2535 for dir in sys.path:
2536 contents.append(html.index(dir, seen))
2537
2538 contents.append(
2539 '<p align=right><font color="#909090" face="helvetica,'
2540 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2541 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002542 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002543
2544 def html_search(key):
2545 """Search results page."""
2546 # scan for modules
2547 search_result = []
2548
2549 def callback(path, modname, desc):
2550 if modname[-9:] == '.__init__':
2551 modname = modname[:-9] + ' (package)'
2552 search_result.append((modname, desc and '- ' + desc))
2553
2554 with warnings.catch_warnings():
2555 warnings.filterwarnings('ignore') # ignore problems during import
2556 ModuleScanner().run(callback, key)
2557
2558 # format page
2559 def bltinlink(name):
2560 return '<a href="%s.html">%s</a>' % (name, name)
2561
2562 results = []
2563 heading = html.heading(
2564 '<big><big><strong>Search Results</strong></big></big>',
2565 '#ffffff', '#7799ee')
2566 for name, desc in search_result:
2567 results.append(bltinlink(name) + desc)
2568 contents = heading + html.bigsection(
2569 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002570 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002571
2572 def html_getfile(path):
2573 """Get and display a source file listing safely."""
Nick Coghlanecace282010-12-03 16:08:46 +00002574 path = path.replace('%20', ' ')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002575 with open(path, 'r') as fp:
2576 lines = html.escape(fp.read())
2577 body = '<pre>%s</pre>' % lines
2578 heading = html.heading(
2579 '<big><big><strong>File Listing</strong></big></big>',
2580 '#ffffff', '#7799ee')
2581 contents = heading + html.bigsection(
2582 'File: %s' % path, '#ffffff', '#ee77aa', body)
Nick Coghlanecace282010-12-03 16:08:46 +00002583 return 'getfile %s' % path, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002584
2585 def html_topics():
2586 """Index of topic texts available."""
2587
2588 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002589 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002590
2591 heading = html.heading(
2592 '<big><big><strong>INDEX</strong></big></big>',
2593 '#ffffff', '#7799ee')
2594 names = sorted(Helper.topics.keys())
2595
2596 contents = html.multicolumn(names, bltinlink)
2597 contents = heading + html.bigsection(
2598 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002599 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002600
2601 def html_keywords():
2602 """Index of keywords."""
2603 heading = html.heading(
2604 '<big><big><strong>INDEX</strong></big></big>',
2605 '#ffffff', '#7799ee')
2606 names = sorted(Helper.keywords.keys())
2607
2608 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002609 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002610
2611 contents = html.multicolumn(names, bltinlink)
2612 contents = heading + html.bigsection(
2613 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002614 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002615
2616 def html_topicpage(topic):
2617 """Topic or keyword help page."""
2618 buf = io.StringIO()
2619 htmlhelp = Helper(buf, buf)
2620 contents, xrefs = htmlhelp._gettopic(topic)
2621 if topic in htmlhelp.keywords:
2622 title = 'KEYWORD'
2623 else:
2624 title = 'TOPIC'
2625 heading = html.heading(
2626 '<big><big><strong>%s</strong></big></big>' % title,
2627 '#ffffff', '#7799ee')
Georg Brandld2f38572011-01-30 08:37:19 +00002628 contents = '<pre>%s</pre>' % html.markup(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002629 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
Georg Brandld2f38572011-01-30 08:37:19 +00002630 if xrefs:
2631 xrefs = sorted(xrefs.split())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002632
Georg Brandld2f38572011-01-30 08:37:19 +00002633 def bltinlink(name):
2634 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002635
Georg Brandld2f38572011-01-30 08:37:19 +00002636 xrefs = html.multicolumn(xrefs, bltinlink)
2637 xrefs = html.section('Related help topics: ',
2638 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002639 return ('%s %s' % (title, topic),
2640 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002641
Georg Brandld2f38572011-01-30 08:37:19 +00002642 def html_getobj(url):
2643 obj = locate(url, forceload=1)
2644 if obj is None and url != 'None':
2645 raise ValueError('could not find object')
2646 title = describe(obj)
2647 content = html.document(obj, url)
2648 return title, content
2649
2650 def html_error(url, exc):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002651 heading = html.heading(
2652 '<big><big><strong>Error</strong></big></big>',
Georg Brandld2f38572011-01-30 08:37:19 +00002653 '#ffffff', '#7799ee')
2654 contents = '<br>'.join(html.escape(line) for line in
2655 format_exception_only(type(exc), exc))
2656 contents = heading + html.bigsection(url, '#ffffff', '#bb0000',
2657 contents)
2658 return "Error - %s" % url, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002659
2660 def get_html_page(url):
2661 """Generate an HTML page for url."""
Georg Brandld2f38572011-01-30 08:37:19 +00002662 complete_url = url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002663 if url.endswith('.html'):
2664 url = url[:-5]
Georg Brandld2f38572011-01-30 08:37:19 +00002665 try:
2666 if url in ("", "index"):
2667 title, content = html_index()
2668 elif url == "topics":
2669 title, content = html_topics()
2670 elif url == "keywords":
2671 title, content = html_keywords()
2672 elif '=' in url:
2673 op, _, url = url.partition('=')
2674 if op == "search?key":
2675 title, content = html_search(url)
2676 elif op == "getfile?key":
2677 title, content = html_getfile(url)
2678 elif op == "topic?key":
2679 # try topics first, then objects.
2680 try:
2681 title, content = html_topicpage(url)
2682 except ValueError:
2683 title, content = html_getobj(url)
2684 elif op == "get?key":
2685 # try objects first, then topics.
2686 if url in ("", "index"):
2687 title, content = html_index()
2688 else:
2689 try:
2690 title, content = html_getobj(url)
2691 except ValueError:
2692 title, content = html_topicpage(url)
2693 else:
2694 raise ValueError('bad pydoc url')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002695 else:
Georg Brandld2f38572011-01-30 08:37:19 +00002696 title, content = html_getobj(url)
2697 except Exception as exc:
2698 # Catch any errors and display them in an error page.
2699 title, content = html_error(complete_url, exc)
2700 return html.page(title, content)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002701
2702 if url.startswith('/'):
2703 url = url[1:]
2704 if content_type == 'text/css':
2705 path_here = os.path.dirname(os.path.realpath(__file__))
Georg Brandld2f38572011-01-30 08:37:19 +00002706 css_path = os.path.join(path_here, url)
2707 with open(css_path) as fp:
2708 return ''.join(fp.readlines())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002709 elif content_type == 'text/html':
2710 return get_html_page(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002711 # Errors outside the url handler are caught by the server.
2712 raise TypeError('unknown content type %r for url %s' % (content_type, url))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002713
2714
2715def browse(port=0, *, open_browser=True):
2716 """Start the enhanced pydoc Web server and open a Web browser.
2717
2718 Use port '0' to start the server on an arbitrary port.
2719 Set open_browser to False to suppress opening a browser.
2720 """
2721 import webbrowser
2722 serverthread = _start_server(_url_handler, port)
2723 if serverthread.error:
2724 print(serverthread.error)
2725 return
2726 if serverthread.serving:
2727 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2728 if open_browser:
2729 webbrowser.open(serverthread.url)
2730 try:
2731 print('Server ready at', serverthread.url)
2732 print(server_help_msg)
2733 while serverthread.serving:
2734 cmd = input('server> ')
2735 cmd = cmd.lower()
2736 if cmd == 'q':
2737 break
2738 elif cmd == 'b':
2739 webbrowser.open(serverthread.url)
2740 else:
2741 print(server_help_msg)
2742 except (KeyboardInterrupt, EOFError):
2743 print()
2744 finally:
2745 if serverthread.serving:
2746 serverthread.stop()
2747 print('Server stopped')
2748
2749
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002750# -------------------------------------------------- command-line interface
2751
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002752def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002753 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002754
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002755def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002756 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002757 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002758 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002759
Nick Coghlan106274b2009-11-15 23:04:33 +00002760 # Scripts don't get the current directory in their path by default
2761 # unless they are run with the '-m' switch
2762 if '' not in sys.path:
2763 scriptdir = os.path.dirname(sys.argv[0])
2764 if scriptdir in sys.path:
2765 sys.path.remove(scriptdir)
2766 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002767
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002768 try:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002769 opts, args = getopt.getopt(sys.argv[1:], 'bgk:p:w')
2770 writing = False
2771 start_server = False
2772 open_browser = False
2773 port = None
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002774 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002775 if opt == '-g':
2776 gui()
2777 return
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002778 if opt == '-b':
2779 start_server = True
2780 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002781 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002782 apropos(val)
2783 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002784 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002785 start_server = True
2786 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002787 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002788 writing = True
2789
2790 if start_server == True:
2791 if port == None:
2792 port = 0
2793 browse(port, open_browser=open_browser)
2794 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002795
2796 if not args: raise BadUsage
2797 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002798 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002799 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002800 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002801 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002802 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002803 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002804 if writing:
2805 if ispath(arg) and os.path.isdir(arg):
2806 writedocs(arg)
2807 else:
2808 writedoc(arg)
2809 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002810 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002811 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002812 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002813
2814 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002815 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002816 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002817
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002818{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002819 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002820 Python keyword, topic, function, module, or package, or a dotted
2821 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002822 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002823 Python source file to document. If name is 'keywords', 'topics',
2824 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002825
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002826{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002827 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002828
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002829{cmd} -p <port>
2830 Start an HTTP server on the given port on the local machine. Port
2831 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002832
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002833{cmd} -b
2834 Start an HTTP server on an arbitrary unused port and open a Web browser
2835 to interactively browse documentation. The -p option can be used with
2836 the -b option to explicitly specify the server port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002837
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002838{cmd} -g
2839 Deprecated.
2840
2841{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002842 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002843 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002844 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002845""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002846
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002847if __name__ == '__main__':
2848 cli()