blob: daa7205bd74e95afd891ba61188f3e7b6c9b0772 [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'
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000206 results.append((name, kind, cls, value))
207 return results
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000208
Raymond Hettinger95801bb2015-08-18 22:25:16 -0700209def sort_attributes(attrs, object):
210 'Sort the attrs list in-place by _fields and then alphabetically by name'
211 # This allows data descriptors to be ordered according
212 # to a _fields attribute if present.
213 fields = getattr(object, '_fields', [])
214 try:
215 field_order = {name : i-len(fields) for (i, name) in enumerate(fields)}
216 except TypeError:
217 field_order = {}
218 keyfunc = lambda attr: (field_order.get(attr[0], 0), attr[0])
219 attrs.sort(key=keyfunc)
220
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000221# ----------------------------------------------------- module manipulation
222
223def ispackage(path):
224 """Guess whether a path refers to a package directory."""
225 if os.path.isdir(path):
Brett Cannonf299abd2015-04-13 14:21:02 -0400226 for ext in ('.py', '.pyc'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000227 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000228 return True
229 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000230
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000231def source_synopsis(file):
232 line = file.readline()
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000233 while line[:1] == '#' or not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000234 line = file.readline()
235 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000236 line = line.strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000237 if line[:4] == 'r"""': line = line[1:]
238 if line[:3] == '"""':
239 line = line[3:]
240 if line[-1:] == '\\': line = line[:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000241 while not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000242 line = file.readline()
243 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000244 result = line.split('"""')[0].strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000245 else: result = None
246 return result
247
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000248def synopsis(filename, cache={}):
249 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000250 mtime = os.stat(filename).st_mtime
Charles-François Natali27c4e882011-07-27 19:40:02 +0200251 lastupdate, result = cache.get(filename, (None, None))
252 if lastupdate is None or lastupdate < mtime:
Eric Snowaed5b222014-01-04 20:38:11 -0700253 # Look for binary suffixes first, falling back to source.
254 if filename.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)):
255 loader_cls = importlib.machinery.SourcelessFileLoader
256 elif filename.endswith(tuple(importlib.machinery.EXTENSION_SUFFIXES)):
257 loader_cls = importlib.machinery.ExtensionFileLoader
258 else:
259 loader_cls = None
260 # Now handle the choice.
261 if loader_cls is None:
262 # Must be a source file.
263 try:
264 file = tokenize.open(filename)
265 except OSError:
266 # module can't be opened, so skip it
267 return None
268 # text modules can be directly examined
269 with file:
270 result = source_synopsis(file)
271 else:
272 # Must be a binary module, which has to be imported.
273 loader = loader_cls('__temp__', filename)
Eric Snow3a62d142014-01-06 20:42:59 -0700274 # XXX We probably don't need to pass in the loader here.
275 spec = importlib.util.spec_from_file_location('__temp__', filename,
276 loader=loader)
Brett Cannoncb66eb02012-05-11 12:58:42 -0400277 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -0400278 module = importlib._bootstrap._load(spec)
Brett Cannoncb66eb02012-05-11 12:58:42 -0400279 except:
280 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000281 del sys.modules['__temp__']
Benjamin Peterson54237f92015-02-16 19:45:01 -0500282 result = module.__doc__.splitlines()[0] if module.__doc__ else None
Eric Snowaed5b222014-01-04 20:38:11 -0700283 # Cache the result.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000284 cache[filename] = (mtime, result)
285 return result
286
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000287class ErrorDuringImport(Exception):
288 """Errors that occurred while trying to import something to document it."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000289 def __init__(self, filename, exc_info):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000290 self.filename = filename
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000291 self.exc, self.value, self.tb = exc_info
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000292
293 def __str__(self):
Guido van Rossuma01a8b62007-05-27 09:20:14 +0000294 exc = self.exc.__name__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000295 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000296
297def importfile(path):
298 """Import a Python source file or compiled file given its path."""
Brett Cannonf4ba4ec2013-06-15 14:25:04 -0400299 magic = importlib.util.MAGIC_NUMBER
Victor Stinnere975af62011-07-04 02:08:50 +0200300 with open(path, 'rb') as file:
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400301 is_bytecode = magic == file.read(len(magic))
302 filename = os.path.basename(path)
303 name, ext = os.path.splitext(filename)
304 if is_bytecode:
Eric Snow32439d62015-05-02 19:15:18 -0600305 loader = importlib._bootstrap_external.SourcelessFileLoader(name, path)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400306 else:
Eric Snow32439d62015-05-02 19:15:18 -0600307 loader = importlib._bootstrap_external.SourceFileLoader(name, path)
Eric Snow3a62d142014-01-06 20:42:59 -0700308 # XXX We probably don't need to pass in the loader here.
309 spec = importlib.util.spec_from_file_location(name, path, loader=loader)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400310 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -0400311 return importlib._bootstrap._load(spec)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400312 except:
313 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000314
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000315def safeimport(path, forceload=0, cache={}):
316 """Import a module; handle errors; return None if the module isn't found.
317
318 If the module *is* found but an exception occurs, it's wrapped in an
319 ErrorDuringImport exception and reraised. Unlike __import__, if a
320 package path is specified, the module at the end of the path is returned,
321 not the package at the beginning. If the optional 'forceload' argument
322 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000323 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000324 # If forceload is 1 and the module has been previously loaded from
325 # disk, we always have to reload the module. Checking the file's
326 # mtime isn't good enough (e.g. the module could contain a class
327 # that inherits from another module that has changed).
328 if forceload and path in sys.modules:
329 if path not in sys.builtin_module_names:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000330 # Remove the module from sys.modules and re-import to try
331 # and avoid problems with partially loaded modules.
332 # Also remove any submodules because they won't appear
333 # in the newly loaded module's namespace if they're already
334 # in sys.modules.
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000335 subs = [m for m in sys.modules if m.startswith(path + '.')]
336 for key in [path] + subs:
337 # Prevent garbage collection.
338 cache[key] = sys.modules[key]
339 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000340 module = __import__(path)
341 except:
342 # Did the error occur before or after the module was found?
343 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000344 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000345 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000346 raise ErrorDuringImport(sys.modules[path].__file__, info)
347 elif exc is SyntaxError:
348 # A SyntaxError occurred before we could execute the module.
349 raise ErrorDuringImport(value.filename, info)
Eric Snow46f97b82016-09-07 16:56:15 -0700350 elif issubclass(exc, ImportError) and value.name == path:
Brett Cannonfd074152012-04-14 14:10:13 -0400351 # No such module in the path.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000352 return None
353 else:
354 # Some other error occurred during the importing process.
355 raise ErrorDuringImport(path, sys.exc_info())
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000356 for part in path.split('.')[1:]:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000357 try: module = getattr(module, part)
358 except AttributeError: return None
359 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000360
361# ---------------------------------------------------- formatter base class
362
363class Doc:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000364
365 PYTHONDOCS = os.environ.get("PYTHONDOCS",
R David Murrayead9bfc2016-06-03 19:28:35 -0400366 "https://docs.python.org/%d.%d/library"
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000367 % sys.version_info[:2])
368
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000369 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000370 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000371 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000372 # 'try' clause is to attempt to handle the possibility that inspect
373 # identifies something in a way that pydoc itself has issues handling;
374 # think 'super' and how it is a descriptor (which raises the exception
375 # by lacking a __name__ attribute) and an instance.
376 try:
377 if inspect.ismodule(object): return self.docmodule(*args)
378 if inspect.isclass(object): return self.docclass(*args)
379 if inspect.isroutine(object): return self.docroutine(*args)
380 except AttributeError:
381 pass
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200382 if inspect.isdatadescriptor(object): return self.docdata(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000383 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000384
385 def fail(self, object, name=None, *args):
386 """Raise an exception for unimplemented types."""
387 message = "don't know how to document object%s of type %s" % (
388 name and ' ' + repr(name), type(object).__name__)
Collin Winterce36ad82007-08-30 01:19:48 +0000389 raise TypeError(message)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000390
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000391 docmodule = docclass = docroutine = docother = docproperty = docdata = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000392
R David Murrayead9bfc2016-06-03 19:28:35 -0400393 def getdocloc(self, object,
394 basedir=os.path.join(sys.base_exec_prefix, "lib",
395 "python%d.%d" % sys.version_info[:2])):
Skip Montanaro4997a692003-09-10 16:47:51 +0000396 """Return the location of module docs or None"""
397
398 try:
399 file = inspect.getabsfile(object)
400 except TypeError:
401 file = '(built-in)'
402
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000403 docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
404
Martin Panter4f8aaf62016-06-12 04:24:06 +0000405 basedir = os.path.normcase(basedir)
Skip Montanaro4997a692003-09-10 16:47:51 +0000406 if (isinstance(object, type(os)) and
407 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
408 'marshal', 'posix', 'signal', 'sys',
Georg Brandl2067bfd2008-05-25 13:05:15 +0000409 '_thread', 'zipimport') or
Skip Montanaro4997a692003-09-10 16:47:51 +0000410 (file.startswith(basedir) and
Brian Curtin49c284c2010-03-31 03:19:28 +0000411 not file.startswith(os.path.join(basedir, 'site-packages')))) and
Brian Curtinedef05b2010-04-01 04:05:25 +0000412 object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
Martin Panter4f8aaf62016-06-12 04:24:06 +0000413 if docloc.startswith(("http://", "https://")):
R David Murrayead9bfc2016-06-03 19:28:35 -0400414 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__.lower())
Skip Montanaro4997a692003-09-10 16:47:51 +0000415 else:
R David Murrayead9bfc2016-06-03 19:28:35 -0400416 docloc = os.path.join(docloc, object.__name__.lower() + ".html")
Skip Montanaro4997a692003-09-10 16:47:51 +0000417 else:
418 docloc = None
419 return docloc
420
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000421# -------------------------------------------- HTML documentation generator
422
423class HTMLRepr(Repr):
424 """Class for safely making an HTML representation of a Python object."""
425 def __init__(self):
426 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000427 self.maxlist = self.maxtuple = 20
428 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000429 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000430
431 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000432 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000433
434 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000435 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000436
437 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000438 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000439 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000440 if hasattr(self, methodname):
441 return getattr(self, methodname)(x, level)
442 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000443
444 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000445 test = cram(x, self.maxstring)
446 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000447 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000448 # Backslashes are only literal in the string and are never
449 # needed to make any special characters, so show a raw string.
450 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000451 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000452 r'<font color="#c040c0">\1</font>',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000453 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000454
Skip Montanarodf708782002-03-07 22:58:02 +0000455 repr_str = repr_string
456
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000457 def repr_instance(self, x, level):
458 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000459 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000460 except:
461 return self.escape('<%s instance>' % x.__class__.__name__)
462
463 repr_unicode = repr_string
464
465class HTMLDoc(Doc):
466 """Formatter class for HTML documentation."""
467
468 # ------------------------------------------- HTML formatting utilities
469
470 _repr_instance = HTMLRepr()
471 repr = _repr_instance.repr
472 escape = _repr_instance.escape
473
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000474 def page(self, title, contents):
475 """Format an HTML page."""
Georg Brandl388faac2009-04-10 08:31:48 +0000476 return '''\
Georg Brandle6066942009-04-10 08:28:28 +0000477<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000478<html><head><title>Python: %s</title>
Georg Brandl388faac2009-04-10 08:31:48 +0000479<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000480</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000481%s
482</body></html>''' % (title, contents)
483
484 def heading(self, title, fgcol, bgcol, extras=''):
485 """Format a page heading."""
486 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000487<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000488<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000489<td valign=bottom>&nbsp;<br>
490<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000491><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000492><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000493 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
494
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000495 def section(self, title, fgcol, bgcol, contents, width=6,
496 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000497 """Format a section with a heading."""
498 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000499 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000500 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000501<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000502<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000503<td colspan=3 valign=bottom>&nbsp;<br>
504<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000505 ''' % (bgcol, fgcol, title)
506 if prelude:
507 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000508<tr bgcolor="%s"><td rowspan=2>%s</td>
509<td colspan=2>%s</td></tr>
510<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
511 else:
512 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000513<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000514
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000515 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000516
517 def bigsection(self, title, *args):
518 """Format a section with a big heading."""
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000519 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000520 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000521
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000522 def preformat(self, text):
523 """Format literal preformatted text."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000524 text = self.escape(text.expandtabs())
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000525 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
526 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000527
528 def multicolumn(self, list, format, cols=4):
529 """Format a list of items into a multi-column list."""
530 result = ''
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000531 rows = (len(list)+cols-1)//cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000532 for col in range(cols):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000533 result = result + '<td width="%d%%" valign=top>' % (100//cols)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000534 for i in range(rows*col, rows*col+rows):
535 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000536 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000537 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000538 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000539
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000540 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000541
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000542 def namelink(self, name, *dicts):
543 """Make a link for an identifier, given name-to-URL mappings."""
544 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000545 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000546 return '<a href="%s">%s</a>' % (dict[name], name)
547 return name
548
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000549 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000550 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000551 name, module = object.__name__, sys.modules.get(object.__module__)
552 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000553 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000554 module.__name__, name, classname(object, modname))
555 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000556
557 def modulelink(self, object):
558 """Make a link for a module."""
559 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
560
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000561 def modpkglink(self, modpkginfo):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000562 """Make a link for a module or package to display in an index."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000563 name, path, ispackage, shadowed = modpkginfo
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000564 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000565 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000566 if path:
567 url = '%s.%s.html' % (path, name)
568 else:
569 url = '%s.html' % name
570 if ispackage:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000571 text = '<strong>%s</strong>&nbsp;(package)' % name
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000572 else:
573 text = name
574 return '<a href="%s">%s</a>' % (url, text)
575
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000576 def filelink(self, url, path):
577 """Make a link to source file."""
578 return '<a href="file:%s">%s</a>' % (url, path)
579
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000580 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
581 """Mark up some plain text, given a context of symbols to look for.
582 Each context dictionary maps object names to anchor names."""
583 escape = escape or self.escape
584 results = []
585 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000586 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
587 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000588 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000589 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000590 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000591 match = pattern.search(text, here)
592 if not match: break
593 start, end = match.span()
594 results.append(escape(text[here:start]))
595
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000596 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000597 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000598 url = escape(all).replace('"', '&quot;')
599 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000600 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000601 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
602 results.append('<a href="%s">%s</a>' % (url, escape(all)))
603 elif pep:
Christian Heimes2202f872008-02-06 14:31:34 +0000604 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000605 results.append('<a href="%s">%s</a>' % (url, escape(all)))
Benjamin Petersoned1160b2014-06-07 16:44:00 -0700606 elif selfdot:
607 # Create a link for methods like 'self.method(...)'
608 # and use <strong> for attributes like 'self.attr'
609 if text[end:end+1] == '(':
610 results.append('self.' + self.namelink(name, methods))
611 else:
612 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000613 elif text[end:end+1] == '(':
614 results.append(self.namelink(name, methods, funcs, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000615 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000616 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000617 here = end
618 results.append(escape(text[here:]))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000619 return ''.join(results)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000620
621 # ---------------------------------------------- type-specific routines
622
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000623 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000624 """Produce HTML for a class tree as given by inspect.getclasstree()."""
625 result = ''
626 for entry in tree:
627 if type(entry) is type(()):
628 c, bases = entry
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000629 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000630 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000631 if bases and bases != (parent,):
632 parents = []
633 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000634 parents.append(self.classlink(base, modname))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000635 result = result + '(' + ', '.join(parents) + ')'
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000636 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000637 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000638 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000639 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000640 return '<dl>\n%s</dl>\n' % result
641
Tim Peters8dd7ade2001-10-18 19:56:17 +0000642 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000643 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000644 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000645 try:
646 all = object.__all__
647 except AttributeError:
648 all = None
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000649 parts = name.split('.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000650 links = []
651 for i in range(len(parts)-1):
652 links.append(
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000653 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000654 ('.'.join(parts[:i+1]), parts[i]))
655 linkedname = '.'.join(links + parts[-1:])
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000656 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000657 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000658 path = inspect.getabsfile(object)
Zachary Wareeb432142014-07-10 11:18:00 -0500659 url = urllib.parse.quote(path)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000660 filelink = self.filelink(url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000661 except TypeError:
662 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000663 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000664 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000665 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000666 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000667 version = version[11:-1].strip()
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000668 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000669 if hasattr(object, '__date__'):
670 info.append(self.escape(str(object.__date__)))
671 if info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000672 head = head + ' (%s)' % ', '.join(info)
Skip Montanaro4997a692003-09-10 16:47:51 +0000673 docloc = self.getdocloc(object)
674 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000675 docloc = '<br><a href="%(docloc)s">Module Reference</a>' % locals()
Skip Montanaro4997a692003-09-10 16:47:51 +0000676 else:
677 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000678 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000679 head, '#ffffff', '#7799ee',
680 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000681
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000682 modules = inspect.getmembers(object, inspect.ismodule)
683
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000684 classes, cdict = [], {}
685 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000686 # if __all__ exists, believe it. Otherwise use old heuristic.
687 if (all is not None or
688 (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700689 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000690 classes.append((key, value))
691 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000692 for key, value in classes:
693 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000694 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000695 module = sys.modules.get(modname)
696 if modname != name and module and hasattr(module, key):
697 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000698 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000699 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000700 funcs, fdict = [], {}
701 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000702 # if __all__ exists, believe it. Otherwise use old heuristic.
703 if (all is not None or
704 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700705 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000706 funcs.append((key, value))
707 fdict[key] = '#-' + key
708 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000709 data = []
710 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700711 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000712 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000713
714 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
715 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000716 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000717
718 if hasattr(object, '__path__'):
719 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000720 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
721 modpkgs.append((modname, name, ispkg, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000722 modpkgs.sort()
723 contents = self.multicolumn(modpkgs, self.modpkglink)
724 result = result + self.bigsection(
725 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000726 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000727 contents = self.multicolumn(
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000728 modules, lambda t: self.modulelink(t[1]))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000729 result = result + self.bigsection(
Christian Heimes7131fd92008-02-19 14:21:46 +0000730 'Modules', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000731
732 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000733 classlist = [value for (key, value) in classes]
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000734 contents = [
735 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000736 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000737 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000738 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000739 'Classes', '#ffffff', '#ee77aa', ' '.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000740 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000741 contents = []
742 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000743 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000744 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000745 'Functions', '#ffffff', '#eeaa77', ' '.join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000746 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000747 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000748 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000749 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000750 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000751 'Data', '#ffffff', '#55aa55', '<br>\n'.join(contents))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000752 if hasattr(object, '__author__'):
753 contents = self.markup(str(object.__author__), self.preformat)
754 result = result + self.bigsection(
755 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000756 if hasattr(object, '__credits__'):
757 contents = self.markup(str(object.__credits__), self.preformat)
758 result = result + self.bigsection(
759 'Credits', '#ffffff', '#7799ee', contents)
760
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000761 return result
762
Tim Peters8dd7ade2001-10-18 19:56:17 +0000763 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
764 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000765 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000766 realname = object.__name__
767 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000768 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000769
Tim Petersb47879b2001-09-24 04:47:19 +0000770 contents = []
771 push = contents.append
772
Tim Petersfa26f7c2001-09-24 08:05:11 +0000773 # Cute little class to pump out a horizontal rule between sections.
774 class HorizontalRule:
775 def __init__(self):
776 self.needone = 0
777 def maybe(self):
778 if self.needone:
779 push('<hr>\n')
780 self.needone = 1
781 hr = HorizontalRule()
782
Tim Petersc86f6ca2001-09-26 21:31:51 +0000783 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000784 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000785 if len(mro) > 2:
786 hr.maybe()
787 push('<dl><dt>Method resolution order:</dt>\n')
788 for base in mro:
789 push('<dd>%s</dd>\n' % self.classlink(base,
790 object.__module__))
791 push('</dl>\n')
792
Tim Petersb47879b2001-09-24 04:47:19 +0000793 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000794 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000795 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000796 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000797 push(msg)
798 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100799 try:
800 value = getattr(object, name)
801 except Exception:
802 # Some descriptors may meet a failure in their __get__.
803 # (bug #1785)
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200804 push(self.docdata(value, name, mod))
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100805 else:
806 push(self.document(value, name, mod,
807 funcs, classes, mdict, object))
Tim Petersb47879b2001-09-24 04:47:19 +0000808 push('\n')
809 return attrs
810
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000811 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000812 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000813 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000814 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000815 push(msg)
816 for name, kind, homecls, value in ok:
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200817 push(self.docdata(value, name, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000818 return attrs
819
Tim Petersfa26f7c2001-09-24 08:05:11 +0000820 def spilldata(msg, attrs, predicate):
821 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000822 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000823 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000824 push(msg)
825 for name, kind, homecls, value in ok:
826 base = self.docother(getattr(object, name), name, mod)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200827 if callable(value) or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000828 doc = getattr(value, "__doc__", None)
829 else:
830 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000831 if doc is None:
832 push('<dl><dt>%s</dl>\n' % base)
833 else:
834 doc = self.markup(getdoc(value), self.preformat,
835 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000836 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000837 push('<dl><dt>%s%s</dl>\n' % (base, doc))
838 push('\n')
839 return attrs
840
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000841 attrs = [(name, kind, cls, value)
842 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -0700843 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000844
Tim Petersb47879b2001-09-24 04:47:19 +0000845 mdict = {}
846 for key, kind, homecls, value in attrs:
847 mdict[key] = anchor = '#' + name + '-' + key
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100848 try:
849 value = getattr(object, name)
850 except Exception:
851 # Some descriptors may meet a failure in their __get__.
852 # (bug #1785)
853 pass
Tim Petersb47879b2001-09-24 04:47:19 +0000854 try:
855 # The value may not be hashable (e.g., a data attr with
856 # a dict or list value).
857 mdict[value] = anchor
858 except TypeError:
859 pass
860
Tim Petersfa26f7c2001-09-24 08:05:11 +0000861 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000862 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000863 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000864 else:
865 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000866 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
867
Georg Brandl1a3284e2007-12-02 09:40:06 +0000868 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000869 attrs = inherited
870 continue
871 elif thisclass is object:
872 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000873 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000874 tag = 'inherited from %s' % self.classlink(thisclass,
875 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000876 tag += ':<br>\n'
877
Raymond Hettinger95801bb2015-08-18 22:25:16 -0700878 sort_attributes(attrs, object)
Tim Petersb47879b2001-09-24 04:47:19 +0000879
880 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000881 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000882 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000883 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000884 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000885 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000886 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000887 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
888 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000889 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000890 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000891 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000892 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000893
894 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000895
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000896 if name == realname:
897 title = '<a name="%s">class <strong>%s</strong></a>' % (
898 name, realname)
899 else:
900 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
901 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000902 if bases:
903 parents = []
904 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000905 parents.append(self.classlink(base, object.__module__))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000906 title = title + '(%s)' % ', '.join(parents)
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +0200907
908 decl = ''
909 try:
910 signature = inspect.signature(object)
911 except (ValueError, TypeError):
912 signature = None
913 if signature:
914 argspec = str(signature)
Serhiy Storchaka213f2292017-01-23 14:02:35 +0200915 if argspec and argspec != '()':
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +0200916 decl = name + self.escape(argspec) + '\n\n'
917
918 doc = getdoc(object)
919 if decl:
920 doc = decl + (doc or '')
921 doc = self.markup(doc, self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000922 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000923
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000924 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000925
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000926 def formatvalue(self, object):
927 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000928 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000929
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000930 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000931 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000932 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000933 realname = object.__name__
934 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000935 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000936 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000937 skipdocs = 0
Larry Hastings24a882b2014-02-20 23:34:46 -0800938 if _is_bound_method(object):
Christian Heimesff737952007-11-27 10:40:20 +0000939 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000940 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000941 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000942 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000943 else:
Christian Heimesff737952007-11-27 10:40:20 +0000944 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000945 note = ' method of %s instance' % self.classlink(
Christian Heimesff737952007-11-27 10:40:20 +0000946 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000947 else:
948 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000949
950 if name == realname:
951 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
952 else:
Serhiy Storchakaa44d34e2018-11-08 08:48:11 +0200953 if cl and inspect.getattr_static(cl, realname, []) is object:
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000954 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000955 cl.__name__ + '-' + realname, realname)
956 skipdocs = 1
957 else:
958 reallink = realname
959 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
960 anchor, name, reallink)
Larry Hastings44e2eaa2013-11-23 15:37:55 -0800961 argspec = None
Larry Hastings24a882b2014-02-20 23:34:46 -0800962 if inspect.isroutine(object):
Larry Hastings5c661892014-01-24 06:17:25 -0800963 try:
964 signature = inspect.signature(object)
965 except (ValueError, TypeError):
966 signature = None
Larry Hastings44e2eaa2013-11-23 15:37:55 -0800967 if signature:
968 argspec = str(signature)
969 if realname == '<lambda>':
970 title = '<strong>%s</strong> <em>lambda</em> ' % name
971 # XXX lambda's won't usually have func_annotations['return']
972 # since the syntax doesn't support but it is possible.
973 # So removing parentheses isn't truly safe.
974 argspec = argspec[1:-1] # remove parentheses
975 if not argspec:
Tim Peters4bcfa312001-09-20 06:08:24 +0000976 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000977
Serhiy Storchaka66dd4aa2014-11-17 23:48:02 +0200978 decl = title + self.escape(argspec) + (note and self.grey(
Tim Peters2306d242001-09-25 03:18:32 +0000979 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000980
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000981 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000982 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000983 else:
984 doc = self.markup(
985 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000986 doc = doc and '<dd><tt>%s</tt></dd>' % doc
987 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000988
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200989 def docdata(self, object, name=None, mod=None, cl=None):
990 """Produce html documentation for a data descriptor."""
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000991 results = []
992 push = results.append
993
994 if name:
995 push('<dl><dt><strong>%s</strong></dt>\n' % name)
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200996 if object.__doc__ is not None:
997 doc = self.markup(getdoc(object), self.preformat)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000998 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000999 push('</dl>\n')
1000
1001 return ''.join(results)
1002
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001003 docproperty = docdata
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001004
Tim Peters8dd7ade2001-10-18 19:56:17 +00001005 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001006 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001007 lhs = name and '<strong>%s</strong> = ' % name or ''
1008 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001009
1010 def index(self, dir, shadowed=None):
1011 """Generate an HTML index for a directory of modules."""
1012 modpkgs = []
1013 if shadowed is None: shadowed = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001014 for importer, name, ispkg in pkgutil.iter_modules([dir]):
Victor Stinner4d652242011-04-12 23:41:50 +02001015 if any((0xD800 <= ord(ch) <= 0xDFFF) for ch in name):
1016 # ignore a module if its name contains a surrogate character
1017 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001018 modpkgs.append((name, '', ispkg, name in shadowed))
1019 shadowed[name] = 1
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001020
1021 modpkgs.sort()
1022 contents = self.multicolumn(modpkgs, self.modpkglink)
1023 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
1024
1025# -------------------------------------------- text documentation generator
1026
1027class TextRepr(Repr):
1028 """Class for safely making a text representation of a Python object."""
1029 def __init__(self):
1030 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001031 self.maxlist = self.maxtuple = 20
1032 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001033 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001034
1035 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +00001036 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001037 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +00001038 if hasattr(self, methodname):
1039 return getattr(self, methodname)(x, level)
1040 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001041
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +00001042 def repr_string(self, x, level):
1043 test = cram(x, self.maxstring)
1044 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001045 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +00001046 # Backslashes are only literal in the string and are never
1047 # needed to make any special characters, so show a raw string.
1048 return 'r' + testrepr[0] + test + testrepr[0]
1049 return testrepr
1050
Skip Montanarodf708782002-03-07 22:58:02 +00001051 repr_str = repr_string
1052
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001053 def repr_instance(self, x, level):
1054 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001055 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001056 except:
1057 return '<%s instance>' % x.__class__.__name__
1058
1059class TextDoc(Doc):
1060 """Formatter class for text documentation."""
1061
1062 # ------------------------------------------- text formatting utilities
1063
1064 _repr_instance = TextRepr()
1065 repr = _repr_instance.repr
1066
1067 def bold(self, text):
1068 """Format a string in bold by overstriking."""
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001069 return ''.join(ch + '\b' + ch for ch in text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001070
1071 def indent(self, text, prefix=' '):
1072 """Indent text by prepending a given prefix to each line."""
1073 if not text: return ''
Collin Winter72e110c2007-07-17 00:27:30 +00001074 lines = [prefix + line for line in text.split('\n')]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001075 if lines: lines[-1] = lines[-1].rstrip()
1076 return '\n'.join(lines)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001077
1078 def section(self, title, contents):
1079 """Format a section with a given heading."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001080 clean_contents = self.indent(contents).rstrip()
1081 return self.bold(title) + '\n' + clean_contents + '\n\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001082
1083 # ---------------------------------------------- type-specific routines
1084
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001085 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001086 """Render in text a class tree as returned by inspect.getclasstree()."""
1087 result = ''
1088 for entry in tree:
1089 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001090 c, bases = entry
1091 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001092 if bases and bases != (parent,):
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001093 parents = (classname(c, modname) for c in bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001094 result = result + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001095 result = result + '\n'
1096 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001097 result = result + self.formattree(
1098 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001099 return result
1100
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001101 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001102 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001103 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001104 synop, desc = splitdoc(getdoc(object))
1105 result = self.section('NAME', name + (synop and ' - ' + synop))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001106 all = getattr(object, '__all__', None)
Skip Montanaro4997a692003-09-10 16:47:51 +00001107 docloc = self.getdocloc(object)
1108 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001109 result = result + self.section('MODULE REFERENCE', docloc + """
1110
Éric Araujo647ef8c2011-09-11 00:43:20 +02001111The following documentation is automatically generated from the Python
1112source files. It may be incomplete, incorrect or include features that
1113are considered implementation detail and may vary between Python
1114implementations. When in doubt, consult the module reference at the
1115location listed above.
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001116""")
Skip Montanaro4997a692003-09-10 16:47:51 +00001117
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001118 if desc:
1119 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001120
1121 classes = []
1122 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001123 # if __all__ exists, believe it. Otherwise use old heuristic.
1124 if (all is not None
1125 or (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001126 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001127 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001128 funcs = []
1129 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001130 # if __all__ exists, believe it. Otherwise use old heuristic.
1131 if (all is not None or
1132 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001133 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001134 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001135 data = []
1136 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001137 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001138 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001139
Christian Heimes1af737c2008-01-23 08:24:23 +00001140 modpkgs = []
1141 modpkgs_names = set()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001142 if hasattr(object, '__path__'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001143 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
Christian Heimes1af737c2008-01-23 08:24:23 +00001144 modpkgs_names.add(modname)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001145 if ispkg:
1146 modpkgs.append(modname + ' (package)')
1147 else:
1148 modpkgs.append(modname)
1149
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001150 modpkgs.sort()
1151 result = result + self.section(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001152 'PACKAGE CONTENTS', '\n'.join(modpkgs))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001153
Christian Heimes1af737c2008-01-23 08:24:23 +00001154 # Detect submodules as sometimes created by C extensions
1155 submodules = []
1156 for key, value in inspect.getmembers(object, inspect.ismodule):
1157 if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1158 submodules.append(key)
1159 if submodules:
1160 submodules.sort()
1161 result = result + self.section(
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001162 'SUBMODULES', '\n'.join(submodules))
Christian Heimes1af737c2008-01-23 08:24:23 +00001163
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001164 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001165 classlist = [value for key, value in classes]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001166 contents = [self.formattree(
1167 inspect.getclasstree(classlist, 1), name)]
1168 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001169 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001170 result = result + self.section('CLASSES', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001171
1172 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001173 contents = []
1174 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001175 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001176 result = result + self.section('FUNCTIONS', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001177
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001178 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001179 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001180 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001181 contents.append(self.docother(value, key, name, maxlen=70))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001182 result = result + self.section('DATA', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001183
1184 if hasattr(object, '__version__'):
1185 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001186 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001187 version = version[11:-1].strip()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001188 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001189 if hasattr(object, '__date__'):
1190 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001191 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001192 result = result + self.section('AUTHOR', str(object.__author__))
1193 if hasattr(object, '__credits__'):
1194 result = result + self.section('CREDITS', str(object.__credits__))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001195 try:
1196 file = inspect.getabsfile(object)
1197 except TypeError:
1198 file = '(built-in)'
1199 result = result + self.section('FILE', file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001200 return result
1201
Georg Brandl9bd45f992010-12-03 09:58:38 +00001202 def docclass(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001203 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001204 realname = object.__name__
1205 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001206 bases = object.__bases__
1207
Tim Petersc86f6ca2001-09-26 21:31:51 +00001208 def makename(c, m=object.__module__):
1209 return classname(c, m)
1210
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001211 if name == realname:
1212 title = 'class ' + self.bold(realname)
1213 else:
1214 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001215 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001216 parents = map(makename, bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001217 title = title + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001218
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001219 contents = []
Tim Peters28355492001-09-23 21:29:55 +00001220 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001221
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001222 try:
1223 signature = inspect.signature(object)
1224 except (ValueError, TypeError):
1225 signature = None
1226 if signature:
1227 argspec = str(signature)
Serhiy Storchaka213f2292017-01-23 14:02:35 +02001228 if argspec and argspec != '()':
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001229 push(name + argspec + '\n')
1230
1231 doc = getdoc(object)
1232 if doc:
1233 push(doc + '\n')
1234
Tim Petersc86f6ca2001-09-26 21:31:51 +00001235 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001236 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001237 if len(mro) > 2:
1238 push("Method resolution order:")
1239 for base in mro:
1240 push(' ' + makename(base))
1241 push('')
1242
Sanyam Khuranaa323cdc2018-10-21 00:22:02 -07001243 # List the built-in subclasses, if any:
1244 subclasses = sorted(
Sanyam Khuranab539cef2018-12-31 10:44:47 +05301245 (str(cls.__name__) for cls in type.__subclasses__(object)
Sanyam Khuranaa323cdc2018-10-21 00:22:02 -07001246 if not cls.__name__.startswith("_") and cls.__module__ == "builtins"),
1247 key=str.lower
1248 )
1249 no_of_subclasses = len(subclasses)
1250 MAX_SUBCLASSES_TO_DISPLAY = 4
1251 if subclasses:
1252 push("Built-in subclasses:")
1253 for subclassname in subclasses[:MAX_SUBCLASSES_TO_DISPLAY]:
1254 push(' ' + subclassname)
1255 if no_of_subclasses > MAX_SUBCLASSES_TO_DISPLAY:
1256 push(' ... and ' +
1257 str(no_of_subclasses - MAX_SUBCLASSES_TO_DISPLAY) +
1258 ' other subclasses')
1259 push('')
1260
Tim Petersf4aad8e2001-09-24 22:40:47 +00001261 # Cute little class to pump out a horizontal rule between sections.
1262 class HorizontalRule:
1263 def __init__(self):
1264 self.needone = 0
1265 def maybe(self):
1266 if self.needone:
1267 push('-' * 70)
1268 self.needone = 1
1269 hr = HorizontalRule()
1270
Tim Peters28355492001-09-23 21:29:55 +00001271 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001272 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001273 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001274 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001275 push(msg)
1276 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +01001277 try:
1278 value = getattr(object, name)
1279 except Exception:
1280 # Some descriptors may meet a failure in their __get__.
1281 # (bug #1785)
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001282 push(self.docdata(value, name, mod))
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +01001283 else:
1284 push(self.document(value,
1285 name, mod, object))
Tim Peters28355492001-09-23 21:29:55 +00001286 return attrs
1287
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001288 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001289 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001290 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001291 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001292 push(msg)
1293 for name, kind, homecls, value in ok:
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001294 push(self.docdata(value, name, mod))
Tim Peters28355492001-09-23 21:29:55 +00001295 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001296
Tim Petersfa26f7c2001-09-24 08:05:11 +00001297 def spilldata(msg, attrs, predicate):
1298 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001299 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001300 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001301 push(msg)
1302 for name, kind, homecls, value in ok:
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001303 if callable(value) or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001304 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001305 else:
1306 doc = None
Serhiy Storchaka056eb022014-02-19 23:05:12 +02001307 try:
1308 obj = getattr(object, name)
1309 except AttributeError:
1310 obj = homecls.__dict__[name]
1311 push(self.docother(obj, name, mod, maxlen=70, doc=doc) +
1312 '\n')
Tim Peters28355492001-09-23 21:29:55 +00001313 return attrs
1314
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001315 attrs = [(name, kind, cls, value)
1316 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -07001317 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001318
Tim Petersfa26f7c2001-09-24 08:05:11 +00001319 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001320 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001321 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001322 else:
1323 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001324 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1325
Georg Brandl1a3284e2007-12-02 09:40:06 +00001326 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001327 attrs = inherited
1328 continue
1329 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001330 tag = "defined here"
1331 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001332 tag = "inherited from %s" % classname(thisclass,
1333 object.__module__)
Raymond Hettinger95801bb2015-08-18 22:25:16 -07001334
1335 sort_attributes(attrs, object)
Tim Peters28355492001-09-23 21:29:55 +00001336
1337 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001338 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001339 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001340 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001341 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001342 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001343 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001344 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1345 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001346 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1347 lambda t: t[1] == 'data')
Ethan Furmanb0c84cd2013-10-20 22:37:39 -07001348
Tim Peters28355492001-09-23 21:29:55 +00001349 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001350 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001351
1352 contents = '\n'.join(contents)
1353 if not contents:
1354 return title + '\n'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001355 return title + '\n' + self.indent(contents.rstrip(), ' | ') + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001356
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001357 def formatvalue(self, object):
1358 """Format an argument default value as text."""
1359 return '=' + self.repr(object)
1360
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001361 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001362 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001363 realname = object.__name__
1364 name = name or realname
1365 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001366 skipdocs = 0
Larry Hastings24a882b2014-02-20 23:34:46 -08001367 if _is_bound_method(object):
Christian Heimesff737952007-11-27 10:40:20 +00001368 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001369 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001370 if imclass is not cl:
1371 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001372 else:
Christian Heimesff737952007-11-27 10:40:20 +00001373 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001374 note = ' method of %s instance' % classname(
Christian Heimesff737952007-11-27 10:40:20 +00001375 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001376 else:
1377 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001378
1379 if name == realname:
1380 title = self.bold(realname)
1381 else:
Serhiy Storchakaa44d34e2018-11-08 08:48:11 +02001382 if cl and inspect.getattr_static(cl, realname, []) is object:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001383 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001384 title = self.bold(name) + ' = ' + realname
Larry Hastings44e2eaa2013-11-23 15:37:55 -08001385 argspec = None
Larry Hastings5c661892014-01-24 06:17:25 -08001386
1387 if inspect.isroutine(object):
1388 try:
1389 signature = inspect.signature(object)
1390 except (ValueError, TypeError):
1391 signature = None
Larry Hastings44e2eaa2013-11-23 15:37:55 -08001392 if signature:
1393 argspec = str(signature)
1394 if realname == '<lambda>':
1395 title = self.bold(name) + ' lambda '
1396 # XXX lambda's won't usually have func_annotations['return']
1397 # since the syntax doesn't support but it is possible.
1398 # So removing parentheses isn't truly safe.
1399 argspec = argspec[1:-1] # remove parentheses
1400 if not argspec:
Tim Peters4bcfa312001-09-20 06:08:24 +00001401 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001402 decl = title + argspec + note
1403
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001404 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001405 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001406 else:
1407 doc = getdoc(object) or ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001408 return decl + '\n' + (doc and self.indent(doc).rstrip() + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001409
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001410 def docdata(self, object, name=None, mod=None, cl=None):
1411 """Produce text documentation for a data descriptor."""
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001412 results = []
1413 push = results.append
1414
1415 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001416 push(self.bold(name))
1417 push('\n')
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001418 doc = getdoc(object) or ''
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001419 if doc:
1420 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001421 push('\n')
1422 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001423
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001424 docproperty = docdata
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001425
Georg Brandl8b813db2005-10-01 16:32:31 +00001426 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001427 """Produce text documentation for a data object."""
1428 repr = self.repr(object)
1429 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001430 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001431 chop = maxlen - len(line)
1432 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001433 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001434 if doc is not None:
1435 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001436 return line
1437
Georg Brandld80d5f42010-12-03 07:47:22 +00001438class _PlainTextDoc(TextDoc):
1439 """Subclass of TextDoc which overrides string styling"""
1440 def bold(self, text):
1441 return text
1442
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001443# --------------------------------------------------------- user interfaces
1444
1445def pager(text):
1446 """The first time this is called, determine what kind of pager to use."""
1447 global pager
1448 pager = getpager()
1449 pager(text)
1450
1451def getpager():
1452 """Decide what method to use for paging through text."""
Benjamin Peterson159824e2014-06-07 20:14:26 -07001453 if not hasattr(sys.stdin, "isatty"):
1454 return plainpager
Guido van Rossuma01a8b62007-05-27 09:20:14 +00001455 if not hasattr(sys.stdout, "isatty"):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001456 return plainpager
1457 if not sys.stdin.isatty() or not sys.stdout.isatty():
1458 return plainpager
doko@ubuntu.com96575452016-06-14 08:39:31 +02001459 use_pager = os.environ.get('MANPAGER') or os.environ.get('PAGER')
1460 if use_pager:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001461 if sys.platform == 'win32': # pipes completely broken in Windows
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001462 return lambda text: tempfilepager(plain(text), use_pager)
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001463 elif os.environ.get('TERM') in ('dumb', 'emacs'):
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001464 return lambda text: pipepager(plain(text), use_pager)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001465 else:
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001466 return lambda text: pipepager(text, use_pager)
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001467 if os.environ.get('TERM') in ('dumb', 'emacs'):
1468 return plainpager
Jesus Cea4791a242012-10-05 03:15:39 +02001469 if sys.platform == 'win32':
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001470 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001471 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001472 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001473
1474 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001475 (fd, filename) = tempfile.mkstemp()
1476 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001477 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001478 if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001479 return lambda text: pipepager(text, 'more')
1480 else:
1481 return ttypager
1482 finally:
1483 os.unlink(filename)
1484
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001485def plain(text):
1486 """Remove boldface formatting from text."""
1487 return re.sub('.\b', '', text)
1488
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001489def pipepager(text, cmd):
1490 """Page through text by feeding it to another program."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001491 import subprocess
1492 proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001493 try:
R David Murray1058cda2015-03-29 15:15:40 -04001494 with io.TextIOWrapper(proc.stdin, errors='backslashreplace') as pipe:
R David Murraye7f5e142015-03-30 10:14:47 -04001495 try:
1496 pipe.write(text)
1497 except KeyboardInterrupt:
1498 # We've hereby abandoned whatever text hasn't been written,
1499 # but the pager is still in control of the terminal.
1500 pass
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001501 except OSError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001502 pass # Ignore broken pipes caused by quitting the pager program.
R David Murray1058cda2015-03-29 15:15:40 -04001503 while True:
1504 try:
1505 proc.wait()
1506 break
1507 except KeyboardInterrupt:
1508 # Ignore ctl-c like the pager itself does. Otherwise the pager is
1509 # left running and the terminal is in raw mode and unusable.
1510 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001511
1512def tempfilepager(text, cmd):
1513 """Page through text by invoking a program on a temporary file."""
1514 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001515 filename = tempfile.mktemp()
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001516 with open(filename, 'w', errors='backslashreplace') as file:
Giampaolo Rodola'2f50aaf2013-02-12 02:04:27 +01001517 file.write(text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001518 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001519 os.system(cmd + ' "' + filename + '"')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001520 finally:
1521 os.unlink(filename)
1522
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001523def _escape_stdout(text):
1524 # Escape non-encodable characters to avoid encoding errors later
1525 encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8'
1526 return text.encode(encoding, 'backslashreplace').decode(encoding)
1527
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001528def ttypager(text):
1529 """Page through text on a text terminal."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001530 lines = plain(_escape_stdout(text)).split('\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001531 try:
1532 import tty
1533 fd = sys.stdin.fileno()
1534 old = tty.tcgetattr(fd)
1535 tty.setcbreak(fd)
1536 getchar = lambda: sys.stdin.read(1)
Serhiy Storchakaab5e9b92014-11-28 00:09:29 +02001537 except (ImportError, AttributeError, io.UnsupportedOperation):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001538 tty = None
1539 getchar = lambda: sys.stdin.readline()[:-1][:1]
1540
1541 try:
Serhiy Storchakaab5e9b92014-11-28 00:09:29 +02001542 try:
1543 h = int(os.environ.get('LINES', 0))
1544 except ValueError:
1545 h = 0
1546 if h <= 1:
1547 h = 25
1548 r = inc = h - 1
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001549 sys.stdout.write('\n'.join(lines[:inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001550 while lines[r:]:
1551 sys.stdout.write('-- more --')
1552 sys.stdout.flush()
1553 c = getchar()
1554
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001555 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001556 sys.stdout.write('\r \r')
1557 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001558 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001559 sys.stdout.write('\r \r' + lines[r] + '\n')
1560 r = r + 1
1561 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001562 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001563 r = r - inc - inc
1564 if r < 0: r = 0
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001565 sys.stdout.write('\n' + '\n'.join(lines[r:r+inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001566 r = r + inc
1567
1568 finally:
1569 if tty:
1570 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1571
1572def plainpager(text):
1573 """Simply print unformatted text. This is the ultimate fallback."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001574 sys.stdout.write(plain(_escape_stdout(text)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001575
1576def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001577 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001578 if inspect.ismodule(thing):
1579 if thing.__name__ in sys.builtin_module_names:
1580 return 'built-in module ' + thing.__name__
1581 if hasattr(thing, '__path__'):
1582 return 'package ' + thing.__name__
1583 else:
1584 return 'module ' + thing.__name__
1585 if inspect.isbuiltin(thing):
1586 return 'built-in function ' + thing.__name__
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001587 if inspect.isgetsetdescriptor(thing):
1588 return 'getset descriptor %s.%s.%s' % (
1589 thing.__objclass__.__module__, thing.__objclass__.__name__,
1590 thing.__name__)
1591 if inspect.ismemberdescriptor(thing):
1592 return 'member descriptor %s.%s.%s' % (
1593 thing.__objclass__.__module__, thing.__objclass__.__name__,
1594 thing.__name__)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001595 if inspect.isclass(thing):
1596 return 'class ' + thing.__name__
1597 if inspect.isfunction(thing):
1598 return 'function ' + thing.__name__
1599 if inspect.ismethod(thing):
1600 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001601 return type(thing).__name__
1602
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001603def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001604 """Locate an object by name or dotted path, importing as necessary."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001605 parts = [part for part in path.split('.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001606 module, n = None, 0
1607 while n < len(parts):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001608 nextmodule = safeimport('.'.join(parts[:n+1]), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001609 if nextmodule: module, n = nextmodule, n + 1
1610 else: break
1611 if module:
1612 object = module
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001613 else:
Éric Araujoe64e51b2011-07-29 17:03:55 +02001614 object = builtins
1615 for part in parts[n:]:
1616 try:
1617 object = getattr(object, part)
1618 except AttributeError:
1619 return None
1620 return object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001621
1622# --------------------------------------- interactive interpreter interface
1623
1624text = TextDoc()
Georg Brandld80d5f42010-12-03 07:47:22 +00001625plaintext = _PlainTextDoc()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001626html = HTMLDoc()
1627
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001628def resolve(thing, forceload=0):
1629 """Given an object or a path to an object, get the object and its name."""
1630 if isinstance(thing, str):
1631 object = locate(thing, forceload)
Serhiy Storchakab6076fb2015-04-21 21:09:48 +03001632 if object is None:
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001633 raise ImportError('''\
1634No Python documentation found for %r.
1635Use help() to get the interactive help utility.
1636Use help(str) for help on the str class.''' % thing)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001637 return object, thing
1638 else:
R David Murrayc43125a2012-04-23 13:23:57 -04001639 name = getattr(thing, '__name__', None)
1640 return thing, name if isinstance(name, str) else None
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001641
Georg Brandld80d5f42010-12-03 07:47:22 +00001642def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
1643 renderer=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001644 """Render text documentation, given an object or a path to an object."""
Georg Brandld80d5f42010-12-03 07:47:22 +00001645 if renderer is None:
1646 renderer = text
Guido van Rossumd8faa362007-04-27 19:54:29 +00001647 object, name = resolve(thing, forceload)
1648 desc = describe(object)
1649 module = inspect.getmodule(object)
1650 if name and '.' in name:
1651 desc += ' in ' + name[:name.rfind('.')]
1652 elif module and module is not object:
1653 desc += ' in module ' + module.__name__
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001654
1655 if not (inspect.ismodule(object) or
Guido van Rossumd8faa362007-04-27 19:54:29 +00001656 inspect.isclass(object) or
1657 inspect.isroutine(object) or
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001658 inspect.isdatadescriptor(object)):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001659 # If the passed object is a piece of data or an instance,
1660 # document its available methods instead of its value.
1661 object = type(object)
1662 desc += ' object'
Georg Brandld80d5f42010-12-03 07:47:22 +00001663 return title % desc + '\n\n' + renderer.document(object, name)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001664
Georg Brandld80d5f42010-12-03 07:47:22 +00001665def doc(thing, title='Python Library Documentation: %s', forceload=0,
1666 output=None):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001667 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001668 try:
Georg Brandld80d5f42010-12-03 07:47:22 +00001669 if output is None:
1670 pager(render_doc(thing, title, forceload))
1671 else:
1672 output.write(render_doc(thing, title, forceload, plaintext))
Guido van Rossumb940e112007-01-10 16:19:56 +00001673 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001674 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001675
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001676def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001677 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001678 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001679 object, name = resolve(thing, forceload)
1680 page = html.page(describe(object), html.document(object, name))
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +03001681 with open(name + '.html', 'w', encoding='utf-8') as file:
1682 file.write(page)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001683 print('wrote', name + '.html')
Guido van Rossumb940e112007-01-10 16:19:56 +00001684 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001685 print(value)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001686
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001687def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001688 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001689 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001690 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1691 writedoc(modname)
1692 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001693
1694class Helper:
Georg Brandl6b38daa2008-06-01 21:05:17 +00001695
1696 # These dictionaries map a topic name to either an alias, or a tuple
1697 # (label, seealso-items). The "label" is the label of the corresponding
1698 # section in the .rst file under Doc/ and an index into the dictionary
Georg Brandl5617db82009-04-27 16:28:57 +00001699 # in pydoc_data/topics.py.
Georg Brandl6b38daa2008-06-01 21:05:17 +00001700 #
1701 # CAUTION: if you change one of these dictionaries, be sure to adapt the
Jelle Zijlstraac317702017-10-05 20:24:46 -07001702 # list of needed labels in Doc/tools/extensions/pyspecific.py and
Georg Brandl5617db82009-04-27 16:28:57 +00001703 # regenerate the pydoc_data/topics.py file by running
Georg Brandl6b38daa2008-06-01 21:05:17 +00001704 # make pydoc-topics
1705 # in Doc/ and copying the output file into the Lib/ directory.
1706
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001707 keywords = {
Ezio Melottib185a042011-04-28 07:42:55 +03001708 'False': '',
1709 'None': '',
1710 'True': '',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001711 'and': 'BOOLEAN',
Guido van Rossumd8faa362007-04-27 19:54:29 +00001712 'as': 'with',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001713 'assert': ('assert', ''),
Jelle Zijlstraac317702017-10-05 20:24:46 -07001714 'async': ('async', ''),
1715 'await': ('await', ''),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001716 'break': ('break', 'while for'),
1717 'class': ('class', 'CLASSES SPECIALMETHODS'),
1718 'continue': ('continue', 'while for'),
1719 'def': ('function', ''),
1720 'del': ('del', 'BASICMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001721 'elif': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001722 'else': ('else', 'while for'),
Georg Brandl0d855392008-08-30 19:53:05 +00001723 'except': 'try',
1724 'finally': 'try',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001725 'for': ('for', 'break continue while'),
Georg Brandl0d855392008-08-30 19:53:05 +00001726 'from': 'import',
Georg Brandl74abf6f2010-11-20 19:54:36 +00001727 'global': ('global', 'nonlocal NAMESPACES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001728 'if': ('if', 'TRUTHVALUE'),
1729 'import': ('import', 'MODULES'),
Georg Brandl395ed242009-09-04 08:07:32 +00001730 'in': ('in', 'SEQUENCEMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001731 'is': 'COMPARISON',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001732 'lambda': ('lambda', 'FUNCTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001733 'nonlocal': ('nonlocal', 'global NAMESPACES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001734 'not': 'BOOLEAN',
1735 'or': 'BOOLEAN',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001736 'pass': ('pass', ''),
1737 'raise': ('raise', 'EXCEPTIONS'),
1738 'return': ('return', 'FUNCTIONS'),
1739 'try': ('try', 'EXCEPTIONS'),
1740 'while': ('while', 'break continue if TRUTHVALUE'),
1741 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1742 'yield': ('yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001743 }
Georg Brandldb7b6b92009-01-01 15:53:14 +00001744 # Either add symbols to this dictionary or to the symbols dictionary
1745 # directly: Whichever is easier. They are merged later.
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001746 _strprefixes = [p + q for p in ('b', 'f', 'r', 'u') for q in ("'", '"')]
Georg Brandldb7b6b92009-01-01 15:53:14 +00001747 _symbols_inverse = {
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001748 'STRINGS' : ("'", "'''", '"', '"""', *_strprefixes),
Georg Brandldb7b6b92009-01-01 15:53:14 +00001749 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1750 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1751 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1752 'UNARY' : ('-', '~'),
1753 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1754 '^=', '<<=', '>>=', '**=', '//='),
1755 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1756 'COMPLEX' : ('j', 'J')
1757 }
1758 symbols = {
1759 '%': 'OPERATORS FORMATTING',
1760 '**': 'POWER',
1761 ',': 'TUPLES LISTS FUNCTIONS',
1762 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1763 '...': 'ELLIPSIS',
1764 ':': 'SLICINGS DICTIONARYLITERALS',
1765 '@': 'def class',
1766 '\\': 'STRINGS',
1767 '_': 'PRIVATENAMES',
1768 '__': 'PRIVATENAMES SPECIALMETHODS',
1769 '`': 'BACKQUOTES',
1770 '(': 'TUPLES FUNCTIONS CALLS',
1771 ')': 'TUPLES FUNCTIONS CALLS',
1772 '[': 'LISTS SUBSCRIPTS SLICINGS',
1773 ']': 'LISTS SUBSCRIPTS SLICINGS'
1774 }
1775 for topic, symbols_ in _symbols_inverse.items():
1776 for symbol in symbols_:
1777 topics = symbols.get(symbol, topic)
1778 if topic not in topics:
1779 topics = topics + ' ' + topic
1780 symbols[symbol] = topics
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001781
1782 topics = {
Georg Brandl6b38daa2008-06-01 21:05:17 +00001783 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1784 'FUNCTIONS CLASSES MODULES FILES inspect'),
1785 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
1786 'FORMATTING TYPES'),
1787 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1788 'FORMATTING': ('formatstrings', 'OPERATORS'),
1789 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1790 'FORMATTING TYPES'),
1791 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1792 'INTEGER': ('integers', 'int range'),
1793 'FLOAT': ('floating', 'float math'),
1794 'COMPLEX': ('imaginary', 'complex cmath'),
1795 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001796 'MAPPINGS': 'DICTIONARIES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001797 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1798 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1799 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1800 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001801 'FRAMEOBJECTS': 'TYPES',
1802 'TRACEBACKS': 'TYPES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001803 'NONE': ('bltin-null-object', ''),
1804 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001805 'SPECIALATTRIBUTES': ('specialattrs', ''),
1806 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1807 'MODULES': ('typesmodules', 'import'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001808 'PACKAGES': 'import',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001809 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1810 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1811 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1812 'LISTS DICTIONARIES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001813 'OPERATORS': 'EXPRESSIONS',
1814 'PRECEDENCE': 'EXPRESSIONS',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001815 'OBJECTS': ('objects', 'TYPES'),
1816 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
Georg Brandl395ed242009-09-04 08:07:32 +00001817 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
1818 'NUMBERMETHODS CLASSES'),
Mark Dickinsona56c4672009-01-27 18:17:45 +00001819 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001820 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1821 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001822 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
Georg Brandl6b38daa2008-06-01 21:05:17 +00001823 'SPECIALMETHODS'),
1824 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1825 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1826 'SPECIALMETHODS'),
1827 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001828 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001829 'DYNAMICFEATURES': ('dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001830 'SCOPING': 'NAMESPACES',
1831 'FRAMES': 'NAMESPACES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001832 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1833 'CONVERSIONS': ('conversions', ''),
1834 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1835 'SPECIALIDENTIFIERS': ('id-classes', ''),
1836 'PRIVATENAMES': ('atom-identifiers', ''),
1837 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
1838 'LISTLITERALS DICTIONARYLITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001839 'TUPLES': 'SEQUENCES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001840 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1841 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1842 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1843 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1844 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1845 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001846 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
1847 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001848 'CALLS': ('calls', 'EXPRESSIONS'),
1849 'POWER': ('power', 'EXPRESSIONS'),
1850 'UNARY': ('unary', 'EXPRESSIONS'),
1851 'BINARY': ('binary', 'EXPRESSIONS'),
1852 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1853 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1854 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1855 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001856 'ASSERTION': 'assert',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001857 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1858 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001859 'DELETION': 'del',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001860 'RETURNING': 'return',
1861 'IMPORTING': 'import',
1862 'CONDITIONAL': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001863 'LOOPING': ('compound', 'for while break continue'),
1864 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1865 'DEBUGGING': ('debugger', 'pdb'),
1866 'CONTEXTMANAGERS': ('context-managers', 'with'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001867 }
1868
Georg Brandl78aa3962010-07-31 21:51:48 +00001869 def __init__(self, input=None, output=None):
1870 self._input = input
1871 self._output = output
1872
Serhiy Storchakabdf6b912017-03-19 08:40:32 +02001873 @property
1874 def input(self):
1875 return self._input or sys.stdin
1876
1877 @property
1878 def output(self):
1879 return self._output or sys.stdout
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001880
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001881 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001882 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001883 self()
1884 return ''
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001885 return '<%s.%s instance>' % (self.__class__.__module__,
1886 self.__class__.__qualname__)
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001887
Alexander Belopolsky2e733c92010-07-04 17:00:20 +00001888 _GoInteractive = object()
1889 def __call__(self, request=_GoInteractive):
1890 if request is not self._GoInteractive:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001891 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001892 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001893 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001894 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001895 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001896You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001897If you want to ask for help on a particular object directly from the
1898interpreter, you can type "help(object)". Executing "help('string')"
1899has the same effect as typing a particular string at the help> prompt.
1900''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001901
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001902 def interact(self):
1903 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001904 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001905 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001906 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001907 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001908 except (KeyboardInterrupt, EOFError):
1909 break
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001910 request = request.strip()
1911
1912 # Make sure significant trailing quoting marks of literals don't
1913 # get deleted while cleaning input
1914 if (len(request) > 2 and request[0] == request[-1] in ("'", '"')
1915 and request[0] not in request[1:-1]):
1916 request = request[1:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001917 if request.lower() in ('q', 'quit'): break
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001918 if request == 'help':
1919 self.intro()
1920 else:
1921 self.help(request)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001922
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001923 def getline(self, prompt):
Guido van Rossum7c086c02008-01-02 03:52:38 +00001924 """Read one line, using input() when appropriate."""
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001925 if self.input is sys.stdin:
Guido van Rossum7c086c02008-01-02 03:52:38 +00001926 return input(prompt)
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001927 else:
1928 self.output.write(prompt)
1929 self.output.flush()
1930 return self.input.readline()
1931
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001932 def help(self, request):
1933 if type(request) is type(''):
R. David Murray1f1b9d32009-05-27 20:56:59 +00001934 request = request.strip()
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001935 if request == 'keywords': self.listkeywords()
Georg Brandldb7b6b92009-01-01 15:53:14 +00001936 elif request == 'symbols': self.listsymbols()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001937 elif request == 'topics': self.listtopics()
1938 elif request == 'modules': self.listmodules()
1939 elif request[:8] == 'modules ':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001940 self.listmodules(request.split()[1])
Georg Brandldb7b6b92009-01-01 15:53:14 +00001941 elif request in self.symbols: self.showsymbol(request)
Ezio Melottib185a042011-04-28 07:42:55 +03001942 elif request in ['True', 'False', 'None']:
1943 # special case these keywords since they are objects too
1944 doc(eval(request), 'Help on %s:')
Raymond Hettinger54f02222002-06-01 14:18:47 +00001945 elif request in self.keywords: self.showtopic(request)
1946 elif request in self.topics: self.showtopic(request)
Georg Brandld80d5f42010-12-03 07:47:22 +00001947 elif request: doc(request, 'Help on %s:', output=self._output)
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001948 else: doc(str, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001949 elif isinstance(request, Helper): self()
Georg Brandld80d5f42010-12-03 07:47:22 +00001950 else: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001951 self.output.write('\n')
1952
1953 def intro(self):
1954 self.output.write('''
Serhiy Storchaka885bdc42016-02-11 13:10:36 +02001955Welcome to Python {0}'s help utility!
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001956
1957If this is your first time using Python, you should definitely check out
oldke5681b92017-12-28 22:37:46 +08001958the tutorial on the Internet at https://docs.python.org/{0}/tutorial/.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001959
1960Enter the name of any module, keyword, or topic to get help on writing
1961Python programs and using Python modules. To quit this help utility and
1962return to the interpreter, just type "quit".
1963
Terry Jan Reedy34200572013-02-11 02:23:13 -05001964To get a list of available modules, keywords, symbols, or topics, type
1965"modules", "keywords", "symbols", or "topics". Each module also comes
1966with a one-line summary of what it does; to list the modules whose name
1967or summary contain a given string such as "spam", type "modules spam".
Serhiy Storchaka885bdc42016-02-11 13:10:36 +02001968'''.format('%d.%d' % sys.version_info[:2]))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001969
1970 def list(self, items, columns=4, width=80):
Guido van Rossum486364b2007-06-30 05:01:58 +00001971 items = list(sorted(items))
1972 colw = width // columns
1973 rows = (len(items) + columns - 1) // columns
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001974 for row in range(rows):
1975 for col in range(columns):
1976 i = col * rows + row
1977 if i < len(items):
1978 self.output.write(items[i])
1979 if col < columns - 1:
Guido van Rossum486364b2007-06-30 05:01:58 +00001980 self.output.write(' ' + ' ' * (colw - 1 - len(items[i])))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001981 self.output.write('\n')
1982
1983 def listkeywords(self):
1984 self.output.write('''
1985Here is a list of the Python keywords. Enter any keyword to get more help.
1986
1987''')
1988 self.list(self.keywords.keys())
1989
Georg Brandldb7b6b92009-01-01 15:53:14 +00001990 def listsymbols(self):
1991 self.output.write('''
1992Here is a list of the punctuation symbols which Python assigns special meaning
1993to. Enter any symbol to get more help.
1994
1995''')
1996 self.list(self.symbols.keys())
1997
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001998 def listtopics(self):
1999 self.output.write('''
2000Here is a list of available topics. Enter any topic name to get more help.
2001
2002''')
2003 self.list(self.topics.keys())
2004
Georg Brandldb7b6b92009-01-01 15:53:14 +00002005 def showtopic(self, topic, more_xrefs=''):
Georg Brandl6b38daa2008-06-01 21:05:17 +00002006 try:
Georg Brandl5617db82009-04-27 16:28:57 +00002007 import pydoc_data.topics
Brett Cannoncd171c82013-07-04 17:43:24 -04002008 except ImportError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002009 self.output.write('''
Georg Brandl6b38daa2008-06-01 21:05:17 +00002010Sorry, topic and keyword documentation is not available because the
Georg Brandl5617db82009-04-27 16:28:57 +00002011module "pydoc_data.topics" could not be found.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002012''')
2013 return
2014 target = self.topics.get(topic, self.keywords.get(topic))
2015 if not target:
2016 self.output.write('no documentation found for %s\n' % repr(topic))
2017 return
2018 if type(target) is type(''):
Georg Brandldb7b6b92009-01-01 15:53:14 +00002019 return self.showtopic(target, more_xrefs)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002020
Georg Brandl6b38daa2008-06-01 21:05:17 +00002021 label, xrefs = target
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002022 try:
Georg Brandl5617db82009-04-27 16:28:57 +00002023 doc = pydoc_data.topics.topics[label]
Georg Brandl6b38daa2008-06-01 21:05:17 +00002024 except KeyError:
2025 self.output.write('no documentation found for %s\n' % repr(topic))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002026 return
Berker Peksagd04f46c2018-07-23 08:37:47 +03002027 doc = doc.strip() + '\n'
Georg Brandldb7b6b92009-01-01 15:53:14 +00002028 if more_xrefs:
2029 xrefs = (xrefs or '') + ' ' + more_xrefs
Ka-Ping Yeeda793892001-04-13 11:02:51 +00002030 if xrefs:
Brett Cannon1448ecf2013-10-04 11:38:59 -04002031 import textwrap
2032 text = 'Related help topics: ' + ', '.join(xrefs.split()) + '\n'
2033 wrapped_text = textwrap.wrap(text, 72)
Berker Peksagd04f46c2018-07-23 08:37:47 +03002034 doc += '\n%s\n' % '\n'.join(wrapped_text)
2035 pager(doc)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002036
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002037 def _gettopic(self, topic, more_xrefs=''):
2038 """Return unbuffered tuple of (topic, xrefs).
2039
Georg Brandld2f38572011-01-30 08:37:19 +00002040 If an error occurs here, the exception is caught and displayed by
2041 the url handler.
2042
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002043 This function duplicates the showtopic method but returns its
2044 result directly so it can be formatted for display in an html page.
2045 """
2046 try:
2047 import pydoc_data.topics
Brett Cannoncd171c82013-07-04 17:43:24 -04002048 except ImportError:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002049 return('''
2050Sorry, topic and keyword documentation is not available because the
2051module "pydoc_data.topics" could not be found.
2052''' , '')
2053 target = self.topics.get(topic, self.keywords.get(topic))
2054 if not target:
Georg Brandld2f38572011-01-30 08:37:19 +00002055 raise ValueError('could not find topic')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002056 if isinstance(target, str):
2057 return self._gettopic(target, more_xrefs)
2058 label, xrefs = target
Georg Brandld2f38572011-01-30 08:37:19 +00002059 doc = pydoc_data.topics.topics[label]
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002060 if more_xrefs:
2061 xrefs = (xrefs or '') + ' ' + more_xrefs
2062 return doc, xrefs
2063
Georg Brandldb7b6b92009-01-01 15:53:14 +00002064 def showsymbol(self, symbol):
2065 target = self.symbols[symbol]
2066 topic, _, xrefs = target.partition(' ')
2067 self.showtopic(topic, xrefs)
2068
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002069 def listmodules(self, key=''):
2070 if key:
2071 self.output.write('''
Terry Jan Reedy34200572013-02-11 02:23:13 -05002072Here is a list of modules whose name or summary contains '{}'.
2073If there are any, enter a module name to get more help.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002074
Terry Jan Reedy34200572013-02-11 02:23:13 -05002075'''.format(key))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002076 apropos(key)
2077 else:
2078 self.output.write('''
2079Please wait a moment while I gather a list of all available modules...
2080
2081''')
2082 modules = {}
2083 def callback(path, modname, desc, modules=modules):
2084 if modname and modname[-9:] == '.__init__':
2085 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002086 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002087 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002088 def onerror(modname):
2089 callback(None, modname, None)
2090 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002091 self.list(modules.keys())
2092 self.output.write('''
2093Enter any module name to get more help. Or, type "modules spam" to search
Terry Jan Reedy34200572013-02-11 02:23:13 -05002094for modules whose name or summary contain the string "spam".
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002095''')
2096
Georg Brandl78aa3962010-07-31 21:51:48 +00002097help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002098
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002099class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002100 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002101
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002102 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002103 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002104 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002105 seen = {}
2106
2107 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002108 if modname != '__main__':
2109 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00002110 if key is None:
2111 callback(None, modname, '')
2112 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002113 name = __import__(modname).__doc__ or ''
2114 desc = name.split('\n')[0]
2115 name = modname + ' - ' + desc
2116 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002117 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002118
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002119 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002120 if self.quit:
2121 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002122
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002123 if key is None:
2124 callback(None, modname, '')
2125 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002126 try:
Eric Snow3a62d142014-01-06 20:42:59 -07002127 spec = pkgutil._get_spec(importer, modname)
Georg Brandl126c8792009-04-05 15:05:48 +00002128 except SyntaxError:
2129 # raised by tests for bad coding cookies or BOM
2130 continue
Eric Snow3a62d142014-01-06 20:42:59 -07002131 loader = spec.loader
Georg Brandl126c8792009-04-05 15:05:48 +00002132 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002133 try:
2134 source = loader.get_source(modname)
Nick Coghlan2824cb52012-07-15 22:12:14 +10002135 except Exception:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002136 if onerror:
2137 onerror(modname)
2138 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002139 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002140 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002141 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002142 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002143 path = None
2144 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002145 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -04002146 module = importlib._bootstrap._load(spec)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002147 except ImportError:
2148 if onerror:
2149 onerror(modname)
2150 continue
Benjamin Peterson54237f92015-02-16 19:45:01 -05002151 desc = module.__doc__.splitlines()[0] if module.__doc__ else ''
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002152 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002153 name = modname + ' - ' + desc
2154 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002155 callback(path, modname, desc)
2156
2157 if completer:
2158 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002159
2160def apropos(key):
2161 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002162 def callback(path, modname, desc):
2163 if modname[-9:] == '.__init__':
2164 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002165 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002166 def onerror(modname):
2167 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002168 with warnings.catch_warnings():
2169 warnings.filterwarnings('ignore') # ignore problems during import
2170 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002171
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002172# --------------------------------------- enhanced Web browser interface
2173
Feanil Patel6a396c92017-09-14 17:54:09 -04002174def _start_server(urlhandler, hostname, port):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002175 """Start an HTTP server thread on a specific port.
2176
2177 Start an HTML/text server thread, so HTML or text documents can be
2178 browsed dynamically and interactively with a Web browser. Example use:
2179
2180 >>> import time
2181 >>> import pydoc
2182
2183 Define a URL handler. To determine what the client is asking
2184 for, check the URL and content_type.
2185
2186 Then get or generate some text or HTML code and return it.
2187
2188 >>> def my_url_handler(url, content_type):
2189 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2190 ... return text
2191
2192 Start server thread on port 0.
2193 If you use port 0, the server will pick a random port number.
2194 You can then use serverthread.port to get the port number.
2195
2196 >>> port = 0
2197 >>> serverthread = pydoc._start_server(my_url_handler, port)
2198
2199 Check that the server is really started. If it is, open browser
2200 and get first page. Use serverthread.url as the starting page.
2201
2202 >>> if serverthread.serving:
2203 ... import webbrowser
2204
2205 The next two lines are commented out so a browser doesn't open if
2206 doctest is run on this module.
2207
2208 #... webbrowser.open(serverthread.url)
2209 #True
2210
2211 Let the server do its thing. We just need to monitor its status.
2212 Use time.sleep so the loop doesn't hog the CPU.
2213
Victor Stinner2cf4c202018-12-17 09:36:36 +01002214 >>> starttime = time.monotonic()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002215 >>> timeout = 1 #seconds
2216
2217 This is a short timeout for testing purposes.
2218
2219 >>> while serverthread.serving:
2220 ... time.sleep(.01)
Victor Stinner2cf4c202018-12-17 09:36:36 +01002221 ... if serverthread.serving and time.monotonic() - starttime > timeout:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002222 ... serverthread.stop()
2223 ... break
2224
2225 Print any errors that may have occurred.
2226
2227 >>> print(serverthread.error)
2228 None
2229 """
2230 import http.server
2231 import email.message
2232 import select
2233 import threading
2234
2235 class DocHandler(http.server.BaseHTTPRequestHandler):
2236
2237 def do_GET(self):
2238 """Process a request from an HTML browser.
2239
2240 The URL received is in self.path.
2241 Get an HTML page from self.urlhandler and send it.
2242 """
2243 if self.path.endswith('.css'):
2244 content_type = 'text/css'
2245 else:
2246 content_type = 'text/html'
2247 self.send_response(200)
Georg Brandld2f38572011-01-30 08:37:19 +00002248 self.send_header('Content-Type', '%s; charset=UTF-8' % content_type)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002249 self.end_headers()
2250 self.wfile.write(self.urlhandler(
2251 self.path, content_type).encode('utf-8'))
2252
2253 def log_message(self, *args):
2254 # Don't log messages.
2255 pass
2256
2257 class DocServer(http.server.HTTPServer):
2258
Feanil Patel6a396c92017-09-14 17:54:09 -04002259 def __init__(self, host, port, callback):
2260 self.host = host
Senthil Kumaran2a42a0b2014-09-17 13:17:58 +08002261 self.address = (self.host, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002262 self.callback = callback
2263 self.base.__init__(self, self.address, self.handler)
2264 self.quit = False
2265
2266 def serve_until_quit(self):
2267 while not self.quit:
2268 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2269 if rd:
2270 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002271 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002272
2273 def server_activate(self):
2274 self.base.server_activate(self)
2275 if self.callback:
2276 self.callback(self)
2277
2278 class ServerThread(threading.Thread):
2279
Feanil Patel6a396c92017-09-14 17:54:09 -04002280 def __init__(self, urlhandler, host, port):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002281 self.urlhandler = urlhandler
Feanil Patel6a396c92017-09-14 17:54:09 -04002282 self.host = host
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002283 self.port = int(port)
2284 threading.Thread.__init__(self)
2285 self.serving = False
2286 self.error = None
2287
2288 def run(self):
2289 """Start the server."""
2290 try:
2291 DocServer.base = http.server.HTTPServer
2292 DocServer.handler = DocHandler
2293 DocHandler.MessageClass = email.message.Message
2294 DocHandler.urlhandler = staticmethod(self.urlhandler)
Feanil Patel6a396c92017-09-14 17:54:09 -04002295 docsvr = DocServer(self.host, self.port, self.ready)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002296 self.docserver = docsvr
2297 docsvr.serve_until_quit()
2298 except Exception as e:
2299 self.error = e
2300
2301 def ready(self, server):
2302 self.serving = True
2303 self.host = server.host
2304 self.port = server.server_port
2305 self.url = 'http://%s:%d/' % (self.host, self.port)
2306
2307 def stop(self):
2308 """Stop the server and this thread nicely"""
2309 self.docserver.quit = True
Victor Stinner4cab2cd2017-08-21 23:24:40 +02002310 self.join()
2311 # explicitly break a reference cycle: DocServer.callback
2312 # has indirectly a reference to ServerThread.
2313 self.docserver = None
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002314 self.serving = False
2315 self.url = None
2316
Feanil Patel6a396c92017-09-14 17:54:09 -04002317 thread = ServerThread(urlhandler, hostname, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002318 thread.start()
2319 # Wait until thread.serving is True to make sure we are
2320 # really up before returning.
2321 while not thread.error and not thread.serving:
2322 time.sleep(.01)
2323 return thread
2324
2325
2326def _url_handler(url, content_type="text/html"):
2327 """The pydoc url handler for use with the pydoc server.
2328
2329 If the content_type is 'text/css', the _pydoc.css style
2330 sheet is read and returned if it exits.
2331
2332 If the content_type is 'text/html', then the result of
2333 get_html_page(url) is returned.
2334 """
2335 class _HTMLDoc(HTMLDoc):
2336
2337 def page(self, title, contents):
2338 """Format an HTML page."""
2339 css_path = "pydoc_data/_pydoc.css"
2340 css_link = (
2341 '<link rel="stylesheet" type="text/css" href="%s">' %
2342 css_path)
2343 return '''\
2344<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Georg Brandld2f38572011-01-30 08:37:19 +00002345<html><head><title>Pydoc: %s</title>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002346<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Georg Brandld2f38572011-01-30 08:37:19 +00002347%s</head><body bgcolor="#f0f0f8">%s<div style="clear:both;padding-top:.5em;">%s</div>
2348</body></html>''' % (title, css_link, html_navbar(), contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002349
2350 def filelink(self, url, path):
2351 return '<a href="getfile?key=%s">%s</a>' % (url, path)
2352
2353
2354 html = _HTMLDoc()
2355
2356 def html_navbar():
Georg Brandld2f38572011-01-30 08:37:19 +00002357 version = html.escape("%s [%s, %s]" % (platform.python_version(),
2358 platform.python_build()[0],
2359 platform.python_compiler()))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002360 return """
2361 <div style='float:left'>
Georg Brandld2f38572011-01-30 08:37:19 +00002362 Python %s<br>%s
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002363 </div>
2364 <div style='float:right'>
2365 <div style='text-align:center'>
2366 <a href="index.html">Module Index</a>
2367 : <a href="topics.html">Topics</a>
2368 : <a href="keywords.html">Keywords</a>
2369 </div>
2370 <div>
Georg Brandld2f38572011-01-30 08:37:19 +00002371 <form action="get" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002372 <input type=text name=key size=15>
2373 <input type=submit value="Get">
Georg Brandld2f38572011-01-30 08:37:19 +00002374 </form>&nbsp;
2375 <form action="search" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002376 <input type=text name=key size=15>
2377 <input type=submit value="Search">
2378 </form>
2379 </div>
2380 </div>
Georg Brandld2f38572011-01-30 08:37:19 +00002381 """ % (version, html.escape(platform.platform(terse=True)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002382
2383 def html_index():
2384 """Module Index page."""
2385
2386 def bltinlink(name):
2387 return '<a href="%s.html">%s</a>' % (name, name)
2388
2389 heading = html.heading(
2390 '<big><big><strong>Index of Modules</strong></big></big>',
2391 '#ffffff', '#7799ee')
2392 names = [name for name in sys.builtin_module_names
2393 if name != '__main__']
2394 contents = html.multicolumn(names, bltinlink)
2395 contents = [heading, '<p>' + html.bigsection(
2396 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2397
2398 seen = {}
2399 for dir in sys.path:
2400 contents.append(html.index(dir, seen))
2401
2402 contents.append(
2403 '<p align=right><font color="#909090" face="helvetica,'
2404 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2405 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002406 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002407
2408 def html_search(key):
2409 """Search results page."""
2410 # scan for modules
2411 search_result = []
2412
2413 def callback(path, modname, desc):
2414 if modname[-9:] == '.__init__':
2415 modname = modname[:-9] + ' (package)'
2416 search_result.append((modname, desc and '- ' + desc))
2417
2418 with warnings.catch_warnings():
2419 warnings.filterwarnings('ignore') # ignore problems during import
Martin Panter9ad0aae2015-11-06 00:27:14 +00002420 def onerror(modname):
2421 pass
2422 ModuleScanner().run(callback, key, onerror=onerror)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002423
2424 # format page
2425 def bltinlink(name):
2426 return '<a href="%s.html">%s</a>' % (name, name)
2427
2428 results = []
2429 heading = html.heading(
2430 '<big><big><strong>Search Results</strong></big></big>',
2431 '#ffffff', '#7799ee')
2432 for name, desc in search_result:
2433 results.append(bltinlink(name) + desc)
2434 contents = heading + html.bigsection(
2435 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002436 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002437
2438 def html_getfile(path):
2439 """Get and display a source file listing safely."""
Zachary Wareeb432142014-07-10 11:18:00 -05002440 path = urllib.parse.unquote(path)
Victor Stinner91e08772011-07-05 14:30:41 +02002441 with tokenize.open(path) as fp:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002442 lines = html.escape(fp.read())
2443 body = '<pre>%s</pre>' % lines
2444 heading = html.heading(
2445 '<big><big><strong>File Listing</strong></big></big>',
2446 '#ffffff', '#7799ee')
2447 contents = heading + html.bigsection(
2448 'File: %s' % path, '#ffffff', '#ee77aa', body)
Nick Coghlanecace282010-12-03 16:08:46 +00002449 return 'getfile %s' % path, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002450
2451 def html_topics():
2452 """Index of topic texts available."""
2453
2454 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002455 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002456
2457 heading = html.heading(
2458 '<big><big><strong>INDEX</strong></big></big>',
2459 '#ffffff', '#7799ee')
2460 names = sorted(Helper.topics.keys())
2461
2462 contents = html.multicolumn(names, bltinlink)
2463 contents = heading + html.bigsection(
2464 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002465 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002466
2467 def html_keywords():
2468 """Index of keywords."""
2469 heading = html.heading(
2470 '<big><big><strong>INDEX</strong></big></big>',
2471 '#ffffff', '#7799ee')
2472 names = sorted(Helper.keywords.keys())
2473
2474 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002475 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002476
2477 contents = html.multicolumn(names, bltinlink)
2478 contents = heading + html.bigsection(
2479 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002480 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002481
2482 def html_topicpage(topic):
2483 """Topic or keyword help page."""
2484 buf = io.StringIO()
2485 htmlhelp = Helper(buf, buf)
2486 contents, xrefs = htmlhelp._gettopic(topic)
2487 if topic in htmlhelp.keywords:
2488 title = 'KEYWORD'
2489 else:
2490 title = 'TOPIC'
2491 heading = html.heading(
2492 '<big><big><strong>%s</strong></big></big>' % title,
2493 '#ffffff', '#7799ee')
Georg Brandld2f38572011-01-30 08:37:19 +00002494 contents = '<pre>%s</pre>' % html.markup(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002495 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
Georg Brandld2f38572011-01-30 08:37:19 +00002496 if xrefs:
2497 xrefs = sorted(xrefs.split())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002498
Georg Brandld2f38572011-01-30 08:37:19 +00002499 def bltinlink(name):
2500 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002501
Georg Brandld2f38572011-01-30 08:37:19 +00002502 xrefs = html.multicolumn(xrefs, bltinlink)
2503 xrefs = html.section('Related help topics: ',
2504 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002505 return ('%s %s' % (title, topic),
2506 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002507
Georg Brandld2f38572011-01-30 08:37:19 +00002508 def html_getobj(url):
2509 obj = locate(url, forceload=1)
2510 if obj is None and url != 'None':
2511 raise ValueError('could not find object')
2512 title = describe(obj)
2513 content = html.document(obj, url)
2514 return title, content
2515
2516 def html_error(url, exc):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002517 heading = html.heading(
2518 '<big><big><strong>Error</strong></big></big>',
Georg Brandld2f38572011-01-30 08:37:19 +00002519 '#ffffff', '#7799ee')
2520 contents = '<br>'.join(html.escape(line) for line in
2521 format_exception_only(type(exc), exc))
2522 contents = heading + html.bigsection(url, '#ffffff', '#bb0000',
2523 contents)
2524 return "Error - %s" % url, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002525
2526 def get_html_page(url):
2527 """Generate an HTML page for url."""
Georg Brandld2f38572011-01-30 08:37:19 +00002528 complete_url = url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002529 if url.endswith('.html'):
2530 url = url[:-5]
Georg Brandld2f38572011-01-30 08:37:19 +00002531 try:
2532 if url in ("", "index"):
2533 title, content = html_index()
2534 elif url == "topics":
2535 title, content = html_topics()
2536 elif url == "keywords":
2537 title, content = html_keywords()
2538 elif '=' in url:
2539 op, _, url = url.partition('=')
2540 if op == "search?key":
2541 title, content = html_search(url)
2542 elif op == "getfile?key":
2543 title, content = html_getfile(url)
2544 elif op == "topic?key":
2545 # try topics first, then objects.
2546 try:
2547 title, content = html_topicpage(url)
2548 except ValueError:
2549 title, content = html_getobj(url)
2550 elif op == "get?key":
2551 # try objects first, then topics.
2552 if url in ("", "index"):
2553 title, content = html_index()
2554 else:
2555 try:
2556 title, content = html_getobj(url)
2557 except ValueError:
2558 title, content = html_topicpage(url)
2559 else:
2560 raise ValueError('bad pydoc url')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002561 else:
Georg Brandld2f38572011-01-30 08:37:19 +00002562 title, content = html_getobj(url)
2563 except Exception as exc:
2564 # Catch any errors and display them in an error page.
2565 title, content = html_error(complete_url, exc)
2566 return html.page(title, content)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002567
2568 if url.startswith('/'):
2569 url = url[1:]
2570 if content_type == 'text/css':
2571 path_here = os.path.dirname(os.path.realpath(__file__))
Georg Brandld2f38572011-01-30 08:37:19 +00002572 css_path = os.path.join(path_here, url)
2573 with open(css_path) as fp:
2574 return ''.join(fp.readlines())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002575 elif content_type == 'text/html':
2576 return get_html_page(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002577 # Errors outside the url handler are caught by the server.
2578 raise TypeError('unknown content type %r for url %s' % (content_type, url))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002579
2580
Feanil Patel6a396c92017-09-14 17:54:09 -04002581def browse(port=0, *, open_browser=True, hostname='localhost'):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002582 """Start the enhanced pydoc Web server and open a Web browser.
2583
2584 Use port '0' to start the server on an arbitrary port.
2585 Set open_browser to False to suppress opening a browser.
2586 """
2587 import webbrowser
Feanil Patel6a396c92017-09-14 17:54:09 -04002588 serverthread = _start_server(_url_handler, hostname, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002589 if serverthread.error:
2590 print(serverthread.error)
2591 return
2592 if serverthread.serving:
2593 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2594 if open_browser:
2595 webbrowser.open(serverthread.url)
2596 try:
2597 print('Server ready at', serverthread.url)
2598 print(server_help_msg)
2599 while serverthread.serving:
2600 cmd = input('server> ')
2601 cmd = cmd.lower()
2602 if cmd == 'q':
2603 break
2604 elif cmd == 'b':
2605 webbrowser.open(serverthread.url)
2606 else:
2607 print(server_help_msg)
2608 except (KeyboardInterrupt, EOFError):
2609 print()
2610 finally:
2611 if serverthread.serving:
2612 serverthread.stop()
2613 print('Server stopped')
2614
2615
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002616# -------------------------------------------------- command-line interface
2617
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002618def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002619 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002620
Nick Coghlan82a94812018-04-15 21:52:57 +10002621def _get_revised_path(given_path, argv0):
2622 """Ensures current directory is on returned path, and argv0 directory is not
2623
2624 Exception: argv0 dir is left alone if it's also pydoc's directory.
2625
2626 Returns a new path entry list, or None if no adjustment is needed.
2627 """
2628 # Scripts may get the current directory in their path by default if they're
2629 # run with the -m switch, or directly from the current directory.
2630 # The interactive prompt also allows imports from the current directory.
2631
2632 # Accordingly, if the current directory is already present, don't make
2633 # any changes to the given_path
2634 if '' in given_path or os.curdir in given_path or os.getcwd() in given_path:
2635 return None
2636
2637 # Otherwise, add the current directory to the given path, and remove the
2638 # script directory (as long as the latter isn't also pydoc's directory.
2639 stdlib_dir = os.path.dirname(__file__)
2640 script_dir = os.path.dirname(argv0)
2641 revised_path = given_path.copy()
2642 if script_dir in given_path and not os.path.samefile(script_dir, stdlib_dir):
2643 revised_path.remove(script_dir)
2644 revised_path.insert(0, os.getcwd())
2645 return revised_path
2646
2647
2648# Note: the tests only cover _get_revised_path, not _adjust_cli_path itself
2649def _adjust_cli_sys_path():
Nick Coghlan1a5c4bd2018-04-15 23:32:05 +10002650 """Ensures current directory is on sys.path, and __main__ directory is not.
Nick Coghlan82a94812018-04-15 21:52:57 +10002651
2652 Exception: __main__ dir is left alone if it's also pydoc's directory.
2653 """
2654 revised_path = _get_revised_path(sys.path, sys.argv[0])
2655 if revised_path is not None:
2656 sys.path[:] = revised_path
2657
2658
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002659def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002660 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002661 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002662 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002663
Nick Coghlan82a94812018-04-15 21:52:57 +10002664 _adjust_cli_sys_path()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002665
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002666 try:
Feanil Patel6a396c92017-09-14 17:54:09 -04002667 opts, args = getopt.getopt(sys.argv[1:], 'bk:n:p:w')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002668 writing = False
2669 start_server = False
2670 open_browser = False
Feanil Patel6a396c92017-09-14 17:54:09 -04002671 port = 0
2672 hostname = 'localhost'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002673 for opt, val in opts:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002674 if opt == '-b':
2675 start_server = True
2676 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002677 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002678 apropos(val)
2679 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002680 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002681 start_server = True
2682 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002683 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002684 writing = True
Feanil Patel6a396c92017-09-14 17:54:09 -04002685 if opt == '-n':
2686 start_server = True
2687 hostname = val
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002688
Benjamin Petersonb29614e2012-10-09 11:16:03 -04002689 if start_server:
Feanil Patel6a396c92017-09-14 17:54:09 -04002690 browse(port, hostname=hostname, open_browser=open_browser)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002691 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002692
2693 if not args: raise BadUsage
2694 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002695 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002696 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002697 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002698 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002699 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002700 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002701 if writing:
2702 if ispath(arg) and os.path.isdir(arg):
2703 writedocs(arg)
2704 else:
2705 writedoc(arg)
2706 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002707 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002708 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002709 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002710
2711 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002712 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002713 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002714
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002715{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002716 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002717 Python keyword, topic, function, module, or package, or a dotted
2718 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002719 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002720 Python source file to document. If name is 'keywords', 'topics',
2721 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002722
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002723{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002724 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002725
Feanil Patel6a396c92017-09-14 17:54:09 -04002726{cmd} -n <hostname>
2727 Start an HTTP server with the given hostname (default: localhost).
2728
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002729{cmd} -p <port>
2730 Start an HTTP server on the given port on the local machine. Port
2731 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002732
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002733{cmd} -b
2734 Start an HTTP server on an arbitrary unused port and open a Web browser
Feanil Patel6a396c92017-09-14 17:54:09 -04002735 to interactively browse documentation. This option can be used in
2736 combination with -n and/or -p.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002737
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002738{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002739 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002740 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002741 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002742""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002743
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002744if __name__ == '__main__':
2745 cli()