blob: 9a22e56686f618822050da56867a07841fb12788 [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
Nick Coghlan7bb30b72010-12-03 09:29:11 +000069import time
Victor Stinnere6c910e2011-06-30 15:55:43 +020070import tokenize
Zachary Wareeb432142014-07-10 11:18:00 -050071import urllib.parse
Nick Coghlan7bb30b72010-12-03 09:29:11 +000072import warnings
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000073from collections import deque
Nick Coghlan7bb30b72010-12-03 09:29:11 +000074from reprlib import Repr
Victor Stinner7fa767e2014-03-20 09:16:38 +010075from traceback import format_exception_only
Nick Coghlan7bb30b72010-12-03 09:29:11 +000076
77
Ka-Ping Yeedd175342001-02-27 14:43:46 +000078# --------------------------------------------------------- common routines
79
Ka-Ping Yeedd175342001-02-27 14:43:46 +000080def pathdirs():
81 """Convert sys.path into a list of absolute, existing, unique paths."""
82 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000083 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000084 for dir in sys.path:
85 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000086 normdir = os.path.normcase(dir)
87 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000088 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000089 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000090 return dirs
91
92def getdoc(object):
93 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000094 result = inspect.getdoc(object) or inspect.getcomments(object)
Neal Norwitz9d72bb42007-04-17 08:48:32 +000095 return result and re.sub('^ *\n', '', result.rstrip()) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000096
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000097def splitdoc(doc):
98 """Split a doc string into a synopsis line (if any) and the rest."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +000099 lines = doc.strip().split('\n')
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000100 if len(lines) == 1:
101 return lines[0], ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000102 elif len(lines) >= 2 and not lines[1].rstrip():
103 return lines[0], '\n'.join(lines[2:])
104 return '', '\n'.join(lines)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000105
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000106def classname(object, modname):
107 """Get a class name and qualify it with a module name if necessary."""
108 name = object.__name__
109 if object.__module__ != modname:
110 name = object.__module__ + '.' + name
111 return name
112
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000113def isdata(object):
Georg Brandl94432422005-07-22 21:52:25 +0000114 """Check if an object is of a type that probably means it's data."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000115 return not (inspect.ismodule(object) or inspect.isclass(object) or
116 inspect.isroutine(object) or inspect.isframe(object) or
117 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000118
119def replace(text, *pairs):
120 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000121 while pairs:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000122 text = pairs[1].join(text.split(pairs[0]))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000123 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000124 return text
125
126def cram(text, maxlen):
127 """Omit part of a string if needed to make it fit in a maximum length."""
128 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000129 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000130 post = max(0, maxlen-3-pre)
131 return text[:pre] + '...' + text[len(text)-post:]
132 return text
133
Brett Cannon84601f12004-06-19 01:22:48 +0000134_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000135def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000136 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000137 # The behaviour of %p is implementation-dependent in terms of case.
Ezio Melotti412c95a2010-02-16 23:31:04 +0000138 return _re_stripid.sub(r'\1', text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000139
Larry Hastings24a882b2014-02-20 23:34:46 -0800140def _is_bound_method(fn):
141 """
142 Returns True if fn is a bound method, regardless of whether
143 fn was implemented in Python or in C.
144 """
145 if inspect.ismethod(fn):
146 return True
147 if inspect.isbuiltin(fn):
148 self = getattr(fn, '__self__', None)
149 return not (inspect.ismodule(self) or (self is None))
150 return False
151
152
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000153def allmethods(cl):
154 methods = {}
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200155 for key, value in inspect.getmembers(cl, inspect.isroutine):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000156 methods[key] = 1
157 for base in cl.__bases__:
158 methods.update(allmethods(base)) # all your base are belong to us
159 for key in methods.keys():
160 methods[key] = getattr(cl, key)
161 return methods
162
Tim Petersfa26f7c2001-09-24 08:05:11 +0000163def _split_list(s, predicate):
164 """Split sequence s via predicate, and return pair ([true], [false]).
165
166 The return value is a 2-tuple of lists,
167 ([x for x in s if predicate(x)],
168 [x for x in s if not predicate(x)])
169 """
170
Tim Peters28355492001-09-23 21:29:55 +0000171 yes = []
172 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000173 for x in s:
174 if predicate(x):
175 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000176 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000177 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000178 return yes, no
179
Raymond Hettinger1103d052011-03-25 14:15:24 -0700180def visiblename(name, all=None, obj=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000181 """Decide whether to show documentation on a variable."""
Brett Cannond340b432012-08-06 17:19:22 -0400182 # Certain special names are redundant or internal.
Eric Snowb523f842013-11-22 09:05:39 -0700183 # XXX Remove __initializing__?
Brett Cannond340b432012-08-06 17:19:22 -0400184 if name in {'__author__', '__builtins__', '__cached__', '__credits__',
Eric Snowb523f842013-11-22 09:05:39 -0700185 '__date__', '__doc__', '__file__', '__spec__',
Brett Cannond340b432012-08-06 17:19:22 -0400186 '__loader__', '__module__', '__name__', '__package__',
187 '__path__', '__qualname__', '__slots__', '__version__'}:
Raymond Hettinger68272942011-03-18 02:22:15 -0700188 return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000189 # Private names are hidden, but special names are displayed.
190 if name.startswith('__') and name.endswith('__'): return 1
Raymond Hettinger1103d052011-03-25 14:15:24 -0700191 # Namedtuples have public fields and methods with a single leading underscore
192 if name.startswith('_') and hasattr(obj, '_fields'):
193 return True
Skip Montanaroa5616d22004-06-11 04:46:12 +0000194 if all is not None:
195 # only document that which the programmer exported in __all__
196 return name in all
197 else:
198 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000199
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000200def classify_class_attrs(object):
201 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000202 results = []
203 for (name, kind, cls, value) in inspect.classify_class_attrs(object):
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000204 if inspect.isdatadescriptor(value):
205 kind = 'data descriptor'
Raymond Hettinger62be3382019-03-24 17:07:47 -0700206 if isinstance(value, property) and value.fset is None:
207 kind = 'readonly property'
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000208 results.append((name, kind, cls, value))
209 return results
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000210
Raymond Hettinger95801bb2015-08-18 22:25:16 -0700211def sort_attributes(attrs, object):
212 'Sort the attrs list in-place by _fields and then alphabetically by name'
213 # This allows data descriptors to be ordered according
214 # to a _fields attribute if present.
215 fields = getattr(object, '_fields', [])
216 try:
217 field_order = {name : i-len(fields) for (i, name) in enumerate(fields)}
218 except TypeError:
219 field_order = {}
220 keyfunc = lambda attr: (field_order.get(attr[0], 0), attr[0])
221 attrs.sort(key=keyfunc)
222
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000223# ----------------------------------------------------- module manipulation
224
225def ispackage(path):
226 """Guess whether a path refers to a package directory."""
227 if os.path.isdir(path):
Brett Cannonf299abd2015-04-13 14:21:02 -0400228 for ext in ('.py', '.pyc'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000229 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000230 return True
231 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000232
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000233def source_synopsis(file):
234 line = file.readline()
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000235 while line[:1] == '#' or not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000236 line = file.readline()
237 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000238 line = line.strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000239 if line[:4] == 'r"""': line = line[1:]
240 if line[:3] == '"""':
241 line = line[3:]
242 if line[-1:] == '\\': line = line[:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000243 while not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000244 line = file.readline()
245 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000246 result = line.split('"""')[0].strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000247 else: result = None
248 return result
249
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000250def synopsis(filename, cache={}):
251 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000252 mtime = os.stat(filename).st_mtime
Charles-François Natali27c4e882011-07-27 19:40:02 +0200253 lastupdate, result = cache.get(filename, (None, None))
254 if lastupdate is None or lastupdate < mtime:
Eric Snowaed5b222014-01-04 20:38:11 -0700255 # Look for binary suffixes first, falling back to source.
256 if filename.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)):
257 loader_cls = importlib.machinery.SourcelessFileLoader
258 elif filename.endswith(tuple(importlib.machinery.EXTENSION_SUFFIXES)):
259 loader_cls = importlib.machinery.ExtensionFileLoader
260 else:
261 loader_cls = None
262 # Now handle the choice.
263 if loader_cls is None:
264 # Must be a source file.
265 try:
266 file = tokenize.open(filename)
267 except OSError:
268 # module can't be opened, so skip it
269 return None
270 # text modules can be directly examined
271 with file:
272 result = source_synopsis(file)
273 else:
274 # Must be a binary module, which has to be imported.
275 loader = loader_cls('__temp__', filename)
Eric Snow3a62d142014-01-06 20:42:59 -0700276 # XXX We probably don't need to pass in the loader here.
277 spec = importlib.util.spec_from_file_location('__temp__', filename,
278 loader=loader)
Brett Cannoncb66eb02012-05-11 12:58:42 -0400279 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -0400280 module = importlib._bootstrap._load(spec)
Brett Cannoncb66eb02012-05-11 12:58:42 -0400281 except:
282 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000283 del sys.modules['__temp__']
Benjamin Peterson54237f92015-02-16 19:45:01 -0500284 result = module.__doc__.splitlines()[0] if module.__doc__ else None
Eric Snowaed5b222014-01-04 20:38:11 -0700285 # Cache the result.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000286 cache[filename] = (mtime, result)
287 return result
288
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000289class ErrorDuringImport(Exception):
290 """Errors that occurred while trying to import something to document it."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000291 def __init__(self, filename, exc_info):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000292 self.filename = filename
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000293 self.exc, self.value, self.tb = exc_info
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000294
295 def __str__(self):
Guido van Rossuma01a8b62007-05-27 09:20:14 +0000296 exc = self.exc.__name__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000297 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000298
299def importfile(path):
300 """Import a Python source file or compiled file given its path."""
Brett Cannonf4ba4ec2013-06-15 14:25:04 -0400301 magic = importlib.util.MAGIC_NUMBER
Victor Stinnere975af62011-07-04 02:08:50 +0200302 with open(path, 'rb') as file:
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400303 is_bytecode = magic == file.read(len(magic))
304 filename = os.path.basename(path)
305 name, ext = os.path.splitext(filename)
306 if is_bytecode:
Eric Snow32439d62015-05-02 19:15:18 -0600307 loader = importlib._bootstrap_external.SourcelessFileLoader(name, path)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400308 else:
Eric Snow32439d62015-05-02 19:15:18 -0600309 loader = importlib._bootstrap_external.SourceFileLoader(name, path)
Eric Snow3a62d142014-01-06 20:42:59 -0700310 # XXX We probably don't need to pass in the loader here.
311 spec = importlib.util.spec_from_file_location(name, path, loader=loader)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400312 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -0400313 return importlib._bootstrap._load(spec)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400314 except:
315 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000316
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000317def safeimport(path, forceload=0, cache={}):
318 """Import a module; handle errors; return None if the module isn't found.
319
320 If the module *is* found but an exception occurs, it's wrapped in an
321 ErrorDuringImport exception and reraised. Unlike __import__, if a
322 package path is specified, the module at the end of the path is returned,
323 not the package at the beginning. If the optional 'forceload' argument
324 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000325 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000326 # If forceload is 1 and the module has been previously loaded from
327 # disk, we always have to reload the module. Checking the file's
328 # mtime isn't good enough (e.g. the module could contain a class
329 # that inherits from another module that has changed).
330 if forceload and path in sys.modules:
331 if path not in sys.builtin_module_names:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000332 # Remove the module from sys.modules and re-import to try
333 # and avoid problems with partially loaded modules.
334 # Also remove any submodules because they won't appear
335 # in the newly loaded module's namespace if they're already
336 # in sys.modules.
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000337 subs = [m for m in sys.modules if m.startswith(path + '.')]
338 for key in [path] + subs:
339 # Prevent garbage collection.
340 cache[key] = sys.modules[key]
341 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000342 module = __import__(path)
343 except:
344 # Did the error occur before or after the module was found?
345 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000346 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000347 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000348 raise ErrorDuringImport(sys.modules[path].__file__, info)
349 elif exc is SyntaxError:
350 # A SyntaxError occurred before we could execute the module.
351 raise ErrorDuringImport(value.filename, info)
Eric Snow46f97b82016-09-07 16:56:15 -0700352 elif issubclass(exc, ImportError) and value.name == path:
Brett Cannonfd074152012-04-14 14:10:13 -0400353 # No such module in the path.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000354 return None
355 else:
356 # Some other error occurred during the importing process.
357 raise ErrorDuringImport(path, sys.exc_info())
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000358 for part in path.split('.')[1:]:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000359 try: module = getattr(module, part)
360 except AttributeError: return None
361 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000362
363# ---------------------------------------------------- formatter base class
364
365class Doc:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000366
367 PYTHONDOCS = os.environ.get("PYTHONDOCS",
R David Murrayead9bfc2016-06-03 19:28:35 -0400368 "https://docs.python.org/%d.%d/library"
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000369 % sys.version_info[:2])
370
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000371 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000372 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000373 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000374 # 'try' clause is to attempt to handle the possibility that inspect
375 # identifies something in a way that pydoc itself has issues handling;
376 # think 'super' and how it is a descriptor (which raises the exception
377 # by lacking a __name__ attribute) and an instance.
378 try:
379 if inspect.ismodule(object): return self.docmodule(*args)
380 if inspect.isclass(object): return self.docclass(*args)
381 if inspect.isroutine(object): return self.docroutine(*args)
382 except AttributeError:
383 pass
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200384 if inspect.isdatadescriptor(object): return self.docdata(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000385 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000386
387 def fail(self, object, name=None, *args):
388 """Raise an exception for unimplemented types."""
389 message = "don't know how to document object%s of type %s" % (
390 name and ' ' + repr(name), type(object).__name__)
Collin Winterce36ad82007-08-30 01:19:48 +0000391 raise TypeError(message)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000392
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000393 docmodule = docclass = docroutine = docother = docproperty = docdata = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000394
R David Murrayead9bfc2016-06-03 19:28:35 -0400395 def getdocloc(self, object,
396 basedir=os.path.join(sys.base_exec_prefix, "lib",
397 "python%d.%d" % sys.version_info[:2])):
Skip Montanaro4997a692003-09-10 16:47:51 +0000398 """Return the location of module docs or None"""
399
400 try:
401 file = inspect.getabsfile(object)
402 except TypeError:
403 file = '(built-in)'
404
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000405 docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
406
Martin Panter4f8aaf62016-06-12 04:24:06 +0000407 basedir = os.path.normcase(basedir)
Skip Montanaro4997a692003-09-10 16:47:51 +0000408 if (isinstance(object, type(os)) and
409 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
410 'marshal', 'posix', 'signal', 'sys',
Georg Brandl2067bfd2008-05-25 13:05:15 +0000411 '_thread', 'zipimport') or
Skip Montanaro4997a692003-09-10 16:47:51 +0000412 (file.startswith(basedir) and
Brian Curtin49c284c2010-03-31 03:19:28 +0000413 not file.startswith(os.path.join(basedir, 'site-packages')))) and
Brian Curtinedef05b2010-04-01 04:05:25 +0000414 object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
Martin Panter4f8aaf62016-06-12 04:24:06 +0000415 if docloc.startswith(("http://", "https://")):
R David Murrayead9bfc2016-06-03 19:28:35 -0400416 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__.lower())
Skip Montanaro4997a692003-09-10 16:47:51 +0000417 else:
R David Murrayead9bfc2016-06-03 19:28:35 -0400418 docloc = os.path.join(docloc, object.__name__.lower() + ".html")
Skip Montanaro4997a692003-09-10 16:47:51 +0000419 else:
420 docloc = None
421 return docloc
422
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000423# -------------------------------------------- HTML documentation generator
424
425class HTMLRepr(Repr):
426 """Class for safely making an HTML representation of a Python object."""
427 def __init__(self):
428 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000429 self.maxlist = self.maxtuple = 20
430 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000431 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000432
433 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000434 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000435
436 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000437 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000438
439 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000440 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000441 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000442 if hasattr(self, methodname):
443 return getattr(self, methodname)(x, level)
444 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000445
446 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000447 test = cram(x, self.maxstring)
448 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000449 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000450 # Backslashes are only literal in the string and are never
451 # needed to make any special characters, so show a raw string.
452 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000453 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000454 r'<font color="#c040c0">\1</font>',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000455 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000456
Skip Montanarodf708782002-03-07 22:58:02 +0000457 repr_str = repr_string
458
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000459 def repr_instance(self, x, level):
460 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000461 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000462 except:
463 return self.escape('<%s instance>' % x.__class__.__name__)
464
465 repr_unicode = repr_string
466
467class HTMLDoc(Doc):
468 """Formatter class for HTML documentation."""
469
470 # ------------------------------------------- HTML formatting utilities
471
472 _repr_instance = HTMLRepr()
473 repr = _repr_instance.repr
474 escape = _repr_instance.escape
475
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000476 def page(self, title, contents):
477 """Format an HTML page."""
Georg Brandl388faac2009-04-10 08:31:48 +0000478 return '''\
Georg Brandle6066942009-04-10 08:28:28 +0000479<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000480<html><head><title>Python: %s</title>
Georg Brandl388faac2009-04-10 08:31:48 +0000481<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000482</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000483%s
484</body></html>''' % (title, contents)
485
486 def heading(self, title, fgcol, bgcol, extras=''):
487 """Format a page heading."""
488 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000489<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000490<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000491<td valign=bottom>&nbsp;<br>
492<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000493><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000494><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000495 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
496
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000497 def section(self, title, fgcol, bgcol, contents, width=6,
498 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000499 """Format a section with a heading."""
500 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000501 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000502 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000503<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000504<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000505<td colspan=3 valign=bottom>&nbsp;<br>
506<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000507 ''' % (bgcol, fgcol, title)
508 if prelude:
509 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000510<tr bgcolor="%s"><td rowspan=2>%s</td>
511<td colspan=2>%s</td></tr>
512<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
513 else:
514 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000515<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000516
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000517 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000518
519 def bigsection(self, title, *args):
520 """Format a section with a big heading."""
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000521 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000522 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000523
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000524 def preformat(self, text):
525 """Format literal preformatted text."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000526 text = self.escape(text.expandtabs())
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000527 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
528 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000529
530 def multicolumn(self, list, format, cols=4):
531 """Format a list of items into a multi-column list."""
532 result = ''
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000533 rows = (len(list)+cols-1)//cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000534 for col in range(cols):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000535 result = result + '<td width="%d%%" valign=top>' % (100//cols)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000536 for i in range(rows*col, rows*col+rows):
537 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000538 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000539 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000540 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000541
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000542 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000543
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000544 def namelink(self, name, *dicts):
545 """Make a link for an identifier, given name-to-URL mappings."""
546 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000547 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000548 return '<a href="%s">%s</a>' % (dict[name], name)
549 return name
550
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000551 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000552 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000553 name, module = object.__name__, sys.modules.get(object.__module__)
554 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000555 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000556 module.__name__, name, classname(object, modname))
557 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000558
559 def modulelink(self, object):
560 """Make a link for a module."""
561 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
562
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000563 def modpkglink(self, modpkginfo):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000564 """Make a link for a module or package to display in an index."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000565 name, path, ispackage, shadowed = modpkginfo
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000566 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000567 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000568 if path:
569 url = '%s.%s.html' % (path, name)
570 else:
571 url = '%s.html' % name
572 if ispackage:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000573 text = '<strong>%s</strong>&nbsp;(package)' % name
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000574 else:
575 text = name
576 return '<a href="%s">%s</a>' % (url, text)
577
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000578 def filelink(self, url, path):
579 """Make a link to source file."""
580 return '<a href="file:%s">%s</a>' % (url, path)
581
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000582 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
583 """Mark up some plain text, given a context of symbols to look for.
584 Each context dictionary maps object names to anchor names."""
585 escape = escape or self.escape
586 results = []
587 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000588 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
589 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000590 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000591 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000592 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000593 match = pattern.search(text, here)
594 if not match: break
595 start, end = match.span()
596 results.append(escape(text[here:start]))
597
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000598 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000599 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000600 url = escape(all).replace('"', '&quot;')
601 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000602 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000603 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
604 results.append('<a href="%s">%s</a>' % (url, escape(all)))
605 elif pep:
Christian Heimes2202f872008-02-06 14:31:34 +0000606 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000607 results.append('<a href="%s">%s</a>' % (url, escape(all)))
Benjamin Petersoned1160b2014-06-07 16:44:00 -0700608 elif selfdot:
609 # Create a link for methods like 'self.method(...)'
610 # and use <strong> for attributes like 'self.attr'
611 if text[end:end+1] == '(':
612 results.append('self.' + self.namelink(name, methods))
613 else:
614 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000615 elif text[end:end+1] == '(':
616 results.append(self.namelink(name, methods, funcs, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000617 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000618 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000619 here = end
620 results.append(escape(text[here:]))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000621 return ''.join(results)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000622
623 # ---------------------------------------------- type-specific routines
624
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000625 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000626 """Produce HTML for a class tree as given by inspect.getclasstree()."""
627 result = ''
628 for entry in tree:
629 if type(entry) is type(()):
630 c, bases = entry
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000631 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000632 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000633 if bases and bases != (parent,):
634 parents = []
635 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000636 parents.append(self.classlink(base, modname))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000637 result = result + '(' + ', '.join(parents) + ')'
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000638 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000639 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000640 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000641 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000642 return '<dl>\n%s</dl>\n' % result
643
Tim Peters8dd7ade2001-10-18 19:56:17 +0000644 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000645 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000646 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000647 try:
648 all = object.__all__
649 except AttributeError:
650 all = None
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000651 parts = name.split('.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000652 links = []
653 for i in range(len(parts)-1):
654 links.append(
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000655 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000656 ('.'.join(parts[:i+1]), parts[i]))
657 linkedname = '.'.join(links + parts[-1:])
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000658 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000659 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000660 path = inspect.getabsfile(object)
Zachary Wareeb432142014-07-10 11:18:00 -0500661 url = urllib.parse.quote(path)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000662 filelink = self.filelink(url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000663 except TypeError:
664 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000665 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000666 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000667 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000668 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000669 version = version[11:-1].strip()
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000670 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000671 if hasattr(object, '__date__'):
672 info.append(self.escape(str(object.__date__)))
673 if info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000674 head = head + ' (%s)' % ', '.join(info)
Skip Montanaro4997a692003-09-10 16:47:51 +0000675 docloc = self.getdocloc(object)
676 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000677 docloc = '<br><a href="%(docloc)s">Module Reference</a>' % locals()
Skip Montanaro4997a692003-09-10 16:47:51 +0000678 else:
679 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000680 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000681 head, '#ffffff', '#7799ee',
682 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000683
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000684 modules = inspect.getmembers(object, inspect.ismodule)
685
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000686 classes, cdict = [], {}
687 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000688 # if __all__ exists, believe it. Otherwise use old heuristic.
689 if (all is not None or
690 (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700691 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000692 classes.append((key, value))
693 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000694 for key, value in classes:
695 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000696 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000697 module = sys.modules.get(modname)
698 if modname != name and module and hasattr(module, key):
699 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000700 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000701 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000702 funcs, fdict = [], {}
703 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000704 # if __all__ exists, believe it. Otherwise use old heuristic.
705 if (all is not None or
706 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700707 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000708 funcs.append((key, value))
709 fdict[key] = '#-' + key
710 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000711 data = []
712 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700713 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000714 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000715
716 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
717 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000718 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000719
720 if hasattr(object, '__path__'):
721 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000722 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
723 modpkgs.append((modname, name, ispkg, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000724 modpkgs.sort()
725 contents = self.multicolumn(modpkgs, self.modpkglink)
726 result = result + self.bigsection(
727 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000728 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000729 contents = self.multicolumn(
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000730 modules, lambda t: self.modulelink(t[1]))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000731 result = result + self.bigsection(
Christian Heimes7131fd92008-02-19 14:21:46 +0000732 'Modules', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000733
734 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000735 classlist = [value for (key, value) in classes]
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000736 contents = [
737 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000738 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000739 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000740 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000741 'Classes', '#ffffff', '#ee77aa', ' '.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000742 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000743 contents = []
744 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000745 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000746 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000747 'Functions', '#ffffff', '#eeaa77', ' '.join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000748 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000749 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000750 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000751 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000752 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000753 'Data', '#ffffff', '#55aa55', '<br>\n'.join(contents))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000754 if hasattr(object, '__author__'):
755 contents = self.markup(str(object.__author__), self.preformat)
756 result = result + self.bigsection(
757 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000758 if hasattr(object, '__credits__'):
759 contents = self.markup(str(object.__credits__), self.preformat)
760 result = result + self.bigsection(
761 'Credits', '#ffffff', '#7799ee', contents)
762
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000763 return result
764
Tim Peters8dd7ade2001-10-18 19:56:17 +0000765 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
766 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000767 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000768 realname = object.__name__
769 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000770 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000771
Tim Petersb47879b2001-09-24 04:47:19 +0000772 contents = []
773 push = contents.append
774
Tim Petersfa26f7c2001-09-24 08:05:11 +0000775 # Cute little class to pump out a horizontal rule between sections.
776 class HorizontalRule:
777 def __init__(self):
778 self.needone = 0
779 def maybe(self):
780 if self.needone:
781 push('<hr>\n')
782 self.needone = 1
783 hr = HorizontalRule()
784
Tim Petersc86f6ca2001-09-26 21:31:51 +0000785 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000786 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000787 if len(mro) > 2:
788 hr.maybe()
789 push('<dl><dt>Method resolution order:</dt>\n')
790 for base in mro:
791 push('<dd>%s</dd>\n' % self.classlink(base,
792 object.__module__))
793 push('</dl>\n')
794
Tim Petersb47879b2001-09-24 04:47:19 +0000795 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000796 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000797 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000798 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000799 push(msg)
800 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100801 try:
802 value = getattr(object, name)
803 except Exception:
804 # Some descriptors may meet a failure in their __get__.
805 # (bug #1785)
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200806 push(self.docdata(value, name, mod))
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100807 else:
808 push(self.document(value, name, mod,
809 funcs, classes, mdict, object))
Tim Petersb47879b2001-09-24 04:47:19 +0000810 push('\n')
811 return attrs
812
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000813 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000814 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000815 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000816 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000817 push(msg)
818 for name, kind, homecls, value in ok:
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200819 push(self.docdata(value, name, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000820 return attrs
821
Tim Petersfa26f7c2001-09-24 08:05:11 +0000822 def spilldata(msg, attrs, predicate):
823 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000824 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000825 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000826 push(msg)
827 for name, kind, homecls, value in ok:
828 base = self.docother(getattr(object, name), name, mod)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200829 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000830 doc = getattr(value, "__doc__", None)
831 else:
832 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000833 if doc is None:
834 push('<dl><dt>%s</dl>\n' % base)
835 else:
836 doc = self.markup(getdoc(value), self.preformat,
837 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000838 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000839 push('<dl><dt>%s%s</dl>\n' % (base, doc))
840 push('\n')
841 return attrs
842
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000843 attrs = [(name, kind, cls, value)
844 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -0700845 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000846
Tim Petersb47879b2001-09-24 04:47:19 +0000847 mdict = {}
848 for key, kind, homecls, value in attrs:
849 mdict[key] = anchor = '#' + name + '-' + key
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100850 try:
851 value = getattr(object, name)
852 except Exception:
853 # Some descriptors may meet a failure in their __get__.
854 # (bug #1785)
855 pass
Tim Petersb47879b2001-09-24 04:47:19 +0000856 try:
857 # The value may not be hashable (e.g., a data attr with
858 # a dict or list value).
859 mdict[value] = anchor
860 except TypeError:
861 pass
862
Tim Petersfa26f7c2001-09-24 08:05:11 +0000863 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000864 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000865 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000866 else:
867 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000868 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
869
Cheryl Sabellac95c93d2019-05-24 06:43:29 -0400870 if object is not builtins.object and thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000871 attrs = inherited
872 continue
873 elif thisclass is object:
874 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000875 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000876 tag = 'inherited from %s' % self.classlink(thisclass,
877 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000878 tag += ':<br>\n'
879
Raymond Hettinger95801bb2015-08-18 22:25:16 -0700880 sort_attributes(attrs, object)
Tim Petersb47879b2001-09-24 04:47:19 +0000881
882 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000883 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000884 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000885 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000886 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000887 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000888 lambda t: t[1] == 'static method')
Raymond Hettinger9dcc0952019-03-25 00:23:39 -0700889 attrs = spilldescriptors("Readonly properties %s" % tag, attrs,
Raymond Hettinger62be3382019-03-24 17:07:47 -0700890 lambda t: t[1] == 'readonly property')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000891 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
892 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000893 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000894 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000895 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000896 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000897
898 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000899
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000900 if name == realname:
901 title = '<a name="%s">class <strong>%s</strong></a>' % (
902 name, realname)
903 else:
904 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
905 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000906 if bases:
907 parents = []
908 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000909 parents.append(self.classlink(base, object.__module__))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000910 title = title + '(%s)' % ', '.join(parents)
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +0200911
912 decl = ''
913 try:
914 signature = inspect.signature(object)
915 except (ValueError, TypeError):
916 signature = None
917 if signature:
918 argspec = str(signature)
Serhiy Storchaka213f2292017-01-23 14:02:35 +0200919 if argspec and argspec != '()':
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +0200920 decl = name + self.escape(argspec) + '\n\n'
921
922 doc = getdoc(object)
923 if decl:
924 doc = decl + (doc or '')
925 doc = self.markup(doc, self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000926 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000927
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000928 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000929
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000930 def formatvalue(self, object):
931 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000932 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000933
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000934 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000935 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000936 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000937 realname = object.__name__
938 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000939 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000940 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000941 skipdocs = 0
Larry Hastings24a882b2014-02-20 23:34:46 -0800942 if _is_bound_method(object):
Christian Heimesff737952007-11-27 10:40:20 +0000943 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000944 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000945 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000946 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000947 else:
Christian Heimesff737952007-11-27 10:40:20 +0000948 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000949 note = ' method of %s instance' % self.classlink(
Christian Heimesff737952007-11-27 10:40:20 +0000950 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000951 else:
952 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000953
Dan Rose2a37f8f2019-05-24 06:38:01 -0500954 if (inspect.iscoroutinefunction(object) or
955 inspect.isasyncgenfunction(object)):
956 asyncqualifier = 'async '
957 else:
958 asyncqualifier = ''
959
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000960 if name == realname:
961 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
962 else:
Serhiy Storchakaa44d34e2018-11-08 08:48:11 +0200963 if cl and inspect.getattr_static(cl, realname, []) is object:
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000964 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000965 cl.__name__ + '-' + realname, realname)
966 skipdocs = 1
967 else:
968 reallink = realname
969 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
970 anchor, name, reallink)
Larry Hastings44e2eaa2013-11-23 15:37:55 -0800971 argspec = None
Larry Hastings24a882b2014-02-20 23:34:46 -0800972 if inspect.isroutine(object):
Larry Hastings5c661892014-01-24 06:17:25 -0800973 try:
974 signature = inspect.signature(object)
975 except (ValueError, TypeError):
976 signature = None
Larry Hastings44e2eaa2013-11-23 15:37:55 -0800977 if signature:
978 argspec = str(signature)
979 if realname == '<lambda>':
980 title = '<strong>%s</strong> <em>lambda</em> ' % name
981 # XXX lambda's won't usually have func_annotations['return']
982 # since the syntax doesn't support but it is possible.
983 # So removing parentheses isn't truly safe.
984 argspec = argspec[1:-1] # remove parentheses
985 if not argspec:
Tim Peters4bcfa312001-09-20 06:08:24 +0000986 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000987
Dan Rose2a37f8f2019-05-24 06:38:01 -0500988 decl = asyncqualifier + title + self.escape(argspec) + (note and
989 self.grey('<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000990
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000991 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000992 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000993 else:
994 doc = self.markup(
995 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000996 doc = doc and '<dd><tt>%s</tt></dd>' % doc
997 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000998
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200999 def docdata(self, object, name=None, mod=None, cl=None):
1000 """Produce html documentation for a data descriptor."""
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001001 results = []
1002 push = results.append
1003
1004 if name:
1005 push('<dl><dt><strong>%s</strong></dt>\n' % name)
Raymond Hettingera694f232019-03-27 13:16:34 -07001006 doc = self.markup(getdoc(object), self.preformat)
1007 if doc:
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001008 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001009 push('</dl>\n')
1010
1011 return ''.join(results)
1012
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001013 docproperty = docdata
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001014
Tim Peters8dd7ade2001-10-18 19:56:17 +00001015 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001016 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001017 lhs = name and '<strong>%s</strong> = ' % name or ''
1018 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001019
1020 def index(self, dir, shadowed=None):
1021 """Generate an HTML index for a directory of modules."""
1022 modpkgs = []
1023 if shadowed is None: shadowed = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001024 for importer, name, ispkg in pkgutil.iter_modules([dir]):
Victor Stinner4d652242011-04-12 23:41:50 +02001025 if any((0xD800 <= ord(ch) <= 0xDFFF) for ch in name):
1026 # ignore a module if its name contains a surrogate character
1027 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001028 modpkgs.append((name, '', ispkg, name in shadowed))
1029 shadowed[name] = 1
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001030
1031 modpkgs.sort()
1032 contents = self.multicolumn(modpkgs, self.modpkglink)
1033 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
1034
1035# -------------------------------------------- text documentation generator
1036
1037class TextRepr(Repr):
1038 """Class for safely making a text representation of a Python object."""
1039 def __init__(self):
1040 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001041 self.maxlist = self.maxtuple = 20
1042 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001043 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001044
1045 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +00001046 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001047 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +00001048 if hasattr(self, methodname):
1049 return getattr(self, methodname)(x, level)
1050 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001051
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +00001052 def repr_string(self, x, level):
1053 test = cram(x, self.maxstring)
1054 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001055 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +00001056 # Backslashes are only literal in the string and are never
1057 # needed to make any special characters, so show a raw string.
1058 return 'r' + testrepr[0] + test + testrepr[0]
1059 return testrepr
1060
Skip Montanarodf708782002-03-07 22:58:02 +00001061 repr_str = repr_string
1062
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001063 def repr_instance(self, x, level):
1064 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001065 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001066 except:
1067 return '<%s instance>' % x.__class__.__name__
1068
1069class TextDoc(Doc):
1070 """Formatter class for text documentation."""
1071
1072 # ------------------------------------------- text formatting utilities
1073
1074 _repr_instance = TextRepr()
1075 repr = _repr_instance.repr
1076
1077 def bold(self, text):
1078 """Format a string in bold by overstriking."""
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001079 return ''.join(ch + '\b' + ch for ch in text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001080
1081 def indent(self, text, prefix=' '):
1082 """Indent text by prepending a given prefix to each line."""
1083 if not text: return ''
Collin Winter72e110c2007-07-17 00:27:30 +00001084 lines = [prefix + line for line in text.split('\n')]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001085 if lines: lines[-1] = lines[-1].rstrip()
1086 return '\n'.join(lines)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001087
1088 def section(self, title, contents):
1089 """Format a section with a given heading."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001090 clean_contents = self.indent(contents).rstrip()
1091 return self.bold(title) + '\n' + clean_contents + '\n\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001092
1093 # ---------------------------------------------- type-specific routines
1094
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001095 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001096 """Render in text a class tree as returned by inspect.getclasstree()."""
1097 result = ''
1098 for entry in tree:
1099 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001100 c, bases = entry
1101 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001102 if bases and bases != (parent,):
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001103 parents = (classname(c, modname) for c in bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001104 result = result + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001105 result = result + '\n'
1106 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001107 result = result + self.formattree(
1108 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001109 return result
1110
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001111 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001112 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001113 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001114 synop, desc = splitdoc(getdoc(object))
1115 result = self.section('NAME', name + (synop and ' - ' + synop))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001116 all = getattr(object, '__all__', None)
Skip Montanaro4997a692003-09-10 16:47:51 +00001117 docloc = self.getdocloc(object)
1118 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001119 result = result + self.section('MODULE REFERENCE', docloc + """
1120
Éric Araujo647ef8c2011-09-11 00:43:20 +02001121The following documentation is automatically generated from the Python
1122source files. It may be incomplete, incorrect or include features that
1123are considered implementation detail and may vary between Python
1124implementations. When in doubt, consult the module reference at the
1125location listed above.
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001126""")
Skip Montanaro4997a692003-09-10 16:47:51 +00001127
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001128 if desc:
1129 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001130
1131 classes = []
1132 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001133 # if __all__ exists, believe it. Otherwise use old heuristic.
1134 if (all is not None
1135 or (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001136 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001137 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001138 funcs = []
1139 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001140 # if __all__ exists, believe it. Otherwise use old heuristic.
1141 if (all is not None or
1142 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001143 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001144 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001145 data = []
1146 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001147 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001148 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001149
Christian Heimes1af737c2008-01-23 08:24:23 +00001150 modpkgs = []
1151 modpkgs_names = set()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001152 if hasattr(object, '__path__'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001153 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
Christian Heimes1af737c2008-01-23 08:24:23 +00001154 modpkgs_names.add(modname)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001155 if ispkg:
1156 modpkgs.append(modname + ' (package)')
1157 else:
1158 modpkgs.append(modname)
1159
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001160 modpkgs.sort()
1161 result = result + self.section(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001162 'PACKAGE CONTENTS', '\n'.join(modpkgs))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001163
Christian Heimes1af737c2008-01-23 08:24:23 +00001164 # Detect submodules as sometimes created by C extensions
1165 submodules = []
1166 for key, value in inspect.getmembers(object, inspect.ismodule):
1167 if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1168 submodules.append(key)
1169 if submodules:
1170 submodules.sort()
1171 result = result + self.section(
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001172 'SUBMODULES', '\n'.join(submodules))
Christian Heimes1af737c2008-01-23 08:24:23 +00001173
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001174 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001175 classlist = [value for key, value in classes]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001176 contents = [self.formattree(
1177 inspect.getclasstree(classlist, 1), name)]
1178 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001179 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001180 result = result + self.section('CLASSES', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001181
1182 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001183 contents = []
1184 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001185 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001186 result = result + self.section('FUNCTIONS', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001187
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001188 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001189 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001190 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001191 contents.append(self.docother(value, key, name, maxlen=70))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001192 result = result + self.section('DATA', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001193
1194 if hasattr(object, '__version__'):
1195 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001196 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001197 version = version[11:-1].strip()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001198 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001199 if hasattr(object, '__date__'):
1200 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001201 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001202 result = result + self.section('AUTHOR', str(object.__author__))
1203 if hasattr(object, '__credits__'):
1204 result = result + self.section('CREDITS', str(object.__credits__))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001205 try:
1206 file = inspect.getabsfile(object)
1207 except TypeError:
1208 file = '(built-in)'
1209 result = result + self.section('FILE', file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001210 return result
1211
Georg Brandl9bd45f992010-12-03 09:58:38 +00001212 def docclass(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001213 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001214 realname = object.__name__
1215 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001216 bases = object.__bases__
1217
Tim Petersc86f6ca2001-09-26 21:31:51 +00001218 def makename(c, m=object.__module__):
1219 return classname(c, m)
1220
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001221 if name == realname:
1222 title = 'class ' + self.bold(realname)
1223 else:
1224 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001225 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001226 parents = map(makename, bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001227 title = title + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001228
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001229 contents = []
Tim Peters28355492001-09-23 21:29:55 +00001230 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001231
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001232 try:
1233 signature = inspect.signature(object)
1234 except (ValueError, TypeError):
1235 signature = None
1236 if signature:
1237 argspec = str(signature)
Serhiy Storchaka213f2292017-01-23 14:02:35 +02001238 if argspec and argspec != '()':
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001239 push(name + argspec + '\n')
1240
1241 doc = getdoc(object)
1242 if doc:
1243 push(doc + '\n')
1244
Tim Petersc86f6ca2001-09-26 21:31:51 +00001245 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001246 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001247 if len(mro) > 2:
1248 push("Method resolution order:")
1249 for base in mro:
1250 push(' ' + makename(base))
1251 push('')
1252
Sanyam Khuranaa323cdc2018-10-21 00:22:02 -07001253 # List the built-in subclasses, if any:
1254 subclasses = sorted(
Sanyam Khuranab539cef2018-12-31 10:44:47 +05301255 (str(cls.__name__) for cls in type.__subclasses__(object)
Sanyam Khuranaa323cdc2018-10-21 00:22:02 -07001256 if not cls.__name__.startswith("_") and cls.__module__ == "builtins"),
1257 key=str.lower
1258 )
1259 no_of_subclasses = len(subclasses)
1260 MAX_SUBCLASSES_TO_DISPLAY = 4
1261 if subclasses:
1262 push("Built-in subclasses:")
1263 for subclassname in subclasses[:MAX_SUBCLASSES_TO_DISPLAY]:
1264 push(' ' + subclassname)
1265 if no_of_subclasses > MAX_SUBCLASSES_TO_DISPLAY:
1266 push(' ... and ' +
1267 str(no_of_subclasses - MAX_SUBCLASSES_TO_DISPLAY) +
1268 ' other subclasses')
1269 push('')
1270
Tim Petersf4aad8e2001-09-24 22:40:47 +00001271 # Cute little class to pump out a horizontal rule between sections.
1272 class HorizontalRule:
1273 def __init__(self):
1274 self.needone = 0
1275 def maybe(self):
1276 if self.needone:
1277 push('-' * 70)
1278 self.needone = 1
1279 hr = HorizontalRule()
1280
Tim Peters28355492001-09-23 21:29:55 +00001281 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001282 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001283 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001284 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001285 push(msg)
1286 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +01001287 try:
1288 value = getattr(object, name)
1289 except Exception:
1290 # Some descriptors may meet a failure in their __get__.
1291 # (bug #1785)
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001292 push(self.docdata(value, name, mod))
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +01001293 else:
1294 push(self.document(value,
1295 name, mod, object))
Tim Peters28355492001-09-23 21:29:55 +00001296 return attrs
1297
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001298 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001299 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001300 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001301 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001302 push(msg)
1303 for name, kind, homecls, value in ok:
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001304 push(self.docdata(value, name, mod))
Tim Peters28355492001-09-23 21:29:55 +00001305 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001306
Tim Petersfa26f7c2001-09-24 08:05:11 +00001307 def spilldata(msg, attrs, predicate):
1308 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001309 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001310 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001311 push(msg)
1312 for name, kind, homecls, value in ok:
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001313 if callable(value) or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001314 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001315 else:
1316 doc = None
Serhiy Storchaka056eb022014-02-19 23:05:12 +02001317 try:
1318 obj = getattr(object, name)
1319 except AttributeError:
1320 obj = homecls.__dict__[name]
1321 push(self.docother(obj, name, mod, maxlen=70, doc=doc) +
1322 '\n')
Tim Peters28355492001-09-23 21:29:55 +00001323 return attrs
1324
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001325 attrs = [(name, kind, cls, value)
1326 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -07001327 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001328
Tim Petersfa26f7c2001-09-24 08:05:11 +00001329 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001330 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001331 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001332 else:
1333 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001334 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1335
Cheryl Sabellac95c93d2019-05-24 06:43:29 -04001336 if object is not builtins.object and thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001337 attrs = inherited
1338 continue
1339 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001340 tag = "defined here"
1341 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001342 tag = "inherited from %s" % classname(thisclass,
1343 object.__module__)
Raymond Hettinger95801bb2015-08-18 22:25:16 -07001344
1345 sort_attributes(attrs, object)
Tim Peters28355492001-09-23 21:29:55 +00001346
1347 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001348 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001349 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001350 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001351 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001352 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001353 lambda t: t[1] == 'static method')
Raymond Hettinger62be3382019-03-24 17:07:47 -07001354 attrs = spilldescriptors("Readonly properties %s:\n" % tag, attrs,
1355 lambda t: t[1] == 'readonly property')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001356 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1357 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001358 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1359 lambda t: t[1] == 'data')
Ethan Furmanb0c84cd2013-10-20 22:37:39 -07001360
Tim Peters28355492001-09-23 21:29:55 +00001361 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001362 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001363
1364 contents = '\n'.join(contents)
1365 if not contents:
1366 return title + '\n'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001367 return title + '\n' + self.indent(contents.rstrip(), ' | ') + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001368
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001369 def formatvalue(self, object):
1370 """Format an argument default value as text."""
1371 return '=' + self.repr(object)
1372
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001373 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001374 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001375 realname = object.__name__
1376 name = name or realname
1377 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001378 skipdocs = 0
Larry Hastings24a882b2014-02-20 23:34:46 -08001379 if _is_bound_method(object):
Christian Heimesff737952007-11-27 10:40:20 +00001380 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001381 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001382 if imclass is not cl:
1383 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001384 else:
Christian Heimesff737952007-11-27 10:40:20 +00001385 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001386 note = ' method of %s instance' % classname(
Christian Heimesff737952007-11-27 10:40:20 +00001387 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001388 else:
1389 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001390
Dan Rose2a37f8f2019-05-24 06:38:01 -05001391 if (inspect.iscoroutinefunction(object) or
1392 inspect.isasyncgenfunction(object)):
1393 asyncqualifier = 'async '
1394 else:
1395 asyncqualifier = ''
1396
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001397 if name == realname:
1398 title = self.bold(realname)
1399 else:
Serhiy Storchakaa44d34e2018-11-08 08:48:11 +02001400 if cl and inspect.getattr_static(cl, realname, []) is object:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001401 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001402 title = self.bold(name) + ' = ' + realname
Larry Hastings44e2eaa2013-11-23 15:37:55 -08001403 argspec = None
Larry Hastings5c661892014-01-24 06:17:25 -08001404
1405 if inspect.isroutine(object):
1406 try:
1407 signature = inspect.signature(object)
1408 except (ValueError, TypeError):
1409 signature = None
Larry Hastings44e2eaa2013-11-23 15:37:55 -08001410 if signature:
1411 argspec = str(signature)
1412 if realname == '<lambda>':
1413 title = self.bold(name) + ' lambda '
1414 # XXX lambda's won't usually have func_annotations['return']
1415 # since the syntax doesn't support but it is possible.
1416 # So removing parentheses isn't truly safe.
1417 argspec = argspec[1:-1] # remove parentheses
1418 if not argspec:
Tim Peters4bcfa312001-09-20 06:08:24 +00001419 argspec = '(...)'
Dan Rose2a37f8f2019-05-24 06:38:01 -05001420 decl = asyncqualifier + title + argspec + note
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001421
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001422 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001423 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001424 else:
1425 doc = getdoc(object) or ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001426 return decl + '\n' + (doc and self.indent(doc).rstrip() + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001427
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001428 def docdata(self, object, name=None, mod=None, cl=None):
1429 """Produce text documentation for a data descriptor."""
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001430 results = []
1431 push = results.append
1432
1433 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001434 push(self.bold(name))
1435 push('\n')
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001436 doc = getdoc(object) or ''
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001437 if doc:
1438 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001439 push('\n')
1440 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001441
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001442 docproperty = docdata
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001443
Georg Brandl8b813db2005-10-01 16:32:31 +00001444 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001445 """Produce text documentation for a data object."""
1446 repr = self.repr(object)
1447 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001448 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001449 chop = maxlen - len(line)
1450 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001451 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001452 if doc is not None:
1453 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001454 return line
1455
Georg Brandld80d5f42010-12-03 07:47:22 +00001456class _PlainTextDoc(TextDoc):
1457 """Subclass of TextDoc which overrides string styling"""
1458 def bold(self, text):
1459 return text
1460
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001461# --------------------------------------------------------- user interfaces
1462
1463def pager(text):
1464 """The first time this is called, determine what kind of pager to use."""
1465 global pager
1466 pager = getpager()
1467 pager(text)
1468
1469def getpager():
1470 """Decide what method to use for paging through text."""
Benjamin Peterson159824e2014-06-07 20:14:26 -07001471 if not hasattr(sys.stdin, "isatty"):
1472 return plainpager
Guido van Rossuma01a8b62007-05-27 09:20:14 +00001473 if not hasattr(sys.stdout, "isatty"):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001474 return plainpager
1475 if not sys.stdin.isatty() or not sys.stdout.isatty():
1476 return plainpager
doko@ubuntu.com96575452016-06-14 08:39:31 +02001477 use_pager = os.environ.get('MANPAGER') or os.environ.get('PAGER')
1478 if use_pager:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001479 if sys.platform == 'win32': # pipes completely broken in Windows
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001480 return lambda text: tempfilepager(plain(text), use_pager)
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001481 elif os.environ.get('TERM') in ('dumb', 'emacs'):
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001482 return lambda text: pipepager(plain(text), use_pager)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001483 else:
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001484 return lambda text: pipepager(text, use_pager)
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001485 if os.environ.get('TERM') in ('dumb', 'emacs'):
1486 return plainpager
Jesus Cea4791a242012-10-05 03:15:39 +02001487 if sys.platform == 'win32':
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001488 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001489 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001490 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001491
1492 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001493 (fd, filename) = tempfile.mkstemp()
1494 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001495 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001496 if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001497 return lambda text: pipepager(text, 'more')
1498 else:
1499 return ttypager
1500 finally:
1501 os.unlink(filename)
1502
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001503def plain(text):
1504 """Remove boldface formatting from text."""
1505 return re.sub('.\b', '', text)
1506
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001507def pipepager(text, cmd):
1508 """Page through text by feeding it to another program."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001509 import subprocess
1510 proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001511 try:
R David Murray1058cda2015-03-29 15:15:40 -04001512 with io.TextIOWrapper(proc.stdin, errors='backslashreplace') as pipe:
R David Murraye7f5e142015-03-30 10:14:47 -04001513 try:
1514 pipe.write(text)
1515 except KeyboardInterrupt:
1516 # We've hereby abandoned whatever text hasn't been written,
1517 # but the pager is still in control of the terminal.
1518 pass
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001519 except OSError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001520 pass # Ignore broken pipes caused by quitting the pager program.
R David Murray1058cda2015-03-29 15:15:40 -04001521 while True:
1522 try:
1523 proc.wait()
1524 break
1525 except KeyboardInterrupt:
1526 # Ignore ctl-c like the pager itself does. Otherwise the pager is
1527 # left running and the terminal is in raw mode and unusable.
1528 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001529
1530def tempfilepager(text, cmd):
1531 """Page through text by invoking a program on a temporary file."""
1532 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001533 filename = tempfile.mktemp()
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001534 with open(filename, 'w', errors='backslashreplace') as file:
Giampaolo Rodola'2f50aaf2013-02-12 02:04:27 +01001535 file.write(text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001536 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001537 os.system(cmd + ' "' + filename + '"')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001538 finally:
1539 os.unlink(filename)
1540
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001541def _escape_stdout(text):
1542 # Escape non-encodable characters to avoid encoding errors later
1543 encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8'
1544 return text.encode(encoding, 'backslashreplace').decode(encoding)
1545
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001546def ttypager(text):
1547 """Page through text on a text terminal."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001548 lines = plain(_escape_stdout(text)).split('\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001549 try:
1550 import tty
1551 fd = sys.stdin.fileno()
1552 old = tty.tcgetattr(fd)
1553 tty.setcbreak(fd)
1554 getchar = lambda: sys.stdin.read(1)
Serhiy Storchakaab5e9b92014-11-28 00:09:29 +02001555 except (ImportError, AttributeError, io.UnsupportedOperation):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001556 tty = None
1557 getchar = lambda: sys.stdin.readline()[:-1][:1]
1558
1559 try:
Serhiy Storchakaab5e9b92014-11-28 00:09:29 +02001560 try:
1561 h = int(os.environ.get('LINES', 0))
1562 except ValueError:
1563 h = 0
1564 if h <= 1:
1565 h = 25
1566 r = inc = h - 1
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001567 sys.stdout.write('\n'.join(lines[:inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001568 while lines[r:]:
1569 sys.stdout.write('-- more --')
1570 sys.stdout.flush()
1571 c = getchar()
1572
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001573 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001574 sys.stdout.write('\r \r')
1575 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001576 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001577 sys.stdout.write('\r \r' + lines[r] + '\n')
1578 r = r + 1
1579 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001580 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001581 r = r - inc - inc
1582 if r < 0: r = 0
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001583 sys.stdout.write('\n' + '\n'.join(lines[r:r+inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001584 r = r + inc
1585
1586 finally:
1587 if tty:
1588 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1589
1590def plainpager(text):
1591 """Simply print unformatted text. This is the ultimate fallback."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001592 sys.stdout.write(plain(_escape_stdout(text)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001593
1594def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001595 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001596 if inspect.ismodule(thing):
1597 if thing.__name__ in sys.builtin_module_names:
1598 return 'built-in module ' + thing.__name__
1599 if hasattr(thing, '__path__'):
1600 return 'package ' + thing.__name__
1601 else:
1602 return 'module ' + thing.__name__
1603 if inspect.isbuiltin(thing):
1604 return 'built-in function ' + thing.__name__
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001605 if inspect.isgetsetdescriptor(thing):
1606 return 'getset descriptor %s.%s.%s' % (
1607 thing.__objclass__.__module__, thing.__objclass__.__name__,
1608 thing.__name__)
1609 if inspect.ismemberdescriptor(thing):
1610 return 'member descriptor %s.%s.%s' % (
1611 thing.__objclass__.__module__, thing.__objclass__.__name__,
1612 thing.__name__)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001613 if inspect.isclass(thing):
1614 return 'class ' + thing.__name__
1615 if inspect.isfunction(thing):
1616 return 'function ' + thing.__name__
1617 if inspect.ismethod(thing):
1618 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001619 return type(thing).__name__
1620
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001621def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001622 """Locate an object by name or dotted path, importing as necessary."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001623 parts = [part for part in path.split('.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001624 module, n = None, 0
1625 while n < len(parts):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001626 nextmodule = safeimport('.'.join(parts[:n+1]), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001627 if nextmodule: module, n = nextmodule, n + 1
1628 else: break
1629 if module:
1630 object = module
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001631 else:
Éric Araujoe64e51b2011-07-29 17:03:55 +02001632 object = builtins
1633 for part in parts[n:]:
1634 try:
1635 object = getattr(object, part)
1636 except AttributeError:
1637 return None
1638 return object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001639
1640# --------------------------------------- interactive interpreter interface
1641
1642text = TextDoc()
Georg Brandld80d5f42010-12-03 07:47:22 +00001643plaintext = _PlainTextDoc()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001644html = HTMLDoc()
1645
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001646def resolve(thing, forceload=0):
1647 """Given an object or a path to an object, get the object and its name."""
1648 if isinstance(thing, str):
1649 object = locate(thing, forceload)
Serhiy Storchakab6076fb2015-04-21 21:09:48 +03001650 if object is None:
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001651 raise ImportError('''\
1652No Python documentation found for %r.
1653Use help() to get the interactive help utility.
1654Use help(str) for help on the str class.''' % thing)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001655 return object, thing
1656 else:
R David Murrayc43125a2012-04-23 13:23:57 -04001657 name = getattr(thing, '__name__', None)
1658 return thing, name if isinstance(name, str) else None
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001659
Georg Brandld80d5f42010-12-03 07:47:22 +00001660def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
1661 renderer=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001662 """Render text documentation, given an object or a path to an object."""
Georg Brandld80d5f42010-12-03 07:47:22 +00001663 if renderer is None:
1664 renderer = text
Guido van Rossumd8faa362007-04-27 19:54:29 +00001665 object, name = resolve(thing, forceload)
1666 desc = describe(object)
1667 module = inspect.getmodule(object)
1668 if name and '.' in name:
1669 desc += ' in ' + name[:name.rfind('.')]
1670 elif module and module is not object:
1671 desc += ' in module ' + module.__name__
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001672
1673 if not (inspect.ismodule(object) or
Guido van Rossumd8faa362007-04-27 19:54:29 +00001674 inspect.isclass(object) or
1675 inspect.isroutine(object) or
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001676 inspect.isdatadescriptor(object)):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001677 # If the passed object is a piece of data or an instance,
1678 # document its available methods instead of its value.
1679 object = type(object)
1680 desc += ' object'
Georg Brandld80d5f42010-12-03 07:47:22 +00001681 return title % desc + '\n\n' + renderer.document(object, name)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001682
Georg Brandld80d5f42010-12-03 07:47:22 +00001683def doc(thing, title='Python Library Documentation: %s', forceload=0,
1684 output=None):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001685 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001686 try:
Georg Brandld80d5f42010-12-03 07:47:22 +00001687 if output is None:
1688 pager(render_doc(thing, title, forceload))
1689 else:
1690 output.write(render_doc(thing, title, forceload, plaintext))
Guido van Rossumb940e112007-01-10 16:19:56 +00001691 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001692 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001693
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001694def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001695 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001696 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001697 object, name = resolve(thing, forceload)
1698 page = html.page(describe(object), html.document(object, name))
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +03001699 with open(name + '.html', 'w', encoding='utf-8') as file:
1700 file.write(page)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001701 print('wrote', name + '.html')
Guido van Rossumb940e112007-01-10 16:19:56 +00001702 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001703 print(value)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001704
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001705def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001706 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001707 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001708 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1709 writedoc(modname)
1710 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001711
1712class Helper:
Georg Brandl6b38daa2008-06-01 21:05:17 +00001713
1714 # These dictionaries map a topic name to either an alias, or a tuple
1715 # (label, seealso-items). The "label" is the label of the corresponding
1716 # section in the .rst file under Doc/ and an index into the dictionary
Georg Brandl5617db82009-04-27 16:28:57 +00001717 # in pydoc_data/topics.py.
Georg Brandl6b38daa2008-06-01 21:05:17 +00001718 #
1719 # CAUTION: if you change one of these dictionaries, be sure to adapt the
Jelle Zijlstraac317702017-10-05 20:24:46 -07001720 # list of needed labels in Doc/tools/extensions/pyspecific.py and
Georg Brandl5617db82009-04-27 16:28:57 +00001721 # regenerate the pydoc_data/topics.py file by running
Georg Brandl6b38daa2008-06-01 21:05:17 +00001722 # make pydoc-topics
1723 # in Doc/ and copying the output file into the Lib/ directory.
1724
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001725 keywords = {
Ezio Melottib185a042011-04-28 07:42:55 +03001726 'False': '',
1727 'None': '',
1728 'True': '',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001729 'and': 'BOOLEAN',
Guido van Rossumd8faa362007-04-27 19:54:29 +00001730 'as': 'with',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001731 'assert': ('assert', ''),
Jelle Zijlstraac317702017-10-05 20:24:46 -07001732 'async': ('async', ''),
1733 'await': ('await', ''),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001734 'break': ('break', 'while for'),
1735 'class': ('class', 'CLASSES SPECIALMETHODS'),
1736 'continue': ('continue', 'while for'),
1737 'def': ('function', ''),
1738 'del': ('del', 'BASICMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001739 'elif': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001740 'else': ('else', 'while for'),
Georg Brandl0d855392008-08-30 19:53:05 +00001741 'except': 'try',
1742 'finally': 'try',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001743 'for': ('for', 'break continue while'),
Georg Brandl0d855392008-08-30 19:53:05 +00001744 'from': 'import',
Georg Brandl74abf6f2010-11-20 19:54:36 +00001745 'global': ('global', 'nonlocal NAMESPACES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001746 'if': ('if', 'TRUTHVALUE'),
1747 'import': ('import', 'MODULES'),
Georg Brandl395ed242009-09-04 08:07:32 +00001748 'in': ('in', 'SEQUENCEMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001749 'is': 'COMPARISON',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001750 'lambda': ('lambda', 'FUNCTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001751 'nonlocal': ('nonlocal', 'global NAMESPACES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001752 'not': 'BOOLEAN',
1753 'or': 'BOOLEAN',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001754 'pass': ('pass', ''),
1755 'raise': ('raise', 'EXCEPTIONS'),
1756 'return': ('return', 'FUNCTIONS'),
1757 'try': ('try', 'EXCEPTIONS'),
1758 'while': ('while', 'break continue if TRUTHVALUE'),
1759 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1760 'yield': ('yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001761 }
Georg Brandldb7b6b92009-01-01 15:53:14 +00001762 # Either add symbols to this dictionary or to the symbols dictionary
1763 # directly: Whichever is easier. They are merged later.
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001764 _strprefixes = [p + q for p in ('b', 'f', 'r', 'u') for q in ("'", '"')]
Georg Brandldb7b6b92009-01-01 15:53:14 +00001765 _symbols_inverse = {
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001766 'STRINGS' : ("'", "'''", '"', '"""', *_strprefixes),
Georg Brandldb7b6b92009-01-01 15:53:14 +00001767 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1768 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1769 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1770 'UNARY' : ('-', '~'),
1771 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1772 '^=', '<<=', '>>=', '**=', '//='),
1773 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1774 'COMPLEX' : ('j', 'J')
1775 }
1776 symbols = {
1777 '%': 'OPERATORS FORMATTING',
1778 '**': 'POWER',
1779 ',': 'TUPLES LISTS FUNCTIONS',
1780 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1781 '...': 'ELLIPSIS',
1782 ':': 'SLICINGS DICTIONARYLITERALS',
1783 '@': 'def class',
1784 '\\': 'STRINGS',
1785 '_': 'PRIVATENAMES',
1786 '__': 'PRIVATENAMES SPECIALMETHODS',
1787 '`': 'BACKQUOTES',
1788 '(': 'TUPLES FUNCTIONS CALLS',
1789 ')': 'TUPLES FUNCTIONS CALLS',
1790 '[': 'LISTS SUBSCRIPTS SLICINGS',
1791 ']': 'LISTS SUBSCRIPTS SLICINGS'
1792 }
1793 for topic, symbols_ in _symbols_inverse.items():
1794 for symbol in symbols_:
1795 topics = symbols.get(symbol, topic)
1796 if topic not in topics:
1797 topics = topics + ' ' + topic
1798 symbols[symbol] = topics
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001799
1800 topics = {
Georg Brandl6b38daa2008-06-01 21:05:17 +00001801 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1802 'FUNCTIONS CLASSES MODULES FILES inspect'),
1803 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
1804 'FORMATTING TYPES'),
1805 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1806 'FORMATTING': ('formatstrings', 'OPERATORS'),
1807 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1808 'FORMATTING TYPES'),
1809 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1810 'INTEGER': ('integers', 'int range'),
1811 'FLOAT': ('floating', 'float math'),
1812 'COMPLEX': ('imaginary', 'complex cmath'),
1813 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001814 'MAPPINGS': 'DICTIONARIES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001815 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1816 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1817 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1818 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001819 'FRAMEOBJECTS': 'TYPES',
1820 'TRACEBACKS': 'TYPES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001821 'NONE': ('bltin-null-object', ''),
1822 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001823 'SPECIALATTRIBUTES': ('specialattrs', ''),
1824 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1825 'MODULES': ('typesmodules', 'import'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001826 'PACKAGES': 'import',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001827 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1828 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1829 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1830 'LISTS DICTIONARIES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001831 'OPERATORS': 'EXPRESSIONS',
1832 'PRECEDENCE': 'EXPRESSIONS',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001833 'OBJECTS': ('objects', 'TYPES'),
1834 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
Georg Brandl395ed242009-09-04 08:07:32 +00001835 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
1836 'NUMBERMETHODS CLASSES'),
Mark Dickinsona56c4672009-01-27 18:17:45 +00001837 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001838 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1839 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001840 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
Georg Brandl6b38daa2008-06-01 21:05:17 +00001841 'SPECIALMETHODS'),
1842 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1843 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1844 'SPECIALMETHODS'),
1845 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001846 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001847 'DYNAMICFEATURES': ('dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001848 'SCOPING': 'NAMESPACES',
1849 'FRAMES': 'NAMESPACES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001850 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1851 'CONVERSIONS': ('conversions', ''),
1852 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1853 'SPECIALIDENTIFIERS': ('id-classes', ''),
1854 'PRIVATENAMES': ('atom-identifiers', ''),
1855 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
1856 'LISTLITERALS DICTIONARYLITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001857 'TUPLES': 'SEQUENCES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001858 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1859 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1860 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1861 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1862 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1863 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001864 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
1865 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001866 'CALLS': ('calls', 'EXPRESSIONS'),
1867 'POWER': ('power', 'EXPRESSIONS'),
1868 'UNARY': ('unary', 'EXPRESSIONS'),
1869 'BINARY': ('binary', 'EXPRESSIONS'),
1870 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1871 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1872 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1873 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001874 'ASSERTION': 'assert',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001875 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1876 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001877 'DELETION': 'del',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001878 'RETURNING': 'return',
1879 'IMPORTING': 'import',
1880 'CONDITIONAL': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001881 'LOOPING': ('compound', 'for while break continue'),
1882 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1883 'DEBUGGING': ('debugger', 'pdb'),
1884 'CONTEXTMANAGERS': ('context-managers', 'with'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001885 }
1886
Georg Brandl78aa3962010-07-31 21:51:48 +00001887 def __init__(self, input=None, output=None):
1888 self._input = input
1889 self._output = output
1890
Serhiy Storchakabdf6b912017-03-19 08:40:32 +02001891 @property
1892 def input(self):
1893 return self._input or sys.stdin
1894
1895 @property
1896 def output(self):
1897 return self._output or sys.stdout
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001898
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001899 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001900 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001901 self()
1902 return ''
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001903 return '<%s.%s instance>' % (self.__class__.__module__,
1904 self.__class__.__qualname__)
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001905
Alexander Belopolsky2e733c92010-07-04 17:00:20 +00001906 _GoInteractive = object()
1907 def __call__(self, request=_GoInteractive):
1908 if request is not self._GoInteractive:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001909 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001910 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001911 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001912 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001913 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001914You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001915If you want to ask for help on a particular object directly from the
1916interpreter, you can type "help(object)". Executing "help('string')"
1917has the same effect as typing a particular string at the help> prompt.
1918''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001919
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001920 def interact(self):
1921 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001922 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001923 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001924 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001925 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001926 except (KeyboardInterrupt, EOFError):
1927 break
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001928 request = request.strip()
1929
1930 # Make sure significant trailing quoting marks of literals don't
1931 # get deleted while cleaning input
1932 if (len(request) > 2 and request[0] == request[-1] in ("'", '"')
1933 and request[0] not in request[1:-1]):
1934 request = request[1:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001935 if request.lower() in ('q', 'quit'): break
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001936 if request == 'help':
1937 self.intro()
1938 else:
1939 self.help(request)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001940
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001941 def getline(self, prompt):
Guido van Rossum7c086c02008-01-02 03:52:38 +00001942 """Read one line, using input() when appropriate."""
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001943 if self.input is sys.stdin:
Guido van Rossum7c086c02008-01-02 03:52:38 +00001944 return input(prompt)
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001945 else:
1946 self.output.write(prompt)
1947 self.output.flush()
1948 return self.input.readline()
1949
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001950 def help(self, request):
1951 if type(request) is type(''):
R. David Murray1f1b9d32009-05-27 20:56:59 +00001952 request = request.strip()
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001953 if request == 'keywords': self.listkeywords()
Georg Brandldb7b6b92009-01-01 15:53:14 +00001954 elif request == 'symbols': self.listsymbols()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001955 elif request == 'topics': self.listtopics()
1956 elif request == 'modules': self.listmodules()
1957 elif request[:8] == 'modules ':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001958 self.listmodules(request.split()[1])
Georg Brandldb7b6b92009-01-01 15:53:14 +00001959 elif request in self.symbols: self.showsymbol(request)
Ezio Melottib185a042011-04-28 07:42:55 +03001960 elif request in ['True', 'False', 'None']:
1961 # special case these keywords since they are objects too
1962 doc(eval(request), 'Help on %s:')
Raymond Hettinger54f02222002-06-01 14:18:47 +00001963 elif request in self.keywords: self.showtopic(request)
1964 elif request in self.topics: self.showtopic(request)
Georg Brandld80d5f42010-12-03 07:47:22 +00001965 elif request: doc(request, 'Help on %s:', output=self._output)
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001966 else: doc(str, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001967 elif isinstance(request, Helper): self()
Georg Brandld80d5f42010-12-03 07:47:22 +00001968 else: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001969 self.output.write('\n')
1970
1971 def intro(self):
1972 self.output.write('''
Serhiy Storchaka885bdc42016-02-11 13:10:36 +02001973Welcome to Python {0}'s help utility!
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001974
1975If this is your first time using Python, you should definitely check out
oldke5681b92017-12-28 22:37:46 +08001976the tutorial on the Internet at https://docs.python.org/{0}/tutorial/.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001977
1978Enter the name of any module, keyword, or topic to get help on writing
1979Python programs and using Python modules. To quit this help utility and
1980return to the interpreter, just type "quit".
1981
Terry Jan Reedy34200572013-02-11 02:23:13 -05001982To get a list of available modules, keywords, symbols, or topics, type
1983"modules", "keywords", "symbols", or "topics". Each module also comes
1984with a one-line summary of what it does; to list the modules whose name
1985or summary contain a given string such as "spam", type "modules spam".
Serhiy Storchaka885bdc42016-02-11 13:10:36 +02001986'''.format('%d.%d' % sys.version_info[:2]))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001987
1988 def list(self, items, columns=4, width=80):
Guido van Rossum486364b2007-06-30 05:01:58 +00001989 items = list(sorted(items))
1990 colw = width // columns
1991 rows = (len(items) + columns - 1) // columns
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001992 for row in range(rows):
1993 for col in range(columns):
1994 i = col * rows + row
1995 if i < len(items):
1996 self.output.write(items[i])
1997 if col < columns - 1:
Guido van Rossum486364b2007-06-30 05:01:58 +00001998 self.output.write(' ' + ' ' * (colw - 1 - len(items[i])))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001999 self.output.write('\n')
2000
2001 def listkeywords(self):
2002 self.output.write('''
2003Here is a list of the Python keywords. Enter any keyword to get more help.
2004
2005''')
2006 self.list(self.keywords.keys())
2007
Georg Brandldb7b6b92009-01-01 15:53:14 +00002008 def listsymbols(self):
2009 self.output.write('''
2010Here is a list of the punctuation symbols which Python assigns special meaning
2011to. Enter any symbol to get more help.
2012
2013''')
2014 self.list(self.symbols.keys())
2015
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002016 def listtopics(self):
2017 self.output.write('''
2018Here is a list of available topics. Enter any topic name to get more help.
2019
2020''')
2021 self.list(self.topics.keys())
2022
Georg Brandldb7b6b92009-01-01 15:53:14 +00002023 def showtopic(self, topic, more_xrefs=''):
Georg Brandl6b38daa2008-06-01 21:05:17 +00002024 try:
Georg Brandl5617db82009-04-27 16:28:57 +00002025 import pydoc_data.topics
Brett Cannoncd171c82013-07-04 17:43:24 -04002026 except ImportError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002027 self.output.write('''
Georg Brandl6b38daa2008-06-01 21:05:17 +00002028Sorry, topic and keyword documentation is not available because the
Georg Brandl5617db82009-04-27 16:28:57 +00002029module "pydoc_data.topics" could not be found.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002030''')
2031 return
2032 target = self.topics.get(topic, self.keywords.get(topic))
2033 if not target:
2034 self.output.write('no documentation found for %s\n' % repr(topic))
2035 return
2036 if type(target) is type(''):
Georg Brandldb7b6b92009-01-01 15:53:14 +00002037 return self.showtopic(target, more_xrefs)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002038
Georg Brandl6b38daa2008-06-01 21:05:17 +00002039 label, xrefs = target
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002040 try:
Georg Brandl5617db82009-04-27 16:28:57 +00002041 doc = pydoc_data.topics.topics[label]
Georg Brandl6b38daa2008-06-01 21:05:17 +00002042 except KeyError:
2043 self.output.write('no documentation found for %s\n' % repr(topic))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002044 return
Berker Peksagd04f46c2018-07-23 08:37:47 +03002045 doc = doc.strip() + '\n'
Georg Brandldb7b6b92009-01-01 15:53:14 +00002046 if more_xrefs:
2047 xrefs = (xrefs or '') + ' ' + more_xrefs
Ka-Ping Yeeda793892001-04-13 11:02:51 +00002048 if xrefs:
Brett Cannon1448ecf2013-10-04 11:38:59 -04002049 import textwrap
2050 text = 'Related help topics: ' + ', '.join(xrefs.split()) + '\n'
2051 wrapped_text = textwrap.wrap(text, 72)
Berker Peksagd04f46c2018-07-23 08:37:47 +03002052 doc += '\n%s\n' % '\n'.join(wrapped_text)
2053 pager(doc)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002054
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002055 def _gettopic(self, topic, more_xrefs=''):
2056 """Return unbuffered tuple of (topic, xrefs).
2057
Georg Brandld2f38572011-01-30 08:37:19 +00002058 If an error occurs here, the exception is caught and displayed by
2059 the url handler.
2060
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002061 This function duplicates the showtopic method but returns its
2062 result directly so it can be formatted for display in an html page.
2063 """
2064 try:
2065 import pydoc_data.topics
Brett Cannoncd171c82013-07-04 17:43:24 -04002066 except ImportError:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002067 return('''
2068Sorry, topic and keyword documentation is not available because the
2069module "pydoc_data.topics" could not be found.
2070''' , '')
2071 target = self.topics.get(topic, self.keywords.get(topic))
2072 if not target:
Georg Brandld2f38572011-01-30 08:37:19 +00002073 raise ValueError('could not find topic')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002074 if isinstance(target, str):
2075 return self._gettopic(target, more_xrefs)
2076 label, xrefs = target
Georg Brandld2f38572011-01-30 08:37:19 +00002077 doc = pydoc_data.topics.topics[label]
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002078 if more_xrefs:
2079 xrefs = (xrefs or '') + ' ' + more_xrefs
2080 return doc, xrefs
2081
Georg Brandldb7b6b92009-01-01 15:53:14 +00002082 def showsymbol(self, symbol):
2083 target = self.symbols[symbol]
2084 topic, _, xrefs = target.partition(' ')
2085 self.showtopic(topic, xrefs)
2086
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002087 def listmodules(self, key=''):
2088 if key:
2089 self.output.write('''
Terry Jan Reedy34200572013-02-11 02:23:13 -05002090Here is a list of modules whose name or summary contains '{}'.
2091If there are any, enter a module name to get more help.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002092
Terry Jan Reedy34200572013-02-11 02:23:13 -05002093'''.format(key))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002094 apropos(key)
2095 else:
2096 self.output.write('''
2097Please wait a moment while I gather a list of all available modules...
2098
2099''')
2100 modules = {}
2101 def callback(path, modname, desc, modules=modules):
2102 if modname and modname[-9:] == '.__init__':
2103 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002104 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002105 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002106 def onerror(modname):
2107 callback(None, modname, None)
2108 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002109 self.list(modules.keys())
2110 self.output.write('''
2111Enter any module name to get more help. Or, type "modules spam" to search
Terry Jan Reedy34200572013-02-11 02:23:13 -05002112for modules whose name or summary contain the string "spam".
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002113''')
2114
Georg Brandl78aa3962010-07-31 21:51:48 +00002115help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002116
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002117class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002118 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002119
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002120 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002121 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002122 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002123 seen = {}
2124
2125 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002126 if modname != '__main__':
2127 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00002128 if key is None:
2129 callback(None, modname, '')
2130 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002131 name = __import__(modname).__doc__ or ''
2132 desc = name.split('\n')[0]
2133 name = modname + ' - ' + desc
2134 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002135 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002136
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002137 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002138 if self.quit:
2139 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002140
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002141 if key is None:
2142 callback(None, modname, '')
2143 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002144 try:
Eric Snow3a62d142014-01-06 20:42:59 -07002145 spec = pkgutil._get_spec(importer, modname)
Georg Brandl126c8792009-04-05 15:05:48 +00002146 except SyntaxError:
2147 # raised by tests for bad coding cookies or BOM
2148 continue
Eric Snow3a62d142014-01-06 20:42:59 -07002149 loader = spec.loader
Georg Brandl126c8792009-04-05 15:05:48 +00002150 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002151 try:
2152 source = loader.get_source(modname)
Nick Coghlan2824cb52012-07-15 22:12:14 +10002153 except Exception:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002154 if onerror:
2155 onerror(modname)
2156 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002157 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002158 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002159 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002160 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002161 path = None
2162 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002163 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -04002164 module = importlib._bootstrap._load(spec)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002165 except ImportError:
2166 if onerror:
2167 onerror(modname)
2168 continue
Benjamin Peterson54237f92015-02-16 19:45:01 -05002169 desc = module.__doc__.splitlines()[0] if module.__doc__ else ''
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002170 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002171 name = modname + ' - ' + desc
2172 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002173 callback(path, modname, desc)
2174
2175 if completer:
2176 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002177
2178def apropos(key):
2179 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002180 def callback(path, modname, desc):
2181 if modname[-9:] == '.__init__':
2182 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002183 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002184 def onerror(modname):
2185 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002186 with warnings.catch_warnings():
2187 warnings.filterwarnings('ignore') # ignore problems during import
2188 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002189
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002190# --------------------------------------- enhanced Web browser interface
2191
Feanil Patel6a396c92017-09-14 17:54:09 -04002192def _start_server(urlhandler, hostname, port):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002193 """Start an HTTP server thread on a specific port.
2194
2195 Start an HTML/text server thread, so HTML or text documents can be
2196 browsed dynamically and interactively with a Web browser. Example use:
2197
2198 >>> import time
2199 >>> import pydoc
2200
2201 Define a URL handler. To determine what the client is asking
2202 for, check the URL and content_type.
2203
2204 Then get or generate some text or HTML code and return it.
2205
2206 >>> def my_url_handler(url, content_type):
2207 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2208 ... return text
2209
2210 Start server thread on port 0.
2211 If you use port 0, the server will pick a random port number.
2212 You can then use serverthread.port to get the port number.
2213
2214 >>> port = 0
2215 >>> serverthread = pydoc._start_server(my_url_handler, port)
2216
2217 Check that the server is really started. If it is, open browser
2218 and get first page. Use serverthread.url as the starting page.
2219
2220 >>> if serverthread.serving:
2221 ... import webbrowser
2222
2223 The next two lines are commented out so a browser doesn't open if
2224 doctest is run on this module.
2225
2226 #... webbrowser.open(serverthread.url)
2227 #True
2228
2229 Let the server do its thing. We just need to monitor its status.
2230 Use time.sleep so the loop doesn't hog the CPU.
2231
Victor Stinner2cf4c202018-12-17 09:36:36 +01002232 >>> starttime = time.monotonic()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002233 >>> timeout = 1 #seconds
2234
2235 This is a short timeout for testing purposes.
2236
2237 >>> while serverthread.serving:
2238 ... time.sleep(.01)
Victor Stinner2cf4c202018-12-17 09:36:36 +01002239 ... if serverthread.serving and time.monotonic() - starttime > timeout:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002240 ... serverthread.stop()
2241 ... break
2242
2243 Print any errors that may have occurred.
2244
2245 >>> print(serverthread.error)
2246 None
2247 """
2248 import http.server
2249 import email.message
2250 import select
2251 import threading
2252
2253 class DocHandler(http.server.BaseHTTPRequestHandler):
2254
2255 def do_GET(self):
2256 """Process a request from an HTML browser.
2257
2258 The URL received is in self.path.
2259 Get an HTML page from self.urlhandler and send it.
2260 """
2261 if self.path.endswith('.css'):
2262 content_type = 'text/css'
2263 else:
2264 content_type = 'text/html'
2265 self.send_response(200)
Georg Brandld2f38572011-01-30 08:37:19 +00002266 self.send_header('Content-Type', '%s; charset=UTF-8' % content_type)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002267 self.end_headers()
2268 self.wfile.write(self.urlhandler(
2269 self.path, content_type).encode('utf-8'))
2270
2271 def log_message(self, *args):
2272 # Don't log messages.
2273 pass
2274
2275 class DocServer(http.server.HTTPServer):
2276
Feanil Patel6a396c92017-09-14 17:54:09 -04002277 def __init__(self, host, port, callback):
2278 self.host = host
Senthil Kumaran2a42a0b2014-09-17 13:17:58 +08002279 self.address = (self.host, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002280 self.callback = callback
2281 self.base.__init__(self, self.address, self.handler)
2282 self.quit = False
2283
2284 def serve_until_quit(self):
2285 while not self.quit:
2286 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2287 if rd:
2288 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002289 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002290
2291 def server_activate(self):
2292 self.base.server_activate(self)
2293 if self.callback:
2294 self.callback(self)
2295
2296 class ServerThread(threading.Thread):
2297
Feanil Patel6a396c92017-09-14 17:54:09 -04002298 def __init__(self, urlhandler, host, port):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002299 self.urlhandler = urlhandler
Feanil Patel6a396c92017-09-14 17:54:09 -04002300 self.host = host
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002301 self.port = int(port)
2302 threading.Thread.__init__(self)
2303 self.serving = False
2304 self.error = None
2305
2306 def run(self):
2307 """Start the server."""
2308 try:
2309 DocServer.base = http.server.HTTPServer
2310 DocServer.handler = DocHandler
2311 DocHandler.MessageClass = email.message.Message
2312 DocHandler.urlhandler = staticmethod(self.urlhandler)
Feanil Patel6a396c92017-09-14 17:54:09 -04002313 docsvr = DocServer(self.host, self.port, self.ready)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002314 self.docserver = docsvr
2315 docsvr.serve_until_quit()
2316 except Exception as e:
2317 self.error = e
2318
2319 def ready(self, server):
2320 self.serving = True
2321 self.host = server.host
2322 self.port = server.server_port
2323 self.url = 'http://%s:%d/' % (self.host, self.port)
2324
2325 def stop(self):
2326 """Stop the server and this thread nicely"""
2327 self.docserver.quit = True
Victor Stinner4cab2cd2017-08-21 23:24:40 +02002328 self.join()
2329 # explicitly break a reference cycle: DocServer.callback
2330 # has indirectly a reference to ServerThread.
2331 self.docserver = None
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002332 self.serving = False
2333 self.url = None
2334
Feanil Patel6a396c92017-09-14 17:54:09 -04002335 thread = ServerThread(urlhandler, hostname, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002336 thread.start()
2337 # Wait until thread.serving is True to make sure we are
2338 # really up before returning.
2339 while not thread.error and not thread.serving:
2340 time.sleep(.01)
2341 return thread
2342
2343
2344def _url_handler(url, content_type="text/html"):
2345 """The pydoc url handler for use with the pydoc server.
2346
2347 If the content_type is 'text/css', the _pydoc.css style
2348 sheet is read and returned if it exits.
2349
2350 If the content_type is 'text/html', then the result of
2351 get_html_page(url) is returned.
2352 """
2353 class _HTMLDoc(HTMLDoc):
2354
2355 def page(self, title, contents):
2356 """Format an HTML page."""
2357 css_path = "pydoc_data/_pydoc.css"
2358 css_link = (
2359 '<link rel="stylesheet" type="text/css" href="%s">' %
2360 css_path)
2361 return '''\
2362<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Georg Brandld2f38572011-01-30 08:37:19 +00002363<html><head><title>Pydoc: %s</title>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002364<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Georg Brandld2f38572011-01-30 08:37:19 +00002365%s</head><body bgcolor="#f0f0f8">%s<div style="clear:both;padding-top:.5em;">%s</div>
2366</body></html>''' % (title, css_link, html_navbar(), contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002367
2368 def filelink(self, url, path):
2369 return '<a href="getfile?key=%s">%s</a>' % (url, path)
2370
2371
2372 html = _HTMLDoc()
2373
2374 def html_navbar():
Georg Brandld2f38572011-01-30 08:37:19 +00002375 version = html.escape("%s [%s, %s]" % (platform.python_version(),
2376 platform.python_build()[0],
2377 platform.python_compiler()))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002378 return """
2379 <div style='float:left'>
Georg Brandld2f38572011-01-30 08:37:19 +00002380 Python %s<br>%s
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002381 </div>
2382 <div style='float:right'>
2383 <div style='text-align:center'>
2384 <a href="index.html">Module Index</a>
2385 : <a href="topics.html">Topics</a>
2386 : <a href="keywords.html">Keywords</a>
2387 </div>
2388 <div>
Georg Brandld2f38572011-01-30 08:37:19 +00002389 <form action="get" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002390 <input type=text name=key size=15>
2391 <input type=submit value="Get">
Georg Brandld2f38572011-01-30 08:37:19 +00002392 </form>&nbsp;
2393 <form action="search" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002394 <input type=text name=key size=15>
2395 <input type=submit value="Search">
2396 </form>
2397 </div>
2398 </div>
Georg Brandld2f38572011-01-30 08:37:19 +00002399 """ % (version, html.escape(platform.platform(terse=True)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002400
2401 def html_index():
2402 """Module Index page."""
2403
2404 def bltinlink(name):
2405 return '<a href="%s.html">%s</a>' % (name, name)
2406
2407 heading = html.heading(
2408 '<big><big><strong>Index of Modules</strong></big></big>',
2409 '#ffffff', '#7799ee')
2410 names = [name for name in sys.builtin_module_names
2411 if name != '__main__']
2412 contents = html.multicolumn(names, bltinlink)
2413 contents = [heading, '<p>' + html.bigsection(
2414 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2415
2416 seen = {}
2417 for dir in sys.path:
2418 contents.append(html.index(dir, seen))
2419
2420 contents.append(
2421 '<p align=right><font color="#909090" face="helvetica,'
2422 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2423 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002424 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002425
2426 def html_search(key):
2427 """Search results page."""
2428 # scan for modules
2429 search_result = []
2430
2431 def callback(path, modname, desc):
2432 if modname[-9:] == '.__init__':
2433 modname = modname[:-9] + ' (package)'
2434 search_result.append((modname, desc and '- ' + desc))
2435
2436 with warnings.catch_warnings():
2437 warnings.filterwarnings('ignore') # ignore problems during import
Martin Panter9ad0aae2015-11-06 00:27:14 +00002438 def onerror(modname):
2439 pass
2440 ModuleScanner().run(callback, key, onerror=onerror)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002441
2442 # format page
2443 def bltinlink(name):
2444 return '<a href="%s.html">%s</a>' % (name, name)
2445
2446 results = []
2447 heading = html.heading(
2448 '<big><big><strong>Search Results</strong></big></big>',
2449 '#ffffff', '#7799ee')
2450 for name, desc in search_result:
2451 results.append(bltinlink(name) + desc)
2452 contents = heading + html.bigsection(
2453 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002454 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002455
2456 def html_getfile(path):
2457 """Get and display a source file listing safely."""
Zachary Wareeb432142014-07-10 11:18:00 -05002458 path = urllib.parse.unquote(path)
Victor Stinner91e08772011-07-05 14:30:41 +02002459 with tokenize.open(path) as fp:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002460 lines = html.escape(fp.read())
2461 body = '<pre>%s</pre>' % lines
2462 heading = html.heading(
2463 '<big><big><strong>File Listing</strong></big></big>',
2464 '#ffffff', '#7799ee')
2465 contents = heading + html.bigsection(
2466 'File: %s' % path, '#ffffff', '#ee77aa', body)
Nick Coghlanecace282010-12-03 16:08:46 +00002467 return 'getfile %s' % path, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002468
2469 def html_topics():
2470 """Index of topic texts available."""
2471
2472 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002473 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002474
2475 heading = html.heading(
2476 '<big><big><strong>INDEX</strong></big></big>',
2477 '#ffffff', '#7799ee')
2478 names = sorted(Helper.topics.keys())
2479
2480 contents = html.multicolumn(names, bltinlink)
2481 contents = heading + html.bigsection(
2482 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002483 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002484
2485 def html_keywords():
2486 """Index of keywords."""
2487 heading = html.heading(
2488 '<big><big><strong>INDEX</strong></big></big>',
2489 '#ffffff', '#7799ee')
2490 names = sorted(Helper.keywords.keys())
2491
2492 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002493 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002494
2495 contents = html.multicolumn(names, bltinlink)
2496 contents = heading + html.bigsection(
2497 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002498 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002499
2500 def html_topicpage(topic):
2501 """Topic or keyword help page."""
2502 buf = io.StringIO()
2503 htmlhelp = Helper(buf, buf)
2504 contents, xrefs = htmlhelp._gettopic(topic)
2505 if topic in htmlhelp.keywords:
2506 title = 'KEYWORD'
2507 else:
2508 title = 'TOPIC'
2509 heading = html.heading(
2510 '<big><big><strong>%s</strong></big></big>' % title,
2511 '#ffffff', '#7799ee')
Georg Brandld2f38572011-01-30 08:37:19 +00002512 contents = '<pre>%s</pre>' % html.markup(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002513 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
Georg Brandld2f38572011-01-30 08:37:19 +00002514 if xrefs:
2515 xrefs = sorted(xrefs.split())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002516
Georg Brandld2f38572011-01-30 08:37:19 +00002517 def bltinlink(name):
2518 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002519
Georg Brandld2f38572011-01-30 08:37:19 +00002520 xrefs = html.multicolumn(xrefs, bltinlink)
2521 xrefs = html.section('Related help topics: ',
2522 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002523 return ('%s %s' % (title, topic),
2524 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002525
Georg Brandld2f38572011-01-30 08:37:19 +00002526 def html_getobj(url):
2527 obj = locate(url, forceload=1)
2528 if obj is None and url != 'None':
2529 raise ValueError('could not find object')
2530 title = describe(obj)
2531 content = html.document(obj, url)
2532 return title, content
2533
2534 def html_error(url, exc):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002535 heading = html.heading(
2536 '<big><big><strong>Error</strong></big></big>',
Georg Brandld2f38572011-01-30 08:37:19 +00002537 '#ffffff', '#7799ee')
2538 contents = '<br>'.join(html.escape(line) for line in
2539 format_exception_only(type(exc), exc))
2540 contents = heading + html.bigsection(url, '#ffffff', '#bb0000',
2541 contents)
2542 return "Error - %s" % url, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002543
2544 def get_html_page(url):
2545 """Generate an HTML page for url."""
Georg Brandld2f38572011-01-30 08:37:19 +00002546 complete_url = url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002547 if url.endswith('.html'):
2548 url = url[:-5]
Georg Brandld2f38572011-01-30 08:37:19 +00002549 try:
2550 if url in ("", "index"):
2551 title, content = html_index()
2552 elif url == "topics":
2553 title, content = html_topics()
2554 elif url == "keywords":
2555 title, content = html_keywords()
2556 elif '=' in url:
2557 op, _, url = url.partition('=')
2558 if op == "search?key":
2559 title, content = html_search(url)
2560 elif op == "getfile?key":
2561 title, content = html_getfile(url)
2562 elif op == "topic?key":
2563 # try topics first, then objects.
2564 try:
2565 title, content = html_topicpage(url)
2566 except ValueError:
2567 title, content = html_getobj(url)
2568 elif op == "get?key":
2569 # try objects first, then topics.
2570 if url in ("", "index"):
2571 title, content = html_index()
2572 else:
2573 try:
2574 title, content = html_getobj(url)
2575 except ValueError:
2576 title, content = html_topicpage(url)
2577 else:
2578 raise ValueError('bad pydoc url')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002579 else:
Georg Brandld2f38572011-01-30 08:37:19 +00002580 title, content = html_getobj(url)
2581 except Exception as exc:
2582 # Catch any errors and display them in an error page.
2583 title, content = html_error(complete_url, exc)
2584 return html.page(title, content)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002585
2586 if url.startswith('/'):
2587 url = url[1:]
2588 if content_type == 'text/css':
2589 path_here = os.path.dirname(os.path.realpath(__file__))
Georg Brandld2f38572011-01-30 08:37:19 +00002590 css_path = os.path.join(path_here, url)
2591 with open(css_path) as fp:
2592 return ''.join(fp.readlines())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002593 elif content_type == 'text/html':
2594 return get_html_page(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002595 # Errors outside the url handler are caught by the server.
2596 raise TypeError('unknown content type %r for url %s' % (content_type, url))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002597
2598
Feanil Patel6a396c92017-09-14 17:54:09 -04002599def browse(port=0, *, open_browser=True, hostname='localhost'):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002600 """Start the enhanced pydoc Web server and open a Web browser.
2601
2602 Use port '0' to start the server on an arbitrary port.
2603 Set open_browser to False to suppress opening a browser.
2604 """
2605 import webbrowser
Feanil Patel6a396c92017-09-14 17:54:09 -04002606 serverthread = _start_server(_url_handler, hostname, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002607 if serverthread.error:
2608 print(serverthread.error)
2609 return
2610 if serverthread.serving:
2611 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2612 if open_browser:
2613 webbrowser.open(serverthread.url)
2614 try:
2615 print('Server ready at', serverthread.url)
2616 print(server_help_msg)
2617 while serverthread.serving:
2618 cmd = input('server> ')
2619 cmd = cmd.lower()
2620 if cmd == 'q':
2621 break
2622 elif cmd == 'b':
2623 webbrowser.open(serverthread.url)
2624 else:
2625 print(server_help_msg)
2626 except (KeyboardInterrupt, EOFError):
2627 print()
2628 finally:
2629 if serverthread.serving:
2630 serverthread.stop()
2631 print('Server stopped')
2632
2633
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002634# -------------------------------------------------- command-line interface
2635
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002636def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002637 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002638
Nick Coghlan82a94812018-04-15 21:52:57 +10002639def _get_revised_path(given_path, argv0):
2640 """Ensures current directory is on returned path, and argv0 directory is not
2641
2642 Exception: argv0 dir is left alone if it's also pydoc's directory.
2643
2644 Returns a new path entry list, or None if no adjustment is needed.
2645 """
2646 # Scripts may get the current directory in their path by default if they're
2647 # run with the -m switch, or directly from the current directory.
2648 # The interactive prompt also allows imports from the current directory.
2649
2650 # Accordingly, if the current directory is already present, don't make
2651 # any changes to the given_path
2652 if '' in given_path or os.curdir in given_path or os.getcwd() in given_path:
2653 return None
2654
2655 # Otherwise, add the current directory to the given path, and remove the
2656 # script directory (as long as the latter isn't also pydoc's directory.
2657 stdlib_dir = os.path.dirname(__file__)
2658 script_dir = os.path.dirname(argv0)
2659 revised_path = given_path.copy()
2660 if script_dir in given_path and not os.path.samefile(script_dir, stdlib_dir):
2661 revised_path.remove(script_dir)
2662 revised_path.insert(0, os.getcwd())
2663 return revised_path
2664
2665
2666# Note: the tests only cover _get_revised_path, not _adjust_cli_path itself
2667def _adjust_cli_sys_path():
Nick Coghlan1a5c4bd2018-04-15 23:32:05 +10002668 """Ensures current directory is on sys.path, and __main__ directory is not.
Nick Coghlan82a94812018-04-15 21:52:57 +10002669
2670 Exception: __main__ dir is left alone if it's also pydoc's directory.
2671 """
2672 revised_path = _get_revised_path(sys.path, sys.argv[0])
2673 if revised_path is not None:
2674 sys.path[:] = revised_path
2675
2676
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002677def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002678 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002679 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002680 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002681
Nick Coghlan82a94812018-04-15 21:52:57 +10002682 _adjust_cli_sys_path()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002683
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002684 try:
Feanil Patel6a396c92017-09-14 17:54:09 -04002685 opts, args = getopt.getopt(sys.argv[1:], 'bk:n:p:w')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002686 writing = False
2687 start_server = False
2688 open_browser = False
Feanil Patel6a396c92017-09-14 17:54:09 -04002689 port = 0
2690 hostname = 'localhost'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002691 for opt, val in opts:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002692 if opt == '-b':
2693 start_server = True
2694 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002695 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002696 apropos(val)
2697 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002698 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002699 start_server = True
2700 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002701 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002702 writing = True
Feanil Patel6a396c92017-09-14 17:54:09 -04002703 if opt == '-n':
2704 start_server = True
2705 hostname = val
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002706
Benjamin Petersonb29614e2012-10-09 11:16:03 -04002707 if start_server:
Feanil Patel6a396c92017-09-14 17:54:09 -04002708 browse(port, hostname=hostname, open_browser=open_browser)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002709 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002710
2711 if not args: raise BadUsage
2712 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002713 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002714 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002715 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002716 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002717 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002718 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002719 if writing:
2720 if ispath(arg) and os.path.isdir(arg):
2721 writedocs(arg)
2722 else:
2723 writedoc(arg)
2724 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002725 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002726 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002727 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002728
2729 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002730 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002731 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002732
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002733{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002734 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002735 Python keyword, topic, function, module, or package, or a dotted
2736 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002737 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002738 Python source file to document. If name is 'keywords', 'topics',
2739 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002740
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002741{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002742 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002743
Feanil Patel6a396c92017-09-14 17:54:09 -04002744{cmd} -n <hostname>
2745 Start an HTTP server with the given hostname (default: localhost).
2746
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002747{cmd} -p <port>
2748 Start an HTTP server on the given port on the local machine. Port
2749 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002750
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002751{cmd} -b
2752 Start an HTTP server on an arbitrary unused port and open a Web browser
Feanil Patel6a396c92017-09-14 17:54:09 -04002753 to interactively browse documentation. This option can be used in
2754 combination with -n and/or -p.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002755
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002756{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002757 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002758 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002759 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002760""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002761
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002762if __name__ == '__main__':
2763 cli()