blob: fa02edaffcabdc5d320ae1980782aa88013da813 [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):
R David Murray9929bc52013-03-19 02:31:06 -0400140 return (inspect.isfunction(obj) or
141 inspect.ismethod(obj) or
142 inspect.isbuiltin(obj) or
143 inspect.ismethoddescriptor(obj))
Tim Peters536d2262001-09-20 05:13:38 +0000144
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000145def allmethods(cl):
146 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000147 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000148 methods[key] = 1
149 for base in cl.__bases__:
150 methods.update(allmethods(base)) # all your base are belong to us
151 for key in methods.keys():
152 methods[key] = getattr(cl, key)
153 return methods
154
Tim Petersfa26f7c2001-09-24 08:05:11 +0000155def _split_list(s, predicate):
156 """Split sequence s via predicate, and return pair ([true], [false]).
157
158 The return value is a 2-tuple of lists,
159 ([x for x in s if predicate(x)],
160 [x for x in s if not predicate(x)])
161 """
162
Tim Peters28355492001-09-23 21:29:55 +0000163 yes = []
164 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000165 for x in s:
166 if predicate(x):
167 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000168 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000169 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000170 return yes, no
171
Raymond Hettinger1103d052011-03-25 14:15:24 -0700172def visiblename(name, all=None, obj=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000173 """Decide whether to show documentation on a variable."""
174 # Certain special names are redundant.
Benjamin Peterson41181742008-07-02 20:22:54 +0000175 _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__',
Barry Warsaw28a691b2010-04-17 00:19:56 +0000176 '__module__', '__name__', '__slots__', '__package__',
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000177 '__cached__', '__author__', '__credits__', '__date__',
178 '__version__')
Benjamin Peterson41181742008-07-02 20:22:54 +0000179 if name in _hidden_names: return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000180 # Private names are hidden, but special names are displayed.
181 if name.startswith('__') and name.endswith('__'): return 1
Raymond Hettinger1103d052011-03-25 14:15:24 -0700182 # Namedtuples have public fields and methods with a single leading underscore
183 if name.startswith('_') and hasattr(obj, '_fields'):
184 return True
Skip Montanaroa5616d22004-06-11 04:46:12 +0000185 if all is not None:
186 # only document that which the programmer exported in __all__
187 return name in all
188 else:
189 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000190
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000191def classify_class_attrs(object):
192 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000193 results = []
194 for (name, kind, cls, value) in inspect.classify_class_attrs(object):
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000195 if inspect.isdatadescriptor(value):
196 kind = 'data descriptor'
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000197 results.append((name, kind, cls, value))
198 return results
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000199
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000200# ----------------------------------------------------- module manipulation
201
202def ispackage(path):
203 """Guess whether a path refers to a package directory."""
204 if os.path.isdir(path):
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000205 for ext in ('.py', '.pyc', '.pyo'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000206 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000207 return True
208 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000209
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000210def source_synopsis(file):
211 line = file.readline()
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000212 while line[:1] == '#' or not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000213 line = file.readline()
214 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000215 line = line.strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000216 if line[:4] == 'r"""': line = line[1:]
217 if line[:3] == '"""':
218 line = line[3:]
219 if line[-1:] == '\\': line = line[:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000220 while not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000221 line = file.readline()
222 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000223 result = line.split('"""')[0].strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000224 else: result = None
225 return result
226
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000227def synopsis(filename, cache={}):
228 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000229 mtime = os.stat(filename).st_mtime
Charles-François Natali27c4e882011-07-27 19:40:02 +0200230 lastupdate, result = cache.get(filename, (None, None))
231 if lastupdate is None or lastupdate < mtime:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000232 info = inspect.getmoduleinfo(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000233 try:
Victor Stinnere6c910e2011-06-30 15:55:43 +0200234 file = tokenize.open(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000235 except IOError:
236 # module can't be opened, so skip it
237 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000238 if info and 'b' in info[2]: # binary modules have to be imported
239 try: module = imp.load_module('__temp__', file, filename, info[1:])
240 except: return None
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000241 result = (module.__doc__ or '').splitlines()[0]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000242 del sys.modules['__temp__']
243 else: # text modules can be directly examined
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000244 result = source_synopsis(file)
245 file.close()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000246 cache[filename] = (mtime, result)
247 return result
248
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000249class ErrorDuringImport(Exception):
250 """Errors that occurred while trying to import something to document it."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000251 def __init__(self, filename, exc_info):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000252 self.filename = filename
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000253 self.exc, self.value, self.tb = exc_info
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000254
255 def __str__(self):
Guido van Rossuma01a8b62007-05-27 09:20:14 +0000256 exc = self.exc.__name__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000257 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000258
259def importfile(path):
260 """Import a Python source file or compiled file given its path."""
261 magic = imp.get_magic()
Victor Stinnere975af62011-07-04 02:08:50 +0200262 with open(path, 'rb') as file:
263 if file.read(len(magic)) == magic:
264 kind = imp.PY_COMPILED
265 else:
266 kind = imp.PY_SOURCE
267 file.seek(0)
268 filename = os.path.basename(path)
269 name, ext = os.path.splitext(filename)
270 try:
271 module = imp.load_module(name, file, path, (ext, 'r', kind))
272 except:
273 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000274 return module
275
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000276def safeimport(path, forceload=0, cache={}):
277 """Import a module; handle errors; return None if the module isn't found.
278
279 If the module *is* found but an exception occurs, it's wrapped in an
280 ErrorDuringImport exception and reraised. Unlike __import__, if a
281 package path is specified, the module at the end of the path is returned,
282 not the package at the beginning. If the optional 'forceload' argument
283 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000284 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000285 # If forceload is 1 and the module has been previously loaded from
286 # disk, we always have to reload the module. Checking the file's
287 # mtime isn't good enough (e.g. the module could contain a class
288 # that inherits from another module that has changed).
289 if forceload and path in sys.modules:
290 if path not in sys.builtin_module_names:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000291 # Remove the module from sys.modules and re-import to try
292 # and avoid problems with partially loaded modules.
293 # Also remove any submodules because they won't appear
294 # in the newly loaded module's namespace if they're already
295 # in sys.modules.
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000296 subs = [m for m in sys.modules if m.startswith(path + '.')]
297 for key in [path] + subs:
298 # Prevent garbage collection.
299 cache[key] = sys.modules[key]
300 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000301 module = __import__(path)
302 except:
303 # Did the error occur before or after the module was found?
304 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000305 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000306 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000307 raise ErrorDuringImport(sys.modules[path].__file__, info)
308 elif exc is SyntaxError:
309 # A SyntaxError occurred before we could execute the module.
310 raise ErrorDuringImport(value.filename, info)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000311 elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport':
Benjamin Peterson0289b152009-06-28 17:22:03 +0000312 # The import error occurred directly in this function,
313 # which means there is no such module in the path.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000314 return None
315 else:
316 # Some other error occurred during the importing process.
317 raise ErrorDuringImport(path, sys.exc_info())
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000318 for part in path.split('.')[1:]:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000319 try: module = getattr(module, part)
320 except AttributeError: return None
321 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000322
323# ---------------------------------------------------- formatter base class
324
325class Doc:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000326
327 PYTHONDOCS = os.environ.get("PYTHONDOCS",
328 "http://docs.python.org/%d.%d/library"
329 % sys.version_info[:2])
330
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000331 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000332 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000333 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000334 # 'try' clause is to attempt to handle the possibility that inspect
335 # identifies something in a way that pydoc itself has issues handling;
336 # think 'super' and how it is a descriptor (which raises the exception
337 # by lacking a __name__ attribute) and an instance.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000338 if inspect.isgetsetdescriptor(object): return self.docdata(*args)
339 if inspect.ismemberdescriptor(object): return self.docdata(*args)
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000340 try:
341 if inspect.ismodule(object): return self.docmodule(*args)
342 if inspect.isclass(object): return self.docclass(*args)
343 if inspect.isroutine(object): return self.docroutine(*args)
344 except AttributeError:
345 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000346 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000347 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000348
349 def fail(self, object, name=None, *args):
350 """Raise an exception for unimplemented types."""
351 message = "don't know how to document object%s of type %s" % (
352 name and ' ' + repr(name), type(object).__name__)
Collin Winterce36ad82007-08-30 01:19:48 +0000353 raise TypeError(message)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000354
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000355 docmodule = docclass = docroutine = docother = docproperty = docdata = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000356
Skip Montanaro4997a692003-09-10 16:47:51 +0000357 def getdocloc(self, object):
358 """Return the location of module docs or None"""
359
360 try:
361 file = inspect.getabsfile(object)
362 except TypeError:
363 file = '(built-in)'
364
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000365 docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
366
Skip Montanaro4997a692003-09-10 16:47:51 +0000367 basedir = os.path.join(sys.exec_prefix, "lib",
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000368 "python%d.%d" % sys.version_info[:2])
Skip Montanaro4997a692003-09-10 16:47:51 +0000369 if (isinstance(object, type(os)) and
370 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
371 'marshal', 'posix', 'signal', 'sys',
Georg Brandl2067bfd2008-05-25 13:05:15 +0000372 '_thread', 'zipimport') or
Skip Montanaro4997a692003-09-10 16:47:51 +0000373 (file.startswith(basedir) and
Brian Curtin49c284c2010-03-31 03:19:28 +0000374 not file.startswith(os.path.join(basedir, 'site-packages')))) and
Brian Curtinedef05b2010-04-01 04:05:25 +0000375 object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
Skip Montanaro4997a692003-09-10 16:47:51 +0000376 if docloc.startswith("http://"):
Georg Brandl86def6c2008-01-21 20:36:10 +0000377 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__)
Skip Montanaro4997a692003-09-10 16:47:51 +0000378 else:
Georg Brandl86def6c2008-01-21 20:36:10 +0000379 docloc = os.path.join(docloc, object.__name__ + ".html")
Skip Montanaro4997a692003-09-10 16:47:51 +0000380 else:
381 docloc = None
382 return docloc
383
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000384# -------------------------------------------- HTML documentation generator
385
386class HTMLRepr(Repr):
387 """Class for safely making an HTML representation of a Python object."""
388 def __init__(self):
389 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000390 self.maxlist = self.maxtuple = 20
391 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000392 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000393
394 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000395 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000396
397 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000398 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000399
400 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000401 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000402 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000403 if hasattr(self, methodname):
404 return getattr(self, methodname)(x, level)
405 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000406
407 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000408 test = cram(x, self.maxstring)
409 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000410 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000411 # Backslashes are only literal in the string and are never
412 # needed to make any special characters, so show a raw string.
413 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000414 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000415 r'<font color="#c040c0">\1</font>',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000416 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000417
Skip Montanarodf708782002-03-07 22:58:02 +0000418 repr_str = repr_string
419
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000420 def repr_instance(self, x, level):
421 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000422 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000423 except:
424 return self.escape('<%s instance>' % x.__class__.__name__)
425
426 repr_unicode = repr_string
427
428class HTMLDoc(Doc):
429 """Formatter class for HTML documentation."""
430
431 # ------------------------------------------- HTML formatting utilities
432
433 _repr_instance = HTMLRepr()
434 repr = _repr_instance.repr
435 escape = _repr_instance.escape
436
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000437 def page(self, title, contents):
438 """Format an HTML page."""
Georg Brandl388faac2009-04-10 08:31:48 +0000439 return '''\
Georg Brandle6066942009-04-10 08:28:28 +0000440<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000441<html><head><title>Python: %s</title>
Georg Brandl388faac2009-04-10 08:31:48 +0000442<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000443</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000444%s
445</body></html>''' % (title, contents)
446
447 def heading(self, title, fgcol, bgcol, extras=''):
448 """Format a page heading."""
449 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000450<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000451<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000452<td valign=bottom>&nbsp;<br>
453<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000454><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000455><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000456 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
457
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000458 def section(self, title, fgcol, bgcol, contents, width=6,
459 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000460 """Format a section with a heading."""
461 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000462 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000463 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000464<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000465<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000466<td colspan=3 valign=bottom>&nbsp;<br>
467<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000468 ''' % (bgcol, fgcol, title)
469 if prelude:
470 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000471<tr bgcolor="%s"><td rowspan=2>%s</td>
472<td colspan=2>%s</td></tr>
473<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
474 else:
475 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000476<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000477
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000478 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000479
480 def bigsection(self, title, *args):
481 """Format a section with a big heading."""
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000482 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000483 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000484
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000485 def preformat(self, text):
486 """Format literal preformatted text."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000487 text = self.escape(text.expandtabs())
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000488 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
489 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000490
491 def multicolumn(self, list, format, cols=4):
492 """Format a list of items into a multi-column list."""
493 result = ''
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000494 rows = (len(list)+cols-1)//cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000495 for col in range(cols):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000496 result = result + '<td width="%d%%" valign=top>' % (100//cols)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000497 for i in range(rows*col, rows*col+rows):
498 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000499 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000500 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000501 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000502
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000503 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000504
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000505 def namelink(self, name, *dicts):
506 """Make a link for an identifier, given name-to-URL mappings."""
507 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000508 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000509 return '<a href="%s">%s</a>' % (dict[name], name)
510 return name
511
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000512 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000513 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000514 name, module = object.__name__, sys.modules.get(object.__module__)
515 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000516 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000517 module.__name__, name, classname(object, modname))
518 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000519
520 def modulelink(self, object):
521 """Make a link for a module."""
522 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
523
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000524 def modpkglink(self, modpkginfo):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000525 """Make a link for a module or package to display in an index."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000526 name, path, ispackage, shadowed = modpkginfo
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000527 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000528 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000529 if path:
530 url = '%s.%s.html' % (path, name)
531 else:
532 url = '%s.html' % name
533 if ispackage:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000534 text = '<strong>%s</strong>&nbsp;(package)' % name
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000535 else:
536 text = name
537 return '<a href="%s">%s</a>' % (url, text)
538
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000539 def filelink(self, url, path):
540 """Make a link to source file."""
541 return '<a href="file:%s">%s</a>' % (url, path)
542
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000543 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
544 """Mark up some plain text, given a context of symbols to look for.
545 Each context dictionary maps object names to anchor names."""
546 escape = escape or self.escape
547 results = []
548 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000549 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
550 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000551 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000552 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000553 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000554 match = pattern.search(text, here)
555 if not match: break
556 start, end = match.span()
557 results.append(escape(text[here:start]))
558
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000559 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000560 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000561 url = escape(all).replace('"', '&quot;')
562 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000563 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000564 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
565 results.append('<a href="%s">%s</a>' % (url, escape(all)))
566 elif pep:
Christian Heimes2202f872008-02-06 14:31:34 +0000567 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000568 results.append('<a href="%s">%s</a>' % (url, escape(all)))
569 elif text[end:end+1] == '(':
570 results.append(self.namelink(name, methods, funcs, classes))
571 elif selfdot:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000572 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000573 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000574 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000575 here = end
576 results.append(escape(text[here:]))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000577 return ''.join(results)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000578
579 # ---------------------------------------------- type-specific routines
580
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000581 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000582 """Produce HTML for a class tree as given by inspect.getclasstree()."""
583 result = ''
584 for entry in tree:
585 if type(entry) is type(()):
586 c, bases = entry
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000587 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000588 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000589 if bases and bases != (parent,):
590 parents = []
591 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000592 parents.append(self.classlink(base, modname))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000593 result = result + '(' + ', '.join(parents) + ')'
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000594 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000595 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000596 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000597 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000598 return '<dl>\n%s</dl>\n' % result
599
Tim Peters8dd7ade2001-10-18 19:56:17 +0000600 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000601 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000602 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000603 try:
604 all = object.__all__
605 except AttributeError:
606 all = None
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000607 parts = name.split('.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000608 links = []
609 for i in range(len(parts)-1):
610 links.append(
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000611 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000612 ('.'.join(parts[:i+1]), parts[i]))
613 linkedname = '.'.join(links + parts[-1:])
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000614 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000615 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000616 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000617 url = path
618 if sys.platform == 'win32':
619 import nturl2path
620 url = nturl2path.pathname2url(path)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000621 filelink = self.filelink(url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000622 except TypeError:
623 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000624 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000625 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000626 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000627 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000628 version = version[11:-1].strip()
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000629 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000630 if hasattr(object, '__date__'):
631 info.append(self.escape(str(object.__date__)))
632 if info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000633 head = head + ' (%s)' % ', '.join(info)
Skip Montanaro4997a692003-09-10 16:47:51 +0000634 docloc = self.getdocloc(object)
635 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000636 docloc = '<br><a href="%(docloc)s">Module Reference</a>' % locals()
Skip Montanaro4997a692003-09-10 16:47:51 +0000637 else:
638 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000639 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000640 head, '#ffffff', '#7799ee',
641 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000642
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000643 modules = inspect.getmembers(object, inspect.ismodule)
644
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000645 classes, cdict = [], {}
646 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000647 # if __all__ exists, believe it. Otherwise use old heuristic.
648 if (all is not None or
649 (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700650 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000651 classes.append((key, value))
652 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000653 for key, value in classes:
654 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000655 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000656 module = sys.modules.get(modname)
657 if modname != name and module and hasattr(module, key):
658 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000659 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000660 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000661 funcs, fdict = [], {}
662 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000663 # if __all__ exists, believe it. Otherwise use old heuristic.
664 if (all is not None or
665 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700666 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000667 funcs.append((key, value))
668 fdict[key] = '#-' + key
669 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000670 data = []
671 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700672 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000673 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000674
675 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
676 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000677 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000678
679 if hasattr(object, '__path__'):
680 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000681 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
682 modpkgs.append((modname, name, ispkg, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000683 modpkgs.sort()
684 contents = self.multicolumn(modpkgs, self.modpkglink)
685 result = result + self.bigsection(
686 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000687 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000688 contents = self.multicolumn(
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000689 modules, lambda t: self.modulelink(t[1]))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000690 result = result + self.bigsection(
Christian Heimes7131fd92008-02-19 14:21:46 +0000691 'Modules', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000692
693 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000694 classlist = [value for (key, value) in classes]
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000695 contents = [
696 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000697 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000698 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000699 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000700 'Classes', '#ffffff', '#ee77aa', ' '.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000701 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000702 contents = []
703 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000704 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000705 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000706 'Functions', '#ffffff', '#eeaa77', ' '.join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000707 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000708 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000709 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000710 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000711 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000712 'Data', '#ffffff', '#55aa55', '<br>\n'.join(contents))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000713 if hasattr(object, '__author__'):
714 contents = self.markup(str(object.__author__), self.preformat)
715 result = result + self.bigsection(
716 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000717 if hasattr(object, '__credits__'):
718 contents = self.markup(str(object.__credits__), self.preformat)
719 result = result + self.bigsection(
720 'Credits', '#ffffff', '#7799ee', contents)
721
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000722 return result
723
Tim Peters8dd7ade2001-10-18 19:56:17 +0000724 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
725 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000726 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000727 realname = object.__name__
728 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000729 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000730
Tim Petersb47879b2001-09-24 04:47:19 +0000731 contents = []
732 push = contents.append
733
Tim Petersfa26f7c2001-09-24 08:05:11 +0000734 # Cute little class to pump out a horizontal rule between sections.
735 class HorizontalRule:
736 def __init__(self):
737 self.needone = 0
738 def maybe(self):
739 if self.needone:
740 push('<hr>\n')
741 self.needone = 1
742 hr = HorizontalRule()
743
Tim Petersc86f6ca2001-09-26 21:31:51 +0000744 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000745 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000746 if len(mro) > 2:
747 hr.maybe()
748 push('<dl><dt>Method resolution order:</dt>\n')
749 for base in mro:
750 push('<dd>%s</dd>\n' % self.classlink(base,
751 object.__module__))
752 push('</dl>\n')
753
Tim Petersb47879b2001-09-24 04:47:19 +0000754 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000755 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000756 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000757 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000758 push(msg)
759 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100760 try:
761 value = getattr(object, name)
762 except Exception:
763 # Some descriptors may meet a failure in their __get__.
764 # (bug #1785)
765 push(self._docdescriptor(name, value, mod))
766 else:
767 push(self.document(value, name, mod,
768 funcs, classes, mdict, object))
Tim Petersb47879b2001-09-24 04:47:19 +0000769 push('\n')
770 return attrs
771
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000772 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000773 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000774 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000775 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000776 push(msg)
777 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000778 push(self._docdescriptor(name, value, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000779 return attrs
780
Tim Petersfa26f7c2001-09-24 08:05:11 +0000781 def spilldata(msg, attrs, predicate):
782 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000783 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000784 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000785 push(msg)
786 for name, kind, homecls, value in ok:
787 base = self.docother(getattr(object, name), name, mod)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200788 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000789 doc = getattr(value, "__doc__", None)
790 else:
791 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000792 if doc is None:
793 push('<dl><dt>%s</dl>\n' % base)
794 else:
795 doc = self.markup(getdoc(value), self.preformat,
796 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000797 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000798 push('<dl><dt>%s%s</dl>\n' % (base, doc))
799 push('\n')
800 return attrs
801
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000802 attrs = [(name, kind, cls, value)
803 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -0700804 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000805
Tim Petersb47879b2001-09-24 04:47:19 +0000806 mdict = {}
807 for key, kind, homecls, value in attrs:
808 mdict[key] = anchor = '#' + name + '-' + key
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100809 try:
810 value = getattr(object, name)
811 except Exception:
812 # Some descriptors may meet a failure in their __get__.
813 # (bug #1785)
814 pass
Tim Petersb47879b2001-09-24 04:47:19 +0000815 try:
816 # The value may not be hashable (e.g., a data attr with
817 # a dict or list value).
818 mdict[value] = anchor
819 except TypeError:
820 pass
821
Tim Petersfa26f7c2001-09-24 08:05:11 +0000822 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000823 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000824 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000825 else:
826 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000827 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
828
Georg Brandl1a3284e2007-12-02 09:40:06 +0000829 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000830 attrs = inherited
831 continue
832 elif thisclass is object:
833 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000834 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000835 tag = 'inherited from %s' % self.classlink(thisclass,
836 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000837 tag += ':<br>\n'
838
839 # Sort attrs by name.
Raymond Hettingerd4cb56d2008-01-30 02:55:10 +0000840 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000841
842 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000843 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000844 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000845 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000846 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000847 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000848 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000849 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
850 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000851 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000852 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000853 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000854 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000855
856 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000857
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000858 if name == realname:
859 title = '<a name="%s">class <strong>%s</strong></a>' % (
860 name, realname)
861 else:
862 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
863 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000864 if bases:
865 parents = []
866 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000867 parents.append(self.classlink(base, object.__module__))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000868 title = title + '(%s)' % ', '.join(parents)
Tim Peters2306d242001-09-25 03:18:32 +0000869 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000870 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000871
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000872 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000873
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000874 def formatvalue(self, object):
875 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000876 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000877
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000878 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000879 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000880 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000881 realname = object.__name__
882 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000883 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000884 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000885 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000886 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +0000887 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000888 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000889 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000890 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000891 else:
Christian Heimesff737952007-11-27 10:40:20 +0000892 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000893 note = ' method of %s instance' % self.classlink(
Christian Heimesff737952007-11-27 10:40:20 +0000894 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000895 else:
896 note = ' unbound %s method' % self.classlink(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +0000897 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000898
899 if name == realname:
900 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
901 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000902 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000903 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000904 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000905 cl.__name__ + '-' + realname, realname)
906 skipdocs = 1
907 else:
908 reallink = realname
909 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
910 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000911 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +0000912 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann = \
913 inspect.getfullargspec(object)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000914 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +0000915 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann,
916 formatvalue=self.formatvalue,
917 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000918 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000919 title = '<strong>%s</strong> <em>lambda</em> ' % name
Guido van Rossum2e65f892007-02-28 22:03:49 +0000920 # XXX lambda's won't usually have func_annotations['return']
921 # since the syntax doesn't support but it is possible.
922 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000923 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000924 else:
925 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000926
Tim Peters2306d242001-09-25 03:18:32 +0000927 decl = title + argspec + (note and self.grey(
928 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000929
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000930 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000931 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000932 else:
933 doc = self.markup(
934 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000935 doc = doc and '<dd><tt>%s</tt></dd>' % doc
936 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000937
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000938 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000939 results = []
940 push = results.append
941
942 if name:
943 push('<dl><dt><strong>%s</strong></dt>\n' % name)
944 if value.__doc__ is not None:
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +0000945 doc = self.markup(getdoc(value), self.preformat)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000946 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000947 push('</dl>\n')
948
949 return ''.join(results)
950
951 def docproperty(self, object, name=None, mod=None, cl=None):
952 """Produce html documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000953 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000954
Tim Peters8dd7ade2001-10-18 19:56:17 +0000955 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000956 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000957 lhs = name and '<strong>%s</strong> = ' % name or ''
958 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000959
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000960 def docdata(self, object, name=None, mod=None, cl=None):
961 """Produce html documentation for a data descriptor."""
962 return self._docdescriptor(name, object, mod)
963
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000964 def index(self, dir, shadowed=None):
965 """Generate an HTML index for a directory of modules."""
966 modpkgs = []
967 if shadowed is None: shadowed = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000968 for importer, name, ispkg in pkgutil.iter_modules([dir]):
969 modpkgs.append((name, '', ispkg, name in shadowed))
970 shadowed[name] = 1
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000971
972 modpkgs.sort()
973 contents = self.multicolumn(modpkgs, self.modpkglink)
974 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
975
976# -------------------------------------------- text documentation generator
977
978class TextRepr(Repr):
979 """Class for safely making a text representation of a Python object."""
980 def __init__(self):
981 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000982 self.maxlist = self.maxtuple = 20
983 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000984 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000985
986 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000987 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000988 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000989 if hasattr(self, methodname):
990 return getattr(self, methodname)(x, level)
991 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000992
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000993 def repr_string(self, x, level):
994 test = cram(x, self.maxstring)
995 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000996 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000997 # Backslashes are only literal in the string and are never
998 # needed to make any special characters, so show a raw string.
999 return 'r' + testrepr[0] + test + testrepr[0]
1000 return testrepr
1001
Skip Montanarodf708782002-03-07 22:58:02 +00001002 repr_str = repr_string
1003
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001004 def repr_instance(self, x, level):
1005 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001006 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001007 except:
1008 return '<%s instance>' % x.__class__.__name__
1009
1010class TextDoc(Doc):
1011 """Formatter class for text documentation."""
1012
1013 # ------------------------------------------- text formatting utilities
1014
1015 _repr_instance = TextRepr()
1016 repr = _repr_instance.repr
1017
1018 def bold(self, text):
1019 """Format a string in bold by overstriking."""
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001020 return ''.join(ch + '\b' + ch for ch in text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001021
1022 def indent(self, text, prefix=' '):
1023 """Indent text by prepending a given prefix to each line."""
1024 if not text: return ''
Collin Winter72e110c2007-07-17 00:27:30 +00001025 lines = [prefix + line for line in text.split('\n')]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001026 if lines: lines[-1] = lines[-1].rstrip()
1027 return '\n'.join(lines)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001028
1029 def section(self, title, contents):
1030 """Format a section with a given heading."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001031 clean_contents = self.indent(contents).rstrip()
1032 return self.bold(title) + '\n' + clean_contents + '\n\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001033
1034 # ---------------------------------------------- type-specific routines
1035
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001036 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001037 """Render in text a class tree as returned by inspect.getclasstree()."""
1038 result = ''
1039 for entry in tree:
1040 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001041 c, bases = entry
1042 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001043 if bases and bases != (parent,):
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001044 parents = (classname(c, modname) for c in bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001045 result = result + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001046 result = result + '\n'
1047 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001048 result = result + self.formattree(
1049 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001050 return result
1051
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001052 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001053 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001054 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001055 synop, desc = splitdoc(getdoc(object))
1056 result = self.section('NAME', name + (synop and ' - ' + synop))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001057 all = getattr(object, '__all__', None)
Skip Montanaro4997a692003-09-10 16:47:51 +00001058 docloc = self.getdocloc(object)
1059 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001060 result = result + self.section('MODULE REFERENCE', docloc + """
1061
Éric Araujo647ef8c2011-09-11 00:43:20 +02001062The following documentation is automatically generated from the Python
1063source files. It may be incomplete, incorrect or include features that
1064are considered implementation detail and may vary between Python
1065implementations. When in doubt, consult the module reference at the
1066location listed above.
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001067""")
Skip Montanaro4997a692003-09-10 16:47:51 +00001068
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001069 if desc:
1070 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001071
1072 classes = []
1073 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001074 # if __all__ exists, believe it. Otherwise use old heuristic.
1075 if (all is not None
1076 or (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001077 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001078 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001079 funcs = []
1080 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001081 # if __all__ exists, believe it. Otherwise use old heuristic.
1082 if (all is not None or
1083 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001084 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001085 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001086 data = []
1087 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001088 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001089 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001090
Christian Heimes1af737c2008-01-23 08:24:23 +00001091 modpkgs = []
1092 modpkgs_names = set()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001093 if hasattr(object, '__path__'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001094 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
Christian Heimes1af737c2008-01-23 08:24:23 +00001095 modpkgs_names.add(modname)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001096 if ispkg:
1097 modpkgs.append(modname + ' (package)')
1098 else:
1099 modpkgs.append(modname)
1100
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001101 modpkgs.sort()
1102 result = result + self.section(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001103 'PACKAGE CONTENTS', '\n'.join(modpkgs))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001104
Christian Heimes1af737c2008-01-23 08:24:23 +00001105 # Detect submodules as sometimes created by C extensions
1106 submodules = []
1107 for key, value in inspect.getmembers(object, inspect.ismodule):
1108 if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1109 submodules.append(key)
1110 if submodules:
1111 submodules.sort()
1112 result = result + self.section(
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001113 'SUBMODULES', '\n'.join(submodules))
Christian Heimes1af737c2008-01-23 08:24:23 +00001114
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001115 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001116 classlist = [value for key, value in classes]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001117 contents = [self.formattree(
1118 inspect.getclasstree(classlist, 1), name)]
1119 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001120 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001121 result = result + self.section('CLASSES', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001122
1123 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001124 contents = []
1125 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001126 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001127 result = result + self.section('FUNCTIONS', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001128
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001129 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001130 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001131 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001132 contents.append(self.docother(value, key, name, maxlen=70))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001133 result = result + self.section('DATA', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001134
1135 if hasattr(object, '__version__'):
1136 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001137 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001138 version = version[11:-1].strip()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001139 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001140 if hasattr(object, '__date__'):
1141 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001142 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001143 result = result + self.section('AUTHOR', str(object.__author__))
1144 if hasattr(object, '__credits__'):
1145 result = result + self.section('CREDITS', str(object.__credits__))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001146 try:
1147 file = inspect.getabsfile(object)
1148 except TypeError:
1149 file = '(built-in)'
1150 result = result + self.section('FILE', file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001151 return result
1152
Georg Brandl9bd45f992010-12-03 09:58:38 +00001153 def docclass(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001154 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001155 realname = object.__name__
1156 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001157 bases = object.__bases__
1158
Tim Petersc86f6ca2001-09-26 21:31:51 +00001159 def makename(c, m=object.__module__):
1160 return classname(c, m)
1161
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001162 if name == realname:
1163 title = 'class ' + self.bold(realname)
1164 else:
1165 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001166 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001167 parents = map(makename, bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001168 title = title + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001169
1170 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001171 contents = doc and [doc + '\n'] or []
1172 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001173
Tim Petersc86f6ca2001-09-26 21:31:51 +00001174 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001175 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001176 if len(mro) > 2:
1177 push("Method resolution order:")
1178 for base in mro:
1179 push(' ' + makename(base))
1180 push('')
1181
Tim Petersf4aad8e2001-09-24 22:40:47 +00001182 # Cute little class to pump out a horizontal rule between sections.
1183 class HorizontalRule:
1184 def __init__(self):
1185 self.needone = 0
1186 def maybe(self):
1187 if self.needone:
1188 push('-' * 70)
1189 self.needone = 1
1190 hr = HorizontalRule()
1191
Tim Peters28355492001-09-23 21:29:55 +00001192 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001193 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001194 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001195 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001196 push(msg)
1197 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +01001198 try:
1199 value = getattr(object, name)
1200 except Exception:
1201 # Some descriptors may meet a failure in their __get__.
1202 # (bug #1785)
1203 push(self._docdescriptor(name, value, mod))
1204 else:
1205 push(self.document(value,
1206 name, mod, object))
Tim Peters28355492001-09-23 21:29:55 +00001207 return attrs
1208
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001209 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001210 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001211 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001212 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001213 push(msg)
1214 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001215 push(self._docdescriptor(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001216 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001217
Tim Petersfa26f7c2001-09-24 08:05:11 +00001218 def spilldata(msg, attrs, predicate):
1219 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001220 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001221 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001222 push(msg)
1223 for name, kind, homecls, value in ok:
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001224 if callable(value) or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001225 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001226 else:
1227 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001228 push(self.docother(getattr(object, name),
Georg Brandl8b813db2005-10-01 16:32:31 +00001229 name, mod, maxlen=70, doc=doc) + '\n')
Tim Peters28355492001-09-23 21:29:55 +00001230 return attrs
1231
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001232 attrs = [(name, kind, cls, value)
1233 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -07001234 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001235
Tim Petersfa26f7c2001-09-24 08:05:11 +00001236 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001237 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001238 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001239 else:
1240 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001241 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1242
Georg Brandl1a3284e2007-12-02 09:40:06 +00001243 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001244 attrs = inherited
1245 continue
1246 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001247 tag = "defined here"
1248 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001249 tag = "inherited from %s" % classname(thisclass,
1250 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001251
1252 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001253 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001254
1255 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001256 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001257 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001258 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001259 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001260 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001261 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001262 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1263 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001264 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1265 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001266 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001267 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001268
1269 contents = '\n'.join(contents)
1270 if not contents:
1271 return title + '\n'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001272 return title + '\n' + self.indent(contents.rstrip(), ' | ') + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001273
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001274 def formatvalue(self, object):
1275 """Format an argument default value as text."""
1276 return '=' + self.repr(object)
1277
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001278 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001279 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001280 realname = object.__name__
1281 name = name or realname
1282 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001283 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001284 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +00001285 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001286 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001287 if imclass is not cl:
1288 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001289 else:
Christian Heimesff737952007-11-27 10:40:20 +00001290 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001291 note = ' method of %s instance' % classname(
Christian Heimesff737952007-11-27 10:40:20 +00001292 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001293 else:
1294 note = ' unbound %s method' % classname(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +00001295 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001296
1297 if name == realname:
1298 title = self.bold(realname)
1299 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001300 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001301 cl.__dict__[realname] is object):
1302 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001303 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001304 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +00001305 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann = \
1306 inspect.getfullargspec(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001307 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +00001308 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann,
1309 formatvalue=self.formatvalue,
1310 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001311 if realname == '<lambda>':
Georg Brandl501dd0d2006-02-17 09:45:40 +00001312 title = self.bold(name) + ' lambda '
Guido van Rossum2e65f892007-02-28 22:03:49 +00001313 # XXX lambda's won't usually have func_annotations['return']
1314 # since the syntax doesn't support but it is possible.
1315 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001316 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001317 else:
1318 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001319 decl = title + argspec + note
1320
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001321 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001322 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001323 else:
1324 doc = getdoc(object) or ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001325 return decl + '\n' + (doc and self.indent(doc).rstrip() + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001326
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001327 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001328 results = []
1329 push = results.append
1330
1331 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001332 push(self.bold(name))
1333 push('\n')
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001334 doc = getdoc(value) or ''
1335 if doc:
1336 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001337 push('\n')
1338 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001339
1340 def docproperty(self, object, name=None, mod=None, cl=None):
1341 """Produce text documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001342 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001343
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001344 def docdata(self, object, name=None, mod=None, cl=None):
1345 """Produce text documentation for a data descriptor."""
1346 return self._docdescriptor(name, object, mod)
1347
Georg Brandl8b813db2005-10-01 16:32:31 +00001348 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001349 """Produce text documentation for a data object."""
1350 repr = self.repr(object)
1351 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001352 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001353 chop = maxlen - len(line)
1354 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001355 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001356 if doc is not None:
1357 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001358 return line
1359
Georg Brandld80d5f42010-12-03 07:47:22 +00001360class _PlainTextDoc(TextDoc):
1361 """Subclass of TextDoc which overrides string styling"""
1362 def bold(self, text):
1363 return text
1364
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001365# --------------------------------------------------------- user interfaces
1366
1367def pager(text):
1368 """The first time this is called, determine what kind of pager to use."""
1369 global pager
1370 pager = getpager()
1371 pager(text)
1372
1373def getpager():
1374 """Decide what method to use for paging through text."""
Guido van Rossuma01a8b62007-05-27 09:20:14 +00001375 if not hasattr(sys.stdout, "isatty"):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001376 return plainpager
1377 if not sys.stdin.isatty() or not sys.stdout.isatty():
1378 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001379 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001380 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001381 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001382 elif os.environ.get('TERM') in ('dumb', 'emacs'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001383 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001384 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001385 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001386 if os.environ.get('TERM') in ('dumb', 'emacs'):
1387 return plainpager
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001388 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001389 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001390 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001391 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001392
1393 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001394 (fd, filename) = tempfile.mkstemp()
1395 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001396 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001397 if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001398 return lambda text: pipepager(text, 'more')
1399 else:
1400 return ttypager
1401 finally:
1402 os.unlink(filename)
1403
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001404def plain(text):
1405 """Remove boldface formatting from text."""
1406 return re.sub('.\b', '', text)
1407
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001408def pipepager(text, cmd):
1409 """Page through text by feeding it to another program."""
1410 pipe = os.popen(cmd, 'w')
1411 try:
1412 pipe.write(text)
1413 pipe.close()
1414 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001415 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001416
1417def tempfilepager(text, cmd):
1418 """Page through text by invoking a program on a temporary file."""
1419 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001420 filename = tempfile.mktemp()
1421 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001422 file.write(text)
1423 file.close()
1424 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001425 os.system(cmd + ' "' + filename + '"')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001426 finally:
1427 os.unlink(filename)
1428
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001429def ttypager(text):
1430 """Page through text on a text terminal."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001431 lines = plain(text).split('\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001432 try:
1433 import tty
1434 fd = sys.stdin.fileno()
1435 old = tty.tcgetattr(fd)
1436 tty.setcbreak(fd)
1437 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001438 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001439 tty = None
1440 getchar = lambda: sys.stdin.readline()[:-1][:1]
1441
1442 try:
1443 r = inc = os.environ.get('LINES', 25) - 1
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001444 sys.stdout.write('\n'.join(lines[:inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001445 while lines[r:]:
1446 sys.stdout.write('-- more --')
1447 sys.stdout.flush()
1448 c = getchar()
1449
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001450 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001451 sys.stdout.write('\r \r')
1452 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001453 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001454 sys.stdout.write('\r \r' + lines[r] + '\n')
1455 r = r + 1
1456 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001457 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001458 r = r - inc - inc
1459 if r < 0: r = 0
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001460 sys.stdout.write('\n' + '\n'.join(lines[r:r+inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001461 r = r + inc
1462
1463 finally:
1464 if tty:
1465 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1466
1467def plainpager(text):
1468 """Simply print unformatted text. This is the ultimate fallback."""
1469 sys.stdout.write(plain(text))
1470
1471def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001472 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001473 if inspect.ismodule(thing):
1474 if thing.__name__ in sys.builtin_module_names:
1475 return 'built-in module ' + thing.__name__
1476 if hasattr(thing, '__path__'):
1477 return 'package ' + thing.__name__
1478 else:
1479 return 'module ' + thing.__name__
1480 if inspect.isbuiltin(thing):
1481 return 'built-in function ' + thing.__name__
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001482 if inspect.isgetsetdescriptor(thing):
1483 return 'getset descriptor %s.%s.%s' % (
1484 thing.__objclass__.__module__, thing.__objclass__.__name__,
1485 thing.__name__)
1486 if inspect.ismemberdescriptor(thing):
1487 return 'member descriptor %s.%s.%s' % (
1488 thing.__objclass__.__module__, thing.__objclass__.__name__,
1489 thing.__name__)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001490 if inspect.isclass(thing):
1491 return 'class ' + thing.__name__
1492 if inspect.isfunction(thing):
1493 return 'function ' + thing.__name__
1494 if inspect.ismethod(thing):
1495 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001496 return type(thing).__name__
1497
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001498def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001499 """Locate an object by name or dotted path, importing as necessary."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001500 parts = [part for part in path.split('.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001501 module, n = None, 0
1502 while n < len(parts):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001503 nextmodule = safeimport('.'.join(parts[:n+1]), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001504 if nextmodule: module, n = nextmodule, n + 1
1505 else: break
1506 if module:
1507 object = module
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001508 else:
Éric Araujoe64e51b2011-07-29 17:03:55 +02001509 object = builtins
1510 for part in parts[n:]:
1511 try:
1512 object = getattr(object, part)
1513 except AttributeError:
1514 return None
1515 return object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001516
1517# --------------------------------------- interactive interpreter interface
1518
1519text = TextDoc()
Georg Brandld80d5f42010-12-03 07:47:22 +00001520plaintext = _PlainTextDoc()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001521html = HTMLDoc()
1522
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001523def resolve(thing, forceload=0):
1524 """Given an object or a path to an object, get the object and its name."""
1525 if isinstance(thing, str):
1526 object = locate(thing, forceload)
1527 if not object:
Collin Winterce36ad82007-08-30 01:19:48 +00001528 raise ImportError('no Python documentation found for %r' % thing)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001529 return object, thing
1530 else:
R David Murrayc43125a2012-04-23 13:23:57 -04001531 name = getattr(thing, '__name__', None)
1532 return thing, name if isinstance(name, str) else None
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001533
Georg Brandld80d5f42010-12-03 07:47:22 +00001534def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
1535 renderer=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001536 """Render text documentation, given an object or a path to an object."""
Georg Brandld80d5f42010-12-03 07:47:22 +00001537 if renderer is None:
1538 renderer = text
Guido van Rossumd8faa362007-04-27 19:54:29 +00001539 object, name = resolve(thing, forceload)
1540 desc = describe(object)
1541 module = inspect.getmodule(object)
1542 if name and '.' in name:
1543 desc += ' in ' + name[:name.rfind('.')]
1544 elif module and module is not object:
1545 desc += ' in module ' + module.__name__
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001546
1547 if not (inspect.ismodule(object) or
Guido van Rossumd8faa362007-04-27 19:54:29 +00001548 inspect.isclass(object) or
1549 inspect.isroutine(object) or
1550 inspect.isgetsetdescriptor(object) or
1551 inspect.ismemberdescriptor(object) or
1552 isinstance(object, property)):
1553 # If the passed object is a piece of data or an instance,
1554 # document its available methods instead of its value.
1555 object = type(object)
1556 desc += ' object'
Georg Brandld80d5f42010-12-03 07:47:22 +00001557 return title % desc + '\n\n' + renderer.document(object, name)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001558
Georg Brandld80d5f42010-12-03 07:47:22 +00001559def doc(thing, title='Python Library Documentation: %s', forceload=0,
1560 output=None):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001561 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001562 try:
Georg Brandld80d5f42010-12-03 07:47:22 +00001563 if output is None:
1564 pager(render_doc(thing, title, forceload))
1565 else:
1566 output.write(render_doc(thing, title, forceload, plaintext))
Guido van Rossumb940e112007-01-10 16:19:56 +00001567 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001568 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001569
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001570def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001571 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001572 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001573 object, name = resolve(thing, forceload)
1574 page = html.page(describe(object), html.document(object, name))
Georg Brandl388faac2009-04-10 08:31:48 +00001575 file = open(name + '.html', 'w', encoding='utf-8')
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001576 file.write(page)
1577 file.close()
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001578 print('wrote', name + '.html')
Guido van Rossumb940e112007-01-10 16:19:56 +00001579 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001580 print(value)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001581
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001582def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001583 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001584 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001585 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1586 writedoc(modname)
1587 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001588
1589class Helper:
Georg Brandl6b38daa2008-06-01 21:05:17 +00001590
1591 # These dictionaries map a topic name to either an alias, or a tuple
1592 # (label, seealso-items). The "label" is the label of the corresponding
1593 # section in the .rst file under Doc/ and an index into the dictionary
Georg Brandl5617db82009-04-27 16:28:57 +00001594 # in pydoc_data/topics.py.
Georg Brandl6b38daa2008-06-01 21:05:17 +00001595 #
1596 # CAUTION: if you change one of these dictionaries, be sure to adapt the
1597 # list of needed labels in Doc/tools/sphinxext/pyspecific.py and
Georg Brandl5617db82009-04-27 16:28:57 +00001598 # regenerate the pydoc_data/topics.py file by running
Georg Brandl6b38daa2008-06-01 21:05:17 +00001599 # make pydoc-topics
1600 # in Doc/ and copying the output file into the Lib/ directory.
1601
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001602 keywords = {
Ezio Melottib185a042011-04-28 07:42:55 +03001603 'False': '',
1604 'None': '',
1605 'True': '',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001606 'and': 'BOOLEAN',
Guido van Rossumd8faa362007-04-27 19:54:29 +00001607 'as': 'with',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001608 'assert': ('assert', ''),
1609 'break': ('break', 'while for'),
1610 'class': ('class', 'CLASSES SPECIALMETHODS'),
1611 'continue': ('continue', 'while for'),
1612 'def': ('function', ''),
1613 'del': ('del', 'BASICMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001614 'elif': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001615 'else': ('else', 'while for'),
Georg Brandl0d855392008-08-30 19:53:05 +00001616 'except': 'try',
1617 'finally': 'try',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001618 'for': ('for', 'break continue while'),
Georg Brandl0d855392008-08-30 19:53:05 +00001619 'from': 'import',
Georg Brandl74abf6f2010-11-20 19:54:36 +00001620 'global': ('global', 'nonlocal NAMESPACES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001621 'if': ('if', 'TRUTHVALUE'),
1622 'import': ('import', 'MODULES'),
Georg Brandl395ed242009-09-04 08:07:32 +00001623 'in': ('in', 'SEQUENCEMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001624 'is': 'COMPARISON',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001625 'lambda': ('lambda', 'FUNCTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001626 'nonlocal': ('nonlocal', 'global NAMESPACES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001627 'not': 'BOOLEAN',
1628 'or': 'BOOLEAN',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001629 'pass': ('pass', ''),
1630 'raise': ('raise', 'EXCEPTIONS'),
1631 'return': ('return', 'FUNCTIONS'),
1632 'try': ('try', 'EXCEPTIONS'),
1633 'while': ('while', 'break continue if TRUTHVALUE'),
1634 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1635 'yield': ('yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001636 }
Georg Brandldb7b6b92009-01-01 15:53:14 +00001637 # Either add symbols to this dictionary or to the symbols dictionary
1638 # directly: Whichever is easier. They are merged later.
1639 _symbols_inverse = {
1640 'STRINGS' : ("'", "'''", "r'", "b'", '"""', '"', 'r"', 'b"'),
1641 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1642 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1643 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1644 'UNARY' : ('-', '~'),
1645 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1646 '^=', '<<=', '>>=', '**=', '//='),
1647 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1648 'COMPLEX' : ('j', 'J')
1649 }
1650 symbols = {
1651 '%': 'OPERATORS FORMATTING',
1652 '**': 'POWER',
1653 ',': 'TUPLES LISTS FUNCTIONS',
1654 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1655 '...': 'ELLIPSIS',
1656 ':': 'SLICINGS DICTIONARYLITERALS',
1657 '@': 'def class',
1658 '\\': 'STRINGS',
1659 '_': 'PRIVATENAMES',
1660 '__': 'PRIVATENAMES SPECIALMETHODS',
1661 '`': 'BACKQUOTES',
1662 '(': 'TUPLES FUNCTIONS CALLS',
1663 ')': 'TUPLES FUNCTIONS CALLS',
1664 '[': 'LISTS SUBSCRIPTS SLICINGS',
1665 ']': 'LISTS SUBSCRIPTS SLICINGS'
1666 }
1667 for topic, symbols_ in _symbols_inverse.items():
1668 for symbol in symbols_:
1669 topics = symbols.get(symbol, topic)
1670 if topic not in topics:
1671 topics = topics + ' ' + topic
1672 symbols[symbol] = topics
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001673
1674 topics = {
Georg Brandl6b38daa2008-06-01 21:05:17 +00001675 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1676 'FUNCTIONS CLASSES MODULES FILES inspect'),
1677 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
1678 'FORMATTING TYPES'),
1679 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1680 'FORMATTING': ('formatstrings', 'OPERATORS'),
1681 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1682 'FORMATTING TYPES'),
1683 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1684 'INTEGER': ('integers', 'int range'),
1685 'FLOAT': ('floating', 'float math'),
1686 'COMPLEX': ('imaginary', 'complex cmath'),
1687 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001688 'MAPPINGS': 'DICTIONARIES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001689 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1690 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1691 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1692 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001693 'FRAMEOBJECTS': 'TYPES',
1694 'TRACEBACKS': 'TYPES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001695 'NONE': ('bltin-null-object', ''),
1696 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
1697 'FILES': ('bltin-file-objects', ''),
1698 'SPECIALATTRIBUTES': ('specialattrs', ''),
1699 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1700 'MODULES': ('typesmodules', 'import'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001701 'PACKAGES': 'import',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001702 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1703 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1704 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1705 'LISTS DICTIONARIES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001706 'OPERATORS': 'EXPRESSIONS',
1707 'PRECEDENCE': 'EXPRESSIONS',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001708 'OBJECTS': ('objects', 'TYPES'),
1709 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
Georg Brandl395ed242009-09-04 08:07:32 +00001710 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
1711 'NUMBERMETHODS CLASSES'),
Mark Dickinsona56c4672009-01-27 18:17:45 +00001712 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001713 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1714 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001715 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
Georg Brandl6b38daa2008-06-01 21:05:17 +00001716 'SPECIALMETHODS'),
1717 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1718 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1719 'SPECIALMETHODS'),
1720 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001721 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001722 'DYNAMICFEATURES': ('dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001723 'SCOPING': 'NAMESPACES',
1724 'FRAMES': 'NAMESPACES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001725 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1726 'CONVERSIONS': ('conversions', ''),
1727 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1728 'SPECIALIDENTIFIERS': ('id-classes', ''),
1729 'PRIVATENAMES': ('atom-identifiers', ''),
1730 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
1731 'LISTLITERALS DICTIONARYLITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001732 'TUPLES': 'SEQUENCES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001733 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1734 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1735 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1736 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1737 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1738 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001739 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
1740 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001741 'CALLS': ('calls', 'EXPRESSIONS'),
1742 'POWER': ('power', 'EXPRESSIONS'),
1743 'UNARY': ('unary', 'EXPRESSIONS'),
1744 'BINARY': ('binary', 'EXPRESSIONS'),
1745 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1746 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1747 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1748 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001749 'ASSERTION': 'assert',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001750 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1751 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001752 'DELETION': 'del',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001753 'RETURNING': 'return',
1754 'IMPORTING': 'import',
1755 'CONDITIONAL': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001756 'LOOPING': ('compound', 'for while break continue'),
1757 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1758 'DEBUGGING': ('debugger', 'pdb'),
1759 'CONTEXTMANAGERS': ('context-managers', 'with'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001760 }
1761
Georg Brandl78aa3962010-07-31 21:51:48 +00001762 def __init__(self, input=None, output=None):
1763 self._input = input
1764 self._output = output
1765
Georg Brandl76ae3972010-08-01 06:32:55 +00001766 input = property(lambda self: self._input or sys.stdin)
1767 output = property(lambda self: self._output or sys.stdout)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001768
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001769 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001770 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001771 self()
1772 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001773 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001774
Alexander Belopolsky2e733c92010-07-04 17:00:20 +00001775 _GoInteractive = object()
1776 def __call__(self, request=_GoInteractive):
1777 if request is not self._GoInteractive:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001778 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001779 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001780 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001781 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001782 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001783You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001784If you want to ask for help on a particular object directly from the
1785interpreter, you can type "help(object)". Executing "help('string')"
1786has the same effect as typing a particular string at the help> prompt.
1787''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001788
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001789 def interact(self):
1790 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001791 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001792 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001793 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001794 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001795 except (KeyboardInterrupt, EOFError):
1796 break
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001797 request = replace(request, '"', '', "'", '').strip()
1798 if request.lower() in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001799 self.help(request)
1800
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001801 def getline(self, prompt):
Guido van Rossum7c086c02008-01-02 03:52:38 +00001802 """Read one line, using input() when appropriate."""
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001803 if self.input is sys.stdin:
Guido van Rossum7c086c02008-01-02 03:52:38 +00001804 return input(prompt)
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001805 else:
1806 self.output.write(prompt)
1807 self.output.flush()
1808 return self.input.readline()
1809
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001810 def help(self, request):
1811 if type(request) is type(''):
R. David Murray1f1b9d32009-05-27 20:56:59 +00001812 request = request.strip()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001813 if request == 'help': self.intro()
1814 elif request == 'keywords': self.listkeywords()
Georg Brandldb7b6b92009-01-01 15:53:14 +00001815 elif request == 'symbols': self.listsymbols()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001816 elif request == 'topics': self.listtopics()
1817 elif request == 'modules': self.listmodules()
1818 elif request[:8] == 'modules ':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001819 self.listmodules(request.split()[1])
Georg Brandldb7b6b92009-01-01 15:53:14 +00001820 elif request in self.symbols: self.showsymbol(request)
Ezio Melottib185a042011-04-28 07:42:55 +03001821 elif request in ['True', 'False', 'None']:
1822 # special case these keywords since they are objects too
1823 doc(eval(request), 'Help on %s:')
Raymond Hettinger54f02222002-06-01 14:18:47 +00001824 elif request in self.keywords: self.showtopic(request)
1825 elif request in self.topics: self.showtopic(request)
Georg Brandld80d5f42010-12-03 07:47:22 +00001826 elif request: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001827 elif isinstance(request, Helper): self()
Georg Brandld80d5f42010-12-03 07:47:22 +00001828 else: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001829 self.output.write('\n')
1830
1831 def intro(self):
1832 self.output.write('''
1833Welcome to Python %s! This is the online help utility.
1834
1835If this is your first time using Python, you should definitely check out
R David Murrayde0f6292012-03-31 12:06:35 -04001836the tutorial on the Internet at http://docs.python.org/%s/tutorial/.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001837
1838Enter the name of any module, keyword, or topic to get help on writing
1839Python programs and using Python modules. To quit this help utility and
1840return to the interpreter, just type "quit".
1841
1842To get a list of available modules, keywords, or topics, type "modules",
1843"keywords", or "topics". Each module also comes with a one-line summary
1844of what it does; to list the modules whose summaries contain a given word
1845such as "spam", type "modules spam".
R David Murrayde0f6292012-03-31 12:06:35 -04001846''' % tuple([sys.version[:3]]*2))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001847
1848 def list(self, items, columns=4, width=80):
Guido van Rossum486364b2007-06-30 05:01:58 +00001849 items = list(sorted(items))
1850 colw = width // columns
1851 rows = (len(items) + columns - 1) // columns
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001852 for row in range(rows):
1853 for col in range(columns):
1854 i = col * rows + row
1855 if i < len(items):
1856 self.output.write(items[i])
1857 if col < columns - 1:
Guido van Rossum486364b2007-06-30 05:01:58 +00001858 self.output.write(' ' + ' ' * (colw - 1 - len(items[i])))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001859 self.output.write('\n')
1860
1861 def listkeywords(self):
1862 self.output.write('''
1863Here is a list of the Python keywords. Enter any keyword to get more help.
1864
1865''')
1866 self.list(self.keywords.keys())
1867
Georg Brandldb7b6b92009-01-01 15:53:14 +00001868 def listsymbols(self):
1869 self.output.write('''
1870Here is a list of the punctuation symbols which Python assigns special meaning
1871to. Enter any symbol to get more help.
1872
1873''')
1874 self.list(self.symbols.keys())
1875
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001876 def listtopics(self):
1877 self.output.write('''
1878Here is a list of available topics. Enter any topic name to get more help.
1879
1880''')
1881 self.list(self.topics.keys())
1882
Georg Brandldb7b6b92009-01-01 15:53:14 +00001883 def showtopic(self, topic, more_xrefs=''):
Georg Brandl6b38daa2008-06-01 21:05:17 +00001884 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001885 import pydoc_data.topics
Georg Brandl6b38daa2008-06-01 21:05:17 +00001886 except ImportError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001887 self.output.write('''
Georg Brandl6b38daa2008-06-01 21:05:17 +00001888Sorry, topic and keyword documentation is not available because the
Georg Brandl5617db82009-04-27 16:28:57 +00001889module "pydoc_data.topics" could not be found.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001890''')
1891 return
1892 target = self.topics.get(topic, self.keywords.get(topic))
1893 if not target:
1894 self.output.write('no documentation found for %s\n' % repr(topic))
1895 return
1896 if type(target) is type(''):
Georg Brandldb7b6b92009-01-01 15:53:14 +00001897 return self.showtopic(target, more_xrefs)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001898
Georg Brandl6b38daa2008-06-01 21:05:17 +00001899 label, xrefs = target
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001900 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001901 doc = pydoc_data.topics.topics[label]
Georg Brandl6b38daa2008-06-01 21:05:17 +00001902 except KeyError:
1903 self.output.write('no documentation found for %s\n' % repr(topic))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001904 return
Georg Brandl6b38daa2008-06-01 21:05:17 +00001905 pager(doc.strip() + '\n')
Georg Brandldb7b6b92009-01-01 15:53:14 +00001906 if more_xrefs:
1907 xrefs = (xrefs or '') + ' ' + more_xrefs
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001908 if xrefs:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001909 import formatter
Guido van Rossum34d19282007-08-09 01:03:29 +00001910 buffer = io.StringIO()
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001911 formatter.DumbWriter(buffer).send_flowing_data(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001912 'Related help topics: ' + ', '.join(xrefs.split()) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001913 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001914
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001915 def _gettopic(self, topic, more_xrefs=''):
1916 """Return unbuffered tuple of (topic, xrefs).
1917
Georg Brandld2f38572011-01-30 08:37:19 +00001918 If an error occurs here, the exception is caught and displayed by
1919 the url handler.
1920
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001921 This function duplicates the showtopic method but returns its
1922 result directly so it can be formatted for display in an html page.
1923 """
1924 try:
1925 import pydoc_data.topics
1926 except ImportError:
1927 return('''
1928Sorry, topic and keyword documentation is not available because the
1929module "pydoc_data.topics" could not be found.
1930''' , '')
1931 target = self.topics.get(topic, self.keywords.get(topic))
1932 if not target:
Georg Brandld2f38572011-01-30 08:37:19 +00001933 raise ValueError('could not find topic')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001934 if isinstance(target, str):
1935 return self._gettopic(target, more_xrefs)
1936 label, xrefs = target
Georg Brandld2f38572011-01-30 08:37:19 +00001937 doc = pydoc_data.topics.topics[label]
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001938 if more_xrefs:
1939 xrefs = (xrefs or '') + ' ' + more_xrefs
1940 return doc, xrefs
1941
Georg Brandldb7b6b92009-01-01 15:53:14 +00001942 def showsymbol(self, symbol):
1943 target = self.symbols[symbol]
1944 topic, _, xrefs = target.partition(' ')
1945 self.showtopic(topic, xrefs)
1946
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001947 def listmodules(self, key=''):
1948 if key:
1949 self.output.write('''
1950Here is a list of matching modules. Enter any module name to get more help.
1951
1952''')
1953 apropos(key)
1954 else:
1955 self.output.write('''
1956Please wait a moment while I gather a list of all available modules...
1957
1958''')
1959 modules = {}
1960 def callback(path, modname, desc, modules=modules):
1961 if modname and modname[-9:] == '.__init__':
1962 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001963 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001964 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001965 def onerror(modname):
1966 callback(None, modname, None)
1967 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001968 self.list(modules.keys())
1969 self.output.write('''
1970Enter any module name to get more help. Or, type "modules spam" to search
1971for modules whose descriptions contain the word "spam".
1972''')
1973
Georg Brandl78aa3962010-07-31 21:51:48 +00001974help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001975
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001976class Scanner:
1977 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001978 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001979 self.roots = roots[:]
1980 self.state = []
1981 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001982 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001983
1984 def next(self):
1985 if not self.state:
1986 if not self.roots:
1987 return None
1988 root = self.roots.pop(0)
1989 self.state = [(root, self.children(root))]
1990 node, children = self.state[-1]
1991 if not children:
1992 self.state.pop()
1993 return self.next()
1994 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001995 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001996 self.state.append((child, self.children(child)))
1997 return child
1998
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001999
2000class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002001 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002002
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002003 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002004 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002005 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002006 seen = {}
2007
2008 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002009 if modname != '__main__':
2010 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00002011 if key is None:
2012 callback(None, modname, '')
2013 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002014 name = __import__(modname).__doc__ or ''
2015 desc = name.split('\n')[0]
2016 name = modname + ' - ' + desc
2017 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002018 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002019
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002020 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002021 if self.quit:
2022 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002023
2024 # XXX Skipping this file is a workaround for a bug
2025 # that causes python to crash with a segfault.
2026 # http://bugs.python.org/issue9319
2027 #
2028 # TODO Remove this once the bug is fixed.
2029 if modname in {'test.badsyntax_pep3120', 'badsyntax_pep3120'}:
2030 continue
2031
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002032 if key is None:
2033 callback(None, modname, '')
2034 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002035 try:
2036 loader = importer.find_module(modname)
2037 except SyntaxError:
2038 # raised by tests for bad coding cookies or BOM
2039 continue
2040 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002041 try:
2042 source = loader.get_source(modname)
2043 except UnicodeDecodeError:
2044 if onerror:
2045 onerror(modname)
2046 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002047 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002048 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002049 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002050 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002051 path = None
2052 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002053 try:
2054 module = loader.load_module(modname)
2055 except ImportError:
2056 if onerror:
2057 onerror(modname)
2058 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002059 desc = (module.__doc__ or '').splitlines()[0]
2060 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002061 name = modname + ' - ' + desc
2062 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002063 callback(path, modname, desc)
2064
2065 if completer:
2066 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002067
2068def apropos(key):
2069 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002070 def callback(path, modname, desc):
2071 if modname[-9:] == '.__init__':
2072 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002073 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002074 def onerror(modname):
2075 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002076 with warnings.catch_warnings():
2077 warnings.filterwarnings('ignore') # ignore problems during import
2078 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002079
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002080# --------------------------------------------------- Web browser interface
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002081
Ka-Ping Yee66246962001-04-12 11:59:50 +00002082def serve(port, callback=None, completer=None):
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002083 import http.server, email.message, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002084
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002085 msg = 'the pydoc.serve() function is deprecated'
2086 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2087
Georg Brandl24420152008-05-26 16:32:26 +00002088 class DocHandler(http.server.BaseHTTPRequestHandler):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002089 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002090 try:
2091 self.send_response(200)
Georg Brandl825fc8b2008-01-19 20:44:32 +00002092 self.send_header('Content-Type', 'text/html; charset=UTF-8')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002093 self.end_headers()
Georg Brandl825fc8b2008-01-19 20:44:32 +00002094 self.wfile.write(html.page(title, contents).encode('utf-8'))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002095 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002096
2097 def do_GET(self):
2098 path = self.path
2099 if path[-5:] == '.html': path = path[:-5]
2100 if path[:1] == '/': path = path[1:]
2101 if path and path != '.':
2102 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002103 obj = locate(path, forceload=1)
Guido van Rossumb940e112007-01-10 16:19:56 +00002104 except ErrorDuringImport as value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002105 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002106 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002107 if obj:
2108 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002109 else:
2110 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002111'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002112 else:
2113 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002114'<big><big><strong>Python: Index of Modules</strong></big></big>',
2115'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002116 def bltinlink(name):
2117 return '<a href="%s.html">%s</a>' % (name, name)
Georg Brandl661b0a12008-01-27 18:16:00 +00002118 names = [x for x in sys.builtin_module_names if x != '__main__']
2119 contents = html.multicolumn(names, bltinlink)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002120 indices = ['<p>' + html.bigsection(
2121 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2122
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002123 seen = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002124 for dir in sys.path:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002125 indices.append(html.index(dir, seen))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002126 contents = heading + ' '.join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00002127<font color="#909090" face="helvetica, arial"><strong>
2128pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002129 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002130
2131 def log_message(self, *args): pass
2132
Georg Brandl24420152008-05-26 16:32:26 +00002133 class DocServer(http.server.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002134 def __init__(self, port, callback):
Ronald Oussoren94f25282010-05-05 19:11:21 +00002135 host = 'localhost'
Senthil Kumaran7ff59132010-08-18 19:32:21 +00002136 self.address = (host, port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00002137 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002138 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002139 self.base.__init__(self, self.address, self.handler)
2140
2141 def serve_until_quit(self):
2142 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002143 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002144 while not self.quit:
2145 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2146 if rd: self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002147 self.server_close()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002148
2149 def server_activate(self):
2150 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002151 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002152
Georg Brandl24420152008-05-26 16:32:26 +00002153 DocServer.base = http.server.HTTPServer
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002154 DocServer.handler = DocHandler
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002155 DocHandler.MessageClass = email.message.Message
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002156 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002157 try:
2158 DocServer(port, callback).serve_until_quit()
2159 except (KeyboardInterrupt, select.error):
2160 pass
2161 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002162 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002163
2164# ----------------------------------------------------- graphical interface
2165
2166def gui():
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002167 """Graphical interface (starts Web server and pops up a control window)."""
2168
2169 msg = ('the pydoc.gui() function and "pydoc -g" option are deprecated\n',
2170 'use "pydoc.browse() function and "pydoc -b" option instead.')
2171 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2172
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002173 class GUI:
2174 def __init__(self, window, port=7464):
2175 self.window = window
2176 self.server = None
2177 self.scanner = None
2178
Georg Brandl14fc4272008-05-17 18:39:55 +00002179 import tkinter
2180 self.server_frm = tkinter.Frame(window)
2181 self.title_lbl = tkinter.Label(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002182 text='Starting server...\n ')
Georg Brandl14fc4272008-05-17 18:39:55 +00002183 self.open_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002184 text='open browser', command=self.open, state='disabled')
Georg Brandl14fc4272008-05-17 18:39:55 +00002185 self.quit_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002186 text='quit serving', command=self.quit, state='disabled')
2187
Georg Brandl14fc4272008-05-17 18:39:55 +00002188 self.search_frm = tkinter.Frame(window)
2189 self.search_lbl = tkinter.Label(self.search_frm, text='Search for')
2190 self.search_ent = tkinter.Entry(self.search_frm)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002191 self.search_ent.bind('<Return>', self.search)
Georg Brandl14fc4272008-05-17 18:39:55 +00002192 self.stop_btn = tkinter.Button(self.search_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002193 text='stop', pady=0, command=self.stop, state='disabled')
2194 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002195 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002196 self.stop_btn.pack(side='right')
2197
2198 self.window.title('pydoc')
2199 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2200 self.title_lbl.pack(side='top', fill='x')
2201 self.open_btn.pack(side='left', fill='x', expand=1)
2202 self.quit_btn.pack(side='right', fill='x', expand=1)
2203 self.server_frm.pack(side='top', fill='x')
2204
2205 self.search_lbl.pack(side='left')
2206 self.search_ent.pack(side='right', fill='x', expand=1)
2207 self.search_frm.pack(side='top', fill='x')
2208 self.search_ent.focus_set()
2209
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002210 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Georg Brandl14fc4272008-05-17 18:39:55 +00002211 self.result_lst = tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002212 self.result_lst.bind('<Button-1>', self.select)
2213 self.result_lst.bind('<Double-Button-1>', self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002214 self.result_scr = tkinter.Scrollbar(window,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002215 orient='vertical', command=self.result_lst.yview)
2216 self.result_lst.config(yscrollcommand=self.result_scr.set)
2217
Georg Brandl14fc4272008-05-17 18:39:55 +00002218 self.result_frm = tkinter.Frame(window)
2219 self.goto_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002220 text='go to selected', command=self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002221 self.hide_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002222 text='hide results', command=self.hide)
2223 self.goto_btn.pack(side='left', fill='x', expand=1)
2224 self.hide_btn.pack(side='right', fill='x', expand=1)
2225
2226 self.window.update()
2227 self.minwidth = self.window.winfo_width()
2228 self.minheight = self.window.winfo_height()
2229 self.bigminheight = (self.server_frm.winfo_reqheight() +
2230 self.search_frm.winfo_reqheight() +
2231 self.result_lst.winfo_reqheight() +
2232 self.result_frm.winfo_reqheight())
2233 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2234 self.expanded = 0
2235 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2236 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002237 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002238
2239 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002240 threading.Thread(
2241 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002242
2243 def ready(self, server):
2244 self.server = server
2245 self.title_lbl.config(
2246 text='Python documentation server at\n' + server.url)
2247 self.open_btn.config(state='normal')
2248 self.quit_btn.config(state='normal')
2249
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002250 def open(self, event=None, url=None):
2251 url = url or self.server.url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002252 import webbrowser
2253 webbrowser.open(url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002254
2255 def quit(self, event=None):
2256 if self.server:
2257 self.server.quit = 1
2258 self.window.quit()
2259
2260 def search(self, event=None):
2261 key = self.search_ent.get()
2262 self.stop_btn.pack(side='right')
2263 self.stop_btn.config(state='normal')
2264 self.search_lbl.config(text='Searching for "%s"...' % key)
2265 self.search_ent.forget()
2266 self.search_lbl.pack(side='left')
2267 self.result_lst.delete(0, 'end')
2268 self.goto_btn.config(state='disabled')
2269 self.expand()
2270
2271 import threading
2272 if self.scanner:
2273 self.scanner.quit = 1
2274 self.scanner = ModuleScanner()
2275 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002276 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002277
2278 def update(self, path, modname, desc):
2279 if modname[-9:] == '.__init__':
2280 modname = modname[:-9] + ' (package)'
2281 self.result_lst.insert('end',
2282 modname + ' - ' + (desc or '(no description)'))
2283
2284 def stop(self, event=None):
2285 if self.scanner:
2286 self.scanner.quit = 1
2287 self.scanner = None
2288
2289 def done(self):
2290 self.scanner = None
2291 self.search_lbl.config(text='Search for')
2292 self.search_lbl.pack(side='left')
2293 self.search_ent.pack(side='right', fill='x', expand=1)
2294 if sys.platform != 'win32': self.stop_btn.forget()
2295 self.stop_btn.config(state='disabled')
2296
2297 def select(self, event=None):
2298 self.goto_btn.config(state='normal')
2299
2300 def goto(self, event=None):
2301 selection = self.result_lst.curselection()
2302 if selection:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002303 modname = self.result_lst.get(selection[0]).split()[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002304 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002305
2306 def collapse(self):
2307 if not self.expanded: return
2308 self.result_frm.forget()
2309 self.result_scr.forget()
2310 self.result_lst.forget()
2311 self.bigwidth = self.window.winfo_width()
2312 self.bigheight = self.window.winfo_height()
2313 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2314 self.window.wm_minsize(self.minwidth, self.minheight)
2315 self.expanded = 0
2316
2317 def expand(self):
2318 if self.expanded: return
2319 self.result_frm.pack(side='bottom', fill='x')
2320 self.result_scr.pack(side='right', fill='y')
2321 self.result_lst.pack(side='top', fill='both', expand=1)
2322 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2323 self.window.wm_minsize(self.minwidth, self.bigminheight)
2324 self.expanded = 1
2325
2326 def hide(self, event=None):
2327 self.stop()
2328 self.collapse()
2329
Georg Brandl14fc4272008-05-17 18:39:55 +00002330 import tkinter
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002331 try:
Georg Brandl14fc4272008-05-17 18:39:55 +00002332 root = tkinter.Tk()
Martin v. Löwise09bd932004-08-22 16:13:26 +00002333 # Tk will crash if pythonw.exe has an XP .manifest
2334 # file and the root has is not destroyed explicitly.
2335 # If the problem is ever fixed in Tk, the explicit
2336 # destroy can go.
2337 try:
2338 gui = GUI(root)
2339 root.mainloop()
2340 finally:
2341 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002342 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002343 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002344
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002345
2346# --------------------------------------- enhanced Web browser interface
2347
2348def _start_server(urlhandler, port):
2349 """Start an HTTP server thread on a specific port.
2350
2351 Start an HTML/text server thread, so HTML or text documents can be
2352 browsed dynamically and interactively with a Web browser. Example use:
2353
2354 >>> import time
2355 >>> import pydoc
2356
2357 Define a URL handler. To determine what the client is asking
2358 for, check the URL and content_type.
2359
2360 Then get or generate some text or HTML code and return it.
2361
2362 >>> def my_url_handler(url, content_type):
2363 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2364 ... return text
2365
2366 Start server thread on port 0.
2367 If you use port 0, the server will pick a random port number.
2368 You can then use serverthread.port to get the port number.
2369
2370 >>> port = 0
2371 >>> serverthread = pydoc._start_server(my_url_handler, port)
2372
2373 Check that the server is really started. If it is, open browser
2374 and get first page. Use serverthread.url as the starting page.
2375
2376 >>> if serverthread.serving:
2377 ... import webbrowser
2378
2379 The next two lines are commented out so a browser doesn't open if
2380 doctest is run on this module.
2381
2382 #... webbrowser.open(serverthread.url)
2383 #True
2384
2385 Let the server do its thing. We just need to monitor its status.
2386 Use time.sleep so the loop doesn't hog the CPU.
2387
2388 >>> starttime = time.time()
2389 >>> timeout = 1 #seconds
2390
2391 This is a short timeout for testing purposes.
2392
2393 >>> while serverthread.serving:
2394 ... time.sleep(.01)
2395 ... if serverthread.serving and time.time() - starttime > timeout:
2396 ... serverthread.stop()
2397 ... break
2398
2399 Print any errors that may have occurred.
2400
2401 >>> print(serverthread.error)
2402 None
2403 """
2404 import http.server
2405 import email.message
2406 import select
2407 import threading
2408
2409 class DocHandler(http.server.BaseHTTPRequestHandler):
2410
2411 def do_GET(self):
2412 """Process a request from an HTML browser.
2413
2414 The URL received is in self.path.
2415 Get an HTML page from self.urlhandler and send it.
2416 """
2417 if self.path.endswith('.css'):
2418 content_type = 'text/css'
2419 else:
2420 content_type = 'text/html'
2421 self.send_response(200)
Georg Brandld2f38572011-01-30 08:37:19 +00002422 self.send_header('Content-Type', '%s; charset=UTF-8' % content_type)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002423 self.end_headers()
2424 self.wfile.write(self.urlhandler(
2425 self.path, content_type).encode('utf-8'))
2426
2427 def log_message(self, *args):
2428 # Don't log messages.
2429 pass
2430
2431 class DocServer(http.server.HTTPServer):
2432
2433 def __init__(self, port, callback):
2434 self.host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
2435 self.address = ('', port)
2436 self.callback = callback
2437 self.base.__init__(self, self.address, self.handler)
2438 self.quit = False
2439
2440 def serve_until_quit(self):
2441 while not self.quit:
2442 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2443 if rd:
2444 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002445 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002446
2447 def server_activate(self):
2448 self.base.server_activate(self)
2449 if self.callback:
2450 self.callback(self)
2451
2452 class ServerThread(threading.Thread):
2453
2454 def __init__(self, urlhandler, port):
2455 self.urlhandler = urlhandler
2456 self.port = int(port)
2457 threading.Thread.__init__(self)
2458 self.serving = False
2459 self.error = None
2460
2461 def run(self):
2462 """Start the server."""
2463 try:
2464 DocServer.base = http.server.HTTPServer
2465 DocServer.handler = DocHandler
2466 DocHandler.MessageClass = email.message.Message
2467 DocHandler.urlhandler = staticmethod(self.urlhandler)
2468 docsvr = DocServer(self.port, self.ready)
2469 self.docserver = docsvr
2470 docsvr.serve_until_quit()
2471 except Exception as e:
2472 self.error = e
2473
2474 def ready(self, server):
2475 self.serving = True
2476 self.host = server.host
2477 self.port = server.server_port
2478 self.url = 'http://%s:%d/' % (self.host, self.port)
2479
2480 def stop(self):
2481 """Stop the server and this thread nicely"""
2482 self.docserver.quit = True
2483 self.serving = False
2484 self.url = None
2485
2486 thread = ServerThread(urlhandler, port)
2487 thread.start()
2488 # Wait until thread.serving is True to make sure we are
2489 # really up before returning.
2490 while not thread.error and not thread.serving:
2491 time.sleep(.01)
2492 return thread
2493
2494
2495def _url_handler(url, content_type="text/html"):
2496 """The pydoc url handler for use with the pydoc server.
2497
2498 If the content_type is 'text/css', the _pydoc.css style
2499 sheet is read and returned if it exits.
2500
2501 If the content_type is 'text/html', then the result of
2502 get_html_page(url) is returned.
2503 """
2504 class _HTMLDoc(HTMLDoc):
2505
2506 def page(self, title, contents):
2507 """Format an HTML page."""
2508 css_path = "pydoc_data/_pydoc.css"
2509 css_link = (
2510 '<link rel="stylesheet" type="text/css" href="%s">' %
2511 css_path)
2512 return '''\
2513<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Georg Brandld2f38572011-01-30 08:37:19 +00002514<html><head><title>Pydoc: %s</title>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002515<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Georg Brandld2f38572011-01-30 08:37:19 +00002516%s</head><body bgcolor="#f0f0f8">%s<div style="clear:both;padding-top:.5em;">%s</div>
2517</body></html>''' % (title, css_link, html_navbar(), contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002518
2519 def filelink(self, url, path):
2520 return '<a href="getfile?key=%s">%s</a>' % (url, path)
2521
2522
2523 html = _HTMLDoc()
2524
2525 def html_navbar():
Georg Brandld2f38572011-01-30 08:37:19 +00002526 version = html.escape("%s [%s, %s]" % (platform.python_version(),
2527 platform.python_build()[0],
2528 platform.python_compiler()))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002529 return """
2530 <div style='float:left'>
Georg Brandld2f38572011-01-30 08:37:19 +00002531 Python %s<br>%s
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002532 </div>
2533 <div style='float:right'>
2534 <div style='text-align:center'>
2535 <a href="index.html">Module Index</a>
2536 : <a href="topics.html">Topics</a>
2537 : <a href="keywords.html">Keywords</a>
2538 </div>
2539 <div>
Georg Brandld2f38572011-01-30 08:37:19 +00002540 <form action="get" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002541 <input type=text name=key size=15>
2542 <input type=submit value="Get">
Georg Brandld2f38572011-01-30 08:37:19 +00002543 </form>&nbsp;
2544 <form action="search" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002545 <input type=text name=key size=15>
2546 <input type=submit value="Search">
2547 </form>
2548 </div>
2549 </div>
Georg Brandld2f38572011-01-30 08:37:19 +00002550 """ % (version, html.escape(platform.platform(terse=True)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002551
2552 def html_index():
2553 """Module Index page."""
2554
2555 def bltinlink(name):
2556 return '<a href="%s.html">%s</a>' % (name, name)
2557
2558 heading = html.heading(
2559 '<big><big><strong>Index of Modules</strong></big></big>',
2560 '#ffffff', '#7799ee')
2561 names = [name for name in sys.builtin_module_names
2562 if name != '__main__']
2563 contents = html.multicolumn(names, bltinlink)
2564 contents = [heading, '<p>' + html.bigsection(
2565 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2566
2567 seen = {}
2568 for dir in sys.path:
2569 contents.append(html.index(dir, seen))
2570
2571 contents.append(
2572 '<p align=right><font color="#909090" face="helvetica,'
2573 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2574 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002575 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002576
2577 def html_search(key):
2578 """Search results page."""
2579 # scan for modules
2580 search_result = []
2581
2582 def callback(path, modname, desc):
2583 if modname[-9:] == '.__init__':
2584 modname = modname[:-9] + ' (package)'
2585 search_result.append((modname, desc and '- ' + desc))
2586
2587 with warnings.catch_warnings():
2588 warnings.filterwarnings('ignore') # ignore problems during import
2589 ModuleScanner().run(callback, key)
2590
2591 # format page
2592 def bltinlink(name):
2593 return '<a href="%s.html">%s</a>' % (name, name)
2594
2595 results = []
2596 heading = html.heading(
2597 '<big><big><strong>Search Results</strong></big></big>',
2598 '#ffffff', '#7799ee')
2599 for name, desc in search_result:
2600 results.append(bltinlink(name) + desc)
2601 contents = heading + html.bigsection(
2602 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002603 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002604
2605 def html_getfile(path):
2606 """Get and display a source file listing safely."""
Nick Coghlanecace282010-12-03 16:08:46 +00002607 path = path.replace('%20', ' ')
Victor Stinner91e08772011-07-05 14:30:41 +02002608 with tokenize.open(path) as fp:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002609 lines = html.escape(fp.read())
2610 body = '<pre>%s</pre>' % lines
2611 heading = html.heading(
2612 '<big><big><strong>File Listing</strong></big></big>',
2613 '#ffffff', '#7799ee')
2614 contents = heading + html.bigsection(
2615 'File: %s' % path, '#ffffff', '#ee77aa', body)
Nick Coghlanecace282010-12-03 16:08:46 +00002616 return 'getfile %s' % path, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002617
2618 def html_topics():
2619 """Index of topic texts available."""
2620
2621 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002622 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002623
2624 heading = html.heading(
2625 '<big><big><strong>INDEX</strong></big></big>',
2626 '#ffffff', '#7799ee')
2627 names = sorted(Helper.topics.keys())
2628
2629 contents = html.multicolumn(names, bltinlink)
2630 contents = heading + html.bigsection(
2631 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002632 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002633
2634 def html_keywords():
2635 """Index of keywords."""
2636 heading = html.heading(
2637 '<big><big><strong>INDEX</strong></big></big>',
2638 '#ffffff', '#7799ee')
2639 names = sorted(Helper.keywords.keys())
2640
2641 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002642 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002643
2644 contents = html.multicolumn(names, bltinlink)
2645 contents = heading + html.bigsection(
2646 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002647 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002648
2649 def html_topicpage(topic):
2650 """Topic or keyword help page."""
2651 buf = io.StringIO()
2652 htmlhelp = Helper(buf, buf)
2653 contents, xrefs = htmlhelp._gettopic(topic)
2654 if topic in htmlhelp.keywords:
2655 title = 'KEYWORD'
2656 else:
2657 title = 'TOPIC'
2658 heading = html.heading(
2659 '<big><big><strong>%s</strong></big></big>' % title,
2660 '#ffffff', '#7799ee')
Georg Brandld2f38572011-01-30 08:37:19 +00002661 contents = '<pre>%s</pre>' % html.markup(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002662 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
Georg Brandld2f38572011-01-30 08:37:19 +00002663 if xrefs:
2664 xrefs = sorted(xrefs.split())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002665
Georg Brandld2f38572011-01-30 08:37:19 +00002666 def bltinlink(name):
2667 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002668
Georg Brandld2f38572011-01-30 08:37:19 +00002669 xrefs = html.multicolumn(xrefs, bltinlink)
2670 xrefs = html.section('Related help topics: ',
2671 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002672 return ('%s %s' % (title, topic),
2673 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002674
Georg Brandld2f38572011-01-30 08:37:19 +00002675 def html_getobj(url):
2676 obj = locate(url, forceload=1)
2677 if obj is None and url != 'None':
2678 raise ValueError('could not find object')
2679 title = describe(obj)
2680 content = html.document(obj, url)
2681 return title, content
2682
2683 def html_error(url, exc):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002684 heading = html.heading(
2685 '<big><big><strong>Error</strong></big></big>',
Georg Brandld2f38572011-01-30 08:37:19 +00002686 '#ffffff', '#7799ee')
2687 contents = '<br>'.join(html.escape(line) for line in
2688 format_exception_only(type(exc), exc))
2689 contents = heading + html.bigsection(url, '#ffffff', '#bb0000',
2690 contents)
2691 return "Error - %s" % url, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002692
2693 def get_html_page(url):
2694 """Generate an HTML page for url."""
Georg Brandld2f38572011-01-30 08:37:19 +00002695 complete_url = url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002696 if url.endswith('.html'):
2697 url = url[:-5]
Georg Brandld2f38572011-01-30 08:37:19 +00002698 try:
2699 if url in ("", "index"):
2700 title, content = html_index()
2701 elif url == "topics":
2702 title, content = html_topics()
2703 elif url == "keywords":
2704 title, content = html_keywords()
2705 elif '=' in url:
2706 op, _, url = url.partition('=')
2707 if op == "search?key":
2708 title, content = html_search(url)
2709 elif op == "getfile?key":
2710 title, content = html_getfile(url)
2711 elif op == "topic?key":
2712 # try topics first, then objects.
2713 try:
2714 title, content = html_topicpage(url)
2715 except ValueError:
2716 title, content = html_getobj(url)
2717 elif op == "get?key":
2718 # try objects first, then topics.
2719 if url in ("", "index"):
2720 title, content = html_index()
2721 else:
2722 try:
2723 title, content = html_getobj(url)
2724 except ValueError:
2725 title, content = html_topicpage(url)
2726 else:
2727 raise ValueError('bad pydoc url')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002728 else:
Georg Brandld2f38572011-01-30 08:37:19 +00002729 title, content = html_getobj(url)
2730 except Exception as exc:
2731 # Catch any errors and display them in an error page.
2732 title, content = html_error(complete_url, exc)
2733 return html.page(title, content)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002734
2735 if url.startswith('/'):
2736 url = url[1:]
2737 if content_type == 'text/css':
2738 path_here = os.path.dirname(os.path.realpath(__file__))
Georg Brandld2f38572011-01-30 08:37:19 +00002739 css_path = os.path.join(path_here, url)
2740 with open(css_path) as fp:
2741 return ''.join(fp.readlines())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002742 elif content_type == 'text/html':
2743 return get_html_page(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002744 # Errors outside the url handler are caught by the server.
2745 raise TypeError('unknown content type %r for url %s' % (content_type, url))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002746
2747
2748def browse(port=0, *, open_browser=True):
2749 """Start the enhanced pydoc Web server and open a Web browser.
2750
2751 Use port '0' to start the server on an arbitrary port.
2752 Set open_browser to False to suppress opening a browser.
2753 """
2754 import webbrowser
2755 serverthread = _start_server(_url_handler, port)
2756 if serverthread.error:
2757 print(serverthread.error)
2758 return
2759 if serverthread.serving:
2760 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2761 if open_browser:
2762 webbrowser.open(serverthread.url)
2763 try:
2764 print('Server ready at', serverthread.url)
2765 print(server_help_msg)
2766 while serverthread.serving:
2767 cmd = input('server> ')
2768 cmd = cmd.lower()
2769 if cmd == 'q':
2770 break
2771 elif cmd == 'b':
2772 webbrowser.open(serverthread.url)
2773 else:
2774 print(server_help_msg)
2775 except (KeyboardInterrupt, EOFError):
2776 print()
2777 finally:
2778 if serverthread.serving:
2779 serverthread.stop()
2780 print('Server stopped')
2781
2782
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002783# -------------------------------------------------- command-line interface
2784
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002785def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002786 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002787
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002788def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002789 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002790 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002791 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002792
Nick Coghlan106274b2009-11-15 23:04:33 +00002793 # Scripts don't get the current directory in their path by default
2794 # unless they are run with the '-m' switch
2795 if '' not in sys.path:
2796 scriptdir = os.path.dirname(sys.argv[0])
2797 if scriptdir in sys.path:
2798 sys.path.remove(scriptdir)
2799 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002800
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002801 try:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002802 opts, args = getopt.getopt(sys.argv[1:], 'bgk:p:w')
2803 writing = False
2804 start_server = False
2805 open_browser = False
2806 port = None
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002807 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002808 if opt == '-g':
2809 gui()
2810 return
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002811 if opt == '-b':
2812 start_server = True
2813 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002814 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002815 apropos(val)
2816 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002817 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002818 start_server = True
2819 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002820 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002821 writing = True
2822
2823 if start_server == True:
2824 if port == None:
2825 port = 0
2826 browse(port, open_browser=open_browser)
2827 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002828
2829 if not args: raise BadUsage
2830 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002831 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002832 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002833 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002834 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002835 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002836 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002837 if writing:
2838 if ispath(arg) and os.path.isdir(arg):
2839 writedocs(arg)
2840 else:
2841 writedoc(arg)
2842 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002843 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002844 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002845 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002846
2847 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002848 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002849 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002850
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002851{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002852 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002853 Python keyword, topic, function, module, or package, or a dotted
2854 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002855 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002856 Python source file to document. If name is 'keywords', 'topics',
2857 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002858
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002859{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002860 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002861
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002862{cmd} -p <port>
2863 Start an HTTP server on the given port on the local machine. Port
2864 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002865
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002866{cmd} -b
2867 Start an HTTP server on an arbitrary unused port and open a Web browser
2868 to interactively browse documentation. The -p option can be used with
2869 the -b option to explicitly specify the server port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002870
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002871{cmd} -g
2872 Deprecated.
2873
2874{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002875 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002876 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002877 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002878""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002879
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002880if __name__ == '__main__':
2881 cli()