blob: 37616fb3edd46beb994c2f377121634a6d5175cc [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 builtins
61import imp
Nick Coghlan7bb30b72010-12-03 09:29:11 +000062import inspect
Victor Stinnere6c910e2011-06-30 15:55:43 +020063import io
64import os
Nick Coghlan7bb30b72010-12-03 09:29:11 +000065import pkgutil
66import platform
67import re
Victor Stinnere6c910e2011-06-30 15:55:43 +020068import sys
Nick Coghlan7bb30b72010-12-03 09:29:11 +000069import time
Victor Stinnere6c910e2011-06-30 15:55:43 +020070import tokenize
Nick Coghlan7bb30b72010-12-03 09:29:11 +000071import warnings
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000072from collections import deque
Nick Coghlan7bb30b72010-12-03 09:29:11 +000073from reprlib import Repr
Georg Brandld2f38572011-01-30 08:37:19 +000074from traceback import extract_tb, format_exception_only
Nick Coghlan7bb30b72010-12-03 09:29:11 +000075
76
Ka-Ping Yeedd175342001-02-27 14:43:46 +000077# --------------------------------------------------------- common routines
78
Ka-Ping Yeedd175342001-02-27 14:43:46 +000079def pathdirs():
80 """Convert sys.path into a list of absolute, existing, unique paths."""
81 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000082 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000083 for dir in sys.path:
84 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000085 normdir = os.path.normcase(dir)
86 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000087 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000088 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000089 return dirs
90
91def getdoc(object):
92 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000093 result = inspect.getdoc(object) or inspect.getcomments(object)
Neal Norwitz9d72bb42007-04-17 08:48:32 +000094 return result and re.sub('^ *\n', '', result.rstrip()) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000095
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000096def splitdoc(doc):
97 """Split a doc string into a synopsis line (if any) and the rest."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +000098 lines = doc.strip().split('\n')
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000099 if len(lines) == 1:
100 return lines[0], ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000101 elif len(lines) >= 2 and not lines[1].rstrip():
102 return lines[0], '\n'.join(lines[2:])
103 return '', '\n'.join(lines)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000104
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000105def classname(object, modname):
106 """Get a class name and qualify it with a module name if necessary."""
107 name = object.__name__
108 if object.__module__ != modname:
109 name = object.__module__ + '.' + name
110 return name
111
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000112def isdata(object):
Georg Brandl94432422005-07-22 21:52:25 +0000113 """Check if an object is of a type that probably means it's data."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000114 return not (inspect.ismodule(object) or inspect.isclass(object) or
115 inspect.isroutine(object) or inspect.isframe(object) or
116 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000117
118def replace(text, *pairs):
119 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000120 while pairs:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000121 text = pairs[1].join(text.split(pairs[0]))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000122 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000123 return text
124
125def cram(text, maxlen):
126 """Omit part of a string if needed to make it fit in a maximum length."""
127 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000128 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000129 post = max(0, maxlen-3-pre)
130 return text[:pre] + '...' + text[len(text)-post:]
131 return text
132
Brett Cannon84601f12004-06-19 01:22:48 +0000133_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000134def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000135 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000136 # The behaviour of %p is implementation-dependent in terms of case.
Ezio Melotti412c95a2010-02-16 23:31:04 +0000137 return _re_stripid.sub(r'\1', text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000138
Brett Cannonc6c1f472004-06-19 01:02:51 +0000139def _is_some_method(obj):
140 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000141
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000142def allmethods(cl):
143 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000144 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000145 methods[key] = 1
146 for base in cl.__bases__:
147 methods.update(allmethods(base)) # all your base are belong to us
148 for key in methods.keys():
149 methods[key] = getattr(cl, key)
150 return methods
151
Tim Petersfa26f7c2001-09-24 08:05:11 +0000152def _split_list(s, predicate):
153 """Split sequence s via predicate, and return pair ([true], [false]).
154
155 The return value is a 2-tuple of lists,
156 ([x for x in s if predicate(x)],
157 [x for x in s if not predicate(x)])
158 """
159
Tim Peters28355492001-09-23 21:29:55 +0000160 yes = []
161 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000162 for x in s:
163 if predicate(x):
164 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000165 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000166 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000167 return yes, no
168
Raymond Hettinger1103d052011-03-25 14:15:24 -0700169def visiblename(name, all=None, obj=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000170 """Decide whether to show documentation on a variable."""
171 # Certain special names are redundant.
Benjamin Peterson41181742008-07-02 20:22:54 +0000172 _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__',
Barry Warsaw28a691b2010-04-17 00:19:56 +0000173 '__module__', '__name__', '__slots__', '__package__',
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000174 '__cached__', '__author__', '__credits__', '__date__',
175 '__version__')
Benjamin Peterson41181742008-07-02 20:22:54 +0000176 if name in _hidden_names: return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000177 # Private names are hidden, but special names are displayed.
178 if name.startswith('__') and name.endswith('__'): return 1
Raymond Hettinger1103d052011-03-25 14:15:24 -0700179 # Namedtuples have public fields and methods with a single leading underscore
180 if name.startswith('_') and hasattr(obj, '_fields'):
181 return True
Skip Montanaroa5616d22004-06-11 04:46:12 +0000182 if all is not None:
183 # only document that which the programmer exported in __all__
184 return name in all
185 else:
186 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000187
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000188def classify_class_attrs(object):
189 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000190 results = []
191 for (name, kind, cls, value) in inspect.classify_class_attrs(object):
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000192 if inspect.isdatadescriptor(value):
193 kind = 'data descriptor'
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000194 results.append((name, kind, cls, value))
195 return results
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000196
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000197# ----------------------------------------------------- module manipulation
198
199def ispackage(path):
200 """Guess whether a path refers to a package directory."""
201 if os.path.isdir(path):
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000202 for ext in ('.py', '.pyc', '.pyo'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000203 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000204 return True
205 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000206
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000207def source_synopsis(file):
208 line = file.readline()
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000209 while line[:1] == '#' or not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000210 line = file.readline()
211 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000212 line = line.strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000213 if line[:4] == 'r"""': line = line[1:]
214 if line[:3] == '"""':
215 line = line[3:]
216 if line[-1:] == '\\': line = line[:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000217 while not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000218 line = file.readline()
219 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000220 result = line.split('"""')[0].strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000221 else: result = None
222 return result
223
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000224def synopsis(filename, cache={}):
225 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000226 mtime = os.stat(filename).st_mtime
Charles-François Natali27c4e882011-07-27 19:40:02 +0200227 lastupdate, result = cache.get(filename, (None, None))
228 if lastupdate is None or lastupdate < mtime:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000229 info = inspect.getmoduleinfo(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000230 try:
Victor Stinnere6c910e2011-06-30 15:55:43 +0200231 file = tokenize.open(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000232 except IOError:
233 # module can't be opened, so skip it
234 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000235 if info and 'b' in info[2]: # binary modules have to be imported
236 try: module = imp.load_module('__temp__', file, filename, info[1:])
237 except: return None
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000238 result = (module.__doc__ or '').splitlines()[0]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000239 del sys.modules['__temp__']
240 else: # text modules can be directly examined
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000241 result = source_synopsis(file)
242 file.close()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000243 cache[filename] = (mtime, result)
244 return result
245
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000246class ErrorDuringImport(Exception):
247 """Errors that occurred while trying to import something to document it."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000248 def __init__(self, filename, exc_info):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000249 self.filename = filename
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000250 self.exc, self.value, self.tb = exc_info
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000251
252 def __str__(self):
Guido van Rossuma01a8b62007-05-27 09:20:14 +0000253 exc = self.exc.__name__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000254 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000255
256def importfile(path):
257 """Import a Python source file or compiled file given its path."""
258 magic = imp.get_magic()
Victor Stinnere975af62011-07-04 02:08:50 +0200259 with open(path, 'rb') as file:
260 if file.read(len(magic)) == magic:
261 kind = imp.PY_COMPILED
262 else:
263 kind = imp.PY_SOURCE
264 file.seek(0)
265 filename = os.path.basename(path)
266 name, ext = os.path.splitext(filename)
267 try:
268 module = imp.load_module(name, file, path, (ext, 'r', kind))
269 except:
270 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000271 return module
272
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000273def safeimport(path, forceload=0, cache={}):
274 """Import a module; handle errors; return None if the module isn't found.
275
276 If the module *is* found but an exception occurs, it's wrapped in an
277 ErrorDuringImport exception and reraised. Unlike __import__, if a
278 package path is specified, the module at the end of the path is returned,
279 not the package at the beginning. If the optional 'forceload' argument
280 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000281 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000282 # If forceload is 1 and the module has been previously loaded from
283 # disk, we always have to reload the module. Checking the file's
284 # mtime isn't good enough (e.g. the module could contain a class
285 # that inherits from another module that has changed).
286 if forceload and path in sys.modules:
287 if path not in sys.builtin_module_names:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000288 # Remove the module from sys.modules and re-import to try
289 # and avoid problems with partially loaded modules.
290 # Also remove any submodules because they won't appear
291 # in the newly loaded module's namespace if they're already
292 # in sys.modules.
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000293 subs = [m for m in sys.modules if m.startswith(path + '.')]
294 for key in [path] + subs:
295 # Prevent garbage collection.
296 cache[key] = sys.modules[key]
297 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000298 module = __import__(path)
299 except:
300 # Did the error occur before or after the module was found?
301 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000302 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000303 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000304 raise ErrorDuringImport(sys.modules[path].__file__, info)
305 elif exc is SyntaxError:
306 # A SyntaxError occurred before we could execute the module.
307 raise ErrorDuringImport(value.filename, info)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000308 elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport':
Benjamin Peterson0289b152009-06-28 17:22:03 +0000309 # The import error occurred directly in this function,
310 # which means there is no such module in the path.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000311 return None
312 else:
313 # Some other error occurred during the importing process.
314 raise ErrorDuringImport(path, sys.exc_info())
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000315 for part in path.split('.')[1:]:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000316 try: module = getattr(module, part)
317 except AttributeError: return None
318 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000319
320# ---------------------------------------------------- formatter base class
321
322class Doc:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000323
324 PYTHONDOCS = os.environ.get("PYTHONDOCS",
325 "http://docs.python.org/%d.%d/library"
326 % sys.version_info[:2])
327
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000328 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000329 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000330 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000331 # 'try' clause is to attempt to handle the possibility that inspect
332 # identifies something in a way that pydoc itself has issues handling;
333 # think 'super' and how it is a descriptor (which raises the exception
334 # by lacking a __name__ attribute) and an instance.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000335 if inspect.isgetsetdescriptor(object): return self.docdata(*args)
336 if inspect.ismemberdescriptor(object): return self.docdata(*args)
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000337 try:
338 if inspect.ismodule(object): return self.docmodule(*args)
339 if inspect.isclass(object): return self.docclass(*args)
340 if inspect.isroutine(object): return self.docroutine(*args)
341 except AttributeError:
342 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000343 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000344 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000345
346 def fail(self, object, name=None, *args):
347 """Raise an exception for unimplemented types."""
348 message = "don't know how to document object%s of type %s" % (
349 name and ' ' + repr(name), type(object).__name__)
Collin Winterce36ad82007-08-30 01:19:48 +0000350 raise TypeError(message)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000351
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000352 docmodule = docclass = docroutine = docother = docproperty = docdata = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000353
Skip Montanaro4997a692003-09-10 16:47:51 +0000354 def getdocloc(self, object):
355 """Return the location of module docs or None"""
356
357 try:
358 file = inspect.getabsfile(object)
359 except TypeError:
360 file = '(built-in)'
361
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000362 docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
363
Skip Montanaro4997a692003-09-10 16:47:51 +0000364 basedir = os.path.join(sys.exec_prefix, "lib",
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000365 "python%d.%d" % sys.version_info[:2])
Skip Montanaro4997a692003-09-10 16:47:51 +0000366 if (isinstance(object, type(os)) and
367 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
368 'marshal', 'posix', 'signal', 'sys',
Georg Brandl2067bfd2008-05-25 13:05:15 +0000369 '_thread', 'zipimport') or
Skip Montanaro4997a692003-09-10 16:47:51 +0000370 (file.startswith(basedir) and
Brian Curtin49c284c2010-03-31 03:19:28 +0000371 not file.startswith(os.path.join(basedir, 'site-packages')))) and
Brian Curtinedef05b2010-04-01 04:05:25 +0000372 object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
Skip Montanaro4997a692003-09-10 16:47:51 +0000373 if docloc.startswith("http://"):
Georg Brandl86def6c2008-01-21 20:36:10 +0000374 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__)
Skip Montanaro4997a692003-09-10 16:47:51 +0000375 else:
Georg Brandl86def6c2008-01-21 20:36:10 +0000376 docloc = os.path.join(docloc, object.__name__ + ".html")
Skip Montanaro4997a692003-09-10 16:47:51 +0000377 else:
378 docloc = None
379 return docloc
380
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000381# -------------------------------------------- HTML documentation generator
382
383class HTMLRepr(Repr):
384 """Class for safely making an HTML representation of a Python object."""
385 def __init__(self):
386 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000387 self.maxlist = self.maxtuple = 20
388 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000389 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000390
391 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000392 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000393
394 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000395 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000396
397 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000398 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000399 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000400 if hasattr(self, methodname):
401 return getattr(self, methodname)(x, level)
402 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000403
404 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000405 test = cram(x, self.maxstring)
406 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000407 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000408 # Backslashes are only literal in the string and are never
409 # needed to make any special characters, so show a raw string.
410 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000411 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000412 r'<font color="#c040c0">\1</font>',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000413 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000414
Skip Montanarodf708782002-03-07 22:58:02 +0000415 repr_str = repr_string
416
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000417 def repr_instance(self, x, level):
418 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000419 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000420 except:
421 return self.escape('<%s instance>' % x.__class__.__name__)
422
423 repr_unicode = repr_string
424
425class HTMLDoc(Doc):
426 """Formatter class for HTML documentation."""
427
428 # ------------------------------------------- HTML formatting utilities
429
430 _repr_instance = HTMLRepr()
431 repr = _repr_instance.repr
432 escape = _repr_instance.escape
433
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000434 def page(self, title, contents):
435 """Format an HTML page."""
Georg Brandl388faac2009-04-10 08:31:48 +0000436 return '''\
Georg Brandle6066942009-04-10 08:28:28 +0000437<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000438<html><head><title>Python: %s</title>
Georg Brandl388faac2009-04-10 08:31:48 +0000439<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000440</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000441%s
442</body></html>''' % (title, contents)
443
444 def heading(self, title, fgcol, bgcol, extras=''):
445 """Format a page heading."""
446 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000447<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000448<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000449<td valign=bottom>&nbsp;<br>
450<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000451><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000452><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000453 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
454
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000455 def section(self, title, fgcol, bgcol, contents, width=6,
456 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000457 """Format a section with a heading."""
458 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000459 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000460 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000461<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000462<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000463<td colspan=3 valign=bottom>&nbsp;<br>
464<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000465 ''' % (bgcol, fgcol, title)
466 if prelude:
467 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000468<tr bgcolor="%s"><td rowspan=2>%s</td>
469<td colspan=2>%s</td></tr>
470<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
471 else:
472 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000473<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000474
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000475 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000476
477 def bigsection(self, title, *args):
478 """Format a section with a big heading."""
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000479 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000480 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000481
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000482 def preformat(self, text):
483 """Format literal preformatted text."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000484 text = self.escape(text.expandtabs())
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000485 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
486 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000487
488 def multicolumn(self, list, format, cols=4):
489 """Format a list of items into a multi-column list."""
490 result = ''
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000491 rows = (len(list)+cols-1)//cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000492 for col in range(cols):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000493 result = result + '<td width="%d%%" valign=top>' % (100//cols)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000494 for i in range(rows*col, rows*col+rows):
495 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000496 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000497 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000498 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000499
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000500 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000501
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000502 def namelink(self, name, *dicts):
503 """Make a link for an identifier, given name-to-URL mappings."""
504 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000505 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000506 return '<a href="%s">%s</a>' % (dict[name], name)
507 return name
508
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000509 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000510 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000511 name, module = object.__name__, sys.modules.get(object.__module__)
512 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000513 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000514 module.__name__, name, classname(object, modname))
515 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000516
517 def modulelink(self, object):
518 """Make a link for a module."""
519 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
520
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000521 def modpkglink(self, modpkginfo):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000522 """Make a link for a module or package to display in an index."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000523 name, path, ispackage, shadowed = modpkginfo
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000524 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000525 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000526 if path:
527 url = '%s.%s.html' % (path, name)
528 else:
529 url = '%s.html' % name
530 if ispackage:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000531 text = '<strong>%s</strong>&nbsp;(package)' % name
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000532 else:
533 text = name
534 return '<a href="%s">%s</a>' % (url, text)
535
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000536 def filelink(self, url, path):
537 """Make a link to source file."""
538 return '<a href="file:%s">%s</a>' % (url, path)
539
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000540 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
541 """Mark up some plain text, given a context of symbols to look for.
542 Each context dictionary maps object names to anchor names."""
543 escape = escape or self.escape
544 results = []
545 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000546 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
547 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000548 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000549 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000550 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000551 match = pattern.search(text, here)
552 if not match: break
553 start, end = match.span()
554 results.append(escape(text[here:start]))
555
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000556 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000557 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000558 url = escape(all).replace('"', '&quot;')
559 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000560 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000561 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
562 results.append('<a href="%s">%s</a>' % (url, escape(all)))
563 elif pep:
Christian Heimes2202f872008-02-06 14:31:34 +0000564 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000565 results.append('<a href="%s">%s</a>' % (url, escape(all)))
566 elif text[end:end+1] == '(':
567 results.append(self.namelink(name, methods, funcs, classes))
568 elif selfdot:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000569 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000570 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000571 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000572 here = end
573 results.append(escape(text[here:]))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000574 return ''.join(results)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000575
576 # ---------------------------------------------- type-specific routines
577
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000578 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000579 """Produce HTML for a class tree as given by inspect.getclasstree()."""
580 result = ''
581 for entry in tree:
582 if type(entry) is type(()):
583 c, bases = entry
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000584 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000585 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000586 if bases and bases != (parent,):
587 parents = []
588 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000589 parents.append(self.classlink(base, modname))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000590 result = result + '(' + ', '.join(parents) + ')'
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000591 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000592 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000593 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000594 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000595 return '<dl>\n%s</dl>\n' % result
596
Tim Peters8dd7ade2001-10-18 19:56:17 +0000597 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000598 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000599 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000600 try:
601 all = object.__all__
602 except AttributeError:
603 all = None
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000604 parts = name.split('.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000605 links = []
606 for i in range(len(parts)-1):
607 links.append(
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000608 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000609 ('.'.join(parts[:i+1]), parts[i]))
610 linkedname = '.'.join(links + parts[-1:])
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000611 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000612 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000613 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000614 url = path
615 if sys.platform == 'win32':
616 import nturl2path
617 url = nturl2path.pathname2url(path)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000618 filelink = self.filelink(url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000619 except TypeError:
620 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000621 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000622 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000623 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000624 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000625 version = version[11:-1].strip()
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000626 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000627 if hasattr(object, '__date__'):
628 info.append(self.escape(str(object.__date__)))
629 if info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000630 head = head + ' (%s)' % ', '.join(info)
Skip Montanaro4997a692003-09-10 16:47:51 +0000631 docloc = self.getdocloc(object)
632 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000633 docloc = '<br><a href="%(docloc)s">Module Reference</a>' % locals()
Skip Montanaro4997a692003-09-10 16:47:51 +0000634 else:
635 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000636 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000637 head, '#ffffff', '#7799ee',
638 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000639
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000640 modules = inspect.getmembers(object, inspect.ismodule)
641
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000642 classes, cdict = [], {}
643 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000644 # if __all__ exists, believe it. Otherwise use old heuristic.
645 if (all is not None or
646 (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700647 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000648 classes.append((key, value))
649 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000650 for key, value in classes:
651 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000652 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000653 module = sys.modules.get(modname)
654 if modname != name and module and hasattr(module, key):
655 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000656 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000657 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000658 funcs, fdict = [], {}
659 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000660 # if __all__ exists, believe it. Otherwise use old heuristic.
661 if (all is not None or
662 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700663 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000664 funcs.append((key, value))
665 fdict[key] = '#-' + key
666 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000667 data = []
668 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700669 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000670 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000671
672 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
673 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000674 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000675
676 if hasattr(object, '__path__'):
677 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000678 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
679 modpkgs.append((modname, name, ispkg, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000680 modpkgs.sort()
681 contents = self.multicolumn(modpkgs, self.modpkglink)
682 result = result + self.bigsection(
683 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000684 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000685 contents = self.multicolumn(
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000686 modules, lambda t: self.modulelink(t[1]))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000687 result = result + self.bigsection(
Christian Heimes7131fd92008-02-19 14:21:46 +0000688 'Modules', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000689
690 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000691 classlist = [value for (key, value) in classes]
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000692 contents = [
693 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000694 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000695 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000696 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000697 'Classes', '#ffffff', '#ee77aa', ' '.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000698 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000699 contents = []
700 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000701 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000702 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000703 'Functions', '#ffffff', '#eeaa77', ' '.join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000704 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000705 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000706 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000707 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000708 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000709 'Data', '#ffffff', '#55aa55', '<br>\n'.join(contents))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000710 if hasattr(object, '__author__'):
711 contents = self.markup(str(object.__author__), self.preformat)
712 result = result + self.bigsection(
713 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000714 if hasattr(object, '__credits__'):
715 contents = self.markup(str(object.__credits__), self.preformat)
716 result = result + self.bigsection(
717 'Credits', '#ffffff', '#7799ee', contents)
718
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000719 return result
720
Tim Peters8dd7ade2001-10-18 19:56:17 +0000721 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
722 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000723 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000724 realname = object.__name__
725 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000726 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000727
Tim Petersb47879b2001-09-24 04:47:19 +0000728 contents = []
729 push = contents.append
730
Tim Petersfa26f7c2001-09-24 08:05:11 +0000731 # Cute little class to pump out a horizontal rule between sections.
732 class HorizontalRule:
733 def __init__(self):
734 self.needone = 0
735 def maybe(self):
736 if self.needone:
737 push('<hr>\n')
738 self.needone = 1
739 hr = HorizontalRule()
740
Tim Petersc86f6ca2001-09-26 21:31:51 +0000741 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000742 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000743 if len(mro) > 2:
744 hr.maybe()
745 push('<dl><dt>Method resolution order:</dt>\n')
746 for base in mro:
747 push('<dd>%s</dd>\n' % self.classlink(base,
748 object.__module__))
749 push('</dl>\n')
750
Tim Petersb47879b2001-09-24 04:47:19 +0000751 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000752 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000753 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000754 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000755 push(msg)
756 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100757 try:
758 value = getattr(object, name)
759 except Exception:
760 # Some descriptors may meet a failure in their __get__.
761 # (bug #1785)
762 push(self._docdescriptor(name, value, mod))
763 else:
764 push(self.document(value, name, mod,
765 funcs, classes, mdict, object))
Tim Petersb47879b2001-09-24 04:47:19 +0000766 push('\n')
767 return attrs
768
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000769 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000770 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:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000775 push(self._docdescriptor(name, value, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000776 return attrs
777
Tim Petersfa26f7c2001-09-24 08:05:11 +0000778 def spilldata(msg, attrs, predicate):
779 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000780 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000781 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000782 push(msg)
783 for name, kind, homecls, value in ok:
784 base = self.docother(getattr(object, name), name, mod)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200785 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000786 doc = getattr(value, "__doc__", None)
787 else:
788 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000789 if doc is None:
790 push('<dl><dt>%s</dl>\n' % base)
791 else:
792 doc = self.markup(getdoc(value), self.preformat,
793 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000794 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000795 push('<dl><dt>%s%s</dl>\n' % (base, doc))
796 push('\n')
797 return attrs
798
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000799 attrs = [(name, kind, cls, value)
800 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -0700801 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000802
Tim Petersb47879b2001-09-24 04:47:19 +0000803 mdict = {}
804 for key, kind, homecls, value in attrs:
805 mdict[key] = anchor = '#' + name + '-' + key
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100806 try:
807 value = getattr(object, name)
808 except Exception:
809 # Some descriptors may meet a failure in their __get__.
810 # (bug #1785)
811 pass
Tim Petersb47879b2001-09-24 04:47:19 +0000812 try:
813 # The value may not be hashable (e.g., a data attr with
814 # a dict or list value).
815 mdict[value] = anchor
816 except TypeError:
817 pass
818
Tim Petersfa26f7c2001-09-24 08:05:11 +0000819 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000820 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000821 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000822 else:
823 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000824 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
825
Georg Brandl1a3284e2007-12-02 09:40:06 +0000826 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000827 attrs = inherited
828 continue
829 elif thisclass is object:
830 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000831 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000832 tag = 'inherited from %s' % self.classlink(thisclass,
833 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000834 tag += ':<br>\n'
835
836 # Sort attrs by name.
Raymond Hettingerd4cb56d2008-01-30 02:55:10 +0000837 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000838
839 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000840 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000841 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000842 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000843 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000844 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000845 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000846 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
847 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000848 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000849 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000850 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000851 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000852
853 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000854
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000855 if name == realname:
856 title = '<a name="%s">class <strong>%s</strong></a>' % (
857 name, realname)
858 else:
859 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
860 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000861 if bases:
862 parents = []
863 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000864 parents.append(self.classlink(base, object.__module__))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000865 title = title + '(%s)' % ', '.join(parents)
Tim Peters2306d242001-09-25 03:18:32 +0000866 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000867 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000868
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000869 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000870
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000871 def formatvalue(self, object):
872 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000873 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000874
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000875 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000876 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000877 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000878 realname = object.__name__
879 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000880 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000881 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000882 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000883 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +0000884 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000885 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000886 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000887 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000888 else:
Christian Heimesff737952007-11-27 10:40:20 +0000889 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000890 note = ' method of %s instance' % self.classlink(
Christian Heimesff737952007-11-27 10:40:20 +0000891 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000892 else:
893 note = ' unbound %s method' % self.classlink(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +0000894 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000895
896 if name == realname:
897 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
898 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000899 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000900 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000901 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000902 cl.__name__ + '-' + realname, realname)
903 skipdocs = 1
904 else:
905 reallink = realname
906 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
907 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000908 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +0000909 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann = \
910 inspect.getfullargspec(object)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000911 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +0000912 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann,
913 formatvalue=self.formatvalue,
914 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000915 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000916 title = '<strong>%s</strong> <em>lambda</em> ' % name
Guido van Rossum2e65f892007-02-28 22:03:49 +0000917 # XXX lambda's won't usually have func_annotations['return']
918 # since the syntax doesn't support but it is possible.
919 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000920 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000921 else:
922 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000923
Tim Peters2306d242001-09-25 03:18:32 +0000924 decl = title + argspec + (note and self.grey(
925 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000926
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000927 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000928 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000929 else:
930 doc = self.markup(
931 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000932 doc = doc and '<dd><tt>%s</tt></dd>' % doc
933 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000934
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000935 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000936 results = []
937 push = results.append
938
939 if name:
940 push('<dl><dt><strong>%s</strong></dt>\n' % name)
941 if value.__doc__ is not None:
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +0000942 doc = self.markup(getdoc(value), self.preformat)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000943 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000944 push('</dl>\n')
945
946 return ''.join(results)
947
948 def docproperty(self, object, name=None, mod=None, cl=None):
949 """Produce html documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000950 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000951
Tim Peters8dd7ade2001-10-18 19:56:17 +0000952 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000953 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000954 lhs = name and '<strong>%s</strong> = ' % name or ''
955 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000956
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000957 def docdata(self, object, name=None, mod=None, cl=None):
958 """Produce html documentation for a data descriptor."""
959 return self._docdescriptor(name, object, mod)
960
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000961 def index(self, dir, shadowed=None):
962 """Generate an HTML index for a directory of modules."""
963 modpkgs = []
964 if shadowed is None: shadowed = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000965 for importer, name, ispkg in pkgutil.iter_modules([dir]):
966 modpkgs.append((name, '', ispkg, name in shadowed))
967 shadowed[name] = 1
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000968
969 modpkgs.sort()
970 contents = self.multicolumn(modpkgs, self.modpkglink)
971 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
972
973# -------------------------------------------- text documentation generator
974
975class TextRepr(Repr):
976 """Class for safely making a text representation of a Python object."""
977 def __init__(self):
978 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000979 self.maxlist = self.maxtuple = 20
980 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000981 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000982
983 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000984 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000985 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000986 if hasattr(self, methodname):
987 return getattr(self, methodname)(x, level)
988 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000989
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000990 def repr_string(self, x, level):
991 test = cram(x, self.maxstring)
992 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000993 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000994 # Backslashes are only literal in the string and are never
995 # needed to make any special characters, so show a raw string.
996 return 'r' + testrepr[0] + test + testrepr[0]
997 return testrepr
998
Skip Montanarodf708782002-03-07 22:58:02 +0000999 repr_str = repr_string
1000
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001001 def repr_instance(self, x, level):
1002 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001003 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001004 except:
1005 return '<%s instance>' % x.__class__.__name__
1006
1007class TextDoc(Doc):
1008 """Formatter class for text documentation."""
1009
1010 # ------------------------------------------- text formatting utilities
1011
1012 _repr_instance = TextRepr()
1013 repr = _repr_instance.repr
1014
1015 def bold(self, text):
1016 """Format a string in bold by overstriking."""
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001017 return ''.join(ch + '\b' + ch for ch in text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001018
1019 def indent(self, text, prefix=' '):
1020 """Indent text by prepending a given prefix to each line."""
1021 if not text: return ''
Collin Winter72e110c2007-07-17 00:27:30 +00001022 lines = [prefix + line for line in text.split('\n')]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001023 if lines: lines[-1] = lines[-1].rstrip()
1024 return '\n'.join(lines)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001025
1026 def section(self, title, contents):
1027 """Format a section with a given heading."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001028 clean_contents = self.indent(contents).rstrip()
1029 return self.bold(title) + '\n' + clean_contents + '\n\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001030
1031 # ---------------------------------------------- type-specific routines
1032
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001033 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001034 """Render in text a class tree as returned by inspect.getclasstree()."""
1035 result = ''
1036 for entry in tree:
1037 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001038 c, bases = entry
1039 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001040 if bases and bases != (parent,):
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001041 parents = (classname(c, modname) for c in bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001042 result = result + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001043 result = result + '\n'
1044 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001045 result = result + self.formattree(
1046 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001047 return result
1048
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001049 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001050 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001051 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001052 synop, desc = splitdoc(getdoc(object))
1053 result = self.section('NAME', name + (synop and ' - ' + synop))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001054 all = getattr(object, '__all__', None)
Skip Montanaro4997a692003-09-10 16:47:51 +00001055 docloc = self.getdocloc(object)
1056 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001057 result = result + self.section('MODULE REFERENCE', docloc + """
1058
Éric Araujo647ef8c2011-09-11 00:43:20 +02001059The following documentation is automatically generated from the Python
1060source files. It may be incomplete, incorrect or include features that
1061are considered implementation detail and may vary between Python
1062implementations. When in doubt, consult the module reference at the
1063location listed above.
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001064""")
Skip Montanaro4997a692003-09-10 16:47:51 +00001065
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001066 if desc:
1067 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001068
1069 classes = []
1070 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001071 # if __all__ exists, believe it. Otherwise use old heuristic.
1072 if (all is not None
1073 or (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001074 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001075 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001076 funcs = []
1077 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001078 # if __all__ exists, believe it. Otherwise use old heuristic.
1079 if (all is not None or
1080 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001081 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001082 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001083 data = []
1084 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001085 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001086 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001087
Christian Heimes1af737c2008-01-23 08:24:23 +00001088 modpkgs = []
1089 modpkgs_names = set()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001090 if hasattr(object, '__path__'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001091 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
Christian Heimes1af737c2008-01-23 08:24:23 +00001092 modpkgs_names.add(modname)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001093 if ispkg:
1094 modpkgs.append(modname + ' (package)')
1095 else:
1096 modpkgs.append(modname)
1097
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001098 modpkgs.sort()
1099 result = result + self.section(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001100 'PACKAGE CONTENTS', '\n'.join(modpkgs))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001101
Christian Heimes1af737c2008-01-23 08:24:23 +00001102 # Detect submodules as sometimes created by C extensions
1103 submodules = []
1104 for key, value in inspect.getmembers(object, inspect.ismodule):
1105 if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1106 submodules.append(key)
1107 if submodules:
1108 submodules.sort()
1109 result = result + self.section(
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001110 'SUBMODULES', '\n'.join(submodules))
Christian Heimes1af737c2008-01-23 08:24:23 +00001111
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001112 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001113 classlist = [value for key, value in classes]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001114 contents = [self.formattree(
1115 inspect.getclasstree(classlist, 1), name)]
1116 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001117 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001118 result = result + self.section('CLASSES', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001119
1120 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001121 contents = []
1122 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001123 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001124 result = result + self.section('FUNCTIONS', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001125
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001126 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001127 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001128 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001129 contents.append(self.docother(value, key, name, maxlen=70))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001130 result = result + self.section('DATA', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001131
1132 if hasattr(object, '__version__'):
1133 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001134 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001135 version = version[11:-1].strip()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001136 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001137 if hasattr(object, '__date__'):
1138 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001139 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001140 result = result + self.section('AUTHOR', str(object.__author__))
1141 if hasattr(object, '__credits__'):
1142 result = result + self.section('CREDITS', str(object.__credits__))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001143 try:
1144 file = inspect.getabsfile(object)
1145 except TypeError:
1146 file = '(built-in)'
1147 result = result + self.section('FILE', file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001148 return result
1149
Georg Brandl9bd45f992010-12-03 09:58:38 +00001150 def docclass(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001151 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001152 realname = object.__name__
1153 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001154 bases = object.__bases__
1155
Tim Petersc86f6ca2001-09-26 21:31:51 +00001156 def makename(c, m=object.__module__):
1157 return classname(c, m)
1158
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001159 if name == realname:
1160 title = 'class ' + self.bold(realname)
1161 else:
1162 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001163 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001164 parents = map(makename, bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001165 title = title + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001166
1167 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001168 contents = doc and [doc + '\n'] or []
1169 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001170
Tim Petersc86f6ca2001-09-26 21:31:51 +00001171 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001172 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001173 if len(mro) > 2:
1174 push("Method resolution order:")
1175 for base in mro:
1176 push(' ' + makename(base))
1177 push('')
1178
Tim Petersf4aad8e2001-09-24 22:40:47 +00001179 # Cute little class to pump out a horizontal rule between sections.
1180 class HorizontalRule:
1181 def __init__(self):
1182 self.needone = 0
1183 def maybe(self):
1184 if self.needone:
1185 push('-' * 70)
1186 self.needone = 1
1187 hr = HorizontalRule()
1188
Tim Peters28355492001-09-23 21:29:55 +00001189 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001190 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001191 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001192 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001193 push(msg)
1194 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +01001195 try:
1196 value = getattr(object, name)
1197 except Exception:
1198 # Some descriptors may meet a failure in their __get__.
1199 # (bug #1785)
1200 push(self._docdescriptor(name, value, mod))
1201 else:
1202 push(self.document(value,
1203 name, mod, object))
Tim Peters28355492001-09-23 21:29:55 +00001204 return attrs
1205
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001206 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001207 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001208 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001209 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001210 push(msg)
1211 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001212 push(self._docdescriptor(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001213 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001214
Tim Petersfa26f7c2001-09-24 08:05:11 +00001215 def spilldata(msg, attrs, predicate):
1216 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001217 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001218 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001219 push(msg)
1220 for name, kind, homecls, value in ok:
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001221 if callable(value) or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001222 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001223 else:
1224 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001225 push(self.docother(getattr(object, name),
Georg Brandl8b813db2005-10-01 16:32:31 +00001226 name, mod, maxlen=70, doc=doc) + '\n')
Tim Peters28355492001-09-23 21:29:55 +00001227 return attrs
1228
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001229 attrs = [(name, kind, cls, value)
1230 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -07001231 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001232
Tim Petersfa26f7c2001-09-24 08:05:11 +00001233 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001234 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001235 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001236 else:
1237 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001238 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1239
Georg Brandl1a3284e2007-12-02 09:40:06 +00001240 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001241 attrs = inherited
1242 continue
1243 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001244 tag = "defined here"
1245 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001246 tag = "inherited from %s" % classname(thisclass,
1247 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001248
1249 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001250 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001251
1252 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001253 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001254 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001255 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001256 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001257 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001258 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001259 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1260 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001261 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1262 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001263 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001264 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001265
1266 contents = '\n'.join(contents)
1267 if not contents:
1268 return title + '\n'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001269 return title + '\n' + self.indent(contents.rstrip(), ' | ') + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001270
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001271 def formatvalue(self, object):
1272 """Format an argument default value as text."""
1273 return '=' + self.repr(object)
1274
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001275 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001276 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001277 realname = object.__name__
1278 name = name or realname
1279 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001280 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001281 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +00001282 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001283 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001284 if imclass is not cl:
1285 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001286 else:
Christian Heimesff737952007-11-27 10:40:20 +00001287 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001288 note = ' method of %s instance' % classname(
Christian Heimesff737952007-11-27 10:40:20 +00001289 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001290 else:
1291 note = ' unbound %s method' % classname(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +00001292 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001293
1294 if name == realname:
1295 title = self.bold(realname)
1296 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001297 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001298 cl.__dict__[realname] is object):
1299 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001300 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001301 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +00001302 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann = \
1303 inspect.getfullargspec(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001304 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +00001305 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann,
1306 formatvalue=self.formatvalue,
1307 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001308 if realname == '<lambda>':
Georg Brandl501dd0d2006-02-17 09:45:40 +00001309 title = self.bold(name) + ' lambda '
Guido van Rossum2e65f892007-02-28 22:03:49 +00001310 # XXX lambda's won't usually have func_annotations['return']
1311 # since the syntax doesn't support but it is possible.
1312 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001313 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001314 else:
1315 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001316 decl = title + argspec + note
1317
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001318 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001319 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001320 else:
1321 doc = getdoc(object) or ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001322 return decl + '\n' + (doc and self.indent(doc).rstrip() + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001323
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001324 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001325 results = []
1326 push = results.append
1327
1328 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001329 push(self.bold(name))
1330 push('\n')
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001331 doc = getdoc(value) or ''
1332 if doc:
1333 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001334 push('\n')
1335 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001336
1337 def docproperty(self, object, name=None, mod=None, cl=None):
1338 """Produce text documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001339 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001340
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001341 def docdata(self, object, name=None, mod=None, cl=None):
1342 """Produce text documentation for a data descriptor."""
1343 return self._docdescriptor(name, object, mod)
1344
Georg Brandl8b813db2005-10-01 16:32:31 +00001345 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001346 """Produce text documentation for a data object."""
1347 repr = self.repr(object)
1348 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001349 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001350 chop = maxlen - len(line)
1351 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001352 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001353 if doc is not None:
1354 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001355 return line
1356
Georg Brandld80d5f42010-12-03 07:47:22 +00001357class _PlainTextDoc(TextDoc):
1358 """Subclass of TextDoc which overrides string styling"""
1359 def bold(self, text):
1360 return text
1361
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001362# --------------------------------------------------------- user interfaces
1363
1364def pager(text):
1365 """The first time this is called, determine what kind of pager to use."""
1366 global pager
1367 pager = getpager()
1368 pager(text)
1369
1370def getpager():
1371 """Decide what method to use for paging through text."""
Guido van Rossuma01a8b62007-05-27 09:20:14 +00001372 if not hasattr(sys.stdout, "isatty"):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001373 return plainpager
1374 if not sys.stdin.isatty() or not sys.stdout.isatty():
1375 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001376 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001377 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001378 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001379 elif os.environ.get('TERM') in ('dumb', 'emacs'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001380 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001381 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001382 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001383 if os.environ.get('TERM') in ('dumb', 'emacs'):
1384 return plainpager
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001385 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001386 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001387 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001388 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001389
1390 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001391 (fd, filename) = tempfile.mkstemp()
1392 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001393 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001394 if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001395 return lambda text: pipepager(text, 'more')
1396 else:
1397 return ttypager
1398 finally:
1399 os.unlink(filename)
1400
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001401def plain(text):
1402 """Remove boldface formatting from text."""
1403 return re.sub('.\b', '', text)
1404
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001405def pipepager(text, cmd):
1406 """Page through text by feeding it to another program."""
1407 pipe = os.popen(cmd, 'w')
1408 try:
1409 pipe.write(text)
1410 pipe.close()
1411 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001412 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001413
1414def tempfilepager(text, cmd):
1415 """Page through text by invoking a program on a temporary file."""
1416 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001417 filename = tempfile.mktemp()
1418 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001419 file.write(text)
1420 file.close()
1421 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001422 os.system(cmd + ' "' + filename + '"')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001423 finally:
1424 os.unlink(filename)
1425
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001426def ttypager(text):
1427 """Page through text on a text terminal."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001428 lines = plain(text).split('\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001429 try:
1430 import tty
1431 fd = sys.stdin.fileno()
1432 old = tty.tcgetattr(fd)
1433 tty.setcbreak(fd)
1434 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001435 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001436 tty = None
1437 getchar = lambda: sys.stdin.readline()[:-1][:1]
1438
1439 try:
1440 r = inc = os.environ.get('LINES', 25) - 1
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001441 sys.stdout.write('\n'.join(lines[:inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001442 while lines[r:]:
1443 sys.stdout.write('-- more --')
1444 sys.stdout.flush()
1445 c = getchar()
1446
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001447 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001448 sys.stdout.write('\r \r')
1449 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001450 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001451 sys.stdout.write('\r \r' + lines[r] + '\n')
1452 r = r + 1
1453 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001454 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001455 r = r - inc - inc
1456 if r < 0: r = 0
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001457 sys.stdout.write('\n' + '\n'.join(lines[r:r+inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001458 r = r + inc
1459
1460 finally:
1461 if tty:
1462 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1463
1464def plainpager(text):
1465 """Simply print unformatted text. This is the ultimate fallback."""
1466 sys.stdout.write(plain(text))
1467
1468def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001469 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001470 if inspect.ismodule(thing):
1471 if thing.__name__ in sys.builtin_module_names:
1472 return 'built-in module ' + thing.__name__
1473 if hasattr(thing, '__path__'):
1474 return 'package ' + thing.__name__
1475 else:
1476 return 'module ' + thing.__name__
1477 if inspect.isbuiltin(thing):
1478 return 'built-in function ' + thing.__name__
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001479 if inspect.isgetsetdescriptor(thing):
1480 return 'getset descriptor %s.%s.%s' % (
1481 thing.__objclass__.__module__, thing.__objclass__.__name__,
1482 thing.__name__)
1483 if inspect.ismemberdescriptor(thing):
1484 return 'member descriptor %s.%s.%s' % (
1485 thing.__objclass__.__module__, thing.__objclass__.__name__,
1486 thing.__name__)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001487 if inspect.isclass(thing):
1488 return 'class ' + thing.__name__
1489 if inspect.isfunction(thing):
1490 return 'function ' + thing.__name__
1491 if inspect.ismethod(thing):
1492 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001493 return type(thing).__name__
1494
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001495def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001496 """Locate an object by name or dotted path, importing as necessary."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001497 parts = [part for part in path.split('.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001498 module, n = None, 0
1499 while n < len(parts):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001500 nextmodule = safeimport('.'.join(parts[:n+1]), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001501 if nextmodule: module, n = nextmodule, n + 1
1502 else: break
1503 if module:
1504 object = module
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001505 else:
Éric Araujoe64e51b2011-07-29 17:03:55 +02001506 object = builtins
1507 for part in parts[n:]:
1508 try:
1509 object = getattr(object, part)
1510 except AttributeError:
1511 return None
1512 return object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001513
1514# --------------------------------------- interactive interpreter interface
1515
1516text = TextDoc()
Georg Brandld80d5f42010-12-03 07:47:22 +00001517plaintext = _PlainTextDoc()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001518html = HTMLDoc()
1519
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001520def resolve(thing, forceload=0):
1521 """Given an object or a path to an object, get the object and its name."""
1522 if isinstance(thing, str):
1523 object = locate(thing, forceload)
1524 if not object:
Collin Winterce36ad82007-08-30 01:19:48 +00001525 raise ImportError('no Python documentation found for %r' % thing)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001526 return object, thing
1527 else:
R David Murrayc43125a2012-04-23 13:23:57 -04001528 name = getattr(thing, '__name__', None)
1529 return thing, name if isinstance(name, str) else None
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001530
Georg Brandld80d5f42010-12-03 07:47:22 +00001531def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
1532 renderer=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001533 """Render text documentation, given an object or a path to an object."""
Georg Brandld80d5f42010-12-03 07:47:22 +00001534 if renderer is None:
1535 renderer = text
Guido van Rossumd8faa362007-04-27 19:54:29 +00001536 object, name = resolve(thing, forceload)
1537 desc = describe(object)
1538 module = inspect.getmodule(object)
1539 if name and '.' in name:
1540 desc += ' in ' + name[:name.rfind('.')]
1541 elif module and module is not object:
1542 desc += ' in module ' + module.__name__
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001543
1544 if not (inspect.ismodule(object) or
Guido van Rossumd8faa362007-04-27 19:54:29 +00001545 inspect.isclass(object) or
1546 inspect.isroutine(object) or
1547 inspect.isgetsetdescriptor(object) or
1548 inspect.ismemberdescriptor(object) or
1549 isinstance(object, property)):
1550 # If the passed object is a piece of data or an instance,
1551 # document its available methods instead of its value.
1552 object = type(object)
1553 desc += ' object'
Georg Brandld80d5f42010-12-03 07:47:22 +00001554 return title % desc + '\n\n' + renderer.document(object, name)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001555
Georg Brandld80d5f42010-12-03 07:47:22 +00001556def doc(thing, title='Python Library Documentation: %s', forceload=0,
1557 output=None):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001558 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001559 try:
Georg Brandld80d5f42010-12-03 07:47:22 +00001560 if output is None:
1561 pager(render_doc(thing, title, forceload))
1562 else:
1563 output.write(render_doc(thing, title, forceload, plaintext))
Guido van Rossumb940e112007-01-10 16:19:56 +00001564 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001565 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001566
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001567def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001568 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001569 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001570 object, name = resolve(thing, forceload)
1571 page = html.page(describe(object), html.document(object, name))
Georg Brandl388faac2009-04-10 08:31:48 +00001572 file = open(name + '.html', 'w', encoding='utf-8')
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001573 file.write(page)
1574 file.close()
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001575 print('wrote', name + '.html')
Guido van Rossumb940e112007-01-10 16:19:56 +00001576 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001577 print(value)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001578
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001579def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001580 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001581 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001582 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1583 writedoc(modname)
1584 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001585
1586class Helper:
Georg Brandl6b38daa2008-06-01 21:05:17 +00001587
1588 # These dictionaries map a topic name to either an alias, or a tuple
1589 # (label, seealso-items). The "label" is the label of the corresponding
1590 # section in the .rst file under Doc/ and an index into the dictionary
Georg Brandl5617db82009-04-27 16:28:57 +00001591 # in pydoc_data/topics.py.
Georg Brandl6b38daa2008-06-01 21:05:17 +00001592 #
1593 # CAUTION: if you change one of these dictionaries, be sure to adapt the
1594 # list of needed labels in Doc/tools/sphinxext/pyspecific.py and
Georg Brandl5617db82009-04-27 16:28:57 +00001595 # regenerate the pydoc_data/topics.py file by running
Georg Brandl6b38daa2008-06-01 21:05:17 +00001596 # make pydoc-topics
1597 # in Doc/ and copying the output file into the Lib/ directory.
1598
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001599 keywords = {
Ezio Melottib185a042011-04-28 07:42:55 +03001600 'False': '',
1601 'None': '',
1602 'True': '',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001603 'and': 'BOOLEAN',
Guido van Rossumd8faa362007-04-27 19:54:29 +00001604 'as': 'with',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001605 'assert': ('assert', ''),
1606 'break': ('break', 'while for'),
1607 'class': ('class', 'CLASSES SPECIALMETHODS'),
1608 'continue': ('continue', 'while for'),
1609 'def': ('function', ''),
1610 'del': ('del', 'BASICMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001611 'elif': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001612 'else': ('else', 'while for'),
Georg Brandl0d855392008-08-30 19:53:05 +00001613 'except': 'try',
1614 'finally': 'try',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001615 'for': ('for', 'break continue while'),
Georg Brandl0d855392008-08-30 19:53:05 +00001616 'from': 'import',
Georg Brandl74abf6f2010-11-20 19:54:36 +00001617 'global': ('global', 'nonlocal NAMESPACES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001618 'if': ('if', 'TRUTHVALUE'),
1619 'import': ('import', 'MODULES'),
Georg Brandl395ed242009-09-04 08:07:32 +00001620 'in': ('in', 'SEQUENCEMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001621 'is': 'COMPARISON',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001622 'lambda': ('lambda', 'FUNCTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001623 'nonlocal': ('nonlocal', 'global NAMESPACES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001624 'not': 'BOOLEAN',
1625 'or': 'BOOLEAN',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001626 'pass': ('pass', ''),
1627 'raise': ('raise', 'EXCEPTIONS'),
1628 'return': ('return', 'FUNCTIONS'),
1629 'try': ('try', 'EXCEPTIONS'),
1630 'while': ('while', 'break continue if TRUTHVALUE'),
1631 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1632 'yield': ('yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001633 }
Georg Brandldb7b6b92009-01-01 15:53:14 +00001634 # Either add symbols to this dictionary or to the symbols dictionary
1635 # directly: Whichever is easier. They are merged later.
1636 _symbols_inverse = {
1637 'STRINGS' : ("'", "'''", "r'", "b'", '"""', '"', 'r"', 'b"'),
1638 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1639 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1640 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1641 'UNARY' : ('-', '~'),
1642 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1643 '^=', '<<=', '>>=', '**=', '//='),
1644 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1645 'COMPLEX' : ('j', 'J')
1646 }
1647 symbols = {
1648 '%': 'OPERATORS FORMATTING',
1649 '**': 'POWER',
1650 ',': 'TUPLES LISTS FUNCTIONS',
1651 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1652 '...': 'ELLIPSIS',
1653 ':': 'SLICINGS DICTIONARYLITERALS',
1654 '@': 'def class',
1655 '\\': 'STRINGS',
1656 '_': 'PRIVATENAMES',
1657 '__': 'PRIVATENAMES SPECIALMETHODS',
1658 '`': 'BACKQUOTES',
1659 '(': 'TUPLES FUNCTIONS CALLS',
1660 ')': 'TUPLES FUNCTIONS CALLS',
1661 '[': 'LISTS SUBSCRIPTS SLICINGS',
1662 ']': 'LISTS SUBSCRIPTS SLICINGS'
1663 }
1664 for topic, symbols_ in _symbols_inverse.items():
1665 for symbol in symbols_:
1666 topics = symbols.get(symbol, topic)
1667 if topic not in topics:
1668 topics = topics + ' ' + topic
1669 symbols[symbol] = topics
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001670
1671 topics = {
Georg Brandl6b38daa2008-06-01 21:05:17 +00001672 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1673 'FUNCTIONS CLASSES MODULES FILES inspect'),
1674 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
1675 'FORMATTING TYPES'),
1676 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1677 'FORMATTING': ('formatstrings', 'OPERATORS'),
1678 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1679 'FORMATTING TYPES'),
1680 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1681 'INTEGER': ('integers', 'int range'),
1682 'FLOAT': ('floating', 'float math'),
1683 'COMPLEX': ('imaginary', 'complex cmath'),
1684 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001685 'MAPPINGS': 'DICTIONARIES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001686 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1687 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1688 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1689 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001690 'FRAMEOBJECTS': 'TYPES',
1691 'TRACEBACKS': 'TYPES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001692 'NONE': ('bltin-null-object', ''),
1693 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
1694 'FILES': ('bltin-file-objects', ''),
1695 'SPECIALATTRIBUTES': ('specialattrs', ''),
1696 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1697 'MODULES': ('typesmodules', 'import'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001698 'PACKAGES': 'import',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001699 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1700 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1701 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1702 'LISTS DICTIONARIES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001703 'OPERATORS': 'EXPRESSIONS',
1704 'PRECEDENCE': 'EXPRESSIONS',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001705 'OBJECTS': ('objects', 'TYPES'),
1706 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
Georg Brandl395ed242009-09-04 08:07:32 +00001707 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
1708 'NUMBERMETHODS CLASSES'),
Mark Dickinsona56c4672009-01-27 18:17:45 +00001709 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001710 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1711 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001712 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
Georg Brandl6b38daa2008-06-01 21:05:17 +00001713 'SPECIALMETHODS'),
1714 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1715 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1716 'SPECIALMETHODS'),
1717 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001718 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001719 'DYNAMICFEATURES': ('dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001720 'SCOPING': 'NAMESPACES',
1721 'FRAMES': 'NAMESPACES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001722 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1723 'CONVERSIONS': ('conversions', ''),
1724 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1725 'SPECIALIDENTIFIERS': ('id-classes', ''),
1726 'PRIVATENAMES': ('atom-identifiers', ''),
1727 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
1728 'LISTLITERALS DICTIONARYLITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001729 'TUPLES': 'SEQUENCES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001730 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1731 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1732 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1733 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1734 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1735 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001736 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
1737 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001738 'CALLS': ('calls', 'EXPRESSIONS'),
1739 'POWER': ('power', 'EXPRESSIONS'),
1740 'UNARY': ('unary', 'EXPRESSIONS'),
1741 'BINARY': ('binary', 'EXPRESSIONS'),
1742 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1743 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1744 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1745 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001746 'ASSERTION': 'assert',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001747 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1748 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001749 'DELETION': 'del',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001750 'RETURNING': 'return',
1751 'IMPORTING': 'import',
1752 'CONDITIONAL': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001753 'LOOPING': ('compound', 'for while break continue'),
1754 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1755 'DEBUGGING': ('debugger', 'pdb'),
1756 'CONTEXTMANAGERS': ('context-managers', 'with'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001757 }
1758
Georg Brandl78aa3962010-07-31 21:51:48 +00001759 def __init__(self, input=None, output=None):
1760 self._input = input
1761 self._output = output
1762
Georg Brandl76ae3972010-08-01 06:32:55 +00001763 input = property(lambda self: self._input or sys.stdin)
1764 output = property(lambda self: self._output or sys.stdout)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001765
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001766 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001767 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001768 self()
1769 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001770 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001771
Alexander Belopolsky2e733c92010-07-04 17:00:20 +00001772 _GoInteractive = object()
1773 def __call__(self, request=_GoInteractive):
1774 if request is not self._GoInteractive:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001775 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001776 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001777 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001778 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001779 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001780You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001781If you want to ask for help on a particular object directly from the
1782interpreter, you can type "help(object)". Executing "help('string')"
1783has the same effect as typing a particular string at the help> prompt.
1784''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001785
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001786 def interact(self):
1787 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001788 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001789 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001790 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001791 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001792 except (KeyboardInterrupt, EOFError):
1793 break
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001794 request = replace(request, '"', '', "'", '').strip()
1795 if request.lower() in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001796 self.help(request)
1797
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001798 def getline(self, prompt):
Guido van Rossum7c086c02008-01-02 03:52:38 +00001799 """Read one line, using input() when appropriate."""
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001800 if self.input is sys.stdin:
Guido van Rossum7c086c02008-01-02 03:52:38 +00001801 return input(prompt)
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001802 else:
1803 self.output.write(prompt)
1804 self.output.flush()
1805 return self.input.readline()
1806
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001807 def help(self, request):
1808 if type(request) is type(''):
R. David Murray1f1b9d32009-05-27 20:56:59 +00001809 request = request.strip()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001810 if request == 'help': self.intro()
1811 elif request == 'keywords': self.listkeywords()
Georg Brandldb7b6b92009-01-01 15:53:14 +00001812 elif request == 'symbols': self.listsymbols()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001813 elif request == 'topics': self.listtopics()
1814 elif request == 'modules': self.listmodules()
1815 elif request[:8] == 'modules ':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001816 self.listmodules(request.split()[1])
Georg Brandldb7b6b92009-01-01 15:53:14 +00001817 elif request in self.symbols: self.showsymbol(request)
Ezio Melottib185a042011-04-28 07:42:55 +03001818 elif request in ['True', 'False', 'None']:
1819 # special case these keywords since they are objects too
1820 doc(eval(request), 'Help on %s:')
Raymond Hettinger54f02222002-06-01 14:18:47 +00001821 elif request in self.keywords: self.showtopic(request)
1822 elif request in self.topics: self.showtopic(request)
Georg Brandld80d5f42010-12-03 07:47:22 +00001823 elif request: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001824 elif isinstance(request, Helper): self()
Georg Brandld80d5f42010-12-03 07:47:22 +00001825 else: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001826 self.output.write('\n')
1827
1828 def intro(self):
1829 self.output.write('''
1830Welcome to Python %s! This is the online help utility.
1831
1832If this is your first time using Python, you should definitely check out
R David Murrayde0f6292012-03-31 12:06:35 -04001833the tutorial on the Internet at http://docs.python.org/%s/tutorial/.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001834
1835Enter the name of any module, keyword, or topic to get help on writing
1836Python programs and using Python modules. To quit this help utility and
1837return to the interpreter, just type "quit".
1838
1839To get a list of available modules, keywords, or topics, type "modules",
1840"keywords", or "topics". Each module also comes with a one-line summary
1841of what it does; to list the modules whose summaries contain a given word
1842such as "spam", type "modules spam".
R David Murrayde0f6292012-03-31 12:06:35 -04001843''' % tuple([sys.version[:3]]*2))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001844
1845 def list(self, items, columns=4, width=80):
Guido van Rossum486364b2007-06-30 05:01:58 +00001846 items = list(sorted(items))
1847 colw = width // columns
1848 rows = (len(items) + columns - 1) // columns
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001849 for row in range(rows):
1850 for col in range(columns):
1851 i = col * rows + row
1852 if i < len(items):
1853 self.output.write(items[i])
1854 if col < columns - 1:
Guido van Rossum486364b2007-06-30 05:01:58 +00001855 self.output.write(' ' + ' ' * (colw - 1 - len(items[i])))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001856 self.output.write('\n')
1857
1858 def listkeywords(self):
1859 self.output.write('''
1860Here is a list of the Python keywords. Enter any keyword to get more help.
1861
1862''')
1863 self.list(self.keywords.keys())
1864
Georg Brandldb7b6b92009-01-01 15:53:14 +00001865 def listsymbols(self):
1866 self.output.write('''
1867Here is a list of the punctuation symbols which Python assigns special meaning
1868to. Enter any symbol to get more help.
1869
1870''')
1871 self.list(self.symbols.keys())
1872
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001873 def listtopics(self):
1874 self.output.write('''
1875Here is a list of available topics. Enter any topic name to get more help.
1876
1877''')
1878 self.list(self.topics.keys())
1879
Georg Brandldb7b6b92009-01-01 15:53:14 +00001880 def showtopic(self, topic, more_xrefs=''):
Georg Brandl6b38daa2008-06-01 21:05:17 +00001881 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001882 import pydoc_data.topics
Georg Brandl6b38daa2008-06-01 21:05:17 +00001883 except ImportError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001884 self.output.write('''
Georg Brandl6b38daa2008-06-01 21:05:17 +00001885Sorry, topic and keyword documentation is not available because the
Georg Brandl5617db82009-04-27 16:28:57 +00001886module "pydoc_data.topics" could not be found.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001887''')
1888 return
1889 target = self.topics.get(topic, self.keywords.get(topic))
1890 if not target:
1891 self.output.write('no documentation found for %s\n' % repr(topic))
1892 return
1893 if type(target) is type(''):
Georg Brandldb7b6b92009-01-01 15:53:14 +00001894 return self.showtopic(target, more_xrefs)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001895
Georg Brandl6b38daa2008-06-01 21:05:17 +00001896 label, xrefs = target
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001897 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001898 doc = pydoc_data.topics.topics[label]
Georg Brandl6b38daa2008-06-01 21:05:17 +00001899 except KeyError:
1900 self.output.write('no documentation found for %s\n' % repr(topic))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001901 return
Georg Brandl6b38daa2008-06-01 21:05:17 +00001902 pager(doc.strip() + '\n')
Georg Brandldb7b6b92009-01-01 15:53:14 +00001903 if more_xrefs:
1904 xrefs = (xrefs or '') + ' ' + more_xrefs
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001905 if xrefs:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001906 import formatter
Guido van Rossum34d19282007-08-09 01:03:29 +00001907 buffer = io.StringIO()
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001908 formatter.DumbWriter(buffer).send_flowing_data(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001909 'Related help topics: ' + ', '.join(xrefs.split()) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001910 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001911
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001912 def _gettopic(self, topic, more_xrefs=''):
1913 """Return unbuffered tuple of (topic, xrefs).
1914
Georg Brandld2f38572011-01-30 08:37:19 +00001915 If an error occurs here, the exception is caught and displayed by
1916 the url handler.
1917
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001918 This function duplicates the showtopic method but returns its
1919 result directly so it can be formatted for display in an html page.
1920 """
1921 try:
1922 import pydoc_data.topics
1923 except ImportError:
1924 return('''
1925Sorry, topic and keyword documentation is not available because the
1926module "pydoc_data.topics" could not be found.
1927''' , '')
1928 target = self.topics.get(topic, self.keywords.get(topic))
1929 if not target:
Georg Brandld2f38572011-01-30 08:37:19 +00001930 raise ValueError('could not find topic')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001931 if isinstance(target, str):
1932 return self._gettopic(target, more_xrefs)
1933 label, xrefs = target
Georg Brandld2f38572011-01-30 08:37:19 +00001934 doc = pydoc_data.topics.topics[label]
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001935 if more_xrefs:
1936 xrefs = (xrefs or '') + ' ' + more_xrefs
1937 return doc, xrefs
1938
Georg Brandldb7b6b92009-01-01 15:53:14 +00001939 def showsymbol(self, symbol):
1940 target = self.symbols[symbol]
1941 topic, _, xrefs = target.partition(' ')
1942 self.showtopic(topic, xrefs)
1943
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001944 def listmodules(self, key=''):
1945 if key:
1946 self.output.write('''
1947Here is a list of matching modules. Enter any module name to get more help.
1948
1949''')
1950 apropos(key)
1951 else:
1952 self.output.write('''
1953Please wait a moment while I gather a list of all available modules...
1954
1955''')
1956 modules = {}
1957 def callback(path, modname, desc, modules=modules):
1958 if modname and modname[-9:] == '.__init__':
1959 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001960 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001961 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001962 def onerror(modname):
1963 callback(None, modname, None)
1964 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001965 self.list(modules.keys())
1966 self.output.write('''
1967Enter any module name to get more help. Or, type "modules spam" to search
1968for modules whose descriptions contain the word "spam".
1969''')
1970
Georg Brandl78aa3962010-07-31 21:51:48 +00001971help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001972
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001973class Scanner:
1974 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001975 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001976 self.roots = roots[:]
1977 self.state = []
1978 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001979 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001980
1981 def next(self):
1982 if not self.state:
1983 if not self.roots:
1984 return None
1985 root = self.roots.pop(0)
1986 self.state = [(root, self.children(root))]
1987 node, children = self.state[-1]
1988 if not children:
1989 self.state.pop()
1990 return self.next()
1991 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001992 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001993 self.state.append((child, self.children(child)))
1994 return child
1995
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001996
1997class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001998 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001999
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002000 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002001 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002002 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002003 seen = {}
2004
2005 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002006 if modname != '__main__':
2007 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00002008 if key is None:
2009 callback(None, modname, '')
2010 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002011 name = __import__(modname).__doc__ or ''
2012 desc = name.split('\n')[0]
2013 name = modname + ' - ' + desc
2014 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002015 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002016
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002017 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002018 if self.quit:
2019 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002020
2021 # XXX Skipping this file is a workaround for a bug
2022 # that causes python to crash with a segfault.
2023 # http://bugs.python.org/issue9319
2024 #
2025 # TODO Remove this once the bug is fixed.
2026 if modname in {'test.badsyntax_pep3120', 'badsyntax_pep3120'}:
2027 continue
2028
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002029 if key is None:
2030 callback(None, modname, '')
2031 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002032 try:
2033 loader = importer.find_module(modname)
2034 except SyntaxError:
2035 # raised by tests for bad coding cookies or BOM
2036 continue
2037 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002038 try:
2039 source = loader.get_source(modname)
2040 except UnicodeDecodeError:
2041 if onerror:
2042 onerror(modname)
2043 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002044 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002045 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002046 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002047 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002048 path = None
2049 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002050 try:
2051 module = loader.load_module(modname)
2052 except ImportError:
2053 if onerror:
2054 onerror(modname)
2055 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002056 desc = (module.__doc__ or '').splitlines()[0]
2057 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002058 name = modname + ' - ' + desc
2059 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002060 callback(path, modname, desc)
2061
2062 if completer:
2063 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002064
2065def apropos(key):
2066 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002067 def callback(path, modname, desc):
2068 if modname[-9:] == '.__init__':
2069 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002070 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002071 def onerror(modname):
2072 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002073 with warnings.catch_warnings():
2074 warnings.filterwarnings('ignore') # ignore problems during import
2075 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002076
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002077# --------------------------------------------------- Web browser interface
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002078
Ka-Ping Yee66246962001-04-12 11:59:50 +00002079def serve(port, callback=None, completer=None):
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002080 import http.server, email.message, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002081
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002082 msg = 'the pydoc.serve() function is deprecated'
2083 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2084
Georg Brandl24420152008-05-26 16:32:26 +00002085 class DocHandler(http.server.BaseHTTPRequestHandler):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002086 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002087 try:
2088 self.send_response(200)
Georg Brandl825fc8b2008-01-19 20:44:32 +00002089 self.send_header('Content-Type', 'text/html; charset=UTF-8')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002090 self.end_headers()
Georg Brandl825fc8b2008-01-19 20:44:32 +00002091 self.wfile.write(html.page(title, contents).encode('utf-8'))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002092 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002093
2094 def do_GET(self):
2095 path = self.path
2096 if path[-5:] == '.html': path = path[:-5]
2097 if path[:1] == '/': path = path[1:]
2098 if path and path != '.':
2099 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002100 obj = locate(path, forceload=1)
Guido van Rossumb940e112007-01-10 16:19:56 +00002101 except ErrorDuringImport as value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002102 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002103 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002104 if obj:
2105 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002106 else:
2107 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002108'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002109 else:
2110 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002111'<big><big><strong>Python: Index of Modules</strong></big></big>',
2112'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002113 def bltinlink(name):
2114 return '<a href="%s.html">%s</a>' % (name, name)
Georg Brandl661b0a12008-01-27 18:16:00 +00002115 names = [x for x in sys.builtin_module_names if x != '__main__']
2116 contents = html.multicolumn(names, bltinlink)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002117 indices = ['<p>' + html.bigsection(
2118 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2119
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002120 seen = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002121 for dir in sys.path:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002122 indices.append(html.index(dir, seen))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002123 contents = heading + ' '.join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00002124<font color="#909090" face="helvetica, arial"><strong>
2125pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002126 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002127
2128 def log_message(self, *args): pass
2129
Georg Brandl24420152008-05-26 16:32:26 +00002130 class DocServer(http.server.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002131 def __init__(self, port, callback):
Ronald Oussoren94f25282010-05-05 19:11:21 +00002132 host = 'localhost'
Senthil Kumaran7ff59132010-08-18 19:32:21 +00002133 self.address = (host, port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00002134 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002135 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002136 self.base.__init__(self, self.address, self.handler)
2137
2138 def serve_until_quit(self):
2139 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002140 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002141 while not self.quit:
2142 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2143 if rd: self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002144 self.server_close()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002145
2146 def server_activate(self):
2147 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002148 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002149
Georg Brandl24420152008-05-26 16:32:26 +00002150 DocServer.base = http.server.HTTPServer
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002151 DocServer.handler = DocHandler
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002152 DocHandler.MessageClass = email.message.Message
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002153 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002154 try:
2155 DocServer(port, callback).serve_until_quit()
2156 except (KeyboardInterrupt, select.error):
2157 pass
2158 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002159 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002160
2161# ----------------------------------------------------- graphical interface
2162
2163def gui():
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002164 """Graphical interface (starts Web server and pops up a control window)."""
2165
2166 msg = ('the pydoc.gui() function and "pydoc -g" option are deprecated\n',
2167 'use "pydoc.browse() function and "pydoc -b" option instead.')
2168 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2169
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002170 class GUI:
2171 def __init__(self, window, port=7464):
2172 self.window = window
2173 self.server = None
2174 self.scanner = None
2175
Georg Brandl14fc4272008-05-17 18:39:55 +00002176 import tkinter
2177 self.server_frm = tkinter.Frame(window)
2178 self.title_lbl = tkinter.Label(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002179 text='Starting server...\n ')
Georg Brandl14fc4272008-05-17 18:39:55 +00002180 self.open_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002181 text='open browser', command=self.open, state='disabled')
Georg Brandl14fc4272008-05-17 18:39:55 +00002182 self.quit_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002183 text='quit serving', command=self.quit, state='disabled')
2184
Georg Brandl14fc4272008-05-17 18:39:55 +00002185 self.search_frm = tkinter.Frame(window)
2186 self.search_lbl = tkinter.Label(self.search_frm, text='Search for')
2187 self.search_ent = tkinter.Entry(self.search_frm)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002188 self.search_ent.bind('<Return>', self.search)
Georg Brandl14fc4272008-05-17 18:39:55 +00002189 self.stop_btn = tkinter.Button(self.search_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002190 text='stop', pady=0, command=self.stop, state='disabled')
2191 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002192 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002193 self.stop_btn.pack(side='right')
2194
2195 self.window.title('pydoc')
2196 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2197 self.title_lbl.pack(side='top', fill='x')
2198 self.open_btn.pack(side='left', fill='x', expand=1)
2199 self.quit_btn.pack(side='right', fill='x', expand=1)
2200 self.server_frm.pack(side='top', fill='x')
2201
2202 self.search_lbl.pack(side='left')
2203 self.search_ent.pack(side='right', fill='x', expand=1)
2204 self.search_frm.pack(side='top', fill='x')
2205 self.search_ent.focus_set()
2206
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002207 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Georg Brandl14fc4272008-05-17 18:39:55 +00002208 self.result_lst = tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002209 self.result_lst.bind('<Button-1>', self.select)
2210 self.result_lst.bind('<Double-Button-1>', self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002211 self.result_scr = tkinter.Scrollbar(window,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002212 orient='vertical', command=self.result_lst.yview)
2213 self.result_lst.config(yscrollcommand=self.result_scr.set)
2214
Georg Brandl14fc4272008-05-17 18:39:55 +00002215 self.result_frm = tkinter.Frame(window)
2216 self.goto_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002217 text='go to selected', command=self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002218 self.hide_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002219 text='hide results', command=self.hide)
2220 self.goto_btn.pack(side='left', fill='x', expand=1)
2221 self.hide_btn.pack(side='right', fill='x', expand=1)
2222
2223 self.window.update()
2224 self.minwidth = self.window.winfo_width()
2225 self.minheight = self.window.winfo_height()
2226 self.bigminheight = (self.server_frm.winfo_reqheight() +
2227 self.search_frm.winfo_reqheight() +
2228 self.result_lst.winfo_reqheight() +
2229 self.result_frm.winfo_reqheight())
2230 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2231 self.expanded = 0
2232 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2233 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002234 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002235
2236 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002237 threading.Thread(
2238 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002239
2240 def ready(self, server):
2241 self.server = server
2242 self.title_lbl.config(
2243 text='Python documentation server at\n' + server.url)
2244 self.open_btn.config(state='normal')
2245 self.quit_btn.config(state='normal')
2246
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002247 def open(self, event=None, url=None):
2248 url = url or self.server.url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002249 import webbrowser
2250 webbrowser.open(url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002251
2252 def quit(self, event=None):
2253 if self.server:
2254 self.server.quit = 1
2255 self.window.quit()
2256
2257 def search(self, event=None):
2258 key = self.search_ent.get()
2259 self.stop_btn.pack(side='right')
2260 self.stop_btn.config(state='normal')
2261 self.search_lbl.config(text='Searching for "%s"...' % key)
2262 self.search_ent.forget()
2263 self.search_lbl.pack(side='left')
2264 self.result_lst.delete(0, 'end')
2265 self.goto_btn.config(state='disabled')
2266 self.expand()
2267
2268 import threading
2269 if self.scanner:
2270 self.scanner.quit = 1
2271 self.scanner = ModuleScanner()
2272 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002273 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002274
2275 def update(self, path, modname, desc):
2276 if modname[-9:] == '.__init__':
2277 modname = modname[:-9] + ' (package)'
2278 self.result_lst.insert('end',
2279 modname + ' - ' + (desc or '(no description)'))
2280
2281 def stop(self, event=None):
2282 if self.scanner:
2283 self.scanner.quit = 1
2284 self.scanner = None
2285
2286 def done(self):
2287 self.scanner = None
2288 self.search_lbl.config(text='Search for')
2289 self.search_lbl.pack(side='left')
2290 self.search_ent.pack(side='right', fill='x', expand=1)
2291 if sys.platform != 'win32': self.stop_btn.forget()
2292 self.stop_btn.config(state='disabled')
2293
2294 def select(self, event=None):
2295 self.goto_btn.config(state='normal')
2296
2297 def goto(self, event=None):
2298 selection = self.result_lst.curselection()
2299 if selection:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002300 modname = self.result_lst.get(selection[0]).split()[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002301 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002302
2303 def collapse(self):
2304 if not self.expanded: return
2305 self.result_frm.forget()
2306 self.result_scr.forget()
2307 self.result_lst.forget()
2308 self.bigwidth = self.window.winfo_width()
2309 self.bigheight = self.window.winfo_height()
2310 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2311 self.window.wm_minsize(self.minwidth, self.minheight)
2312 self.expanded = 0
2313
2314 def expand(self):
2315 if self.expanded: return
2316 self.result_frm.pack(side='bottom', fill='x')
2317 self.result_scr.pack(side='right', fill='y')
2318 self.result_lst.pack(side='top', fill='both', expand=1)
2319 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2320 self.window.wm_minsize(self.minwidth, self.bigminheight)
2321 self.expanded = 1
2322
2323 def hide(self, event=None):
2324 self.stop()
2325 self.collapse()
2326
Georg Brandl14fc4272008-05-17 18:39:55 +00002327 import tkinter
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002328 try:
Georg Brandl14fc4272008-05-17 18:39:55 +00002329 root = tkinter.Tk()
Martin v. Löwise09bd932004-08-22 16:13:26 +00002330 # Tk will crash if pythonw.exe has an XP .manifest
2331 # file and the root has is not destroyed explicitly.
2332 # If the problem is ever fixed in Tk, the explicit
2333 # destroy can go.
2334 try:
2335 gui = GUI(root)
2336 root.mainloop()
2337 finally:
2338 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002339 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002340 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002341
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002342
2343# --------------------------------------- enhanced Web browser interface
2344
2345def _start_server(urlhandler, port):
2346 """Start an HTTP server thread on a specific port.
2347
2348 Start an HTML/text server thread, so HTML or text documents can be
2349 browsed dynamically and interactively with a Web browser. Example use:
2350
2351 >>> import time
2352 >>> import pydoc
2353
2354 Define a URL handler. To determine what the client is asking
2355 for, check the URL and content_type.
2356
2357 Then get or generate some text or HTML code and return it.
2358
2359 >>> def my_url_handler(url, content_type):
2360 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2361 ... return text
2362
2363 Start server thread on port 0.
2364 If you use port 0, the server will pick a random port number.
2365 You can then use serverthread.port to get the port number.
2366
2367 >>> port = 0
2368 >>> serverthread = pydoc._start_server(my_url_handler, port)
2369
2370 Check that the server is really started. If it is, open browser
2371 and get first page. Use serverthread.url as the starting page.
2372
2373 >>> if serverthread.serving:
2374 ... import webbrowser
2375
2376 The next two lines are commented out so a browser doesn't open if
2377 doctest is run on this module.
2378
2379 #... webbrowser.open(serverthread.url)
2380 #True
2381
2382 Let the server do its thing. We just need to monitor its status.
2383 Use time.sleep so the loop doesn't hog the CPU.
2384
2385 >>> starttime = time.time()
2386 >>> timeout = 1 #seconds
2387
2388 This is a short timeout for testing purposes.
2389
2390 >>> while serverthread.serving:
2391 ... time.sleep(.01)
2392 ... if serverthread.serving and time.time() - starttime > timeout:
2393 ... serverthread.stop()
2394 ... break
2395
2396 Print any errors that may have occurred.
2397
2398 >>> print(serverthread.error)
2399 None
2400 """
2401 import http.server
2402 import email.message
2403 import select
2404 import threading
2405
2406 class DocHandler(http.server.BaseHTTPRequestHandler):
2407
2408 def do_GET(self):
2409 """Process a request from an HTML browser.
2410
2411 The URL received is in self.path.
2412 Get an HTML page from self.urlhandler and send it.
2413 """
2414 if self.path.endswith('.css'):
2415 content_type = 'text/css'
2416 else:
2417 content_type = 'text/html'
2418 self.send_response(200)
Georg Brandld2f38572011-01-30 08:37:19 +00002419 self.send_header('Content-Type', '%s; charset=UTF-8' % content_type)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002420 self.end_headers()
2421 self.wfile.write(self.urlhandler(
2422 self.path, content_type).encode('utf-8'))
2423
2424 def log_message(self, *args):
2425 # Don't log messages.
2426 pass
2427
2428 class DocServer(http.server.HTTPServer):
2429
2430 def __init__(self, port, callback):
2431 self.host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
2432 self.address = ('', port)
2433 self.callback = callback
2434 self.base.__init__(self, self.address, self.handler)
2435 self.quit = False
2436
2437 def serve_until_quit(self):
2438 while not self.quit:
2439 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2440 if rd:
2441 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002442 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002443
2444 def server_activate(self):
2445 self.base.server_activate(self)
2446 if self.callback:
2447 self.callback(self)
2448
2449 class ServerThread(threading.Thread):
2450
2451 def __init__(self, urlhandler, port):
2452 self.urlhandler = urlhandler
2453 self.port = int(port)
2454 threading.Thread.__init__(self)
2455 self.serving = False
2456 self.error = None
2457
2458 def run(self):
2459 """Start the server."""
2460 try:
2461 DocServer.base = http.server.HTTPServer
2462 DocServer.handler = DocHandler
2463 DocHandler.MessageClass = email.message.Message
2464 DocHandler.urlhandler = staticmethod(self.urlhandler)
2465 docsvr = DocServer(self.port, self.ready)
2466 self.docserver = docsvr
2467 docsvr.serve_until_quit()
2468 except Exception as e:
2469 self.error = e
2470
2471 def ready(self, server):
2472 self.serving = True
2473 self.host = server.host
2474 self.port = server.server_port
2475 self.url = 'http://%s:%d/' % (self.host, self.port)
2476
2477 def stop(self):
2478 """Stop the server and this thread nicely"""
2479 self.docserver.quit = True
2480 self.serving = False
2481 self.url = None
2482
2483 thread = ServerThread(urlhandler, port)
2484 thread.start()
2485 # Wait until thread.serving is True to make sure we are
2486 # really up before returning.
2487 while not thread.error and not thread.serving:
2488 time.sleep(.01)
2489 return thread
2490
2491
2492def _url_handler(url, content_type="text/html"):
2493 """The pydoc url handler for use with the pydoc server.
2494
2495 If the content_type is 'text/css', the _pydoc.css style
2496 sheet is read and returned if it exits.
2497
2498 If the content_type is 'text/html', then the result of
2499 get_html_page(url) is returned.
2500 """
2501 class _HTMLDoc(HTMLDoc):
2502
2503 def page(self, title, contents):
2504 """Format an HTML page."""
2505 css_path = "pydoc_data/_pydoc.css"
2506 css_link = (
2507 '<link rel="stylesheet" type="text/css" href="%s">' %
2508 css_path)
2509 return '''\
2510<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Georg Brandld2f38572011-01-30 08:37:19 +00002511<html><head><title>Pydoc: %s</title>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002512<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Georg Brandld2f38572011-01-30 08:37:19 +00002513%s</head><body bgcolor="#f0f0f8">%s<div style="clear:both;padding-top:.5em;">%s</div>
2514</body></html>''' % (title, css_link, html_navbar(), contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002515
2516 def filelink(self, url, path):
2517 return '<a href="getfile?key=%s">%s</a>' % (url, path)
2518
2519
2520 html = _HTMLDoc()
2521
2522 def html_navbar():
Georg Brandld2f38572011-01-30 08:37:19 +00002523 version = html.escape("%s [%s, %s]" % (platform.python_version(),
2524 platform.python_build()[0],
2525 platform.python_compiler()))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002526 return """
2527 <div style='float:left'>
Georg Brandld2f38572011-01-30 08:37:19 +00002528 Python %s<br>%s
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002529 </div>
2530 <div style='float:right'>
2531 <div style='text-align:center'>
2532 <a href="index.html">Module Index</a>
2533 : <a href="topics.html">Topics</a>
2534 : <a href="keywords.html">Keywords</a>
2535 </div>
2536 <div>
Georg Brandld2f38572011-01-30 08:37:19 +00002537 <form action="get" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002538 <input type=text name=key size=15>
2539 <input type=submit value="Get">
Georg Brandld2f38572011-01-30 08:37:19 +00002540 </form>&nbsp;
2541 <form action="search" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002542 <input type=text name=key size=15>
2543 <input type=submit value="Search">
2544 </form>
2545 </div>
2546 </div>
Georg Brandld2f38572011-01-30 08:37:19 +00002547 """ % (version, html.escape(platform.platform(terse=True)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002548
2549 def html_index():
2550 """Module Index page."""
2551
2552 def bltinlink(name):
2553 return '<a href="%s.html">%s</a>' % (name, name)
2554
2555 heading = html.heading(
2556 '<big><big><strong>Index of Modules</strong></big></big>',
2557 '#ffffff', '#7799ee')
2558 names = [name for name in sys.builtin_module_names
2559 if name != '__main__']
2560 contents = html.multicolumn(names, bltinlink)
2561 contents = [heading, '<p>' + html.bigsection(
2562 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2563
2564 seen = {}
2565 for dir in sys.path:
2566 contents.append(html.index(dir, seen))
2567
2568 contents.append(
2569 '<p align=right><font color="#909090" face="helvetica,'
2570 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2571 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002572 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002573
2574 def html_search(key):
2575 """Search results page."""
2576 # scan for modules
2577 search_result = []
2578
2579 def callback(path, modname, desc):
2580 if modname[-9:] == '.__init__':
2581 modname = modname[:-9] + ' (package)'
2582 search_result.append((modname, desc and '- ' + desc))
2583
2584 with warnings.catch_warnings():
2585 warnings.filterwarnings('ignore') # ignore problems during import
2586 ModuleScanner().run(callback, key)
2587
2588 # format page
2589 def bltinlink(name):
2590 return '<a href="%s.html">%s</a>' % (name, name)
2591
2592 results = []
2593 heading = html.heading(
2594 '<big><big><strong>Search Results</strong></big></big>',
2595 '#ffffff', '#7799ee')
2596 for name, desc in search_result:
2597 results.append(bltinlink(name) + desc)
2598 contents = heading + html.bigsection(
2599 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002600 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002601
2602 def html_getfile(path):
2603 """Get and display a source file listing safely."""
Nick Coghlanecace282010-12-03 16:08:46 +00002604 path = path.replace('%20', ' ')
Victor Stinner91e08772011-07-05 14:30:41 +02002605 with tokenize.open(path) as fp:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002606 lines = html.escape(fp.read())
2607 body = '<pre>%s</pre>' % lines
2608 heading = html.heading(
2609 '<big><big><strong>File Listing</strong></big></big>',
2610 '#ffffff', '#7799ee')
2611 contents = heading + html.bigsection(
2612 'File: %s' % path, '#ffffff', '#ee77aa', body)
Nick Coghlanecace282010-12-03 16:08:46 +00002613 return 'getfile %s' % path, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002614
2615 def html_topics():
2616 """Index of topic texts available."""
2617
2618 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002619 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002620
2621 heading = html.heading(
2622 '<big><big><strong>INDEX</strong></big></big>',
2623 '#ffffff', '#7799ee')
2624 names = sorted(Helper.topics.keys())
2625
2626 contents = html.multicolumn(names, bltinlink)
2627 contents = heading + html.bigsection(
2628 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002629 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002630
2631 def html_keywords():
2632 """Index of keywords."""
2633 heading = html.heading(
2634 '<big><big><strong>INDEX</strong></big></big>',
2635 '#ffffff', '#7799ee')
2636 names = sorted(Helper.keywords.keys())
2637
2638 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002639 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002640
2641 contents = html.multicolumn(names, bltinlink)
2642 contents = heading + html.bigsection(
2643 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002644 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002645
2646 def html_topicpage(topic):
2647 """Topic or keyword help page."""
2648 buf = io.StringIO()
2649 htmlhelp = Helper(buf, buf)
2650 contents, xrefs = htmlhelp._gettopic(topic)
2651 if topic in htmlhelp.keywords:
2652 title = 'KEYWORD'
2653 else:
2654 title = 'TOPIC'
2655 heading = html.heading(
2656 '<big><big><strong>%s</strong></big></big>' % title,
2657 '#ffffff', '#7799ee')
Georg Brandld2f38572011-01-30 08:37:19 +00002658 contents = '<pre>%s</pre>' % html.markup(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002659 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
Georg Brandld2f38572011-01-30 08:37:19 +00002660 if xrefs:
2661 xrefs = sorted(xrefs.split())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002662
Georg Brandld2f38572011-01-30 08:37:19 +00002663 def bltinlink(name):
2664 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002665
Georg Brandld2f38572011-01-30 08:37:19 +00002666 xrefs = html.multicolumn(xrefs, bltinlink)
2667 xrefs = html.section('Related help topics: ',
2668 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002669 return ('%s %s' % (title, topic),
2670 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002671
Georg Brandld2f38572011-01-30 08:37:19 +00002672 def html_getobj(url):
2673 obj = locate(url, forceload=1)
2674 if obj is None and url != 'None':
2675 raise ValueError('could not find object')
2676 title = describe(obj)
2677 content = html.document(obj, url)
2678 return title, content
2679
2680 def html_error(url, exc):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002681 heading = html.heading(
2682 '<big><big><strong>Error</strong></big></big>',
Georg Brandld2f38572011-01-30 08:37:19 +00002683 '#ffffff', '#7799ee')
2684 contents = '<br>'.join(html.escape(line) for line in
2685 format_exception_only(type(exc), exc))
2686 contents = heading + html.bigsection(url, '#ffffff', '#bb0000',
2687 contents)
2688 return "Error - %s" % url, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002689
2690 def get_html_page(url):
2691 """Generate an HTML page for url."""
Georg Brandld2f38572011-01-30 08:37:19 +00002692 complete_url = url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002693 if url.endswith('.html'):
2694 url = url[:-5]
Georg Brandld2f38572011-01-30 08:37:19 +00002695 try:
2696 if url in ("", "index"):
2697 title, content = html_index()
2698 elif url == "topics":
2699 title, content = html_topics()
2700 elif url == "keywords":
2701 title, content = html_keywords()
2702 elif '=' in url:
2703 op, _, url = url.partition('=')
2704 if op == "search?key":
2705 title, content = html_search(url)
2706 elif op == "getfile?key":
2707 title, content = html_getfile(url)
2708 elif op == "topic?key":
2709 # try topics first, then objects.
2710 try:
2711 title, content = html_topicpage(url)
2712 except ValueError:
2713 title, content = html_getobj(url)
2714 elif op == "get?key":
2715 # try objects first, then topics.
2716 if url in ("", "index"):
2717 title, content = html_index()
2718 else:
2719 try:
2720 title, content = html_getobj(url)
2721 except ValueError:
2722 title, content = html_topicpage(url)
2723 else:
2724 raise ValueError('bad pydoc url')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002725 else:
Georg Brandld2f38572011-01-30 08:37:19 +00002726 title, content = html_getobj(url)
2727 except Exception as exc:
2728 # Catch any errors and display them in an error page.
2729 title, content = html_error(complete_url, exc)
2730 return html.page(title, content)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002731
2732 if url.startswith('/'):
2733 url = url[1:]
2734 if content_type == 'text/css':
2735 path_here = os.path.dirname(os.path.realpath(__file__))
Georg Brandld2f38572011-01-30 08:37:19 +00002736 css_path = os.path.join(path_here, url)
2737 with open(css_path) as fp:
2738 return ''.join(fp.readlines())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002739 elif content_type == 'text/html':
2740 return get_html_page(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002741 # Errors outside the url handler are caught by the server.
2742 raise TypeError('unknown content type %r for url %s' % (content_type, url))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002743
2744
2745def browse(port=0, *, open_browser=True):
2746 """Start the enhanced pydoc Web server and open a Web browser.
2747
2748 Use port '0' to start the server on an arbitrary port.
2749 Set open_browser to False to suppress opening a browser.
2750 """
2751 import webbrowser
2752 serverthread = _start_server(_url_handler, port)
2753 if serverthread.error:
2754 print(serverthread.error)
2755 return
2756 if serverthread.serving:
2757 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2758 if open_browser:
2759 webbrowser.open(serverthread.url)
2760 try:
2761 print('Server ready at', serverthread.url)
2762 print(server_help_msg)
2763 while serverthread.serving:
2764 cmd = input('server> ')
2765 cmd = cmd.lower()
2766 if cmd == 'q':
2767 break
2768 elif cmd == 'b':
2769 webbrowser.open(serverthread.url)
2770 else:
2771 print(server_help_msg)
2772 except (KeyboardInterrupt, EOFError):
2773 print()
2774 finally:
2775 if serverthread.serving:
2776 serverthread.stop()
2777 print('Server stopped')
2778
2779
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002780# -------------------------------------------------- command-line interface
2781
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002782def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002783 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002784
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002785def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002786 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002787 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002788 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002789
Nick Coghlan106274b2009-11-15 23:04:33 +00002790 # Scripts don't get the current directory in their path by default
2791 # unless they are run with the '-m' switch
2792 if '' not in sys.path:
2793 scriptdir = os.path.dirname(sys.argv[0])
2794 if scriptdir in sys.path:
2795 sys.path.remove(scriptdir)
2796 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002797
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002798 try:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002799 opts, args = getopt.getopt(sys.argv[1:], 'bgk:p:w')
2800 writing = False
2801 start_server = False
2802 open_browser = False
2803 port = None
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002804 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002805 if opt == '-g':
2806 gui()
2807 return
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002808 if opt == '-b':
2809 start_server = True
2810 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002811 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002812 apropos(val)
2813 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002814 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002815 start_server = True
2816 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002817 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002818 writing = True
2819
2820 if start_server == True:
2821 if port == None:
2822 port = 0
2823 browse(port, open_browser=open_browser)
2824 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002825
2826 if not args: raise BadUsage
2827 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002828 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002829 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002830 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002831 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002832 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002833 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002834 if writing:
2835 if ispath(arg) and os.path.isdir(arg):
2836 writedocs(arg)
2837 else:
2838 writedoc(arg)
2839 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002840 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002841 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002842 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002843
2844 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002845 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002846 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002847
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002848{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002849 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002850 Python keyword, topic, function, module, or package, or a dotted
2851 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002852 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002853 Python source file to document. If name is 'keywords', 'topics',
2854 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002855
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002856{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002857 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002858
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002859{cmd} -p <port>
2860 Start an HTTP server on the given port on the local machine. Port
2861 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002862
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002863{cmd} -b
2864 Start an HTTP server on an arbitrary unused port and open a Web browser
2865 to interactively browse documentation. The -p option can be used with
2866 the -b option to explicitly specify the server port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002867
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002868{cmd} -g
2869 Deprecated.
2870
2871{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002872 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002873 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002874 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002875""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002876
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002877if __name__ == '__main__':
2878 cli()