blob: f172700a15f9d94ecdd6ddf31effae2e71b36fb8 [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
R David Murray3d050dd2014-04-19 12:59:30 -04004At the Python interactive prompt, calling help(thing) on a Python object
5documents the object, and calling help() starts up an interactive
6help session.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00007
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00008Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00009
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000010Run "pydoc <name>" to show documentation on something. <name> may be
11the name of a function, module, package, or a dotted reference to a
12class or function within a module or module in a package. If the
13argument contains a path segment delimiter (e.g. slash on Unix,
14backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000015
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000016Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000018
Feanil Patel6a396c92017-09-14 17:54:09 -040019Run "pydoc -n <hostname>" to start an HTTP server with the given
20hostname (default: localhost) on the local machine.
21
Nick Coghlan7bb30b72010-12-03 09:29:11 +000022Run "pydoc -p <port>" to start an HTTP server on the given port on the
23local machine. Port number 0 can be used to get an arbitrary unused port.
24
25Run "pydoc -b" to start an HTTP server on an arbitrary unused port and
Feanil Patel6a396c92017-09-14 17:54:09 -040026open a Web browser to interactively browse documentation. Combine with
27the -n and -p options to control the hostname and port used.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000028
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000029Run "pydoc -w <name>" to write out the HTML documentation for a module
30to a file named "<name>.html".
Skip Montanaro4997a692003-09-10 16:47:51 +000031
32Module docs for core modules are assumed to be in
33
Martin Panter4f8aaf62016-06-12 04:24:06 +000034 https://docs.python.org/X.Y/library/
Skip Montanaro4997a692003-09-10 16:47:51 +000035
36This can be overridden by setting the PYTHONDOCS environment variable
37to a different URL or to a local directory containing the Library
38Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000039"""
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000040__all__ = ['help']
Ka-Ping Yeedd175342001-02-27 14:43:46 +000041__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000042__date__ = "26 February 2001"
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000043
Martin v. Löwis6fe8f192004-11-14 10:21:04 +000044__credits__ = """Guido van Rossum, for an excellent programming language.
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000045Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000046Paul Prescod, for all his work on onlinehelp.
47Richard Chamberlain, for the first implementation of textdoc.
Raymond Hettingered2dbe32005-01-01 07:51:01 +000048"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000049
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000050# Known bugs that can't be fixed here:
Brett Cannonf4ba4ec2013-06-15 14:25:04 -040051# - synopsis() cannot be prevented from clobbering existing
52# loaded modules.
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000053# - If the __file__ attribute on a module is a relative path and
54# the current directory is changed with os.chdir(), an incorrect
55# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000056
Nick Coghlan7bb30b72010-12-03 09:29:11 +000057import builtins
Brett Cannond5e6f2e2013-06-11 17:09:36 -040058import importlib._bootstrap
Eric Snow32439d62015-05-02 19:15:18 -060059import importlib._bootstrap_external
Brett Cannoncb66eb02012-05-11 12:58:42 -040060import importlib.machinery
Brett Cannonf4ba4ec2013-06-15 14:25:04 -040061import importlib.util
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
Victor Stinner4fac7ed2020-02-12 13:02:29 +010069import sysconfig
Nick Coghlan7bb30b72010-12-03 09:29:11 +000070import time
Victor Stinnere6c910e2011-06-30 15:55:43 +020071import tokenize
Zachary Wareeb432142014-07-10 11:18:00 -050072import urllib.parse
Nick Coghlan7bb30b72010-12-03 09:29:11 +000073import warnings
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000074from collections import deque
Nick Coghlan7bb30b72010-12-03 09:29:11 +000075from reprlib import Repr
Victor Stinner7fa767e2014-03-20 09:16:38 +010076from traceback import format_exception_only
Nick Coghlan7bb30b72010-12-03 09:29:11 +000077
78
Ka-Ping Yeedd175342001-02-27 14:43:46 +000079# --------------------------------------------------------- common routines
80
Ka-Ping Yeedd175342001-02-27 14:43:46 +000081def pathdirs():
82 """Convert sys.path into a list of absolute, existing, unique paths."""
83 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000084 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000085 for dir in sys.path:
86 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000087 normdir = os.path.normcase(dir)
88 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000089 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000090 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000091 return dirs
92
93def getdoc(object):
94 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000095 result = inspect.getdoc(object) or inspect.getcomments(object)
Neal Norwitz9d72bb42007-04-17 08:48:32 +000096 return result and re.sub('^ *\n', '', result.rstrip()) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000097
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000098def splitdoc(doc):
99 """Split a doc string into a synopsis line (if any) and the rest."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000100 lines = doc.strip().split('\n')
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000101 if len(lines) == 1:
102 return lines[0], ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000103 elif len(lines) >= 2 and not lines[1].rstrip():
104 return lines[0], '\n'.join(lines[2:])
105 return '', '\n'.join(lines)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000106
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000107def classname(object, modname):
108 """Get a class name and qualify it with a module name if necessary."""
109 name = object.__name__
110 if object.__module__ != modname:
111 name = object.__module__ + '.' + name
112 return name
113
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000114def isdata(object):
Georg Brandl94432422005-07-22 21:52:25 +0000115 """Check if an object is of a type that probably means it's data."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000116 return not (inspect.ismodule(object) or inspect.isclass(object) or
117 inspect.isroutine(object) or inspect.isframe(object) or
118 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000119
120def replace(text, *pairs):
121 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000122 while pairs:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000123 text = pairs[1].join(text.split(pairs[0]))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000124 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000125 return text
126
127def cram(text, maxlen):
128 """Omit part of a string if needed to make it fit in a maximum length."""
129 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000130 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000131 post = max(0, maxlen-3-pre)
132 return text[:pre] + '...' + text[len(text)-post:]
133 return text
134
Brett Cannon84601f12004-06-19 01:22:48 +0000135_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000136def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000137 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000138 # The behaviour of %p is implementation-dependent in terms of case.
Ezio Melotti412c95a2010-02-16 23:31:04 +0000139 return _re_stripid.sub(r'\1', text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000140
Larry Hastings24a882b2014-02-20 23:34:46 -0800141def _is_bound_method(fn):
142 """
143 Returns True if fn is a bound method, regardless of whether
144 fn was implemented in Python or in C.
145 """
146 if inspect.ismethod(fn):
147 return True
148 if inspect.isbuiltin(fn):
149 self = getattr(fn, '__self__', None)
150 return not (inspect.ismodule(self) or (self is None))
151 return False
152
153
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000154def allmethods(cl):
155 methods = {}
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200156 for key, value in inspect.getmembers(cl, inspect.isroutine):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000157 methods[key] = 1
158 for base in cl.__bases__:
159 methods.update(allmethods(base)) # all your base are belong to us
160 for key in methods.keys():
161 methods[key] = getattr(cl, key)
162 return methods
163
Tim Petersfa26f7c2001-09-24 08:05:11 +0000164def _split_list(s, predicate):
165 """Split sequence s via predicate, and return pair ([true], [false]).
166
167 The return value is a 2-tuple of lists,
168 ([x for x in s if predicate(x)],
169 [x for x in s if not predicate(x)])
170 """
171
Tim Peters28355492001-09-23 21:29:55 +0000172 yes = []
173 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000174 for x in s:
175 if predicate(x):
176 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000177 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000178 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000179 return yes, no
180
Raymond Hettinger1103d052011-03-25 14:15:24 -0700181def visiblename(name, all=None, obj=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000182 """Decide whether to show documentation on a variable."""
Brett Cannond340b432012-08-06 17:19:22 -0400183 # Certain special names are redundant or internal.
Eric Snowb523f842013-11-22 09:05:39 -0700184 # XXX Remove __initializing__?
Brett Cannond340b432012-08-06 17:19:22 -0400185 if name in {'__author__', '__builtins__', '__cached__', '__credits__',
Eric Snowb523f842013-11-22 09:05:39 -0700186 '__date__', '__doc__', '__file__', '__spec__',
Brett Cannond340b432012-08-06 17:19:22 -0400187 '__loader__', '__module__', '__name__', '__package__',
188 '__path__', '__qualname__', '__slots__', '__version__'}:
Raymond Hettinger68272942011-03-18 02:22:15 -0700189 return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000190 # Private names are hidden, but special names are displayed.
191 if name.startswith('__') and name.endswith('__'): return 1
Raymond Hettinger1103d052011-03-25 14:15:24 -0700192 # Namedtuples have public fields and methods with a single leading underscore
193 if name.startswith('_') and hasattr(obj, '_fields'):
194 return True
Skip Montanaroa5616d22004-06-11 04:46:12 +0000195 if all is not None:
196 # only document that which the programmer exported in __all__
197 return name in all
198 else:
199 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000200
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000201def classify_class_attrs(object):
202 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000203 results = []
204 for (name, kind, cls, value) in inspect.classify_class_attrs(object):
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000205 if inspect.isdatadescriptor(value):
206 kind = 'data descriptor'
Raymond Hettinger62be3382019-03-24 17:07:47 -0700207 if isinstance(value, property) and value.fset is None:
208 kind = 'readonly property'
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000209 results.append((name, kind, cls, value))
210 return results
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000211
Raymond Hettinger95801bb2015-08-18 22:25:16 -0700212def sort_attributes(attrs, object):
213 'Sort the attrs list in-place by _fields and then alphabetically by name'
214 # This allows data descriptors to be ordered according
215 # to a _fields attribute if present.
216 fields = getattr(object, '_fields', [])
217 try:
218 field_order = {name : i-len(fields) for (i, name) in enumerate(fields)}
219 except TypeError:
220 field_order = {}
221 keyfunc = lambda attr: (field_order.get(attr[0], 0), attr[0])
222 attrs.sort(key=keyfunc)
223
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000224# ----------------------------------------------------- module manipulation
225
226def ispackage(path):
227 """Guess whether a path refers to a package directory."""
228 if os.path.isdir(path):
Brett Cannonf299abd2015-04-13 14:21:02 -0400229 for ext in ('.py', '.pyc'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000230 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000231 return True
232 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000233
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000234def source_synopsis(file):
235 line = file.readline()
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000236 while line[:1] == '#' or not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000237 line = file.readline()
238 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000239 line = line.strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000240 if line[:4] == 'r"""': line = line[1:]
241 if line[:3] == '"""':
242 line = line[3:]
243 if line[-1:] == '\\': line = line[:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000244 while not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000245 line = file.readline()
246 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000247 result = line.split('"""')[0].strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000248 else: result = None
249 return result
250
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000251def synopsis(filename, cache={}):
252 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000253 mtime = os.stat(filename).st_mtime
Charles-François Natali27c4e882011-07-27 19:40:02 +0200254 lastupdate, result = cache.get(filename, (None, None))
255 if lastupdate is None or lastupdate < mtime:
Eric Snowaed5b222014-01-04 20:38:11 -0700256 # Look for binary suffixes first, falling back to source.
257 if filename.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)):
258 loader_cls = importlib.machinery.SourcelessFileLoader
259 elif filename.endswith(tuple(importlib.machinery.EXTENSION_SUFFIXES)):
260 loader_cls = importlib.machinery.ExtensionFileLoader
261 else:
262 loader_cls = None
263 # Now handle the choice.
264 if loader_cls is None:
265 # Must be a source file.
266 try:
267 file = tokenize.open(filename)
268 except OSError:
269 # module can't be opened, so skip it
270 return None
271 # text modules can be directly examined
272 with file:
273 result = source_synopsis(file)
274 else:
275 # Must be a binary module, which has to be imported.
276 loader = loader_cls('__temp__', filename)
Eric Snow3a62d142014-01-06 20:42:59 -0700277 # XXX We probably don't need to pass in the loader here.
278 spec = importlib.util.spec_from_file_location('__temp__', filename,
279 loader=loader)
Brett Cannoncb66eb02012-05-11 12:58:42 -0400280 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -0400281 module = importlib._bootstrap._load(spec)
Brett Cannoncb66eb02012-05-11 12:58:42 -0400282 except:
283 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000284 del sys.modules['__temp__']
Benjamin Peterson54237f92015-02-16 19:45:01 -0500285 result = module.__doc__.splitlines()[0] if module.__doc__ else None
Eric Snowaed5b222014-01-04 20:38:11 -0700286 # Cache the result.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000287 cache[filename] = (mtime, result)
288 return result
289
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000290class ErrorDuringImport(Exception):
291 """Errors that occurred while trying to import something to document it."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000292 def __init__(self, filename, exc_info):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000293 self.filename = filename
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000294 self.exc, self.value, self.tb = exc_info
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000295
296 def __str__(self):
Guido van Rossuma01a8b62007-05-27 09:20:14 +0000297 exc = self.exc.__name__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000298 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000299
300def importfile(path):
301 """Import a Python source file or compiled file given its path."""
Brett Cannonf4ba4ec2013-06-15 14:25:04 -0400302 magic = importlib.util.MAGIC_NUMBER
Victor Stinnere975af62011-07-04 02:08:50 +0200303 with open(path, 'rb') as file:
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400304 is_bytecode = magic == file.read(len(magic))
305 filename = os.path.basename(path)
306 name, ext = os.path.splitext(filename)
307 if is_bytecode:
Eric Snow32439d62015-05-02 19:15:18 -0600308 loader = importlib._bootstrap_external.SourcelessFileLoader(name, path)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400309 else:
Eric Snow32439d62015-05-02 19:15:18 -0600310 loader = importlib._bootstrap_external.SourceFileLoader(name, path)
Eric Snow3a62d142014-01-06 20:42:59 -0700311 # XXX We probably don't need to pass in the loader here.
312 spec = importlib.util.spec_from_file_location(name, path, loader=loader)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400313 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -0400314 return importlib._bootstrap._load(spec)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400315 except:
316 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000317
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000318def safeimport(path, forceload=0, cache={}):
319 """Import a module; handle errors; return None if the module isn't found.
320
321 If the module *is* found but an exception occurs, it's wrapped in an
322 ErrorDuringImport exception and reraised. Unlike __import__, if a
323 package path is specified, the module at the end of the path is returned,
324 not the package at the beginning. If the optional 'forceload' argument
325 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000326 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000327 # If forceload is 1 and the module has been previously loaded from
328 # disk, we always have to reload the module. Checking the file's
329 # mtime isn't good enough (e.g. the module could contain a class
330 # that inherits from another module that has changed).
331 if forceload and path in sys.modules:
332 if path not in sys.builtin_module_names:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000333 # Remove the module from sys.modules and re-import to try
334 # and avoid problems with partially loaded modules.
335 # Also remove any submodules because they won't appear
336 # in the newly loaded module's namespace if they're already
337 # in sys.modules.
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000338 subs = [m for m in sys.modules if m.startswith(path + '.')]
339 for key in [path] + subs:
340 # Prevent garbage collection.
341 cache[key] = sys.modules[key]
342 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000343 module = __import__(path)
344 except:
345 # Did the error occur before or after the module was found?
346 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000347 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000348 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000349 raise ErrorDuringImport(sys.modules[path].__file__, info)
350 elif exc is SyntaxError:
351 # A SyntaxError occurred before we could execute the module.
352 raise ErrorDuringImport(value.filename, info)
Eric Snow46f97b82016-09-07 16:56:15 -0700353 elif issubclass(exc, ImportError) and value.name == path:
Brett Cannonfd074152012-04-14 14:10:13 -0400354 # No such module in the path.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000355 return None
356 else:
357 # Some other error occurred during the importing process.
358 raise ErrorDuringImport(path, sys.exc_info())
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000359 for part in path.split('.')[1:]:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000360 try: module = getattr(module, part)
361 except AttributeError: return None
362 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000363
364# ---------------------------------------------------- formatter base class
365
366class Doc:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000367
368 PYTHONDOCS = os.environ.get("PYTHONDOCS",
R David Murrayead9bfc2016-06-03 19:28:35 -0400369 "https://docs.python.org/%d.%d/library"
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000370 % sys.version_info[:2])
371
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000372 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000373 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000374 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000375 # 'try' clause is to attempt to handle the possibility that inspect
376 # identifies something in a way that pydoc itself has issues handling;
377 # think 'super' and how it is a descriptor (which raises the exception
378 # by lacking a __name__ attribute) and an instance.
379 try:
380 if inspect.ismodule(object): return self.docmodule(*args)
381 if inspect.isclass(object): return self.docclass(*args)
382 if inspect.isroutine(object): return self.docroutine(*args)
383 except AttributeError:
384 pass
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200385 if inspect.isdatadescriptor(object): return self.docdata(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000386 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000387
388 def fail(self, object, name=None, *args):
389 """Raise an exception for unimplemented types."""
390 message = "don't know how to document object%s of type %s" % (
391 name and ' ' + repr(name), type(object).__name__)
Collin Winterce36ad82007-08-30 01:19:48 +0000392 raise TypeError(message)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000393
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000394 docmodule = docclass = docroutine = docother = docproperty = docdata = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000395
Victor Stinner4fac7ed2020-02-12 13:02:29 +0100396 def getdocloc(self, object, basedir=sysconfig.get_path('stdlib')):
Skip Montanaro4997a692003-09-10 16:47:51 +0000397 """Return the location of module docs or None"""
398
399 try:
400 file = inspect.getabsfile(object)
401 except TypeError:
402 file = '(built-in)'
403
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000404 docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
405
Martin Panter4f8aaf62016-06-12 04:24:06 +0000406 basedir = os.path.normcase(basedir)
Skip Montanaro4997a692003-09-10 16:47:51 +0000407 if (isinstance(object, type(os)) and
408 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
409 'marshal', 'posix', 'signal', 'sys',
Georg Brandl2067bfd2008-05-25 13:05:15 +0000410 '_thread', 'zipimport') or
Skip Montanaro4997a692003-09-10 16:47:51 +0000411 (file.startswith(basedir) and
Brian Curtin49c284c2010-03-31 03:19:28 +0000412 not file.startswith(os.path.join(basedir, 'site-packages')))) and
Brian Curtinedef05b2010-04-01 04:05:25 +0000413 object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
Martin Panter4f8aaf62016-06-12 04:24:06 +0000414 if docloc.startswith(("http://", "https://")):
R David Murrayead9bfc2016-06-03 19:28:35 -0400415 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__.lower())
Skip Montanaro4997a692003-09-10 16:47:51 +0000416 else:
R David Murrayead9bfc2016-06-03 19:28:35 -0400417 docloc = os.path.join(docloc, object.__name__.lower() + ".html")
Skip Montanaro4997a692003-09-10 16:47:51 +0000418 else:
419 docloc = None
420 return docloc
421
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000422# -------------------------------------------- HTML documentation generator
423
424class HTMLRepr(Repr):
425 """Class for safely making an HTML representation of a Python object."""
426 def __init__(self):
427 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000428 self.maxlist = self.maxtuple = 20
429 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000430 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000431
432 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000433 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000434
435 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000436 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000437
438 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000439 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000440 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000441 if hasattr(self, methodname):
442 return getattr(self, methodname)(x, level)
443 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000444
445 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000446 test = cram(x, self.maxstring)
447 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000448 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000449 # Backslashes are only literal in the string and are never
450 # needed to make any special characters, so show a raw string.
451 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000452 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000453 r'<font color="#c040c0">\1</font>',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000454 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000455
Skip Montanarodf708782002-03-07 22:58:02 +0000456 repr_str = repr_string
457
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000458 def repr_instance(self, x, level):
459 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000460 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000461 except:
462 return self.escape('<%s instance>' % x.__class__.__name__)
463
464 repr_unicode = repr_string
465
466class HTMLDoc(Doc):
467 """Formatter class for HTML documentation."""
468
469 # ------------------------------------------- HTML formatting utilities
470
471 _repr_instance = HTMLRepr()
472 repr = _repr_instance.repr
473 escape = _repr_instance.escape
474
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000475 def page(self, title, contents):
476 """Format an HTML page."""
Georg Brandl388faac2009-04-10 08:31:48 +0000477 return '''\
Georg Brandle6066942009-04-10 08:28:28 +0000478<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000479<html><head><title>Python: %s</title>
Georg Brandl388faac2009-04-10 08:31:48 +0000480<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000481</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000482%s
483</body></html>''' % (title, contents)
484
485 def heading(self, title, fgcol, bgcol, extras=''):
486 """Format a page heading."""
487 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000488<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000489<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000490<td valign=bottom>&nbsp;<br>
491<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000492><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000493><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000494 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
495
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000496 def section(self, title, fgcol, bgcol, contents, width=6,
497 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000498 """Format a section with a heading."""
499 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000500 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000501 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000502<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000503<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000504<td colspan=3 valign=bottom>&nbsp;<br>
505<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000506 ''' % (bgcol, fgcol, title)
507 if prelude:
508 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000509<tr bgcolor="%s"><td rowspan=2>%s</td>
510<td colspan=2>%s</td></tr>
511<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
512 else:
513 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000514<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000515
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000516 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000517
518 def bigsection(self, title, *args):
519 """Format a section with a big heading."""
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000520 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000521 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000522
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000523 def preformat(self, text):
524 """Format literal preformatted text."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000525 text = self.escape(text.expandtabs())
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000526 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
527 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000528
529 def multicolumn(self, list, format, cols=4):
530 """Format a list of items into a multi-column list."""
531 result = ''
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000532 rows = (len(list)+cols-1)//cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000533 for col in range(cols):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000534 result = result + '<td width="%d%%" valign=top>' % (100//cols)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000535 for i in range(rows*col, rows*col+rows):
536 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000537 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000538 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000539 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000540
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000541 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000542
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000543 def namelink(self, name, *dicts):
544 """Make a link for an identifier, given name-to-URL mappings."""
545 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000546 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000547 return '<a href="%s">%s</a>' % (dict[name], name)
548 return name
549
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000550 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000551 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000552 name, module = object.__name__, sys.modules.get(object.__module__)
553 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000554 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000555 module.__name__, name, classname(object, modname))
556 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000557
558 def modulelink(self, object):
559 """Make a link for a module."""
560 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
561
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000562 def modpkglink(self, modpkginfo):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000563 """Make a link for a module or package to display in an index."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000564 name, path, ispackage, shadowed = modpkginfo
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000565 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000566 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000567 if path:
568 url = '%s.%s.html' % (path, name)
569 else:
570 url = '%s.html' % name
571 if ispackage:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000572 text = '<strong>%s</strong>&nbsp;(package)' % name
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000573 else:
574 text = name
575 return '<a href="%s">%s</a>' % (url, text)
576
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000577 def filelink(self, url, path):
578 """Make a link to source file."""
579 return '<a href="file:%s">%s</a>' % (url, path)
580
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000581 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
582 """Mark up some plain text, given a context of symbols to look for.
583 Each context dictionary maps object names to anchor names."""
584 escape = escape or self.escape
585 results = []
586 here = 0
Kirill61289d42019-11-13 19:13:53 +0300587 pattern = re.compile(r'\b((http|https|ftp)://\S+[\w/]|'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000588 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000589 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000590 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000591 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000592 match = pattern.search(text, here)
593 if not match: break
594 start, end = match.span()
595 results.append(escape(text[here:start]))
596
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000597 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000598 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000599 url = escape(all).replace('"', '&quot;')
600 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000601 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000602 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
603 results.append('<a href="%s">%s</a>' % (url, escape(all)))
604 elif pep:
Christian Heimes2202f872008-02-06 14:31:34 +0000605 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000606 results.append('<a href="%s">%s</a>' % (url, escape(all)))
Benjamin Petersoned1160b2014-06-07 16:44:00 -0700607 elif selfdot:
608 # Create a link for methods like 'self.method(...)'
609 # and use <strong> for attributes like 'self.attr'
610 if text[end:end+1] == '(':
611 results.append('self.' + self.namelink(name, methods))
612 else:
613 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000614 elif text[end:end+1] == '(':
615 results.append(self.namelink(name, methods, funcs, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000616 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000617 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000618 here = end
619 results.append(escape(text[here:]))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000620 return ''.join(results)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000621
622 # ---------------------------------------------- type-specific routines
623
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000624 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000625 """Produce HTML for a class tree as given by inspect.getclasstree()."""
626 result = ''
627 for entry in tree:
628 if type(entry) is type(()):
629 c, bases = entry
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000630 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000631 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000632 if bases and bases != (parent,):
633 parents = []
634 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000635 parents.append(self.classlink(base, modname))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000636 result = result + '(' + ', '.join(parents) + ')'
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000637 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000638 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000639 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000640 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000641 return '<dl>\n%s</dl>\n' % result
642
Tim Peters8dd7ade2001-10-18 19:56:17 +0000643 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000644 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000645 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000646 try:
647 all = object.__all__
648 except AttributeError:
649 all = None
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000650 parts = name.split('.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000651 links = []
652 for i in range(len(parts)-1):
653 links.append(
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000654 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000655 ('.'.join(parts[:i+1]), parts[i]))
656 linkedname = '.'.join(links + parts[-1:])
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000657 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000658 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000659 path = inspect.getabsfile(object)
Zachary Wareeb432142014-07-10 11:18:00 -0500660 url = urllib.parse.quote(path)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000661 filelink = self.filelink(url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000662 except TypeError:
663 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000664 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000665 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000666 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000667 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000668 version = version[11:-1].strip()
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000669 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000670 if hasattr(object, '__date__'):
671 info.append(self.escape(str(object.__date__)))
672 if info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000673 head = head + ' (%s)' % ', '.join(info)
Skip Montanaro4997a692003-09-10 16:47:51 +0000674 docloc = self.getdocloc(object)
675 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000676 docloc = '<br><a href="%(docloc)s">Module Reference</a>' % locals()
Skip Montanaro4997a692003-09-10 16:47:51 +0000677 else:
678 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000679 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000680 head, '#ffffff', '#7799ee',
681 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000682
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000683 modules = inspect.getmembers(object, inspect.ismodule)
684
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000685 classes, cdict = [], {}
686 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000687 # if __all__ exists, believe it. Otherwise use old heuristic.
688 if (all is not None or
689 (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700690 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000691 classes.append((key, value))
692 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000693 for key, value in classes:
694 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000695 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000696 module = sys.modules.get(modname)
697 if modname != name and module and hasattr(module, key):
698 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000699 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000700 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000701 funcs, fdict = [], {}
702 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000703 # if __all__ exists, believe it. Otherwise use old heuristic.
704 if (all is not None or
705 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700706 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000707 funcs.append((key, value))
708 fdict[key] = '#-' + key
709 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000710 data = []
711 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700712 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000713 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000714
715 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
716 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000717 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000718
719 if hasattr(object, '__path__'):
720 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000721 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
722 modpkgs.append((modname, name, ispkg, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000723 modpkgs.sort()
724 contents = self.multicolumn(modpkgs, self.modpkglink)
725 result = result + self.bigsection(
726 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000727 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000728 contents = self.multicolumn(
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000729 modules, lambda t: self.modulelink(t[1]))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000730 result = result + self.bigsection(
Christian Heimes7131fd92008-02-19 14:21:46 +0000731 'Modules', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000732
733 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000734 classlist = [value for (key, value) in classes]
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000735 contents = [
736 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000737 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000738 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000739 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000740 'Classes', '#ffffff', '#ee77aa', ' '.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000741 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000742 contents = []
743 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000744 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000745 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000746 'Functions', '#ffffff', '#eeaa77', ' '.join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000747 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000748 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000749 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000750 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000751 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000752 'Data', '#ffffff', '#55aa55', '<br>\n'.join(contents))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000753 if hasattr(object, '__author__'):
754 contents = self.markup(str(object.__author__), self.preformat)
755 result = result + self.bigsection(
756 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000757 if hasattr(object, '__credits__'):
758 contents = self.markup(str(object.__credits__), self.preformat)
759 result = result + self.bigsection(
760 'Credits', '#ffffff', '#7799ee', contents)
761
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000762 return result
763
Tim Peters8dd7ade2001-10-18 19:56:17 +0000764 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
765 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000766 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000767 realname = object.__name__
768 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000769 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000770
Tim Petersb47879b2001-09-24 04:47:19 +0000771 contents = []
772 push = contents.append
773
Tim Petersfa26f7c2001-09-24 08:05:11 +0000774 # Cute little class to pump out a horizontal rule between sections.
775 class HorizontalRule:
776 def __init__(self):
777 self.needone = 0
778 def maybe(self):
779 if self.needone:
780 push('<hr>\n')
781 self.needone = 1
782 hr = HorizontalRule()
783
Tim Petersc86f6ca2001-09-26 21:31:51 +0000784 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000785 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000786 if len(mro) > 2:
787 hr.maybe()
788 push('<dl><dt>Method resolution order:</dt>\n')
789 for base in mro:
790 push('<dd>%s</dd>\n' % self.classlink(base,
791 object.__module__))
792 push('</dl>\n')
793
Tim Petersb47879b2001-09-24 04:47:19 +0000794 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000795 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000796 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000797 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000798 push(msg)
799 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100800 try:
801 value = getattr(object, name)
802 except Exception:
803 # Some descriptors may meet a failure in their __get__.
804 # (bug #1785)
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200805 push(self.docdata(value, name, mod))
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100806 else:
807 push(self.document(value, name, mod,
808 funcs, classes, mdict, object))
Tim Petersb47879b2001-09-24 04:47:19 +0000809 push('\n')
810 return attrs
811
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000812 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000813 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000814 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000815 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000816 push(msg)
817 for name, kind, homecls, value in ok:
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200818 push(self.docdata(value, name, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000819 return attrs
820
Tim Petersfa26f7c2001-09-24 08:05:11 +0000821 def spilldata(msg, attrs, predicate):
822 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000823 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000824 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000825 push(msg)
826 for name, kind, homecls, value in ok:
827 base = self.docother(getattr(object, name), name, mod)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200828 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000829 doc = getattr(value, "__doc__", None)
830 else:
831 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000832 if doc is None:
833 push('<dl><dt>%s</dl>\n' % base)
834 else:
835 doc = self.markup(getdoc(value), self.preformat,
836 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000837 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000838 push('<dl><dt>%s%s</dl>\n' % (base, doc))
839 push('\n')
840 return attrs
841
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000842 attrs = [(name, kind, cls, value)
843 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -0700844 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000845
Tim Petersb47879b2001-09-24 04:47:19 +0000846 mdict = {}
847 for key, kind, homecls, value in attrs:
848 mdict[key] = anchor = '#' + name + '-' + key
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100849 try:
850 value = getattr(object, name)
851 except Exception:
852 # Some descriptors may meet a failure in their __get__.
853 # (bug #1785)
854 pass
Tim Petersb47879b2001-09-24 04:47:19 +0000855 try:
856 # The value may not be hashable (e.g., a data attr with
857 # a dict or list value).
858 mdict[value] = anchor
859 except TypeError:
860 pass
861
Tim Petersfa26f7c2001-09-24 08:05:11 +0000862 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000863 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000864 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000865 else:
866 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000867 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
868
Cheryl Sabellac95c93d2019-05-24 06:43:29 -0400869 if object is not builtins.object and thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000870 attrs = inherited
871 continue
872 elif thisclass is object:
873 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000874 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000875 tag = 'inherited from %s' % self.classlink(thisclass,
876 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000877 tag += ':<br>\n'
878
Raymond Hettinger95801bb2015-08-18 22:25:16 -0700879 sort_attributes(attrs, object)
Tim Petersb47879b2001-09-24 04:47:19 +0000880
881 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000882 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000883 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000884 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000885 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000886 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000887 lambda t: t[1] == 'static method')
Raymond Hettinger9dcc0952019-03-25 00:23:39 -0700888 attrs = spilldescriptors("Readonly properties %s" % tag, attrs,
Raymond Hettinger62be3382019-03-24 17:07:47 -0700889 lambda t: t[1] == 'readonly property')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000890 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
891 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000892 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000893 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000894 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000895 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000896
897 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000898
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000899 if name == realname:
900 title = '<a name="%s">class <strong>%s</strong></a>' % (
901 name, realname)
902 else:
903 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
904 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000905 if bases:
906 parents = []
907 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000908 parents.append(self.classlink(base, object.__module__))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000909 title = title + '(%s)' % ', '.join(parents)
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +0200910
911 decl = ''
912 try:
913 signature = inspect.signature(object)
914 except (ValueError, TypeError):
915 signature = None
916 if signature:
917 argspec = str(signature)
Serhiy Storchaka213f2292017-01-23 14:02:35 +0200918 if argspec and argspec != '()':
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +0200919 decl = name + self.escape(argspec) + '\n\n'
920
921 doc = getdoc(object)
922 if decl:
923 doc = decl + (doc or '')
924 doc = self.markup(doc, self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000925 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000926
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000927 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000928
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000929 def formatvalue(self, object):
930 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000931 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000932
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000933 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000934 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000935 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000936 realname = object.__name__
937 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000938 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000939 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000940 skipdocs = 0
Larry Hastings24a882b2014-02-20 23:34:46 -0800941 if _is_bound_method(object):
Christian Heimesff737952007-11-27 10:40:20 +0000942 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000943 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000944 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000945 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000946 else:
Christian Heimesff737952007-11-27 10:40:20 +0000947 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000948 note = ' method of %s instance' % self.classlink(
Christian Heimesff737952007-11-27 10:40:20 +0000949 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000950 else:
951 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000952
Dan Rose2a37f8f2019-05-24 06:38:01 -0500953 if (inspect.iscoroutinefunction(object) or
954 inspect.isasyncgenfunction(object)):
955 asyncqualifier = 'async '
956 else:
957 asyncqualifier = ''
958
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000959 if name == realname:
960 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
961 else:
Serhiy Storchakaa44d34e2018-11-08 08:48:11 +0200962 if cl and inspect.getattr_static(cl, realname, []) is object:
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000963 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000964 cl.__name__ + '-' + realname, realname)
965 skipdocs = 1
966 else:
967 reallink = realname
968 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
969 anchor, name, reallink)
Larry Hastings44e2eaa2013-11-23 15:37:55 -0800970 argspec = None
Larry Hastings24a882b2014-02-20 23:34:46 -0800971 if inspect.isroutine(object):
Larry Hastings5c661892014-01-24 06:17:25 -0800972 try:
973 signature = inspect.signature(object)
974 except (ValueError, TypeError):
975 signature = None
Larry Hastings44e2eaa2013-11-23 15:37:55 -0800976 if signature:
977 argspec = str(signature)
978 if realname == '<lambda>':
979 title = '<strong>%s</strong> <em>lambda</em> ' % name
980 # XXX lambda's won't usually have func_annotations['return']
981 # since the syntax doesn't support but it is possible.
982 # So removing parentheses isn't truly safe.
983 argspec = argspec[1:-1] # remove parentheses
984 if not argspec:
Tim Peters4bcfa312001-09-20 06:08:24 +0000985 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000986
Dan Rose2a37f8f2019-05-24 06:38:01 -0500987 decl = asyncqualifier + title + self.escape(argspec) + (note and
988 self.grey('<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000989
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000990 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000991 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000992 else:
993 doc = self.markup(
994 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000995 doc = doc and '<dd><tt>%s</tt></dd>' % doc
996 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000997
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200998 def docdata(self, object, name=None, mod=None, cl=None):
999 """Produce html documentation for a data descriptor."""
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001000 results = []
1001 push = results.append
1002
1003 if name:
1004 push('<dl><dt><strong>%s</strong></dt>\n' % name)
Raymond Hettingera694f232019-03-27 13:16:34 -07001005 doc = self.markup(getdoc(object), self.preformat)
1006 if doc:
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001007 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001008 push('</dl>\n')
1009
1010 return ''.join(results)
1011
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001012 docproperty = docdata
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001013
Tim Peters8dd7ade2001-10-18 19:56:17 +00001014 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001015 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001016 lhs = name and '<strong>%s</strong> = ' % name or ''
1017 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001018
1019 def index(self, dir, shadowed=None):
1020 """Generate an HTML index for a directory of modules."""
1021 modpkgs = []
1022 if shadowed is None: shadowed = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001023 for importer, name, ispkg in pkgutil.iter_modules([dir]):
Victor Stinner4d652242011-04-12 23:41:50 +02001024 if any((0xD800 <= ord(ch) <= 0xDFFF) for ch in name):
1025 # ignore a module if its name contains a surrogate character
1026 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001027 modpkgs.append((name, '', ispkg, name in shadowed))
1028 shadowed[name] = 1
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001029
1030 modpkgs.sort()
1031 contents = self.multicolumn(modpkgs, self.modpkglink)
1032 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
1033
1034# -------------------------------------------- text documentation generator
1035
1036class TextRepr(Repr):
1037 """Class for safely making a text representation of a Python object."""
1038 def __init__(self):
1039 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001040 self.maxlist = self.maxtuple = 20
1041 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001042 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001043
1044 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +00001045 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001046 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +00001047 if hasattr(self, methodname):
1048 return getattr(self, methodname)(x, level)
1049 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001050
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +00001051 def repr_string(self, x, level):
1052 test = cram(x, self.maxstring)
1053 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001054 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +00001055 # Backslashes are only literal in the string and are never
1056 # needed to make any special characters, so show a raw string.
1057 return 'r' + testrepr[0] + test + testrepr[0]
1058 return testrepr
1059
Skip Montanarodf708782002-03-07 22:58:02 +00001060 repr_str = repr_string
1061
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001062 def repr_instance(self, x, level):
1063 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001064 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001065 except:
1066 return '<%s instance>' % x.__class__.__name__
1067
1068class TextDoc(Doc):
1069 """Formatter class for text documentation."""
1070
1071 # ------------------------------------------- text formatting utilities
1072
1073 _repr_instance = TextRepr()
1074 repr = _repr_instance.repr
1075
1076 def bold(self, text):
1077 """Format a string in bold by overstriking."""
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001078 return ''.join(ch + '\b' + ch for ch in text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001079
1080 def indent(self, text, prefix=' '):
1081 """Indent text by prepending a given prefix to each line."""
1082 if not text: return ''
Collin Winter72e110c2007-07-17 00:27:30 +00001083 lines = [prefix + line for line in text.split('\n')]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001084 if lines: lines[-1] = lines[-1].rstrip()
1085 return '\n'.join(lines)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001086
1087 def section(self, title, contents):
1088 """Format a section with a given heading."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001089 clean_contents = self.indent(contents).rstrip()
1090 return self.bold(title) + '\n' + clean_contents + '\n\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001091
1092 # ---------------------------------------------- type-specific routines
1093
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001094 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001095 """Render in text a class tree as returned by inspect.getclasstree()."""
1096 result = ''
1097 for entry in tree:
1098 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001099 c, bases = entry
1100 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001101 if bases and bases != (parent,):
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001102 parents = (classname(c, modname) for c in bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001103 result = result + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001104 result = result + '\n'
1105 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001106 result = result + self.formattree(
1107 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001108 return result
1109
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001110 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001111 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001112 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001113 synop, desc = splitdoc(getdoc(object))
1114 result = self.section('NAME', name + (synop and ' - ' + synop))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001115 all = getattr(object, '__all__', None)
Skip Montanaro4997a692003-09-10 16:47:51 +00001116 docloc = self.getdocloc(object)
1117 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001118 result = result + self.section('MODULE REFERENCE', docloc + """
1119
Éric Araujo647ef8c2011-09-11 00:43:20 +02001120The following documentation is automatically generated from the Python
1121source files. It may be incomplete, incorrect or include features that
1122are considered implementation detail and may vary between Python
1123implementations. When in doubt, consult the module reference at the
1124location listed above.
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001125""")
Skip Montanaro4997a692003-09-10 16:47:51 +00001126
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001127 if desc:
1128 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001129
1130 classes = []
1131 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001132 # if __all__ exists, believe it. Otherwise use old heuristic.
1133 if (all is not None
1134 or (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001135 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001136 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001137 funcs = []
1138 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001139 # if __all__ exists, believe it. Otherwise use old heuristic.
1140 if (all is not None or
1141 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001142 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001143 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001144 data = []
1145 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001146 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001147 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001148
Christian Heimes1af737c2008-01-23 08:24:23 +00001149 modpkgs = []
1150 modpkgs_names = set()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001151 if hasattr(object, '__path__'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001152 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
Christian Heimes1af737c2008-01-23 08:24:23 +00001153 modpkgs_names.add(modname)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001154 if ispkg:
1155 modpkgs.append(modname + ' (package)')
1156 else:
1157 modpkgs.append(modname)
1158
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001159 modpkgs.sort()
1160 result = result + self.section(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001161 'PACKAGE CONTENTS', '\n'.join(modpkgs))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001162
Christian Heimes1af737c2008-01-23 08:24:23 +00001163 # Detect submodules as sometimes created by C extensions
1164 submodules = []
1165 for key, value in inspect.getmembers(object, inspect.ismodule):
1166 if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1167 submodules.append(key)
1168 if submodules:
1169 submodules.sort()
1170 result = result + self.section(
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001171 'SUBMODULES', '\n'.join(submodules))
Christian Heimes1af737c2008-01-23 08:24:23 +00001172
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001173 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001174 classlist = [value for key, value in classes]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001175 contents = [self.formattree(
1176 inspect.getclasstree(classlist, 1), name)]
1177 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001178 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001179 result = result + self.section('CLASSES', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001180
1181 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001182 contents = []
1183 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001184 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001185 result = result + self.section('FUNCTIONS', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001186
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001187 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001188 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001189 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001190 contents.append(self.docother(value, key, name, maxlen=70))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001191 result = result + self.section('DATA', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001192
1193 if hasattr(object, '__version__'):
1194 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001195 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001196 version = version[11:-1].strip()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001197 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001198 if hasattr(object, '__date__'):
1199 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001200 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001201 result = result + self.section('AUTHOR', str(object.__author__))
1202 if hasattr(object, '__credits__'):
1203 result = result + self.section('CREDITS', str(object.__credits__))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001204 try:
1205 file = inspect.getabsfile(object)
1206 except TypeError:
1207 file = '(built-in)'
1208 result = result + self.section('FILE', file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001209 return result
1210
Georg Brandl9bd45f992010-12-03 09:58:38 +00001211 def docclass(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001212 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001213 realname = object.__name__
1214 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001215 bases = object.__bases__
1216
Tim Petersc86f6ca2001-09-26 21:31:51 +00001217 def makename(c, m=object.__module__):
1218 return classname(c, m)
1219
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001220 if name == realname:
1221 title = 'class ' + self.bold(realname)
1222 else:
1223 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001224 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001225 parents = map(makename, bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001226 title = title + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001227
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001228 contents = []
Tim Peters28355492001-09-23 21:29:55 +00001229 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001230
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001231 try:
1232 signature = inspect.signature(object)
1233 except (ValueError, TypeError):
1234 signature = None
1235 if signature:
1236 argspec = str(signature)
Serhiy Storchaka213f2292017-01-23 14:02:35 +02001237 if argspec and argspec != '()':
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001238 push(name + argspec + '\n')
1239
1240 doc = getdoc(object)
1241 if doc:
1242 push(doc + '\n')
1243
Tim Petersc86f6ca2001-09-26 21:31:51 +00001244 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001245 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001246 if len(mro) > 2:
1247 push("Method resolution order:")
1248 for base in mro:
1249 push(' ' + makename(base))
1250 push('')
1251
Sanyam Khuranaa323cdc2018-10-21 00:22:02 -07001252 # List the built-in subclasses, if any:
1253 subclasses = sorted(
Sanyam Khuranab539cef2018-12-31 10:44:47 +05301254 (str(cls.__name__) for cls in type.__subclasses__(object)
Sanyam Khuranaa323cdc2018-10-21 00:22:02 -07001255 if not cls.__name__.startswith("_") and cls.__module__ == "builtins"),
1256 key=str.lower
1257 )
1258 no_of_subclasses = len(subclasses)
1259 MAX_SUBCLASSES_TO_DISPLAY = 4
1260 if subclasses:
1261 push("Built-in subclasses:")
1262 for subclassname in subclasses[:MAX_SUBCLASSES_TO_DISPLAY]:
1263 push(' ' + subclassname)
1264 if no_of_subclasses > MAX_SUBCLASSES_TO_DISPLAY:
1265 push(' ... and ' +
1266 str(no_of_subclasses - MAX_SUBCLASSES_TO_DISPLAY) +
1267 ' other subclasses')
1268 push('')
1269
Tim Petersf4aad8e2001-09-24 22:40:47 +00001270 # Cute little class to pump out a horizontal rule between sections.
1271 class HorizontalRule:
1272 def __init__(self):
1273 self.needone = 0
1274 def maybe(self):
1275 if self.needone:
1276 push('-' * 70)
1277 self.needone = 1
1278 hr = HorizontalRule()
1279
Tim Peters28355492001-09-23 21:29:55 +00001280 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001281 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001282 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001283 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001284 push(msg)
1285 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +01001286 try:
1287 value = getattr(object, name)
1288 except Exception:
1289 # Some descriptors may meet a failure in their __get__.
1290 # (bug #1785)
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001291 push(self.docdata(value, name, mod))
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +01001292 else:
1293 push(self.document(value,
1294 name, mod, object))
Tim Peters28355492001-09-23 21:29:55 +00001295 return attrs
1296
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001297 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001298 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001299 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001300 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001301 push(msg)
1302 for name, kind, homecls, value in ok:
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001303 push(self.docdata(value, name, mod))
Tim Peters28355492001-09-23 21:29:55 +00001304 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001305
Tim Petersfa26f7c2001-09-24 08:05:11 +00001306 def spilldata(msg, attrs, predicate):
1307 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001308 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001309 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001310 push(msg)
1311 for name, kind, homecls, value in ok:
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001312 if callable(value) or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001313 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001314 else:
1315 doc = None
Serhiy Storchaka056eb022014-02-19 23:05:12 +02001316 try:
1317 obj = getattr(object, name)
1318 except AttributeError:
1319 obj = homecls.__dict__[name]
1320 push(self.docother(obj, name, mod, maxlen=70, doc=doc) +
1321 '\n')
Tim Peters28355492001-09-23 21:29:55 +00001322 return attrs
1323
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001324 attrs = [(name, kind, cls, value)
1325 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -07001326 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001327
Tim Petersfa26f7c2001-09-24 08:05:11 +00001328 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001329 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001330 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001331 else:
1332 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001333 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1334
Cheryl Sabellac95c93d2019-05-24 06:43:29 -04001335 if object is not builtins.object and thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001336 attrs = inherited
1337 continue
1338 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001339 tag = "defined here"
1340 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001341 tag = "inherited from %s" % classname(thisclass,
1342 object.__module__)
Raymond Hettinger95801bb2015-08-18 22:25:16 -07001343
1344 sort_attributes(attrs, object)
Tim Peters28355492001-09-23 21:29:55 +00001345
1346 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001347 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001348 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001349 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001350 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001351 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001352 lambda t: t[1] == 'static method')
Raymond Hettinger62be3382019-03-24 17:07:47 -07001353 attrs = spilldescriptors("Readonly properties %s:\n" % tag, attrs,
1354 lambda t: t[1] == 'readonly property')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001355 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1356 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001357 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1358 lambda t: t[1] == 'data')
Ethan Furmanb0c84cd2013-10-20 22:37:39 -07001359
Tim Peters28355492001-09-23 21:29:55 +00001360 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001361 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001362
1363 contents = '\n'.join(contents)
1364 if not contents:
1365 return title + '\n'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001366 return title + '\n' + self.indent(contents.rstrip(), ' | ') + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001367
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001368 def formatvalue(self, object):
1369 """Format an argument default value as text."""
1370 return '=' + self.repr(object)
1371
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001372 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001373 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001374 realname = object.__name__
1375 name = name or realname
1376 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001377 skipdocs = 0
Larry Hastings24a882b2014-02-20 23:34:46 -08001378 if _is_bound_method(object):
Christian Heimesff737952007-11-27 10:40:20 +00001379 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001380 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001381 if imclass is not cl:
1382 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001383 else:
Christian Heimesff737952007-11-27 10:40:20 +00001384 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001385 note = ' method of %s instance' % classname(
Christian Heimesff737952007-11-27 10:40:20 +00001386 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001387 else:
1388 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001389
Dan Rose2a37f8f2019-05-24 06:38:01 -05001390 if (inspect.iscoroutinefunction(object) or
1391 inspect.isasyncgenfunction(object)):
1392 asyncqualifier = 'async '
1393 else:
1394 asyncqualifier = ''
1395
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001396 if name == realname:
1397 title = self.bold(realname)
1398 else:
Serhiy Storchakaa44d34e2018-11-08 08:48:11 +02001399 if cl and inspect.getattr_static(cl, realname, []) is object:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001400 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001401 title = self.bold(name) + ' = ' + realname
Larry Hastings44e2eaa2013-11-23 15:37:55 -08001402 argspec = None
Larry Hastings5c661892014-01-24 06:17:25 -08001403
1404 if inspect.isroutine(object):
1405 try:
1406 signature = inspect.signature(object)
1407 except (ValueError, TypeError):
1408 signature = None
Larry Hastings44e2eaa2013-11-23 15:37:55 -08001409 if signature:
1410 argspec = str(signature)
1411 if realname == '<lambda>':
1412 title = self.bold(name) + ' lambda '
1413 # XXX lambda's won't usually have func_annotations['return']
1414 # since the syntax doesn't support but it is possible.
1415 # So removing parentheses isn't truly safe.
1416 argspec = argspec[1:-1] # remove parentheses
1417 if not argspec:
Tim Peters4bcfa312001-09-20 06:08:24 +00001418 argspec = '(...)'
Dan Rose2a37f8f2019-05-24 06:38:01 -05001419 decl = asyncqualifier + title + argspec + note
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001420
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001421 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001422 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001423 else:
1424 doc = getdoc(object) or ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001425 return decl + '\n' + (doc and self.indent(doc).rstrip() + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001426
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001427 def docdata(self, object, name=None, mod=None, cl=None):
1428 """Produce text documentation for a data descriptor."""
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001429 results = []
1430 push = results.append
1431
1432 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001433 push(self.bold(name))
1434 push('\n')
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001435 doc = getdoc(object) or ''
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001436 if doc:
1437 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001438 push('\n')
1439 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001440
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001441 docproperty = docdata
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001442
Georg Brandl8b813db2005-10-01 16:32:31 +00001443 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001444 """Produce text documentation for a data object."""
1445 repr = self.repr(object)
1446 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001447 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001448 chop = maxlen - len(line)
1449 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001450 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001451 if doc is not None:
1452 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001453 return line
1454
Georg Brandld80d5f42010-12-03 07:47:22 +00001455class _PlainTextDoc(TextDoc):
1456 """Subclass of TextDoc which overrides string styling"""
1457 def bold(self, text):
1458 return text
1459
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001460# --------------------------------------------------------- user interfaces
1461
1462def pager(text):
1463 """The first time this is called, determine what kind of pager to use."""
1464 global pager
1465 pager = getpager()
1466 pager(text)
1467
1468def getpager():
1469 """Decide what method to use for paging through text."""
Benjamin Peterson159824e2014-06-07 20:14:26 -07001470 if not hasattr(sys.stdin, "isatty"):
1471 return plainpager
Guido van Rossuma01a8b62007-05-27 09:20:14 +00001472 if not hasattr(sys.stdout, "isatty"):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001473 return plainpager
1474 if not sys.stdin.isatty() or not sys.stdout.isatty():
1475 return plainpager
doko@ubuntu.com96575452016-06-14 08:39:31 +02001476 use_pager = os.environ.get('MANPAGER') or os.environ.get('PAGER')
1477 if use_pager:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001478 if sys.platform == 'win32': # pipes completely broken in Windows
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001479 return lambda text: tempfilepager(plain(text), use_pager)
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001480 elif os.environ.get('TERM') in ('dumb', 'emacs'):
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001481 return lambda text: pipepager(plain(text), use_pager)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001482 else:
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001483 return lambda text: pipepager(text, use_pager)
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001484 if os.environ.get('TERM') in ('dumb', 'emacs'):
1485 return plainpager
Jesus Cea4791a242012-10-05 03:15:39 +02001486 if sys.platform == 'win32':
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001487 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001488 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001489 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001490
1491 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001492 (fd, filename) = tempfile.mkstemp()
1493 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001494 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001495 if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001496 return lambda text: pipepager(text, 'more')
1497 else:
1498 return ttypager
1499 finally:
1500 os.unlink(filename)
1501
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001502def plain(text):
1503 """Remove boldface formatting from text."""
1504 return re.sub('.\b', '', text)
1505
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001506def pipepager(text, cmd):
1507 """Page through text by feeding it to another program."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001508 import subprocess
1509 proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001510 try:
R David Murray1058cda2015-03-29 15:15:40 -04001511 with io.TextIOWrapper(proc.stdin, errors='backslashreplace') as pipe:
R David Murraye7f5e142015-03-30 10:14:47 -04001512 try:
1513 pipe.write(text)
1514 except KeyboardInterrupt:
1515 # We've hereby abandoned whatever text hasn't been written,
1516 # but the pager is still in control of the terminal.
1517 pass
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001518 except OSError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001519 pass # Ignore broken pipes caused by quitting the pager program.
R David Murray1058cda2015-03-29 15:15:40 -04001520 while True:
1521 try:
1522 proc.wait()
1523 break
1524 except KeyboardInterrupt:
1525 # Ignore ctl-c like the pager itself does. Otherwise the pager is
1526 # left running and the terminal is in raw mode and unusable.
1527 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001528
1529def tempfilepager(text, cmd):
1530 """Page through text by invoking a program on a temporary file."""
1531 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001532 filename = tempfile.mktemp()
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001533 with open(filename, 'w', errors='backslashreplace') as file:
Giampaolo Rodola'2f50aaf2013-02-12 02:04:27 +01001534 file.write(text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001535 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001536 os.system(cmd + ' "' + filename + '"')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001537 finally:
1538 os.unlink(filename)
1539
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001540def _escape_stdout(text):
1541 # Escape non-encodable characters to avoid encoding errors later
1542 encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8'
1543 return text.encode(encoding, 'backslashreplace').decode(encoding)
1544
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001545def ttypager(text):
1546 """Page through text on a text terminal."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001547 lines = plain(_escape_stdout(text)).split('\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001548 try:
1549 import tty
1550 fd = sys.stdin.fileno()
1551 old = tty.tcgetattr(fd)
1552 tty.setcbreak(fd)
1553 getchar = lambda: sys.stdin.read(1)
Serhiy Storchakaab5e9b92014-11-28 00:09:29 +02001554 except (ImportError, AttributeError, io.UnsupportedOperation):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001555 tty = None
1556 getchar = lambda: sys.stdin.readline()[:-1][:1]
1557
1558 try:
Serhiy Storchakaab5e9b92014-11-28 00:09:29 +02001559 try:
1560 h = int(os.environ.get('LINES', 0))
1561 except ValueError:
1562 h = 0
1563 if h <= 1:
1564 h = 25
1565 r = inc = h - 1
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001566 sys.stdout.write('\n'.join(lines[:inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001567 while lines[r:]:
1568 sys.stdout.write('-- more --')
1569 sys.stdout.flush()
1570 c = getchar()
1571
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001572 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001573 sys.stdout.write('\r \r')
1574 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001575 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001576 sys.stdout.write('\r \r' + lines[r] + '\n')
1577 r = r + 1
1578 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001579 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001580 r = r - inc - inc
1581 if r < 0: r = 0
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001582 sys.stdout.write('\n' + '\n'.join(lines[r:r+inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001583 r = r + inc
1584
1585 finally:
1586 if tty:
1587 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1588
1589def plainpager(text):
1590 """Simply print unformatted text. This is the ultimate fallback."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001591 sys.stdout.write(plain(_escape_stdout(text)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001592
1593def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001594 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001595 if inspect.ismodule(thing):
1596 if thing.__name__ in sys.builtin_module_names:
1597 return 'built-in module ' + thing.__name__
1598 if hasattr(thing, '__path__'):
1599 return 'package ' + thing.__name__
1600 else:
1601 return 'module ' + thing.__name__
1602 if inspect.isbuiltin(thing):
1603 return 'built-in function ' + thing.__name__
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001604 if inspect.isgetsetdescriptor(thing):
1605 return 'getset descriptor %s.%s.%s' % (
1606 thing.__objclass__.__module__, thing.__objclass__.__name__,
1607 thing.__name__)
1608 if inspect.ismemberdescriptor(thing):
1609 return 'member descriptor %s.%s.%s' % (
1610 thing.__objclass__.__module__, thing.__objclass__.__name__,
1611 thing.__name__)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001612 if inspect.isclass(thing):
1613 return 'class ' + thing.__name__
1614 if inspect.isfunction(thing):
1615 return 'function ' + thing.__name__
1616 if inspect.ismethod(thing):
1617 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001618 return type(thing).__name__
1619
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001620def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001621 """Locate an object by name or dotted path, importing as necessary."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001622 parts = [part for part in path.split('.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001623 module, n = None, 0
1624 while n < len(parts):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001625 nextmodule = safeimport('.'.join(parts[:n+1]), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001626 if nextmodule: module, n = nextmodule, n + 1
1627 else: break
1628 if module:
1629 object = module
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001630 else:
Éric Araujoe64e51b2011-07-29 17:03:55 +02001631 object = builtins
1632 for part in parts[n:]:
1633 try:
1634 object = getattr(object, part)
1635 except AttributeError:
1636 return None
1637 return object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001638
1639# --------------------------------------- interactive interpreter interface
1640
1641text = TextDoc()
Georg Brandld80d5f42010-12-03 07:47:22 +00001642plaintext = _PlainTextDoc()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001643html = HTMLDoc()
1644
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001645def resolve(thing, forceload=0):
1646 """Given an object or a path to an object, get the object and its name."""
1647 if isinstance(thing, str):
1648 object = locate(thing, forceload)
Serhiy Storchakab6076fb2015-04-21 21:09:48 +03001649 if object is None:
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001650 raise ImportError('''\
1651No Python documentation found for %r.
1652Use help() to get the interactive help utility.
1653Use help(str) for help on the str class.''' % thing)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001654 return object, thing
1655 else:
R David Murrayc43125a2012-04-23 13:23:57 -04001656 name = getattr(thing, '__name__', None)
1657 return thing, name if isinstance(name, str) else None
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001658
Georg Brandld80d5f42010-12-03 07:47:22 +00001659def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
1660 renderer=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001661 """Render text documentation, given an object or a path to an object."""
Georg Brandld80d5f42010-12-03 07:47:22 +00001662 if renderer is None:
1663 renderer = text
Guido van Rossumd8faa362007-04-27 19:54:29 +00001664 object, name = resolve(thing, forceload)
1665 desc = describe(object)
1666 module = inspect.getmodule(object)
1667 if name and '.' in name:
1668 desc += ' in ' + name[:name.rfind('.')]
1669 elif module and module is not object:
1670 desc += ' in module ' + module.__name__
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001671
1672 if not (inspect.ismodule(object) or
Guido van Rossumd8faa362007-04-27 19:54:29 +00001673 inspect.isclass(object) or
1674 inspect.isroutine(object) or
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001675 inspect.isdatadescriptor(object)):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001676 # If the passed object is a piece of data or an instance,
1677 # document its available methods instead of its value.
1678 object = type(object)
1679 desc += ' object'
Georg Brandld80d5f42010-12-03 07:47:22 +00001680 return title % desc + '\n\n' + renderer.document(object, name)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001681
Georg Brandld80d5f42010-12-03 07:47:22 +00001682def doc(thing, title='Python Library Documentation: %s', forceload=0,
1683 output=None):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001684 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001685 try:
Georg Brandld80d5f42010-12-03 07:47:22 +00001686 if output is None:
1687 pager(render_doc(thing, title, forceload))
1688 else:
1689 output.write(render_doc(thing, title, forceload, plaintext))
Guido van Rossumb940e112007-01-10 16:19:56 +00001690 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001691 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001692
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001693def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001694 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001695 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001696 object, name = resolve(thing, forceload)
1697 page = html.page(describe(object), html.document(object, name))
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +03001698 with open(name + '.html', 'w', encoding='utf-8') as file:
1699 file.write(page)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001700 print('wrote', name + '.html')
Guido van Rossumb940e112007-01-10 16:19:56 +00001701 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001702 print(value)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001703
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001704def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001705 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001706 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001707 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1708 writedoc(modname)
1709 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001710
1711class Helper:
Georg Brandl6b38daa2008-06-01 21:05:17 +00001712
1713 # These dictionaries map a topic name to either an alias, or a tuple
1714 # (label, seealso-items). The "label" is the label of the corresponding
1715 # section in the .rst file under Doc/ and an index into the dictionary
Georg Brandl5617db82009-04-27 16:28:57 +00001716 # in pydoc_data/topics.py.
Georg Brandl6b38daa2008-06-01 21:05:17 +00001717 #
1718 # CAUTION: if you change one of these dictionaries, be sure to adapt the
Jelle Zijlstraac317702017-10-05 20:24:46 -07001719 # list of needed labels in Doc/tools/extensions/pyspecific.py and
Georg Brandl5617db82009-04-27 16:28:57 +00001720 # regenerate the pydoc_data/topics.py file by running
Georg Brandl6b38daa2008-06-01 21:05:17 +00001721 # make pydoc-topics
1722 # in Doc/ and copying the output file into the Lib/ directory.
1723
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001724 keywords = {
Ezio Melottib185a042011-04-28 07:42:55 +03001725 'False': '',
1726 'None': '',
1727 'True': '',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001728 'and': 'BOOLEAN',
Guido van Rossumd8faa362007-04-27 19:54:29 +00001729 'as': 'with',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001730 'assert': ('assert', ''),
Jelle Zijlstraac317702017-10-05 20:24:46 -07001731 'async': ('async', ''),
1732 'await': ('await', ''),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001733 'break': ('break', 'while for'),
1734 'class': ('class', 'CLASSES SPECIALMETHODS'),
1735 'continue': ('continue', 'while for'),
1736 'def': ('function', ''),
1737 'del': ('del', 'BASICMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001738 'elif': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001739 'else': ('else', 'while for'),
Georg Brandl0d855392008-08-30 19:53:05 +00001740 'except': 'try',
1741 'finally': 'try',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001742 'for': ('for', 'break continue while'),
Georg Brandl0d855392008-08-30 19:53:05 +00001743 'from': 'import',
Georg Brandl74abf6f2010-11-20 19:54:36 +00001744 'global': ('global', 'nonlocal NAMESPACES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001745 'if': ('if', 'TRUTHVALUE'),
1746 'import': ('import', 'MODULES'),
Georg Brandl395ed242009-09-04 08:07:32 +00001747 'in': ('in', 'SEQUENCEMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001748 'is': 'COMPARISON',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001749 'lambda': ('lambda', 'FUNCTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001750 'nonlocal': ('nonlocal', 'global NAMESPACES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001751 'not': 'BOOLEAN',
1752 'or': 'BOOLEAN',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001753 'pass': ('pass', ''),
1754 'raise': ('raise', 'EXCEPTIONS'),
1755 'return': ('return', 'FUNCTIONS'),
1756 'try': ('try', 'EXCEPTIONS'),
1757 'while': ('while', 'break continue if TRUTHVALUE'),
1758 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1759 'yield': ('yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001760 }
Georg Brandldb7b6b92009-01-01 15:53:14 +00001761 # Either add symbols to this dictionary or to the symbols dictionary
1762 # directly: Whichever is easier. They are merged later.
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001763 _strprefixes = [p + q for p in ('b', 'f', 'r', 'u') for q in ("'", '"')]
Georg Brandldb7b6b92009-01-01 15:53:14 +00001764 _symbols_inverse = {
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001765 'STRINGS' : ("'", "'''", '"', '"""', *_strprefixes),
Georg Brandldb7b6b92009-01-01 15:53:14 +00001766 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1767 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1768 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1769 'UNARY' : ('-', '~'),
1770 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1771 '^=', '<<=', '>>=', '**=', '//='),
1772 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1773 'COMPLEX' : ('j', 'J')
1774 }
1775 symbols = {
1776 '%': 'OPERATORS FORMATTING',
1777 '**': 'POWER',
1778 ',': 'TUPLES LISTS FUNCTIONS',
1779 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1780 '...': 'ELLIPSIS',
1781 ':': 'SLICINGS DICTIONARYLITERALS',
1782 '@': 'def class',
1783 '\\': 'STRINGS',
1784 '_': 'PRIVATENAMES',
1785 '__': 'PRIVATENAMES SPECIALMETHODS',
1786 '`': 'BACKQUOTES',
1787 '(': 'TUPLES FUNCTIONS CALLS',
1788 ')': 'TUPLES FUNCTIONS CALLS',
1789 '[': 'LISTS SUBSCRIPTS SLICINGS',
1790 ']': 'LISTS SUBSCRIPTS SLICINGS'
1791 }
1792 for topic, symbols_ in _symbols_inverse.items():
1793 for symbol in symbols_:
1794 topics = symbols.get(symbol, topic)
1795 if topic not in topics:
1796 topics = topics + ' ' + topic
1797 symbols[symbol] = topics
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001798
1799 topics = {
Georg Brandl6b38daa2008-06-01 21:05:17 +00001800 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1801 'FUNCTIONS CLASSES MODULES FILES inspect'),
1802 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
1803 'FORMATTING TYPES'),
1804 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1805 'FORMATTING': ('formatstrings', 'OPERATORS'),
1806 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1807 'FORMATTING TYPES'),
1808 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1809 'INTEGER': ('integers', 'int range'),
1810 'FLOAT': ('floating', 'float math'),
1811 'COMPLEX': ('imaginary', 'complex cmath'),
1812 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001813 'MAPPINGS': 'DICTIONARIES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001814 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1815 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1816 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1817 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001818 'FRAMEOBJECTS': 'TYPES',
1819 'TRACEBACKS': 'TYPES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001820 'NONE': ('bltin-null-object', ''),
1821 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001822 'SPECIALATTRIBUTES': ('specialattrs', ''),
1823 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1824 'MODULES': ('typesmodules', 'import'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001825 'PACKAGES': 'import',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001826 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1827 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1828 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1829 'LISTS DICTIONARIES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001830 'OPERATORS': 'EXPRESSIONS',
1831 'PRECEDENCE': 'EXPRESSIONS',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001832 'OBJECTS': ('objects', 'TYPES'),
1833 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
Georg Brandl395ed242009-09-04 08:07:32 +00001834 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
1835 'NUMBERMETHODS CLASSES'),
Mark Dickinsona56c4672009-01-27 18:17:45 +00001836 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001837 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1838 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001839 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
Georg Brandl6b38daa2008-06-01 21:05:17 +00001840 'SPECIALMETHODS'),
1841 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1842 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1843 'SPECIALMETHODS'),
1844 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001845 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001846 'DYNAMICFEATURES': ('dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001847 'SCOPING': 'NAMESPACES',
1848 'FRAMES': 'NAMESPACES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001849 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1850 'CONVERSIONS': ('conversions', ''),
1851 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1852 'SPECIALIDENTIFIERS': ('id-classes', ''),
1853 'PRIVATENAMES': ('atom-identifiers', ''),
1854 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
1855 'LISTLITERALS DICTIONARYLITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001856 'TUPLES': 'SEQUENCES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001857 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1858 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1859 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1860 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1861 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1862 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001863 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
1864 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001865 'CALLS': ('calls', 'EXPRESSIONS'),
1866 'POWER': ('power', 'EXPRESSIONS'),
1867 'UNARY': ('unary', 'EXPRESSIONS'),
1868 'BINARY': ('binary', 'EXPRESSIONS'),
1869 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1870 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1871 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1872 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001873 'ASSERTION': 'assert',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001874 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1875 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001876 'DELETION': 'del',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001877 'RETURNING': 'return',
1878 'IMPORTING': 'import',
1879 'CONDITIONAL': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001880 'LOOPING': ('compound', 'for while break continue'),
1881 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1882 'DEBUGGING': ('debugger', 'pdb'),
1883 'CONTEXTMANAGERS': ('context-managers', 'with'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001884 }
1885
Georg Brandl78aa3962010-07-31 21:51:48 +00001886 def __init__(self, input=None, output=None):
1887 self._input = input
1888 self._output = output
1889
Serhiy Storchakabdf6b912017-03-19 08:40:32 +02001890 @property
1891 def input(self):
1892 return self._input or sys.stdin
1893
1894 @property
1895 def output(self):
1896 return self._output or sys.stdout
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001897
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001898 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001899 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001900 self()
1901 return ''
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001902 return '<%s.%s instance>' % (self.__class__.__module__,
1903 self.__class__.__qualname__)
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001904
Alexander Belopolsky2e733c92010-07-04 17:00:20 +00001905 _GoInteractive = object()
1906 def __call__(self, request=_GoInteractive):
1907 if request is not self._GoInteractive:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001908 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001909 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001910 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001911 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001912 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001913You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001914If you want to ask for help on a particular object directly from the
1915interpreter, you can type "help(object)". Executing "help('string')"
1916has the same effect as typing a particular string at the help> prompt.
1917''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001918
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001919 def interact(self):
1920 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001921 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001922 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001923 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001924 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001925 except (KeyboardInterrupt, EOFError):
1926 break
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001927 request = request.strip()
1928
1929 # Make sure significant trailing quoting marks of literals don't
1930 # get deleted while cleaning input
1931 if (len(request) > 2 and request[0] == request[-1] in ("'", '"')
1932 and request[0] not in request[1:-1]):
1933 request = request[1:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001934 if request.lower() in ('q', 'quit'): break
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001935 if request == 'help':
1936 self.intro()
1937 else:
1938 self.help(request)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001939
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001940 def getline(self, prompt):
Guido van Rossum7c086c02008-01-02 03:52:38 +00001941 """Read one line, using input() when appropriate."""
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001942 if self.input is sys.stdin:
Guido van Rossum7c086c02008-01-02 03:52:38 +00001943 return input(prompt)
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001944 else:
1945 self.output.write(prompt)
1946 self.output.flush()
1947 return self.input.readline()
1948
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001949 def help(self, request):
1950 if type(request) is type(''):
R. David Murray1f1b9d32009-05-27 20:56:59 +00001951 request = request.strip()
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001952 if request == 'keywords': self.listkeywords()
Georg Brandldb7b6b92009-01-01 15:53:14 +00001953 elif request == 'symbols': self.listsymbols()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001954 elif request == 'topics': self.listtopics()
1955 elif request == 'modules': self.listmodules()
1956 elif request[:8] == 'modules ':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001957 self.listmodules(request.split()[1])
Georg Brandldb7b6b92009-01-01 15:53:14 +00001958 elif request in self.symbols: self.showsymbol(request)
Ezio Melottib185a042011-04-28 07:42:55 +03001959 elif request in ['True', 'False', 'None']:
1960 # special case these keywords since they are objects too
1961 doc(eval(request), 'Help on %s:')
Raymond Hettinger54f02222002-06-01 14:18:47 +00001962 elif request in self.keywords: self.showtopic(request)
1963 elif request in self.topics: self.showtopic(request)
Georg Brandld80d5f42010-12-03 07:47:22 +00001964 elif request: doc(request, 'Help on %s:', output=self._output)
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001965 else: doc(str, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001966 elif isinstance(request, Helper): self()
Georg Brandld80d5f42010-12-03 07:47:22 +00001967 else: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001968 self.output.write('\n')
1969
1970 def intro(self):
1971 self.output.write('''
Serhiy Storchaka885bdc42016-02-11 13:10:36 +02001972Welcome to Python {0}'s help utility!
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001973
1974If this is your first time using Python, you should definitely check out
oldke5681b92017-12-28 22:37:46 +08001975the tutorial on the Internet at https://docs.python.org/{0}/tutorial/.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001976
1977Enter the name of any module, keyword, or topic to get help on writing
1978Python programs and using Python modules. To quit this help utility and
1979return to the interpreter, just type "quit".
1980
Terry Jan Reedy34200572013-02-11 02:23:13 -05001981To get a list of available modules, keywords, symbols, or topics, type
1982"modules", "keywords", "symbols", or "topics". Each module also comes
1983with a one-line summary of what it does; to list the modules whose name
1984or summary contain a given string such as "spam", type "modules spam".
Serhiy Storchaka885bdc42016-02-11 13:10:36 +02001985'''.format('%d.%d' % sys.version_info[:2]))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001986
1987 def list(self, items, columns=4, width=80):
Guido van Rossum486364b2007-06-30 05:01:58 +00001988 items = list(sorted(items))
1989 colw = width // columns
1990 rows = (len(items) + columns - 1) // columns
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001991 for row in range(rows):
1992 for col in range(columns):
1993 i = col * rows + row
1994 if i < len(items):
1995 self.output.write(items[i])
1996 if col < columns - 1:
Guido van Rossum486364b2007-06-30 05:01:58 +00001997 self.output.write(' ' + ' ' * (colw - 1 - len(items[i])))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001998 self.output.write('\n')
1999
2000 def listkeywords(self):
2001 self.output.write('''
2002Here is a list of the Python keywords. Enter any keyword to get more help.
2003
2004''')
2005 self.list(self.keywords.keys())
2006
Georg Brandldb7b6b92009-01-01 15:53:14 +00002007 def listsymbols(self):
2008 self.output.write('''
2009Here is a list of the punctuation symbols which Python assigns special meaning
2010to. Enter any symbol to get more help.
2011
2012''')
2013 self.list(self.symbols.keys())
2014
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002015 def listtopics(self):
2016 self.output.write('''
2017Here is a list of available topics. Enter any topic name to get more help.
2018
2019''')
2020 self.list(self.topics.keys())
2021
Georg Brandldb7b6b92009-01-01 15:53:14 +00002022 def showtopic(self, topic, more_xrefs=''):
Georg Brandl6b38daa2008-06-01 21:05:17 +00002023 try:
Georg Brandl5617db82009-04-27 16:28:57 +00002024 import pydoc_data.topics
Brett Cannoncd171c82013-07-04 17:43:24 -04002025 except ImportError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002026 self.output.write('''
Georg Brandl6b38daa2008-06-01 21:05:17 +00002027Sorry, topic and keyword documentation is not available because the
Georg Brandl5617db82009-04-27 16:28:57 +00002028module "pydoc_data.topics" could not be found.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002029''')
2030 return
2031 target = self.topics.get(topic, self.keywords.get(topic))
2032 if not target:
2033 self.output.write('no documentation found for %s\n' % repr(topic))
2034 return
2035 if type(target) is type(''):
Georg Brandldb7b6b92009-01-01 15:53:14 +00002036 return self.showtopic(target, more_xrefs)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002037
Georg Brandl6b38daa2008-06-01 21:05:17 +00002038 label, xrefs = target
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002039 try:
Georg Brandl5617db82009-04-27 16:28:57 +00002040 doc = pydoc_data.topics.topics[label]
Georg Brandl6b38daa2008-06-01 21:05:17 +00002041 except KeyError:
2042 self.output.write('no documentation found for %s\n' % repr(topic))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002043 return
Berker Peksagd04f46c2018-07-23 08:37:47 +03002044 doc = doc.strip() + '\n'
Georg Brandldb7b6b92009-01-01 15:53:14 +00002045 if more_xrefs:
2046 xrefs = (xrefs or '') + ' ' + more_xrefs
Ka-Ping Yeeda793892001-04-13 11:02:51 +00002047 if xrefs:
Brett Cannon1448ecf2013-10-04 11:38:59 -04002048 import textwrap
2049 text = 'Related help topics: ' + ', '.join(xrefs.split()) + '\n'
2050 wrapped_text = textwrap.wrap(text, 72)
Berker Peksagd04f46c2018-07-23 08:37:47 +03002051 doc += '\n%s\n' % '\n'.join(wrapped_text)
2052 pager(doc)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002053
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002054 def _gettopic(self, topic, more_xrefs=''):
2055 """Return unbuffered tuple of (topic, xrefs).
2056
Georg Brandld2f38572011-01-30 08:37:19 +00002057 If an error occurs here, the exception is caught and displayed by
2058 the url handler.
2059
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002060 This function duplicates the showtopic method but returns its
2061 result directly so it can be formatted for display in an html page.
2062 """
2063 try:
2064 import pydoc_data.topics
Brett Cannoncd171c82013-07-04 17:43:24 -04002065 except ImportError:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002066 return('''
2067Sorry, topic and keyword documentation is not available because the
2068module "pydoc_data.topics" could not be found.
2069''' , '')
2070 target = self.topics.get(topic, self.keywords.get(topic))
2071 if not target:
Georg Brandld2f38572011-01-30 08:37:19 +00002072 raise ValueError('could not find topic')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002073 if isinstance(target, str):
2074 return self._gettopic(target, more_xrefs)
2075 label, xrefs = target
Georg Brandld2f38572011-01-30 08:37:19 +00002076 doc = pydoc_data.topics.topics[label]
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002077 if more_xrefs:
2078 xrefs = (xrefs or '') + ' ' + more_xrefs
2079 return doc, xrefs
2080
Georg Brandldb7b6b92009-01-01 15:53:14 +00002081 def showsymbol(self, symbol):
2082 target = self.symbols[symbol]
2083 topic, _, xrefs = target.partition(' ')
2084 self.showtopic(topic, xrefs)
2085
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002086 def listmodules(self, key=''):
2087 if key:
2088 self.output.write('''
Terry Jan Reedy34200572013-02-11 02:23:13 -05002089Here is a list of modules whose name or summary contains '{}'.
2090If there are any, enter a module name to get more help.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002091
Terry Jan Reedy34200572013-02-11 02:23:13 -05002092'''.format(key))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002093 apropos(key)
2094 else:
2095 self.output.write('''
2096Please wait a moment while I gather a list of all available modules...
2097
2098''')
2099 modules = {}
2100 def callback(path, modname, desc, modules=modules):
2101 if modname and modname[-9:] == '.__init__':
2102 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002103 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002104 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002105 def onerror(modname):
2106 callback(None, modname, None)
2107 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002108 self.list(modules.keys())
2109 self.output.write('''
2110Enter any module name to get more help. Or, type "modules spam" to search
Terry Jan Reedy34200572013-02-11 02:23:13 -05002111for modules whose name or summary contain the string "spam".
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002112''')
2113
Georg Brandl78aa3962010-07-31 21:51:48 +00002114help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002115
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002116class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002117 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002118
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002119 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002120 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002121 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002122 seen = {}
2123
2124 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002125 if modname != '__main__':
2126 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00002127 if key is None:
2128 callback(None, modname, '')
2129 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002130 name = __import__(modname).__doc__ or ''
2131 desc = name.split('\n')[0]
2132 name = modname + ' - ' + desc
2133 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002134 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002135
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002136 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002137 if self.quit:
2138 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002139
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002140 if key is None:
2141 callback(None, modname, '')
2142 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002143 try:
Eric Snow3a62d142014-01-06 20:42:59 -07002144 spec = pkgutil._get_spec(importer, modname)
Georg Brandl126c8792009-04-05 15:05:48 +00002145 except SyntaxError:
2146 # raised by tests for bad coding cookies or BOM
2147 continue
Eric Snow3a62d142014-01-06 20:42:59 -07002148 loader = spec.loader
Georg Brandl126c8792009-04-05 15:05:48 +00002149 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002150 try:
2151 source = loader.get_source(modname)
Nick Coghlan2824cb52012-07-15 22:12:14 +10002152 except Exception:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002153 if onerror:
2154 onerror(modname)
2155 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002156 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002157 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002158 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002159 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002160 path = None
2161 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002162 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -04002163 module = importlib._bootstrap._load(spec)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002164 except ImportError:
2165 if onerror:
2166 onerror(modname)
2167 continue
Benjamin Peterson54237f92015-02-16 19:45:01 -05002168 desc = module.__doc__.splitlines()[0] if module.__doc__ else ''
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002169 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002170 name = modname + ' - ' + desc
2171 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002172 callback(path, modname, desc)
2173
2174 if completer:
2175 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002176
2177def apropos(key):
2178 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002179 def callback(path, modname, desc):
2180 if modname[-9:] == '.__init__':
2181 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002182 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002183 def onerror(modname):
2184 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002185 with warnings.catch_warnings():
2186 warnings.filterwarnings('ignore') # ignore problems during import
2187 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002188
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002189# --------------------------------------- enhanced Web browser interface
2190
Feanil Patel6a396c92017-09-14 17:54:09 -04002191def _start_server(urlhandler, hostname, port):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002192 """Start an HTTP server thread on a specific port.
2193
2194 Start an HTML/text server thread, so HTML or text documents can be
2195 browsed dynamically and interactively with a Web browser. Example use:
2196
2197 >>> import time
2198 >>> import pydoc
2199
2200 Define a URL handler. To determine what the client is asking
2201 for, check the URL and content_type.
2202
2203 Then get or generate some text or HTML code and return it.
2204
2205 >>> def my_url_handler(url, content_type):
2206 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2207 ... return text
2208
2209 Start server thread on port 0.
2210 If you use port 0, the server will pick a random port number.
2211 You can then use serverthread.port to get the port number.
2212
2213 >>> port = 0
2214 >>> serverthread = pydoc._start_server(my_url_handler, port)
2215
2216 Check that the server is really started. If it is, open browser
2217 and get first page. Use serverthread.url as the starting page.
2218
2219 >>> if serverthread.serving:
2220 ... import webbrowser
2221
2222 The next two lines are commented out so a browser doesn't open if
2223 doctest is run on this module.
2224
2225 #... webbrowser.open(serverthread.url)
2226 #True
2227
2228 Let the server do its thing. We just need to monitor its status.
2229 Use time.sleep so the loop doesn't hog the CPU.
2230
Victor Stinner2cf4c202018-12-17 09:36:36 +01002231 >>> starttime = time.monotonic()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002232 >>> timeout = 1 #seconds
2233
2234 This is a short timeout for testing purposes.
2235
2236 >>> while serverthread.serving:
2237 ... time.sleep(.01)
Victor Stinner2cf4c202018-12-17 09:36:36 +01002238 ... if serverthread.serving and time.monotonic() - starttime > timeout:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002239 ... serverthread.stop()
2240 ... break
2241
2242 Print any errors that may have occurred.
2243
2244 >>> print(serverthread.error)
2245 None
2246 """
2247 import http.server
2248 import email.message
2249 import select
2250 import threading
2251
2252 class DocHandler(http.server.BaseHTTPRequestHandler):
2253
2254 def do_GET(self):
2255 """Process a request from an HTML browser.
2256
2257 The URL received is in self.path.
2258 Get an HTML page from self.urlhandler and send it.
2259 """
2260 if self.path.endswith('.css'):
2261 content_type = 'text/css'
2262 else:
2263 content_type = 'text/html'
2264 self.send_response(200)
Georg Brandld2f38572011-01-30 08:37:19 +00002265 self.send_header('Content-Type', '%s; charset=UTF-8' % content_type)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002266 self.end_headers()
2267 self.wfile.write(self.urlhandler(
2268 self.path, content_type).encode('utf-8'))
2269
2270 def log_message(self, *args):
2271 # Don't log messages.
2272 pass
2273
2274 class DocServer(http.server.HTTPServer):
2275
Feanil Patel6a396c92017-09-14 17:54:09 -04002276 def __init__(self, host, port, callback):
2277 self.host = host
Senthil Kumaran2a42a0b2014-09-17 13:17:58 +08002278 self.address = (self.host, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002279 self.callback = callback
2280 self.base.__init__(self, self.address, self.handler)
2281 self.quit = False
2282
2283 def serve_until_quit(self):
2284 while not self.quit:
2285 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2286 if rd:
2287 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002288 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002289
2290 def server_activate(self):
2291 self.base.server_activate(self)
2292 if self.callback:
2293 self.callback(self)
2294
2295 class ServerThread(threading.Thread):
2296
Feanil Patel6a396c92017-09-14 17:54:09 -04002297 def __init__(self, urlhandler, host, port):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002298 self.urlhandler = urlhandler
Feanil Patel6a396c92017-09-14 17:54:09 -04002299 self.host = host
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002300 self.port = int(port)
2301 threading.Thread.__init__(self)
2302 self.serving = False
2303 self.error = None
2304
2305 def run(self):
2306 """Start the server."""
2307 try:
2308 DocServer.base = http.server.HTTPServer
2309 DocServer.handler = DocHandler
2310 DocHandler.MessageClass = email.message.Message
2311 DocHandler.urlhandler = staticmethod(self.urlhandler)
Feanil Patel6a396c92017-09-14 17:54:09 -04002312 docsvr = DocServer(self.host, self.port, self.ready)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002313 self.docserver = docsvr
2314 docsvr.serve_until_quit()
2315 except Exception as e:
2316 self.error = e
2317
2318 def ready(self, server):
2319 self.serving = True
2320 self.host = server.host
2321 self.port = server.server_port
2322 self.url = 'http://%s:%d/' % (self.host, self.port)
2323
2324 def stop(self):
2325 """Stop the server and this thread nicely"""
2326 self.docserver.quit = True
Victor Stinner4cab2cd2017-08-21 23:24:40 +02002327 self.join()
2328 # explicitly break a reference cycle: DocServer.callback
2329 # has indirectly a reference to ServerThread.
2330 self.docserver = None
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002331 self.serving = False
2332 self.url = None
2333
Feanil Patel6a396c92017-09-14 17:54:09 -04002334 thread = ServerThread(urlhandler, hostname, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002335 thread.start()
2336 # Wait until thread.serving is True to make sure we are
2337 # really up before returning.
2338 while not thread.error and not thread.serving:
2339 time.sleep(.01)
2340 return thread
2341
2342
2343def _url_handler(url, content_type="text/html"):
2344 """The pydoc url handler for use with the pydoc server.
2345
2346 If the content_type is 'text/css', the _pydoc.css style
2347 sheet is read and returned if it exits.
2348
2349 If the content_type is 'text/html', then the result of
2350 get_html_page(url) is returned.
2351 """
2352 class _HTMLDoc(HTMLDoc):
2353
2354 def page(self, title, contents):
2355 """Format an HTML page."""
2356 css_path = "pydoc_data/_pydoc.css"
2357 css_link = (
2358 '<link rel="stylesheet" type="text/css" href="%s">' %
2359 css_path)
2360 return '''\
2361<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Georg Brandld2f38572011-01-30 08:37:19 +00002362<html><head><title>Pydoc: %s</title>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002363<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Georg Brandld2f38572011-01-30 08:37:19 +00002364%s</head><body bgcolor="#f0f0f8">%s<div style="clear:both;padding-top:.5em;">%s</div>
2365</body></html>''' % (title, css_link, html_navbar(), contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002366
2367 def filelink(self, url, path):
2368 return '<a href="getfile?key=%s">%s</a>' % (url, path)
2369
2370
2371 html = _HTMLDoc()
2372
2373 def html_navbar():
Georg Brandld2f38572011-01-30 08:37:19 +00002374 version = html.escape("%s [%s, %s]" % (platform.python_version(),
2375 platform.python_build()[0],
2376 platform.python_compiler()))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002377 return """
2378 <div style='float:left'>
Georg Brandld2f38572011-01-30 08:37:19 +00002379 Python %s<br>%s
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002380 </div>
2381 <div style='float:right'>
2382 <div style='text-align:center'>
2383 <a href="index.html">Module Index</a>
2384 : <a href="topics.html">Topics</a>
2385 : <a href="keywords.html">Keywords</a>
2386 </div>
2387 <div>
Georg Brandld2f38572011-01-30 08:37:19 +00002388 <form action="get" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002389 <input type=text name=key size=15>
2390 <input type=submit value="Get">
Georg Brandld2f38572011-01-30 08:37:19 +00002391 </form>&nbsp;
2392 <form action="search" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002393 <input type=text name=key size=15>
2394 <input type=submit value="Search">
2395 </form>
2396 </div>
2397 </div>
Georg Brandld2f38572011-01-30 08:37:19 +00002398 """ % (version, html.escape(platform.platform(terse=True)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002399
2400 def html_index():
2401 """Module Index page."""
2402
2403 def bltinlink(name):
2404 return '<a href="%s.html">%s</a>' % (name, name)
2405
2406 heading = html.heading(
2407 '<big><big><strong>Index of Modules</strong></big></big>',
2408 '#ffffff', '#7799ee')
2409 names = [name for name in sys.builtin_module_names
2410 if name != '__main__']
2411 contents = html.multicolumn(names, bltinlink)
2412 contents = [heading, '<p>' + html.bigsection(
2413 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2414
2415 seen = {}
2416 for dir in sys.path:
2417 contents.append(html.index(dir, seen))
2418
2419 contents.append(
2420 '<p align=right><font color="#909090" face="helvetica,'
2421 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2422 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002423 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002424
2425 def html_search(key):
2426 """Search results page."""
2427 # scan for modules
2428 search_result = []
2429
2430 def callback(path, modname, desc):
2431 if modname[-9:] == '.__init__':
2432 modname = modname[:-9] + ' (package)'
2433 search_result.append((modname, desc and '- ' + desc))
2434
2435 with warnings.catch_warnings():
2436 warnings.filterwarnings('ignore') # ignore problems during import
Martin Panter9ad0aae2015-11-06 00:27:14 +00002437 def onerror(modname):
2438 pass
2439 ModuleScanner().run(callback, key, onerror=onerror)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002440
2441 # format page
2442 def bltinlink(name):
2443 return '<a href="%s.html">%s</a>' % (name, name)
2444
2445 results = []
2446 heading = html.heading(
2447 '<big><big><strong>Search Results</strong></big></big>',
2448 '#ffffff', '#7799ee')
2449 for name, desc in search_result:
2450 results.append(bltinlink(name) + desc)
2451 contents = heading + html.bigsection(
2452 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002453 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002454
2455 def html_getfile(path):
2456 """Get and display a source file listing safely."""
Zachary Wareeb432142014-07-10 11:18:00 -05002457 path = urllib.parse.unquote(path)
Victor Stinner91e08772011-07-05 14:30:41 +02002458 with tokenize.open(path) as fp:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002459 lines = html.escape(fp.read())
2460 body = '<pre>%s</pre>' % lines
2461 heading = html.heading(
2462 '<big><big><strong>File Listing</strong></big></big>',
2463 '#ffffff', '#7799ee')
2464 contents = heading + html.bigsection(
2465 'File: %s' % path, '#ffffff', '#ee77aa', body)
Nick Coghlanecace282010-12-03 16:08:46 +00002466 return 'getfile %s' % path, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002467
2468 def html_topics():
2469 """Index of topic texts available."""
2470
2471 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002472 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002473
2474 heading = html.heading(
2475 '<big><big><strong>INDEX</strong></big></big>',
2476 '#ffffff', '#7799ee')
2477 names = sorted(Helper.topics.keys())
2478
2479 contents = html.multicolumn(names, bltinlink)
2480 contents = heading + html.bigsection(
2481 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002482 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002483
2484 def html_keywords():
2485 """Index of keywords."""
2486 heading = html.heading(
2487 '<big><big><strong>INDEX</strong></big></big>',
2488 '#ffffff', '#7799ee')
2489 names = sorted(Helper.keywords.keys())
2490
2491 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002492 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002493
2494 contents = html.multicolumn(names, bltinlink)
2495 contents = heading + html.bigsection(
2496 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002497 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002498
2499 def html_topicpage(topic):
2500 """Topic or keyword help page."""
2501 buf = io.StringIO()
2502 htmlhelp = Helper(buf, buf)
2503 contents, xrefs = htmlhelp._gettopic(topic)
2504 if topic in htmlhelp.keywords:
2505 title = 'KEYWORD'
2506 else:
2507 title = 'TOPIC'
2508 heading = html.heading(
2509 '<big><big><strong>%s</strong></big></big>' % title,
2510 '#ffffff', '#7799ee')
Georg Brandld2f38572011-01-30 08:37:19 +00002511 contents = '<pre>%s</pre>' % html.markup(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002512 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
Georg Brandld2f38572011-01-30 08:37:19 +00002513 if xrefs:
2514 xrefs = sorted(xrefs.split())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002515
Georg Brandld2f38572011-01-30 08:37:19 +00002516 def bltinlink(name):
2517 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002518
Georg Brandld2f38572011-01-30 08:37:19 +00002519 xrefs = html.multicolumn(xrefs, bltinlink)
2520 xrefs = html.section('Related help topics: ',
2521 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002522 return ('%s %s' % (title, topic),
2523 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002524
Georg Brandld2f38572011-01-30 08:37:19 +00002525 def html_getobj(url):
2526 obj = locate(url, forceload=1)
2527 if obj is None and url != 'None':
2528 raise ValueError('could not find object')
2529 title = describe(obj)
2530 content = html.document(obj, url)
2531 return title, content
2532
2533 def html_error(url, exc):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002534 heading = html.heading(
2535 '<big><big><strong>Error</strong></big></big>',
Georg Brandld2f38572011-01-30 08:37:19 +00002536 '#ffffff', '#7799ee')
2537 contents = '<br>'.join(html.escape(line) for line in
2538 format_exception_only(type(exc), exc))
2539 contents = heading + html.bigsection(url, '#ffffff', '#bb0000',
2540 contents)
2541 return "Error - %s" % url, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002542
2543 def get_html_page(url):
2544 """Generate an HTML page for url."""
Georg Brandld2f38572011-01-30 08:37:19 +00002545 complete_url = url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002546 if url.endswith('.html'):
2547 url = url[:-5]
Georg Brandld2f38572011-01-30 08:37:19 +00002548 try:
2549 if url in ("", "index"):
2550 title, content = html_index()
2551 elif url == "topics":
2552 title, content = html_topics()
2553 elif url == "keywords":
2554 title, content = html_keywords()
2555 elif '=' in url:
2556 op, _, url = url.partition('=')
2557 if op == "search?key":
2558 title, content = html_search(url)
2559 elif op == "getfile?key":
2560 title, content = html_getfile(url)
2561 elif op == "topic?key":
2562 # try topics first, then objects.
2563 try:
2564 title, content = html_topicpage(url)
2565 except ValueError:
2566 title, content = html_getobj(url)
2567 elif op == "get?key":
2568 # try objects first, then topics.
2569 if url in ("", "index"):
2570 title, content = html_index()
2571 else:
2572 try:
2573 title, content = html_getobj(url)
2574 except ValueError:
2575 title, content = html_topicpage(url)
2576 else:
2577 raise ValueError('bad pydoc url')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002578 else:
Georg Brandld2f38572011-01-30 08:37:19 +00002579 title, content = html_getobj(url)
2580 except Exception as exc:
2581 # Catch any errors and display them in an error page.
2582 title, content = html_error(complete_url, exc)
2583 return html.page(title, content)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002584
2585 if url.startswith('/'):
2586 url = url[1:]
2587 if content_type == 'text/css':
2588 path_here = os.path.dirname(os.path.realpath(__file__))
Georg Brandld2f38572011-01-30 08:37:19 +00002589 css_path = os.path.join(path_here, url)
2590 with open(css_path) as fp:
2591 return ''.join(fp.readlines())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002592 elif content_type == 'text/html':
2593 return get_html_page(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002594 # Errors outside the url handler are caught by the server.
2595 raise TypeError('unknown content type %r for url %s' % (content_type, url))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002596
2597
Feanil Patel6a396c92017-09-14 17:54:09 -04002598def browse(port=0, *, open_browser=True, hostname='localhost'):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002599 """Start the enhanced pydoc Web server and open a Web browser.
2600
2601 Use port '0' to start the server on an arbitrary port.
2602 Set open_browser to False to suppress opening a browser.
2603 """
2604 import webbrowser
Feanil Patel6a396c92017-09-14 17:54:09 -04002605 serverthread = _start_server(_url_handler, hostname, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002606 if serverthread.error:
2607 print(serverthread.error)
2608 return
2609 if serverthread.serving:
2610 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2611 if open_browser:
2612 webbrowser.open(serverthread.url)
2613 try:
2614 print('Server ready at', serverthread.url)
2615 print(server_help_msg)
2616 while serverthread.serving:
2617 cmd = input('server> ')
2618 cmd = cmd.lower()
2619 if cmd == 'q':
2620 break
2621 elif cmd == 'b':
2622 webbrowser.open(serverthread.url)
2623 else:
2624 print(server_help_msg)
2625 except (KeyboardInterrupt, EOFError):
2626 print()
2627 finally:
2628 if serverthread.serving:
2629 serverthread.stop()
2630 print('Server stopped')
2631
2632
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002633# -------------------------------------------------- command-line interface
2634
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002635def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002636 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002637
Nick Coghlan82a94812018-04-15 21:52:57 +10002638def _get_revised_path(given_path, argv0):
2639 """Ensures current directory is on returned path, and argv0 directory is not
2640
2641 Exception: argv0 dir is left alone if it's also pydoc's directory.
2642
2643 Returns a new path entry list, or None if no adjustment is needed.
2644 """
2645 # Scripts may get the current directory in their path by default if they're
2646 # run with the -m switch, or directly from the current directory.
2647 # The interactive prompt also allows imports from the current directory.
2648
2649 # Accordingly, if the current directory is already present, don't make
2650 # any changes to the given_path
2651 if '' in given_path or os.curdir in given_path or os.getcwd() in given_path:
2652 return None
2653
2654 # Otherwise, add the current directory to the given path, and remove the
2655 # script directory (as long as the latter isn't also pydoc's directory.
2656 stdlib_dir = os.path.dirname(__file__)
2657 script_dir = os.path.dirname(argv0)
2658 revised_path = given_path.copy()
2659 if script_dir in given_path and not os.path.samefile(script_dir, stdlib_dir):
2660 revised_path.remove(script_dir)
2661 revised_path.insert(0, os.getcwd())
2662 return revised_path
2663
2664
2665# Note: the tests only cover _get_revised_path, not _adjust_cli_path itself
2666def _adjust_cli_sys_path():
Nick Coghlan1a5c4bd2018-04-15 23:32:05 +10002667 """Ensures current directory is on sys.path, and __main__ directory is not.
Nick Coghlan82a94812018-04-15 21:52:57 +10002668
2669 Exception: __main__ dir is left alone if it's also pydoc's directory.
2670 """
2671 revised_path = _get_revised_path(sys.path, sys.argv[0])
2672 if revised_path is not None:
2673 sys.path[:] = revised_path
2674
2675
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002676def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002677 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002678 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002679 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002680
Nick Coghlan82a94812018-04-15 21:52:57 +10002681 _adjust_cli_sys_path()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002682
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002683 try:
Feanil Patel6a396c92017-09-14 17:54:09 -04002684 opts, args = getopt.getopt(sys.argv[1:], 'bk:n:p:w')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002685 writing = False
2686 start_server = False
2687 open_browser = False
Feanil Patel6a396c92017-09-14 17:54:09 -04002688 port = 0
2689 hostname = 'localhost'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002690 for opt, val in opts:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002691 if opt == '-b':
2692 start_server = True
2693 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002694 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002695 apropos(val)
2696 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002697 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002698 start_server = True
2699 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002700 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002701 writing = True
Feanil Patel6a396c92017-09-14 17:54:09 -04002702 if opt == '-n':
2703 start_server = True
2704 hostname = val
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002705
Benjamin Petersonb29614e2012-10-09 11:16:03 -04002706 if start_server:
Feanil Patel6a396c92017-09-14 17:54:09 -04002707 browse(port, hostname=hostname, open_browser=open_browser)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002708 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002709
2710 if not args: raise BadUsage
2711 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002712 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002713 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002714 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002715 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002716 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002717 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002718 if writing:
2719 if ispath(arg) and os.path.isdir(arg):
2720 writedocs(arg)
2721 else:
2722 writedoc(arg)
2723 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002724 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002725 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002726 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002727
2728 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002729 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002730 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002731
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002732{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002733 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002734 Python keyword, topic, function, module, or package, or a dotted
2735 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002736 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002737 Python source file to document. If name is 'keywords', 'topics',
2738 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002739
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002740{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002741 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002742
Feanil Patel6a396c92017-09-14 17:54:09 -04002743{cmd} -n <hostname>
2744 Start an HTTP server with the given hostname (default: localhost).
2745
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002746{cmd} -p <port>
2747 Start an HTTP server on the given port on the local machine. Port
2748 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002749
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002750{cmd} -b
2751 Start an HTTP server on an arbitrary unused port and open a Web browser
Feanil Patel6a396c92017-09-14 17:54:09 -04002752 to interactively browse documentation. This option can be used in
2753 combination with -n and/or -p.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002754
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002755{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002756 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002757 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002758 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002759""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002760
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002761if __name__ == '__main__':
2762 cli()