blob: 1855cd1cf27cc52d0f19cc586e6f4f10d00d207d [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
73from traceback import extract_tb
74
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
1885 If an error occurs, topic is the error message, and xrefs is ''.
1886 This function duplicates the showtopic method but returns its
1887 result directly so it can be formatted for display in an html page.
1888 """
1889 try:
1890 import pydoc_data.topics
1891 except ImportError:
1892 return('''
1893Sorry, topic and keyword documentation is not available because the
1894module "pydoc_data.topics" could not be found.
1895''' , '')
1896 target = self.topics.get(topic, self.keywords.get(topic))
1897 if not target:
1898 return 'no documentation found for %r' % topic, ''
1899 if isinstance(target, str):
1900 return self._gettopic(target, more_xrefs)
1901 label, xrefs = target
1902 try:
1903 doc = pydoc_data.topics.topics[label]
1904 except KeyError:
1905 return 'no documentation found for %r' % topic, ''
1906 if more_xrefs:
1907 xrefs = (xrefs or '') + ' ' + more_xrefs
1908 return doc, xrefs
1909
Georg Brandldb7b6b92009-01-01 15:53:14 +00001910 def showsymbol(self, symbol):
1911 target = self.symbols[symbol]
1912 topic, _, xrefs = target.partition(' ')
1913 self.showtopic(topic, xrefs)
1914
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001915 def listmodules(self, key=''):
1916 if key:
1917 self.output.write('''
1918Here is a list of matching modules. Enter any module name to get more help.
1919
1920''')
1921 apropos(key)
1922 else:
1923 self.output.write('''
1924Please wait a moment while I gather a list of all available modules...
1925
1926''')
1927 modules = {}
1928 def callback(path, modname, desc, modules=modules):
1929 if modname and modname[-9:] == '.__init__':
1930 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001931 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001932 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001933 def onerror(modname):
1934 callback(None, modname, None)
1935 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001936 self.list(modules.keys())
1937 self.output.write('''
1938Enter any module name to get more help. Or, type "modules spam" to search
1939for modules whose descriptions contain the word "spam".
1940''')
1941
Georg Brandl78aa3962010-07-31 21:51:48 +00001942help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001943
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001944class Scanner:
1945 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001946 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001947 self.roots = roots[:]
1948 self.state = []
1949 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001950 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001951
1952 def next(self):
1953 if not self.state:
1954 if not self.roots:
1955 return None
1956 root = self.roots.pop(0)
1957 self.state = [(root, self.children(root))]
1958 node, children = self.state[-1]
1959 if not children:
1960 self.state.pop()
1961 return self.next()
1962 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001963 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001964 self.state.append((child, self.children(child)))
1965 return child
1966
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001967
1968class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001969 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001970
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001971 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001972 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001973 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001974 seen = {}
1975
1976 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001977 if modname != '__main__':
1978 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001979 if key is None:
1980 callback(None, modname, '')
1981 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001982 name = __import__(modname).__doc__ or ''
1983 desc = name.split('\n')[0]
1984 name = modname + ' - ' + desc
1985 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001986 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001987
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001988 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001989 if self.quit:
1990 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001991
1992 # XXX Skipping this file is a workaround for a bug
1993 # that causes python to crash with a segfault.
1994 # http://bugs.python.org/issue9319
1995 #
1996 # TODO Remove this once the bug is fixed.
1997 if modname in {'test.badsyntax_pep3120', 'badsyntax_pep3120'}:
1998 continue
1999
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002000 if key is None:
2001 callback(None, modname, '')
2002 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002003 try:
2004 loader = importer.find_module(modname)
2005 except SyntaxError:
2006 # raised by tests for bad coding cookies or BOM
2007 continue
2008 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002009 try:
2010 source = loader.get_source(modname)
2011 except UnicodeDecodeError:
2012 if onerror:
2013 onerror(modname)
2014 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002015 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002016 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002017 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002018 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002019 path = None
2020 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002021 try:
2022 module = loader.load_module(modname)
2023 except ImportError:
2024 if onerror:
2025 onerror(modname)
2026 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002027 desc = (module.__doc__ or '').splitlines()[0]
2028 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002029 name = modname + ' - ' + desc
2030 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002031 callback(path, modname, desc)
2032
2033 if completer:
2034 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002035
2036def apropos(key):
2037 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002038 def callback(path, modname, desc):
2039 if modname[-9:] == '.__init__':
2040 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002041 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002042 def onerror(modname):
2043 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002044 with warnings.catch_warnings():
2045 warnings.filterwarnings('ignore') # ignore problems during import
2046 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002047
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002048# --------------------------------------------------- Web browser interface
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002049
Ka-Ping Yee66246962001-04-12 11:59:50 +00002050def serve(port, callback=None, completer=None):
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002051 import http.server, email.message, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002052
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002053 msg = 'the pydoc.serve() function is deprecated'
2054 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2055
Georg Brandl24420152008-05-26 16:32:26 +00002056 class DocHandler(http.server.BaseHTTPRequestHandler):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002057 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002058 try:
2059 self.send_response(200)
Georg Brandl825fc8b2008-01-19 20:44:32 +00002060 self.send_header('Content-Type', 'text/html; charset=UTF-8')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002061 self.end_headers()
Georg Brandl825fc8b2008-01-19 20:44:32 +00002062 self.wfile.write(html.page(title, contents).encode('utf-8'))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002063 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002064
2065 def do_GET(self):
2066 path = self.path
2067 if path[-5:] == '.html': path = path[:-5]
2068 if path[:1] == '/': path = path[1:]
2069 if path and path != '.':
2070 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002071 obj = locate(path, forceload=1)
Guido van Rossumb940e112007-01-10 16:19:56 +00002072 except ErrorDuringImport as value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002073 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002074 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002075 if obj:
2076 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002077 else:
2078 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002079'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002080 else:
2081 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002082'<big><big><strong>Python: Index of Modules</strong></big></big>',
2083'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002084 def bltinlink(name):
2085 return '<a href="%s.html">%s</a>' % (name, name)
Georg Brandl661b0a12008-01-27 18:16:00 +00002086 names = [x for x in sys.builtin_module_names if x != '__main__']
2087 contents = html.multicolumn(names, bltinlink)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002088 indices = ['<p>' + html.bigsection(
2089 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2090
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002091 seen = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002092 for dir in sys.path:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002093 indices.append(html.index(dir, seen))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002094 contents = heading + ' '.join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00002095<font color="#909090" face="helvetica, arial"><strong>
2096pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002097 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002098
2099 def log_message(self, *args): pass
2100
Georg Brandl24420152008-05-26 16:32:26 +00002101 class DocServer(http.server.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002102 def __init__(self, port, callback):
Ronald Oussoren94f25282010-05-05 19:11:21 +00002103 host = 'localhost'
Senthil Kumaran7ff59132010-08-18 19:32:21 +00002104 self.address = (host, port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00002105 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002106 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002107 self.base.__init__(self, self.address, self.handler)
2108
2109 def serve_until_quit(self):
2110 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002111 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002112 while not self.quit:
2113 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2114 if rd: self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002115 self.server_close()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002116
2117 def server_activate(self):
2118 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002119 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002120
Georg Brandl24420152008-05-26 16:32:26 +00002121 DocServer.base = http.server.HTTPServer
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002122 DocServer.handler = DocHandler
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002123 DocHandler.MessageClass = email.message.Message
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002124 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002125 try:
2126 DocServer(port, callback).serve_until_quit()
2127 except (KeyboardInterrupt, select.error):
2128 pass
2129 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002130 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002131
2132# ----------------------------------------------------- graphical interface
2133
2134def gui():
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002135 """Graphical interface (starts Web server and pops up a control window)."""
2136
2137 msg = ('the pydoc.gui() function and "pydoc -g" option are deprecated\n',
2138 'use "pydoc.browse() function and "pydoc -b" option instead.')
2139 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2140
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002141 class GUI:
2142 def __init__(self, window, port=7464):
2143 self.window = window
2144 self.server = None
2145 self.scanner = None
2146
Georg Brandl14fc4272008-05-17 18:39:55 +00002147 import tkinter
2148 self.server_frm = tkinter.Frame(window)
2149 self.title_lbl = tkinter.Label(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002150 text='Starting server...\n ')
Georg Brandl14fc4272008-05-17 18:39:55 +00002151 self.open_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002152 text='open browser', command=self.open, state='disabled')
Georg Brandl14fc4272008-05-17 18:39:55 +00002153 self.quit_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002154 text='quit serving', command=self.quit, state='disabled')
2155
Georg Brandl14fc4272008-05-17 18:39:55 +00002156 self.search_frm = tkinter.Frame(window)
2157 self.search_lbl = tkinter.Label(self.search_frm, text='Search for')
2158 self.search_ent = tkinter.Entry(self.search_frm)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002159 self.search_ent.bind('<Return>', self.search)
Georg Brandl14fc4272008-05-17 18:39:55 +00002160 self.stop_btn = tkinter.Button(self.search_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002161 text='stop', pady=0, command=self.stop, state='disabled')
2162 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002163 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002164 self.stop_btn.pack(side='right')
2165
2166 self.window.title('pydoc')
2167 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2168 self.title_lbl.pack(side='top', fill='x')
2169 self.open_btn.pack(side='left', fill='x', expand=1)
2170 self.quit_btn.pack(side='right', fill='x', expand=1)
2171 self.server_frm.pack(side='top', fill='x')
2172
2173 self.search_lbl.pack(side='left')
2174 self.search_ent.pack(side='right', fill='x', expand=1)
2175 self.search_frm.pack(side='top', fill='x')
2176 self.search_ent.focus_set()
2177
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002178 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Georg Brandl14fc4272008-05-17 18:39:55 +00002179 self.result_lst = tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002180 self.result_lst.bind('<Button-1>', self.select)
2181 self.result_lst.bind('<Double-Button-1>', self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002182 self.result_scr = tkinter.Scrollbar(window,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002183 orient='vertical', command=self.result_lst.yview)
2184 self.result_lst.config(yscrollcommand=self.result_scr.set)
2185
Georg Brandl14fc4272008-05-17 18:39:55 +00002186 self.result_frm = tkinter.Frame(window)
2187 self.goto_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002188 text='go to selected', command=self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002189 self.hide_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002190 text='hide results', command=self.hide)
2191 self.goto_btn.pack(side='left', fill='x', expand=1)
2192 self.hide_btn.pack(side='right', fill='x', expand=1)
2193
2194 self.window.update()
2195 self.minwidth = self.window.winfo_width()
2196 self.minheight = self.window.winfo_height()
2197 self.bigminheight = (self.server_frm.winfo_reqheight() +
2198 self.search_frm.winfo_reqheight() +
2199 self.result_lst.winfo_reqheight() +
2200 self.result_frm.winfo_reqheight())
2201 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2202 self.expanded = 0
2203 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2204 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002205 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002206
2207 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002208 threading.Thread(
2209 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002210
2211 def ready(self, server):
2212 self.server = server
2213 self.title_lbl.config(
2214 text='Python documentation server at\n' + server.url)
2215 self.open_btn.config(state='normal')
2216 self.quit_btn.config(state='normal')
2217
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002218 def open(self, event=None, url=None):
2219 url = url or self.server.url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002220 import webbrowser
2221 webbrowser.open(url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002222
2223 def quit(self, event=None):
2224 if self.server:
2225 self.server.quit = 1
2226 self.window.quit()
2227
2228 def search(self, event=None):
2229 key = self.search_ent.get()
2230 self.stop_btn.pack(side='right')
2231 self.stop_btn.config(state='normal')
2232 self.search_lbl.config(text='Searching for "%s"...' % key)
2233 self.search_ent.forget()
2234 self.search_lbl.pack(side='left')
2235 self.result_lst.delete(0, 'end')
2236 self.goto_btn.config(state='disabled')
2237 self.expand()
2238
2239 import threading
2240 if self.scanner:
2241 self.scanner.quit = 1
2242 self.scanner = ModuleScanner()
2243 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002244 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002245
2246 def update(self, path, modname, desc):
2247 if modname[-9:] == '.__init__':
2248 modname = modname[:-9] + ' (package)'
2249 self.result_lst.insert('end',
2250 modname + ' - ' + (desc or '(no description)'))
2251
2252 def stop(self, event=None):
2253 if self.scanner:
2254 self.scanner.quit = 1
2255 self.scanner = None
2256
2257 def done(self):
2258 self.scanner = None
2259 self.search_lbl.config(text='Search for')
2260 self.search_lbl.pack(side='left')
2261 self.search_ent.pack(side='right', fill='x', expand=1)
2262 if sys.platform != 'win32': self.stop_btn.forget()
2263 self.stop_btn.config(state='disabled')
2264
2265 def select(self, event=None):
2266 self.goto_btn.config(state='normal')
2267
2268 def goto(self, event=None):
2269 selection = self.result_lst.curselection()
2270 if selection:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002271 modname = self.result_lst.get(selection[0]).split()[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002272 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002273
2274 def collapse(self):
2275 if not self.expanded: return
2276 self.result_frm.forget()
2277 self.result_scr.forget()
2278 self.result_lst.forget()
2279 self.bigwidth = self.window.winfo_width()
2280 self.bigheight = self.window.winfo_height()
2281 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2282 self.window.wm_minsize(self.minwidth, self.minheight)
2283 self.expanded = 0
2284
2285 def expand(self):
2286 if self.expanded: return
2287 self.result_frm.pack(side='bottom', fill='x')
2288 self.result_scr.pack(side='right', fill='y')
2289 self.result_lst.pack(side='top', fill='both', expand=1)
2290 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2291 self.window.wm_minsize(self.minwidth, self.bigminheight)
2292 self.expanded = 1
2293
2294 def hide(self, event=None):
2295 self.stop()
2296 self.collapse()
2297
Georg Brandl14fc4272008-05-17 18:39:55 +00002298 import tkinter
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002299 try:
Georg Brandl14fc4272008-05-17 18:39:55 +00002300 root = tkinter.Tk()
Martin v. Löwise09bd932004-08-22 16:13:26 +00002301 # Tk will crash if pythonw.exe has an XP .manifest
2302 # file and the root has is not destroyed explicitly.
2303 # If the problem is ever fixed in Tk, the explicit
2304 # destroy can go.
2305 try:
2306 gui = GUI(root)
2307 root.mainloop()
2308 finally:
2309 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002310 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002311 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002312
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002313
2314# --------------------------------------- enhanced Web browser interface
2315
2316def _start_server(urlhandler, port):
2317 """Start an HTTP server thread on a specific port.
2318
2319 Start an HTML/text server thread, so HTML or text documents can be
2320 browsed dynamically and interactively with a Web browser. Example use:
2321
2322 >>> import time
2323 >>> import pydoc
2324
2325 Define a URL handler. To determine what the client is asking
2326 for, check the URL and content_type.
2327
2328 Then get or generate some text or HTML code and return it.
2329
2330 >>> def my_url_handler(url, content_type):
2331 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2332 ... return text
2333
2334 Start server thread on port 0.
2335 If you use port 0, the server will pick a random port number.
2336 You can then use serverthread.port to get the port number.
2337
2338 >>> port = 0
2339 >>> serverthread = pydoc._start_server(my_url_handler, port)
2340
2341 Check that the server is really started. If it is, open browser
2342 and get first page. Use serverthread.url as the starting page.
2343
2344 >>> if serverthread.serving:
2345 ... import webbrowser
2346
2347 The next two lines are commented out so a browser doesn't open if
2348 doctest is run on this module.
2349
2350 #... webbrowser.open(serverthread.url)
2351 #True
2352
2353 Let the server do its thing. We just need to monitor its status.
2354 Use time.sleep so the loop doesn't hog the CPU.
2355
2356 >>> starttime = time.time()
2357 >>> timeout = 1 #seconds
2358
2359 This is a short timeout for testing purposes.
2360
2361 >>> while serverthread.serving:
2362 ... time.sleep(.01)
2363 ... if serverthread.serving and time.time() - starttime > timeout:
2364 ... serverthread.stop()
2365 ... break
2366
2367 Print any errors that may have occurred.
2368
2369 >>> print(serverthread.error)
2370 None
2371 """
2372 import http.server
2373 import email.message
2374 import select
2375 import threading
2376
2377 class DocHandler(http.server.BaseHTTPRequestHandler):
2378
2379 def do_GET(self):
2380 """Process a request from an HTML browser.
2381
2382 The URL received is in self.path.
2383 Get an HTML page from self.urlhandler and send it.
2384 """
2385 if self.path.endswith('.css'):
2386 content_type = 'text/css'
2387 else:
2388 content_type = 'text/html'
2389 self.send_response(200)
2390 self.send_header('Content-Type', '%s;charset=UTF-8' % content_type)
2391 self.end_headers()
2392 self.wfile.write(self.urlhandler(
2393 self.path, content_type).encode('utf-8'))
2394
2395 def log_message(self, *args):
2396 # Don't log messages.
2397 pass
2398
2399 class DocServer(http.server.HTTPServer):
2400
2401 def __init__(self, port, callback):
2402 self.host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
2403 self.address = ('', port)
2404 self.callback = callback
2405 self.base.__init__(self, self.address, self.handler)
2406 self.quit = False
2407
2408 def serve_until_quit(self):
2409 while not self.quit:
2410 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2411 if rd:
2412 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002413 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002414
2415 def server_activate(self):
2416 self.base.server_activate(self)
2417 if self.callback:
2418 self.callback(self)
2419
2420 class ServerThread(threading.Thread):
2421
2422 def __init__(self, urlhandler, port):
2423 self.urlhandler = urlhandler
2424 self.port = int(port)
2425 threading.Thread.__init__(self)
2426 self.serving = False
2427 self.error = None
2428
2429 def run(self):
2430 """Start the server."""
2431 try:
2432 DocServer.base = http.server.HTTPServer
2433 DocServer.handler = DocHandler
2434 DocHandler.MessageClass = email.message.Message
2435 DocHandler.urlhandler = staticmethod(self.urlhandler)
2436 docsvr = DocServer(self.port, self.ready)
2437 self.docserver = docsvr
2438 docsvr.serve_until_quit()
2439 except Exception as e:
2440 self.error = e
2441
2442 def ready(self, server):
2443 self.serving = True
2444 self.host = server.host
2445 self.port = server.server_port
2446 self.url = 'http://%s:%d/' % (self.host, self.port)
2447
2448 def stop(self):
2449 """Stop the server and this thread nicely"""
2450 self.docserver.quit = True
2451 self.serving = False
2452 self.url = None
2453
2454 thread = ServerThread(urlhandler, port)
2455 thread.start()
2456 # Wait until thread.serving is True to make sure we are
2457 # really up before returning.
2458 while not thread.error and not thread.serving:
2459 time.sleep(.01)
2460 return thread
2461
2462
2463def _url_handler(url, content_type="text/html"):
2464 """The pydoc url handler for use with the pydoc server.
2465
2466 If the content_type is 'text/css', the _pydoc.css style
2467 sheet is read and returned if it exits.
2468
2469 If the content_type is 'text/html', then the result of
2470 get_html_page(url) is returned.
2471 """
2472 class _HTMLDoc(HTMLDoc):
2473
2474 def page(self, title, contents):
2475 """Format an HTML page."""
2476 css_path = "pydoc_data/_pydoc.css"
2477 css_link = (
2478 '<link rel="stylesheet" type="text/css" href="%s">' %
2479 css_path)
2480 return '''\
2481<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
2482<html><head><title>Python: %s</title>
2483<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
2484%s</head><body bgcolor="#f0f0f8">%s
2485</body></html>''' % (title, css_link, contents)
2486
2487 def filelink(self, url, path):
2488 return '<a href="getfile?key=%s">%s</a>' % (url, path)
2489
2490
2491 html = _HTMLDoc()
2492
2493 def html_navbar():
2494 version = "%s [%s, %s]" % (platform.python_version(),
2495 platform.python_build()[0],
2496 platform.python_compiler())
2497 return """
2498 <div style='float:left'>
2499 Python %s<br>%s<br><br>
2500 </div>
2501 <div style='float:right'>
2502 <div style='text-align:center'>
2503 <a href="index.html">Module Index</a>
2504 : <a href="topics.html">Topics</a>
2505 : <a href="keywords.html">Keywords</a>
2506 </div>
2507 <div>
2508 <form action="get" style='float:left'>
2509 <input type=text name=key size=15>
2510 <input type=submit value="Get">
2511 &nbsp;&nbsp;&nbsp;
2512 </form>
2513 <form action="search" style='float:right'>
2514 <input type=text name=key size=15>
2515 <input type=submit value="Search">
2516 </form>
2517 </div>
2518 </div>
2519 <div clear='all'>&nbsp;</div>
2520 """ % (version, platform.platform(terse=True))
2521
2522 def html_index():
2523 """Module Index page."""
2524
2525 def bltinlink(name):
2526 return '<a href="%s.html">%s</a>' % (name, name)
2527
2528 heading = html.heading(
2529 '<big><big><strong>Index of Modules</strong></big></big>',
2530 '#ffffff', '#7799ee')
2531 names = [name for name in sys.builtin_module_names
2532 if name != '__main__']
2533 contents = html.multicolumn(names, bltinlink)
2534 contents = [heading, '<p>' + html.bigsection(
2535 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2536
2537 seen = {}
2538 for dir in sys.path:
2539 contents.append(html.index(dir, seen))
2540
2541 contents.append(
2542 '<p align=right><font color="#909090" face="helvetica,'
2543 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2544 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002545 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002546
2547 def html_search(key):
2548 """Search results page."""
2549 # scan for modules
2550 search_result = []
2551
2552 def callback(path, modname, desc):
2553 if modname[-9:] == '.__init__':
2554 modname = modname[:-9] + ' (package)'
2555 search_result.append((modname, desc and '- ' + desc))
2556
2557 with warnings.catch_warnings():
2558 warnings.filterwarnings('ignore') # ignore problems during import
2559 ModuleScanner().run(callback, key)
2560
2561 # format page
2562 def bltinlink(name):
2563 return '<a href="%s.html">%s</a>' % (name, name)
2564
2565 results = []
2566 heading = html.heading(
2567 '<big><big><strong>Search Results</strong></big></big>',
2568 '#ffffff', '#7799ee')
2569 for name, desc in search_result:
2570 results.append(bltinlink(name) + desc)
2571 contents = heading + html.bigsection(
2572 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002573 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002574
2575 def html_getfile(path):
2576 """Get and display a source file listing safely."""
Nick Coghlanecace282010-12-03 16:08:46 +00002577 path = path.replace('%20', ' ')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002578 with open(path, 'r') as fp:
2579 lines = html.escape(fp.read())
2580 body = '<pre>%s</pre>' % lines
2581 heading = html.heading(
2582 '<big><big><strong>File Listing</strong></big></big>',
2583 '#ffffff', '#7799ee')
2584 contents = heading + html.bigsection(
2585 'File: %s' % path, '#ffffff', '#ee77aa', body)
Nick Coghlanecace282010-12-03 16:08:46 +00002586 return 'getfile %s' % path, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002587
2588 def html_topics():
2589 """Index of topic texts available."""
2590
2591 def bltinlink(name):
2592 return '<a href="%s.html">%s</a>' % (name, name)
2593
2594 heading = html.heading(
2595 '<big><big><strong>INDEX</strong></big></big>',
2596 '#ffffff', '#7799ee')
2597 names = sorted(Helper.topics.keys())
2598
2599 contents = html.multicolumn(names, bltinlink)
2600 contents = heading + html.bigsection(
2601 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002602 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002603
2604 def html_keywords():
2605 """Index of keywords."""
2606 heading = html.heading(
2607 '<big><big><strong>INDEX</strong></big></big>',
2608 '#ffffff', '#7799ee')
2609 names = sorted(Helper.keywords.keys())
2610
2611 def bltinlink(name):
2612 return '<a href="%s.html">%s</a>' % (name, name)
2613
2614 contents = html.multicolumn(names, bltinlink)
2615 contents = heading + html.bigsection(
2616 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002617 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002618
2619 def html_topicpage(topic):
2620 """Topic or keyword help page."""
2621 buf = io.StringIO()
2622 htmlhelp = Helper(buf, buf)
2623 contents, xrefs = htmlhelp._gettopic(topic)
2624 if topic in htmlhelp.keywords:
2625 title = 'KEYWORD'
2626 else:
2627 title = 'TOPIC'
2628 heading = html.heading(
2629 '<big><big><strong>%s</strong></big></big>' % title,
2630 '#ffffff', '#7799ee')
2631 contents = '<pre>%s</pre>' % contents
2632 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
2633 xrefs = sorted(xrefs.split())
2634
2635 def bltinlink(name):
2636 return '<a href="%s.html">%s</a>' % (name, name)
2637
2638 xrefs = html.multicolumn(xrefs, bltinlink)
2639 xrefs = html.section('Related help topics: ',
2640 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002641 return ('%s %s' % (title, topic),
2642 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002643
2644 def html_error(url):
2645 heading = html.heading(
2646 '<big><big><strong>Error</strong></big></big>',
2647 '#ffffff', '#ee0000')
2648 return heading + url
2649
2650 def get_html_page(url):
2651 """Generate an HTML page for url."""
2652 if url.endswith('.html'):
2653 url = url[:-5]
2654 if url.startswith('/'):
2655 url = url[1:]
2656 if url.startswith("get?key="):
2657 url = url[8:]
2658 title = url
2659 contents = ''
2660 if url in ("", ".", "index"):
Nick Coghlanecace282010-12-03 16:08:46 +00002661 title, contents = html_index()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002662 elif url == "topics":
Nick Coghlanecace282010-12-03 16:08:46 +00002663 title, contents = html_topics()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002664 elif url == "keywords":
Nick Coghlanecace282010-12-03 16:08:46 +00002665 title, contents = html_keywords()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002666 elif url.startswith("search?key="):
Nick Coghlanecace282010-12-03 16:08:46 +00002667 title, contents = html_search(url[11:])
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002668 elif url.startswith("getfile?key="):
2669 url = url[12:]
2670 try:
Nick Coghlanecace282010-12-03 16:08:46 +00002671 title, contents = html_getfile(url)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002672 except IOError:
2673 contents = html_error('could not read file %r' % url)
2674 title = 'Read Error'
2675 else:
2676 obj = None
2677 try:
2678 obj = locate(url, forceload=1)
2679 except ErrorDuringImport as value:
2680 contents = html.escape(str(value))
2681 if obj:
2682 title = describe(obj)
2683 contents = html.document(obj, url)
2684 elif url in Helper.keywords or url in Helper.topics:
Nick Coghlanecace282010-12-03 16:08:46 +00002685 title, contents = html_topicpage(url)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002686 else:
2687 contents = html_error(
2688 'no Python documentation found for %r' % url)
2689 title = 'Error'
2690 return html.page(title, html_navbar() + contents)
2691
2692 if url.startswith('/'):
2693 url = url[1:]
2694 if content_type == 'text/css':
2695 path_here = os.path.dirname(os.path.realpath(__file__))
2696 try:
2697 with open(os.path.join(path_here, url)) as fp:
2698 return ''.join(fp.readlines())
2699 except IOError:
2700 return 'Error: can not open css file %r' % url
2701 elif content_type == 'text/html':
2702 return get_html_page(url)
2703 return 'Error: unknown content type %r' % content_type
2704
2705
2706def browse(port=0, *, open_browser=True):
2707 """Start the enhanced pydoc Web server and open a Web browser.
2708
2709 Use port '0' to start the server on an arbitrary port.
2710 Set open_browser to False to suppress opening a browser.
2711 """
2712 import webbrowser
2713 serverthread = _start_server(_url_handler, port)
2714 if serverthread.error:
2715 print(serverthread.error)
2716 return
2717 if serverthread.serving:
2718 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2719 if open_browser:
2720 webbrowser.open(serverthread.url)
2721 try:
2722 print('Server ready at', serverthread.url)
2723 print(server_help_msg)
2724 while serverthread.serving:
2725 cmd = input('server> ')
2726 cmd = cmd.lower()
2727 if cmd == 'q':
2728 break
2729 elif cmd == 'b':
2730 webbrowser.open(serverthread.url)
2731 else:
2732 print(server_help_msg)
2733 except (KeyboardInterrupt, EOFError):
2734 print()
2735 finally:
2736 if serverthread.serving:
2737 serverthread.stop()
2738 print('Server stopped')
2739
2740
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002741# -------------------------------------------------- command-line interface
2742
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002743def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002744 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002745
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002746def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002747 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002748 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002749 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002750
Nick Coghlan106274b2009-11-15 23:04:33 +00002751 # Scripts don't get the current directory in their path by default
2752 # unless they are run with the '-m' switch
2753 if '' not in sys.path:
2754 scriptdir = os.path.dirname(sys.argv[0])
2755 if scriptdir in sys.path:
2756 sys.path.remove(scriptdir)
2757 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002758
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002759 try:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002760 opts, args = getopt.getopt(sys.argv[1:], 'bgk:p:w')
2761 writing = False
2762 start_server = False
2763 open_browser = False
2764 port = None
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002765 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002766 if opt == '-g':
2767 gui()
2768 return
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002769 if opt == '-b':
2770 start_server = True
2771 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002772 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002773 apropos(val)
2774 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002775 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002776 start_server = True
2777 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002778 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002779 writing = True
2780
2781 if start_server == True:
2782 if port == None:
2783 port = 0
2784 browse(port, open_browser=open_browser)
2785 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002786
2787 if not args: raise BadUsage
2788 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002789 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002790 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002791 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002792 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002793 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002794 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002795 if writing:
2796 if ispath(arg) and os.path.isdir(arg):
2797 writedocs(arg)
2798 else:
2799 writedoc(arg)
2800 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002801 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002802 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002803 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002804
2805 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002806 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002807 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002808
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002809{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002810 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002811 Python keyword, topic, function, module, or package, or a dotted
2812 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002813 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002814 Python source file to document. If name is 'keywords', 'topics',
2815 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002816
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002817{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002818 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002819
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002820{cmd} -p <port>
2821 Start an HTTP server on the given port on the local machine. Port
2822 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002823
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002824{cmd} -b
2825 Start an HTTP server on an arbitrary unused port and open a Web browser
2826 to interactively browse documentation. The -p option can be used with
2827 the -b option to explicitly specify the server port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002828
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002829{cmd} -g
2830 Deprecated.
2831
2832{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002833 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002834 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002835 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002836""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002837
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002838if __name__ == '__main__':
2839 cli()