blob: 8eecd66a2c2fbf3c2e910868dc0cfac265c383e0 [file] [log] [blame]
Benjamin Peterson90f5ba52010-03-11 22:53:45 +00001#!/usr/bin/env python3
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002"""Generate Python documentation in HTML or text for interactive use.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00003
R David Murray3d050dd2014-04-19 12:59:30 -04004At the Python interactive prompt, calling help(thing) on a Python object
5documents the object, and calling help() starts up an interactive
6help session.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00007
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00008Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00009
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000010Run "pydoc <name>" to show documentation on something. <name> may be
11the name of a function, module, package, or a dotted reference to a
12class or function within a module or module in a package. If the
13argument contains a path segment delimiter (e.g. slash on Unix,
14backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000015
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000016Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000018
Feanil Patel6a396c92017-09-14 17:54:09 -040019Run "pydoc -n <hostname>" to start an HTTP server with the given
20hostname (default: localhost) on the local machine.
21
Nick Coghlan7bb30b72010-12-03 09:29:11 +000022Run "pydoc -p <port>" to start an HTTP server on the given port on the
23local machine. Port number 0 can be used to get an arbitrary unused port.
24
25Run "pydoc -b" to start an HTTP server on an arbitrary unused port and
Feanil Patel6a396c92017-09-14 17:54:09 -040026open a Web browser to interactively browse documentation. Combine with
27the -n and -p options to control the hostname and port used.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000028
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000029Run "pydoc -w <name>" to write out the HTML documentation for a module
30to a file named "<name>.html".
Skip Montanaro4997a692003-09-10 16:47:51 +000031
32Module docs for core modules are assumed to be in
33
Martin Panter4f8aaf62016-06-12 04:24:06 +000034 https://docs.python.org/X.Y/library/
Skip Montanaro4997a692003-09-10 16:47:51 +000035
36This can be overridden by setting the PYTHONDOCS environment variable
37to a different URL or to a local directory containing the Library
38Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000039"""
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000040__all__ = ['help']
Ka-Ping Yeedd175342001-02-27 14:43:46 +000041__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000042__date__ = "26 February 2001"
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000043
Martin v. Löwis6fe8f192004-11-14 10:21:04 +000044__credits__ = """Guido van Rossum, for an excellent programming language.
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000045Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000046Paul Prescod, for all his work on onlinehelp.
47Richard Chamberlain, for the first implementation of textdoc.
Raymond Hettingered2dbe32005-01-01 07:51:01 +000048"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000049
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000050# Known bugs that can't be fixed here:
Brett Cannonf4ba4ec2013-06-15 14:25:04 -040051# - synopsis() cannot be prevented from clobbering existing
52# loaded modules.
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000053# - If the __file__ attribute on a module is a relative path and
54# the current directory is changed with os.chdir(), an incorrect
55# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000056
Nick Coghlan7bb30b72010-12-03 09:29:11 +000057import builtins
Brett Cannond5e6f2e2013-06-11 17:09:36 -040058import importlib._bootstrap
Eric Snow32439d62015-05-02 19:15:18 -060059import importlib._bootstrap_external
Brett Cannoncb66eb02012-05-11 12:58:42 -040060import importlib.machinery
Brett Cannonf4ba4ec2013-06-15 14:25:04 -040061import importlib.util
Nick Coghlan7bb30b72010-12-03 09:29:11 +000062import inspect
Victor Stinnere6c910e2011-06-30 15:55:43 +020063import io
64import os
Nick Coghlan7bb30b72010-12-03 09:29:11 +000065import pkgutil
66import platform
67import re
Victor Stinnere6c910e2011-06-30 15:55:43 +020068import sys
Victor Stinner4fac7ed2020-02-12 13:02:29 +010069import sysconfig
Nick Coghlan7bb30b72010-12-03 09:29:11 +000070import time
Victor Stinnere6c910e2011-06-30 15:55:43 +020071import tokenize
Zachary Wareeb432142014-07-10 11:18:00 -050072import urllib.parse
Nick Coghlan7bb30b72010-12-03 09:29:11 +000073import warnings
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000074from collections import deque
Nick Coghlan7bb30b72010-12-03 09:29:11 +000075from reprlib import Repr
Victor Stinner7fa767e2014-03-20 09:16:38 +010076from traceback import format_exception_only
Nick Coghlan7bb30b72010-12-03 09:29:11 +000077
78
Ka-Ping Yeedd175342001-02-27 14:43:46 +000079# --------------------------------------------------------- common routines
80
Ka-Ping Yeedd175342001-02-27 14:43:46 +000081def pathdirs():
82 """Convert sys.path into a list of absolute, existing, unique paths."""
83 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000084 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000085 for dir in sys.path:
86 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000087 normdir = os.path.normcase(dir)
88 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000089 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000090 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000091 return dirs
92
Serhiy Storchaka08b47c32020-05-18 20:25:07 +030093def _findclass(func):
94 cls = sys.modules.get(func.__module__)
95 if cls is None:
96 return None
97 for name in func.__qualname__.split('.')[:-1]:
98 cls = getattr(cls, name)
99 if not inspect.isclass(cls):
100 return None
101 return cls
102
103def _finddoc(obj):
104 if inspect.ismethod(obj):
105 name = obj.__func__.__name__
106 self = obj.__self__
107 if (inspect.isclass(self) and
108 getattr(getattr(self, name, None), '__func__') is obj.__func__):
109 # classmethod
110 cls = self
111 else:
112 cls = self.__class__
113 elif inspect.isfunction(obj):
114 name = obj.__name__
115 cls = _findclass(obj)
116 if cls is None or getattr(cls, name) is not obj:
117 return None
118 elif inspect.isbuiltin(obj):
119 name = obj.__name__
120 self = obj.__self__
121 if (inspect.isclass(self) and
122 self.__qualname__ + '.' + name == obj.__qualname__):
123 # classmethod
124 cls = self
125 else:
126 cls = self.__class__
127 # Should be tested before isdatadescriptor().
128 elif isinstance(obj, property):
129 func = obj.fget
130 name = func.__name__
131 cls = _findclass(func)
132 if cls is None or getattr(cls, name) is not obj:
133 return None
134 elif inspect.ismethoddescriptor(obj) or inspect.isdatadescriptor(obj):
135 name = obj.__name__
136 cls = obj.__objclass__
137 if getattr(cls, name) is not obj:
138 return None
139 if inspect.ismemberdescriptor(obj):
140 slots = getattr(cls, '__slots__', None)
141 if isinstance(slots, dict) and name in slots:
142 return slots[name]
143 else:
144 return None
145 for base in cls.__mro__:
146 try:
147 doc = _getowndoc(getattr(base, name))
148 except AttributeError:
149 continue
150 if doc is not None:
151 return doc
152 return None
153
154def _getowndoc(obj):
155 """Get the documentation string for an object if it is not
156 inherited from its class."""
157 try:
158 doc = object.__getattribute__(obj, '__doc__')
159 if doc is None:
160 return None
161 if obj is not type:
162 typedoc = type(obj).__doc__
163 if isinstance(typedoc, str) and typedoc == doc:
164 return None
165 return doc
166 except AttributeError:
167 return None
168
169def _getdoc(object):
170 """Get the documentation string for an object.
171
172 All tabs are expanded to spaces. To clean up docstrings that are
173 indented to line up with blocks of code, any whitespace than can be
174 uniformly removed from the second line onwards is removed."""
175 doc = _getowndoc(object)
176 if doc is None:
177 try:
178 doc = _finddoc(object)
179 except (AttributeError, TypeError):
180 return None
181 if not isinstance(doc, str):
182 return None
183 return inspect.cleandoc(doc)
184
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000185def getdoc(object):
186 """Get the doc string or comments for an object."""
Serhiy Storchaka08b47c32020-05-18 20:25:07 +0300187 result = _getdoc(object) or inspect.getcomments(object)
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000188 return result and re.sub('^ *\n', '', result.rstrip()) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000189
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000190def splitdoc(doc):
191 """Split a doc string into a synopsis line (if any) and the rest."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000192 lines = doc.strip().split('\n')
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000193 if len(lines) == 1:
194 return lines[0], ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000195 elif len(lines) >= 2 and not lines[1].rstrip():
196 return lines[0], '\n'.join(lines[2:])
197 return '', '\n'.join(lines)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000198
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000199def classname(object, modname):
200 """Get a class name and qualify it with a module name if necessary."""
201 name = object.__name__
202 if object.__module__ != modname:
203 name = object.__module__ + '.' + name
204 return name
205
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000206def isdata(object):
Georg Brandl94432422005-07-22 21:52:25 +0000207 """Check if an object is of a type that probably means it's data."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000208 return not (inspect.ismodule(object) or inspect.isclass(object) or
209 inspect.isroutine(object) or inspect.isframe(object) or
210 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000211
212def replace(text, *pairs):
213 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000214 while pairs:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000215 text = pairs[1].join(text.split(pairs[0]))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000216 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000217 return text
218
219def cram(text, maxlen):
220 """Omit part of a string if needed to make it fit in a maximum length."""
221 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000222 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000223 post = max(0, maxlen-3-pre)
224 return text[:pre] + '...' + text[len(text)-post:]
225 return text
226
Brett Cannon84601f12004-06-19 01:22:48 +0000227_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000228def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000229 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000230 # The behaviour of %p is implementation-dependent in terms of case.
Ezio Melotti412c95a2010-02-16 23:31:04 +0000231 return _re_stripid.sub(r'\1', text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000232
Larry Hastings24a882b2014-02-20 23:34:46 -0800233def _is_bound_method(fn):
234 """
235 Returns True if fn is a bound method, regardless of whether
236 fn was implemented in Python or in C.
237 """
238 if inspect.ismethod(fn):
239 return True
240 if inspect.isbuiltin(fn):
241 self = getattr(fn, '__self__', None)
242 return not (inspect.ismodule(self) or (self is None))
243 return False
244
245
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000246def allmethods(cl):
247 methods = {}
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200248 for key, value in inspect.getmembers(cl, inspect.isroutine):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000249 methods[key] = 1
250 for base in cl.__bases__:
251 methods.update(allmethods(base)) # all your base are belong to us
252 for key in methods.keys():
253 methods[key] = getattr(cl, key)
254 return methods
255
Tim Petersfa26f7c2001-09-24 08:05:11 +0000256def _split_list(s, predicate):
257 """Split sequence s via predicate, and return pair ([true], [false]).
258
259 The return value is a 2-tuple of lists,
260 ([x for x in s if predicate(x)],
261 [x for x in s if not predicate(x)])
262 """
263
Tim Peters28355492001-09-23 21:29:55 +0000264 yes = []
265 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000266 for x in s:
267 if predicate(x):
268 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000269 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000270 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000271 return yes, no
272
Raymond Hettinger1103d052011-03-25 14:15:24 -0700273def visiblename(name, all=None, obj=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000274 """Decide whether to show documentation on a variable."""
Brett Cannond340b432012-08-06 17:19:22 -0400275 # Certain special names are redundant or internal.
Eric Snowb523f842013-11-22 09:05:39 -0700276 # XXX Remove __initializing__?
Brett Cannond340b432012-08-06 17:19:22 -0400277 if name in {'__author__', '__builtins__', '__cached__', '__credits__',
Eric Snowb523f842013-11-22 09:05:39 -0700278 '__date__', '__doc__', '__file__', '__spec__',
Brett Cannond340b432012-08-06 17:19:22 -0400279 '__loader__', '__module__', '__name__', '__package__',
280 '__path__', '__qualname__', '__slots__', '__version__'}:
Raymond Hettinger68272942011-03-18 02:22:15 -0700281 return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000282 # Private names are hidden, but special names are displayed.
283 if name.startswith('__') and name.endswith('__'): return 1
Raymond Hettinger1103d052011-03-25 14:15:24 -0700284 # Namedtuples have public fields and methods with a single leading underscore
285 if name.startswith('_') and hasattr(obj, '_fields'):
286 return True
Skip Montanaroa5616d22004-06-11 04:46:12 +0000287 if all is not None:
288 # only document that which the programmer exported in __all__
289 return name in all
290 else:
291 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000292
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000293def classify_class_attrs(object):
294 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000295 results = []
296 for (name, kind, cls, value) in inspect.classify_class_attrs(object):
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000297 if inspect.isdatadescriptor(value):
298 kind = 'data descriptor'
Raymond Hettinger62be3382019-03-24 17:07:47 -0700299 if isinstance(value, property) and value.fset is None:
300 kind = 'readonly property'
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000301 results.append((name, kind, cls, value))
302 return results
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000303
Raymond Hettinger95801bb2015-08-18 22:25:16 -0700304def sort_attributes(attrs, object):
305 'Sort the attrs list in-place by _fields and then alphabetically by name'
306 # This allows data descriptors to be ordered according
307 # to a _fields attribute if present.
308 fields = getattr(object, '_fields', [])
309 try:
310 field_order = {name : i-len(fields) for (i, name) in enumerate(fields)}
311 except TypeError:
312 field_order = {}
313 keyfunc = lambda attr: (field_order.get(attr[0], 0), attr[0])
314 attrs.sort(key=keyfunc)
315
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000316# ----------------------------------------------------- module manipulation
317
318def ispackage(path):
319 """Guess whether a path refers to a package directory."""
320 if os.path.isdir(path):
Brett Cannonf299abd2015-04-13 14:21:02 -0400321 for ext in ('.py', '.pyc'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000322 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000323 return True
324 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000325
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000326def source_synopsis(file):
327 line = file.readline()
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000328 while line[:1] == '#' or not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000329 line = file.readline()
330 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000331 line = line.strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000332 if line[:4] == 'r"""': line = line[1:]
333 if line[:3] == '"""':
334 line = line[3:]
335 if line[-1:] == '\\': line = line[:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000336 while not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000337 line = file.readline()
338 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000339 result = line.split('"""')[0].strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000340 else: result = None
341 return result
342
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000343def synopsis(filename, cache={}):
344 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000345 mtime = os.stat(filename).st_mtime
Charles-François Natali27c4e882011-07-27 19:40:02 +0200346 lastupdate, result = cache.get(filename, (None, None))
347 if lastupdate is None or lastupdate < mtime:
Eric Snowaed5b222014-01-04 20:38:11 -0700348 # Look for binary suffixes first, falling back to source.
349 if filename.endswith(tuple(importlib.machinery.BYTECODE_SUFFIXES)):
350 loader_cls = importlib.machinery.SourcelessFileLoader
351 elif filename.endswith(tuple(importlib.machinery.EXTENSION_SUFFIXES)):
352 loader_cls = importlib.machinery.ExtensionFileLoader
353 else:
354 loader_cls = None
355 # Now handle the choice.
356 if loader_cls is None:
357 # Must be a source file.
358 try:
359 file = tokenize.open(filename)
360 except OSError:
361 # module can't be opened, so skip it
362 return None
363 # text modules can be directly examined
364 with file:
365 result = source_synopsis(file)
366 else:
367 # Must be a binary module, which has to be imported.
368 loader = loader_cls('__temp__', filename)
Eric Snow3a62d142014-01-06 20:42:59 -0700369 # XXX We probably don't need to pass in the loader here.
370 spec = importlib.util.spec_from_file_location('__temp__', filename,
371 loader=loader)
Brett Cannoncb66eb02012-05-11 12:58:42 -0400372 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -0400373 module = importlib._bootstrap._load(spec)
Brett Cannoncb66eb02012-05-11 12:58:42 -0400374 except:
375 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000376 del sys.modules['__temp__']
Benjamin Peterson54237f92015-02-16 19:45:01 -0500377 result = module.__doc__.splitlines()[0] if module.__doc__ else None
Eric Snowaed5b222014-01-04 20:38:11 -0700378 # Cache the result.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000379 cache[filename] = (mtime, result)
380 return result
381
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000382class ErrorDuringImport(Exception):
383 """Errors that occurred while trying to import something to document it."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000384 def __init__(self, filename, exc_info):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000385 self.filename = filename
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000386 self.exc, self.value, self.tb = exc_info
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000387
388 def __str__(self):
Guido van Rossuma01a8b62007-05-27 09:20:14 +0000389 exc = self.exc.__name__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000390 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000391
392def importfile(path):
393 """Import a Python source file or compiled file given its path."""
Brett Cannonf4ba4ec2013-06-15 14:25:04 -0400394 magic = importlib.util.MAGIC_NUMBER
Victor Stinnere975af62011-07-04 02:08:50 +0200395 with open(path, 'rb') as file:
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400396 is_bytecode = magic == file.read(len(magic))
397 filename = os.path.basename(path)
398 name, ext = os.path.splitext(filename)
399 if is_bytecode:
Eric Snow32439d62015-05-02 19:15:18 -0600400 loader = importlib._bootstrap_external.SourcelessFileLoader(name, path)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400401 else:
Eric Snow32439d62015-05-02 19:15:18 -0600402 loader = importlib._bootstrap_external.SourceFileLoader(name, path)
Eric Snow3a62d142014-01-06 20:42:59 -0700403 # XXX We probably don't need to pass in the loader here.
404 spec = importlib.util.spec_from_file_location(name, path, loader=loader)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400405 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -0400406 return importlib._bootstrap._load(spec)
Brett Cannond5e6f2e2013-06-11 17:09:36 -0400407 except:
408 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000409
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000410def safeimport(path, forceload=0, cache={}):
411 """Import a module; handle errors; return None if the module isn't found.
412
413 If the module *is* found but an exception occurs, it's wrapped in an
414 ErrorDuringImport exception and reraised. Unlike __import__, if a
415 package path is specified, the module at the end of the path is returned,
416 not the package at the beginning. If the optional 'forceload' argument
417 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000418 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000419 # If forceload is 1 and the module has been previously loaded from
420 # disk, we always have to reload the module. Checking the file's
421 # mtime isn't good enough (e.g. the module could contain a class
422 # that inherits from another module that has changed).
423 if forceload and path in sys.modules:
424 if path not in sys.builtin_module_names:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000425 # Remove the module from sys.modules and re-import to try
426 # and avoid problems with partially loaded modules.
427 # Also remove any submodules because they won't appear
428 # in the newly loaded module's namespace if they're already
429 # in sys.modules.
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000430 subs = [m for m in sys.modules if m.startswith(path + '.')]
431 for key in [path] + subs:
432 # Prevent garbage collection.
433 cache[key] = sys.modules[key]
434 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000435 module = __import__(path)
436 except:
437 # Did the error occur before or after the module was found?
438 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000439 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000440 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000441 raise ErrorDuringImport(sys.modules[path].__file__, info)
442 elif exc is SyntaxError:
443 # A SyntaxError occurred before we could execute the module.
444 raise ErrorDuringImport(value.filename, info)
Eric Snow46f97b82016-09-07 16:56:15 -0700445 elif issubclass(exc, ImportError) and value.name == path:
Brett Cannonfd074152012-04-14 14:10:13 -0400446 # No such module in the path.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000447 return None
448 else:
449 # Some other error occurred during the importing process.
450 raise ErrorDuringImport(path, sys.exc_info())
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000451 for part in path.split('.')[1:]:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000452 try: module = getattr(module, part)
453 except AttributeError: return None
454 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000455
456# ---------------------------------------------------- formatter base class
457
458class Doc:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000459
460 PYTHONDOCS = os.environ.get("PYTHONDOCS",
R David Murrayead9bfc2016-06-03 19:28:35 -0400461 "https://docs.python.org/%d.%d/library"
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000462 % sys.version_info[:2])
463
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000464 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000465 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000466 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000467 # 'try' clause is to attempt to handle the possibility that inspect
468 # identifies something in a way that pydoc itself has issues handling;
469 # think 'super' and how it is a descriptor (which raises the exception
470 # by lacking a __name__ attribute) and an instance.
471 try:
472 if inspect.ismodule(object): return self.docmodule(*args)
473 if inspect.isclass(object): return self.docclass(*args)
474 if inspect.isroutine(object): return self.docroutine(*args)
475 except AttributeError:
476 pass
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200477 if inspect.isdatadescriptor(object): return self.docdata(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000478 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000479
480 def fail(self, object, name=None, *args):
481 """Raise an exception for unimplemented types."""
482 message = "don't know how to document object%s of type %s" % (
483 name and ' ' + repr(name), type(object).__name__)
Collin Winterce36ad82007-08-30 01:19:48 +0000484 raise TypeError(message)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000485
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000486 docmodule = docclass = docroutine = docother = docproperty = docdata = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000487
Victor Stinner4fac7ed2020-02-12 13:02:29 +0100488 def getdocloc(self, object, basedir=sysconfig.get_path('stdlib')):
Skip Montanaro4997a692003-09-10 16:47:51 +0000489 """Return the location of module docs or None"""
490
491 try:
492 file = inspect.getabsfile(object)
493 except TypeError:
494 file = '(built-in)'
495
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000496 docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
497
Martin Panter4f8aaf62016-06-12 04:24:06 +0000498 basedir = os.path.normcase(basedir)
Skip Montanaro4997a692003-09-10 16:47:51 +0000499 if (isinstance(object, type(os)) and
500 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
501 'marshal', 'posix', 'signal', 'sys',
Georg Brandl2067bfd2008-05-25 13:05:15 +0000502 '_thread', 'zipimport') or
Skip Montanaro4997a692003-09-10 16:47:51 +0000503 (file.startswith(basedir) and
Brian Curtin49c284c2010-03-31 03:19:28 +0000504 not file.startswith(os.path.join(basedir, 'site-packages')))) and
Brian Curtinedef05b2010-04-01 04:05:25 +0000505 object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
Martin Panter4f8aaf62016-06-12 04:24:06 +0000506 if docloc.startswith(("http://", "https://")):
Julien Palardeb9983c2021-01-25 15:50:14 +0100507 docloc = "{}/{}.html".format(docloc.rstrip("/"), object.__name__.lower())
Skip Montanaro4997a692003-09-10 16:47:51 +0000508 else:
R David Murrayead9bfc2016-06-03 19:28:35 -0400509 docloc = os.path.join(docloc, object.__name__.lower() + ".html")
Skip Montanaro4997a692003-09-10 16:47:51 +0000510 else:
511 docloc = None
512 return docloc
513
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000514# -------------------------------------------- HTML documentation generator
515
516class HTMLRepr(Repr):
517 """Class for safely making an HTML representation of a Python object."""
518 def __init__(self):
519 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000520 self.maxlist = self.maxtuple = 20
521 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000522 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000523
524 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000525 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000526
527 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000528 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000529
530 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000531 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000532 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000533 if hasattr(self, methodname):
534 return getattr(self, methodname)(x, level)
535 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000536
537 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000538 test = cram(x, self.maxstring)
539 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000540 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000541 # Backslashes are only literal in the string and are never
542 # needed to make any special characters, so show a raw string.
543 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000544 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000545 r'<font color="#c040c0">\1</font>',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000546 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000547
Skip Montanarodf708782002-03-07 22:58:02 +0000548 repr_str = repr_string
549
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000550 def repr_instance(self, x, level):
551 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000552 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000553 except:
554 return self.escape('<%s instance>' % x.__class__.__name__)
555
556 repr_unicode = repr_string
557
558class HTMLDoc(Doc):
559 """Formatter class for HTML documentation."""
560
561 # ------------------------------------------- HTML formatting utilities
562
563 _repr_instance = HTMLRepr()
564 repr = _repr_instance.repr
565 escape = _repr_instance.escape
566
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000567 def page(self, title, contents):
568 """Format an HTML page."""
Georg Brandl388faac2009-04-10 08:31:48 +0000569 return '''\
Georg Brandle6066942009-04-10 08:28:28 +0000570<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000571<html><head><title>Python: %s</title>
Georg Brandl388faac2009-04-10 08:31:48 +0000572<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000573</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000574%s
575</body></html>''' % (title, contents)
576
577 def heading(self, title, fgcol, bgcol, extras=''):
578 """Format a page heading."""
579 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000580<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000581<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000582<td valign=bottom>&nbsp;<br>
583<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000584><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000585><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000586 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
587
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000588 def section(self, title, fgcol, bgcol, contents, width=6,
589 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000590 """Format a section with a heading."""
591 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000592 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000593 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000594<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000595<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000596<td colspan=3 valign=bottom>&nbsp;<br>
597<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000598 ''' % (bgcol, fgcol, title)
599 if prelude:
600 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000601<tr bgcolor="%s"><td rowspan=2>%s</td>
602<td colspan=2>%s</td></tr>
603<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
604 else:
605 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000606<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000607
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000608 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000609
610 def bigsection(self, title, *args):
611 """Format a section with a big heading."""
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000612 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000613 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000614
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000615 def preformat(self, text):
616 """Format literal preformatted text."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000617 text = self.escape(text.expandtabs())
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000618 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
619 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000620
621 def multicolumn(self, list, format, cols=4):
622 """Format a list of items into a multi-column list."""
623 result = ''
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000624 rows = (len(list)+cols-1)//cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000625 for col in range(cols):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000626 result = result + '<td width="%d%%" valign=top>' % (100//cols)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000627 for i in range(rows*col, rows*col+rows):
628 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000629 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000630 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000631 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000632
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000633 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000634
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000635 def namelink(self, name, *dicts):
636 """Make a link for an identifier, given name-to-URL mappings."""
637 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000638 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000639 return '<a href="%s">%s</a>' % (dict[name], name)
640 return name
641
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000642 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000643 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000644 name, module = object.__name__, sys.modules.get(object.__module__)
645 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000646 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000647 module.__name__, name, classname(object, modname))
648 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000649
650 def modulelink(self, object):
651 """Make a link for a module."""
652 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
653
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000654 def modpkglink(self, modpkginfo):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000655 """Make a link for a module or package to display in an index."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000656 name, path, ispackage, shadowed = modpkginfo
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000657 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000658 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000659 if path:
660 url = '%s.%s.html' % (path, name)
661 else:
662 url = '%s.html' % name
663 if ispackage:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000664 text = '<strong>%s</strong>&nbsp;(package)' % name
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000665 else:
666 text = name
667 return '<a href="%s">%s</a>' % (url, text)
668
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000669 def filelink(self, url, path):
670 """Make a link to source file."""
671 return '<a href="file:%s">%s</a>' % (url, path)
672
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000673 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
674 """Mark up some plain text, given a context of symbols to look for.
675 Each context dictionary maps object names to anchor names."""
676 escape = escape or self.escape
677 results = []
678 here = 0
Kirill61289d42019-11-13 19:13:53 +0300679 pattern = re.compile(r'\b((http|https|ftp)://\S+[\w/]|'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000680 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000681 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000682 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000683 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000684 match = pattern.search(text, here)
685 if not match: break
686 start, end = match.span()
687 results.append(escape(text[here:start]))
688
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000689 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000690 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000691 url = escape(all).replace('"', '&quot;')
692 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000693 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000694 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
695 results.append('<a href="%s">%s</a>' % (url, escape(all)))
696 elif pep:
Christian Heimes2202f872008-02-06 14:31:34 +0000697 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000698 results.append('<a href="%s">%s</a>' % (url, escape(all)))
Benjamin Petersoned1160b2014-06-07 16:44:00 -0700699 elif selfdot:
700 # Create a link for methods like 'self.method(...)'
701 # and use <strong> for attributes like 'self.attr'
702 if text[end:end+1] == '(':
703 results.append('self.' + self.namelink(name, methods))
704 else:
705 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000706 elif text[end:end+1] == '(':
707 results.append(self.namelink(name, methods, funcs, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000708 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000709 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000710 here = end
711 results.append(escape(text[here:]))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000712 return ''.join(results)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000713
714 # ---------------------------------------------- type-specific routines
715
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000716 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000717 """Produce HTML for a class tree as given by inspect.getclasstree()."""
718 result = ''
719 for entry in tree:
720 if type(entry) is type(()):
721 c, bases = entry
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000722 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000723 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000724 if bases and bases != (parent,):
725 parents = []
726 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000727 parents.append(self.classlink(base, modname))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000728 result = result + '(' + ', '.join(parents) + ')'
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000729 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000730 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000731 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000732 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000733 return '<dl>\n%s</dl>\n' % result
734
Tim Peters8dd7ade2001-10-18 19:56:17 +0000735 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000736 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000737 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000738 try:
739 all = object.__all__
740 except AttributeError:
741 all = None
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000742 parts = name.split('.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000743 links = []
744 for i in range(len(parts)-1):
745 links.append(
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000746 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000747 ('.'.join(parts[:i+1]), parts[i]))
748 linkedname = '.'.join(links + parts[-1:])
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000749 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000750 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000751 path = inspect.getabsfile(object)
Zachary Wareeb432142014-07-10 11:18:00 -0500752 url = urllib.parse.quote(path)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000753 filelink = self.filelink(url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000754 except TypeError:
755 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000756 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000757 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000758 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000759 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000760 version = version[11:-1].strip()
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000761 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000762 if hasattr(object, '__date__'):
763 info.append(self.escape(str(object.__date__)))
764 if info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000765 head = head + ' (%s)' % ', '.join(info)
Skip Montanaro4997a692003-09-10 16:47:51 +0000766 docloc = self.getdocloc(object)
767 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000768 docloc = '<br><a href="%(docloc)s">Module Reference</a>' % locals()
Skip Montanaro4997a692003-09-10 16:47:51 +0000769 else:
770 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000771 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000772 head, '#ffffff', '#7799ee',
773 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000774
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000775 modules = inspect.getmembers(object, inspect.ismodule)
776
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000777 classes, cdict = [], {}
778 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000779 # if __all__ exists, believe it. Otherwise use old heuristic.
780 if (all is not None or
781 (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700782 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000783 classes.append((key, value))
784 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000785 for key, value in classes:
786 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000787 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000788 module = sys.modules.get(modname)
789 if modname != name and module and hasattr(module, key):
790 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000791 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000792 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000793 funcs, fdict = [], {}
794 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000795 # if __all__ exists, believe it. Otherwise use old heuristic.
796 if (all is not None or
797 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700798 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000799 funcs.append((key, value))
800 fdict[key] = '#-' + key
801 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000802 data = []
803 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700804 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000805 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000806
807 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
808 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000809 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000810
811 if hasattr(object, '__path__'):
812 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000813 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
814 modpkgs.append((modname, name, ispkg, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000815 modpkgs.sort()
816 contents = self.multicolumn(modpkgs, self.modpkglink)
817 result = result + self.bigsection(
818 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000819 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000820 contents = self.multicolumn(
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000821 modules, lambda t: self.modulelink(t[1]))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000822 result = result + self.bigsection(
Christian Heimes7131fd92008-02-19 14:21:46 +0000823 'Modules', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000824
825 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000826 classlist = [value for (key, value) in classes]
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000827 contents = [
828 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000829 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000830 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000831 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000832 'Classes', '#ffffff', '#ee77aa', ' '.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000833 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000834 contents = []
835 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000836 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000837 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000838 'Functions', '#ffffff', '#eeaa77', ' '.join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000839 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000840 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000841 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000842 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000843 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000844 'Data', '#ffffff', '#55aa55', '<br>\n'.join(contents))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000845 if hasattr(object, '__author__'):
846 contents = self.markup(str(object.__author__), self.preformat)
847 result = result + self.bigsection(
848 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000849 if hasattr(object, '__credits__'):
850 contents = self.markup(str(object.__credits__), self.preformat)
851 result = result + self.bigsection(
852 'Credits', '#ffffff', '#7799ee', contents)
853
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000854 return result
855
Tim Peters8dd7ade2001-10-18 19:56:17 +0000856 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
857 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000858 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000859 realname = object.__name__
860 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000861 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000862
Tim Petersb47879b2001-09-24 04:47:19 +0000863 contents = []
864 push = contents.append
865
Tim Petersfa26f7c2001-09-24 08:05:11 +0000866 # Cute little class to pump out a horizontal rule between sections.
867 class HorizontalRule:
868 def __init__(self):
869 self.needone = 0
870 def maybe(self):
871 if self.needone:
872 push('<hr>\n')
873 self.needone = 1
874 hr = HorizontalRule()
875
Tim Petersc86f6ca2001-09-26 21:31:51 +0000876 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000877 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000878 if len(mro) > 2:
879 hr.maybe()
880 push('<dl><dt>Method resolution order:</dt>\n')
881 for base in mro:
882 push('<dd>%s</dd>\n' % self.classlink(base,
883 object.__module__))
884 push('</dl>\n')
885
Tim Petersb47879b2001-09-24 04:47:19 +0000886 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000887 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000888 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000889 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000890 push(msg)
891 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100892 try:
893 value = getattr(object, name)
894 except Exception:
895 # Some descriptors may meet a failure in their __get__.
896 # (bug #1785)
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200897 push(self.docdata(value, name, mod))
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100898 else:
899 push(self.document(value, name, mod,
900 funcs, classes, mdict, object))
Tim Petersb47879b2001-09-24 04:47:19 +0000901 push('\n')
902 return attrs
903
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000904 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000905 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000906 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000907 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000908 push(msg)
909 for name, kind, homecls, value in ok:
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +0200910 push(self.docdata(value, name, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000911 return attrs
912
Tim Petersfa26f7c2001-09-24 08:05:11 +0000913 def spilldata(msg, attrs, predicate):
914 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000915 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000916 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000917 push(msg)
918 for name, kind, homecls, value in ok:
919 base = self.docother(getattr(object, name), name, mod)
Serhiy Storchakafbf27862020-04-15 23:00:20 +0300920 doc = getdoc(value)
921 if not doc:
Tim Petersb47879b2001-09-24 04:47:19 +0000922 push('<dl><dt>%s</dl>\n' % base)
923 else:
924 doc = self.markup(getdoc(value), self.preformat,
925 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000926 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000927 push('<dl><dt>%s%s</dl>\n' % (base, doc))
928 push('\n')
929 return attrs
930
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000931 attrs = [(name, kind, cls, value)
932 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -0700933 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000934
Tim Petersb47879b2001-09-24 04:47:19 +0000935 mdict = {}
936 for key, kind, homecls, value in attrs:
937 mdict[key] = anchor = '#' + name + '-' + key
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100938 try:
939 value = getattr(object, name)
940 except Exception:
941 # Some descriptors may meet a failure in their __get__.
942 # (bug #1785)
943 pass
Tim Petersb47879b2001-09-24 04:47:19 +0000944 try:
945 # The value may not be hashable (e.g., a data attr with
946 # a dict or list value).
947 mdict[value] = anchor
948 except TypeError:
949 pass
950
Tim Petersfa26f7c2001-09-24 08:05:11 +0000951 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000952 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000953 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000954 else:
955 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000956 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
957
Cheryl Sabellac95c93d2019-05-24 06:43:29 -0400958 if object is not builtins.object and thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000959 attrs = inherited
960 continue
961 elif thisclass is object:
962 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000963 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000964 tag = 'inherited from %s' % self.classlink(thisclass,
965 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000966 tag += ':<br>\n'
967
Raymond Hettinger95801bb2015-08-18 22:25:16 -0700968 sort_attributes(attrs, object)
Tim Petersb47879b2001-09-24 04:47:19 +0000969
970 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000971 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000972 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000973 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000974 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000975 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000976 lambda t: t[1] == 'static method')
Raymond Hettinger9dcc0952019-03-25 00:23:39 -0700977 attrs = spilldescriptors("Readonly properties %s" % tag, attrs,
Raymond Hettinger62be3382019-03-24 17:07:47 -0700978 lambda t: t[1] == 'readonly property')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000979 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
980 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000981 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000982 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000983 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000984 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000985
986 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000987
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000988 if name == realname:
989 title = '<a name="%s">class <strong>%s</strong></a>' % (
990 name, realname)
991 else:
992 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
993 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000994 if bases:
995 parents = []
996 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000997 parents.append(self.classlink(base, object.__module__))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000998 title = title + '(%s)' % ', '.join(parents)
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +0200999
1000 decl = ''
1001 try:
1002 signature = inspect.signature(object)
1003 except (ValueError, TypeError):
1004 signature = None
1005 if signature:
1006 argspec = str(signature)
Serhiy Storchaka213f2292017-01-23 14:02:35 +02001007 if argspec and argspec != '()':
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001008 decl = name + self.escape(argspec) + '\n\n'
1009
1010 doc = getdoc(object)
1011 if decl:
1012 doc = decl + (doc or '')
1013 doc = self.markup(doc, self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001014 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +00001015
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001016 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001017
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001018 def formatvalue(self, object):
1019 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +00001020 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001021
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001022 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001023 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001024 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001025 realname = object.__name__
1026 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001027 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001028 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001029 skipdocs = 0
Larry Hastings24a882b2014-02-20 23:34:46 -08001030 if _is_bound_method(object):
Christian Heimesff737952007-11-27 10:40:20 +00001031 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001032 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001033 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001034 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001035 else:
Christian Heimesff737952007-11-27 10:40:20 +00001036 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001037 note = ' method of %s instance' % self.classlink(
Christian Heimesff737952007-11-27 10:40:20 +00001038 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001039 else:
1040 note = ' unbound %s method' % self.classlink(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001041
Dan Rose2a37f8f2019-05-24 06:38:01 -05001042 if (inspect.iscoroutinefunction(object) or
1043 inspect.isasyncgenfunction(object)):
1044 asyncqualifier = 'async '
1045 else:
1046 asyncqualifier = ''
1047
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001048 if name == realname:
1049 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
1050 else:
Serhiy Storchakaa44d34e2018-11-08 08:48:11 +02001051 if cl and inspect.getattr_static(cl, realname, []) is object:
Ka-Ping Yeee280c062001-03-23 14:05:53 +00001052 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001053 cl.__name__ + '-' + realname, realname)
1054 skipdocs = 1
1055 else:
1056 reallink = realname
1057 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
1058 anchor, name, reallink)
Larry Hastings44e2eaa2013-11-23 15:37:55 -08001059 argspec = None
Larry Hastings24a882b2014-02-20 23:34:46 -08001060 if inspect.isroutine(object):
Larry Hastings5c661892014-01-24 06:17:25 -08001061 try:
1062 signature = inspect.signature(object)
1063 except (ValueError, TypeError):
1064 signature = None
Larry Hastings44e2eaa2013-11-23 15:37:55 -08001065 if signature:
1066 argspec = str(signature)
1067 if realname == '<lambda>':
1068 title = '<strong>%s</strong> <em>lambda</em> ' % name
1069 # XXX lambda's won't usually have func_annotations['return']
1070 # since the syntax doesn't support but it is possible.
1071 # So removing parentheses isn't truly safe.
1072 argspec = argspec[1:-1] # remove parentheses
1073 if not argspec:
Tim Peters4bcfa312001-09-20 06:08:24 +00001074 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001075
Dan Rose2a37f8f2019-05-24 06:38:01 -05001076 decl = asyncqualifier + title + self.escape(argspec) + (note and
1077 self.grey('<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001078
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001079 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +00001080 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001081 else:
1082 doc = self.markup(
1083 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +00001084 doc = doc and '<dd><tt>%s</tt></dd>' % doc
1085 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001086
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001087 def docdata(self, object, name=None, mod=None, cl=None):
1088 """Produce html documentation for a data descriptor."""
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001089 results = []
1090 push = results.append
1091
1092 if name:
1093 push('<dl><dt><strong>%s</strong></dt>\n' % name)
Raymond Hettingera694f232019-03-27 13:16:34 -07001094 doc = self.markup(getdoc(object), self.preformat)
1095 if doc:
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001096 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001097 push('</dl>\n')
1098
1099 return ''.join(results)
1100
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001101 docproperty = docdata
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001102
Tim Peters8dd7ade2001-10-18 19:56:17 +00001103 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001104 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001105 lhs = name and '<strong>%s</strong> = ' % name or ''
1106 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001107
1108 def index(self, dir, shadowed=None):
1109 """Generate an HTML index for a directory of modules."""
1110 modpkgs = []
1111 if shadowed is None: shadowed = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001112 for importer, name, ispkg in pkgutil.iter_modules([dir]):
Victor Stinner4d652242011-04-12 23:41:50 +02001113 if any((0xD800 <= ord(ch) <= 0xDFFF) for ch in name):
1114 # ignore a module if its name contains a surrogate character
1115 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001116 modpkgs.append((name, '', ispkg, name in shadowed))
1117 shadowed[name] = 1
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001118
1119 modpkgs.sort()
1120 contents = self.multicolumn(modpkgs, self.modpkglink)
1121 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
1122
1123# -------------------------------------------- text documentation generator
1124
1125class TextRepr(Repr):
1126 """Class for safely making a text representation of a Python object."""
1127 def __init__(self):
1128 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001129 self.maxlist = self.maxtuple = 20
1130 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001131 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001132
1133 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +00001134 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001135 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +00001136 if hasattr(self, methodname):
1137 return getattr(self, methodname)(x, level)
1138 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001139
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +00001140 def repr_string(self, x, level):
1141 test = cram(x, self.maxstring)
1142 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001143 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +00001144 # Backslashes are only literal in the string and are never
1145 # needed to make any special characters, so show a raw string.
1146 return 'r' + testrepr[0] + test + testrepr[0]
1147 return testrepr
1148
Skip Montanarodf708782002-03-07 22:58:02 +00001149 repr_str = repr_string
1150
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001151 def repr_instance(self, x, level):
1152 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001153 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001154 except:
1155 return '<%s instance>' % x.__class__.__name__
1156
1157class TextDoc(Doc):
1158 """Formatter class for text documentation."""
1159
1160 # ------------------------------------------- text formatting utilities
1161
1162 _repr_instance = TextRepr()
1163 repr = _repr_instance.repr
1164
1165 def bold(self, text):
1166 """Format a string in bold by overstriking."""
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001167 return ''.join(ch + '\b' + ch for ch in text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001168
1169 def indent(self, text, prefix=' '):
1170 """Indent text by prepending a given prefix to each line."""
1171 if not text: return ''
Collin Winter72e110c2007-07-17 00:27:30 +00001172 lines = [prefix + line for line in text.split('\n')]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001173 if lines: lines[-1] = lines[-1].rstrip()
1174 return '\n'.join(lines)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001175
1176 def section(self, title, contents):
1177 """Format a section with a given heading."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001178 clean_contents = self.indent(contents).rstrip()
1179 return self.bold(title) + '\n' + clean_contents + '\n\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001180
1181 # ---------------------------------------------- type-specific routines
1182
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001183 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001184 """Render in text a class tree as returned by inspect.getclasstree()."""
1185 result = ''
1186 for entry in tree:
1187 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001188 c, bases = entry
1189 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001190 if bases and bases != (parent,):
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001191 parents = (classname(c, modname) for c in bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001192 result = result + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001193 result = result + '\n'
1194 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001195 result = result + self.formattree(
1196 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001197 return result
1198
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001199 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001200 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001201 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001202 synop, desc = splitdoc(getdoc(object))
1203 result = self.section('NAME', name + (synop and ' - ' + synop))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001204 all = getattr(object, '__all__', None)
Skip Montanaro4997a692003-09-10 16:47:51 +00001205 docloc = self.getdocloc(object)
1206 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001207 result = result + self.section('MODULE REFERENCE', docloc + """
1208
Éric Araujo647ef8c2011-09-11 00:43:20 +02001209The following documentation is automatically generated from the Python
1210source files. It may be incomplete, incorrect or include features that
1211are considered implementation detail and may vary between Python
1212implementations. When in doubt, consult the module reference at the
1213location listed above.
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001214""")
Skip Montanaro4997a692003-09-10 16:47:51 +00001215
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001216 if desc:
1217 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001218
1219 classes = []
1220 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001221 # if __all__ exists, believe it. Otherwise use old heuristic.
1222 if (all is not None
1223 or (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001224 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001225 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001226 funcs = []
1227 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001228 # if __all__ exists, believe it. Otherwise use old heuristic.
1229 if (all is not None or
1230 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001231 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001232 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001233 data = []
1234 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001235 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001236 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001237
Christian Heimes1af737c2008-01-23 08:24:23 +00001238 modpkgs = []
1239 modpkgs_names = set()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001240 if hasattr(object, '__path__'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001241 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
Christian Heimes1af737c2008-01-23 08:24:23 +00001242 modpkgs_names.add(modname)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001243 if ispkg:
1244 modpkgs.append(modname + ' (package)')
1245 else:
1246 modpkgs.append(modname)
1247
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001248 modpkgs.sort()
1249 result = result + self.section(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001250 'PACKAGE CONTENTS', '\n'.join(modpkgs))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001251
Christian Heimes1af737c2008-01-23 08:24:23 +00001252 # Detect submodules as sometimes created by C extensions
1253 submodules = []
1254 for key, value in inspect.getmembers(object, inspect.ismodule):
1255 if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1256 submodules.append(key)
1257 if submodules:
1258 submodules.sort()
1259 result = result + self.section(
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001260 'SUBMODULES', '\n'.join(submodules))
Christian Heimes1af737c2008-01-23 08:24:23 +00001261
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001262 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001263 classlist = [value for key, value in classes]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001264 contents = [self.formattree(
1265 inspect.getclasstree(classlist, 1), name)]
1266 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001267 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001268 result = result + self.section('CLASSES', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001269
1270 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001271 contents = []
1272 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001273 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001274 result = result + self.section('FUNCTIONS', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001275
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001276 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001277 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001278 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001279 contents.append(self.docother(value, key, name, maxlen=70))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001280 result = result + self.section('DATA', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001281
1282 if hasattr(object, '__version__'):
1283 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001284 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001285 version = version[11:-1].strip()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001286 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001287 if hasattr(object, '__date__'):
1288 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001289 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001290 result = result + self.section('AUTHOR', str(object.__author__))
1291 if hasattr(object, '__credits__'):
1292 result = result + self.section('CREDITS', str(object.__credits__))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001293 try:
1294 file = inspect.getabsfile(object)
1295 except TypeError:
1296 file = '(built-in)'
1297 result = result + self.section('FILE', file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001298 return result
1299
Georg Brandl9bd45f992010-12-03 09:58:38 +00001300 def docclass(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001301 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001302 realname = object.__name__
1303 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001304 bases = object.__bases__
1305
Tim Petersc86f6ca2001-09-26 21:31:51 +00001306 def makename(c, m=object.__module__):
1307 return classname(c, m)
1308
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001309 if name == realname:
1310 title = 'class ' + self.bold(realname)
1311 else:
1312 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001313 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001314 parents = map(makename, bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001315 title = title + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001316
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001317 contents = []
Tim Peters28355492001-09-23 21:29:55 +00001318 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001319
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001320 try:
1321 signature = inspect.signature(object)
1322 except (ValueError, TypeError):
1323 signature = None
1324 if signature:
1325 argspec = str(signature)
Serhiy Storchaka213f2292017-01-23 14:02:35 +02001326 if argspec and argspec != '()':
Serhiy Storchakaccb5f3c2017-01-23 12:37:00 +02001327 push(name + argspec + '\n')
1328
1329 doc = getdoc(object)
1330 if doc:
1331 push(doc + '\n')
1332
Tim Petersc86f6ca2001-09-26 21:31:51 +00001333 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001334 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001335 if len(mro) > 2:
1336 push("Method resolution order:")
1337 for base in mro:
1338 push(' ' + makename(base))
1339 push('')
1340
Sanyam Khuranaa323cdc2018-10-21 00:22:02 -07001341 # List the built-in subclasses, if any:
1342 subclasses = sorted(
Sanyam Khuranab539cef2018-12-31 10:44:47 +05301343 (str(cls.__name__) for cls in type.__subclasses__(object)
Sanyam Khuranaa323cdc2018-10-21 00:22:02 -07001344 if not cls.__name__.startswith("_") and cls.__module__ == "builtins"),
1345 key=str.lower
1346 )
1347 no_of_subclasses = len(subclasses)
1348 MAX_SUBCLASSES_TO_DISPLAY = 4
1349 if subclasses:
1350 push("Built-in subclasses:")
1351 for subclassname in subclasses[:MAX_SUBCLASSES_TO_DISPLAY]:
1352 push(' ' + subclassname)
1353 if no_of_subclasses > MAX_SUBCLASSES_TO_DISPLAY:
1354 push(' ... and ' +
1355 str(no_of_subclasses - MAX_SUBCLASSES_TO_DISPLAY) +
1356 ' other subclasses')
1357 push('')
1358
Tim Petersf4aad8e2001-09-24 22:40:47 +00001359 # Cute little class to pump out a horizontal rule between sections.
1360 class HorizontalRule:
1361 def __init__(self):
1362 self.needone = 0
1363 def maybe(self):
1364 if self.needone:
1365 push('-' * 70)
1366 self.needone = 1
1367 hr = HorizontalRule()
1368
Tim Peters28355492001-09-23 21:29:55 +00001369 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001370 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001371 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001372 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001373 push(msg)
1374 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +01001375 try:
1376 value = getattr(object, name)
1377 except Exception:
1378 # Some descriptors may meet a failure in their __get__.
1379 # (bug #1785)
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001380 push(self.docdata(value, name, mod))
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +01001381 else:
1382 push(self.document(value,
1383 name, mod, object))
Tim Peters28355492001-09-23 21:29:55 +00001384 return attrs
1385
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001386 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001387 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001388 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001389 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001390 push(msg)
1391 for name, kind, homecls, value in ok:
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001392 push(self.docdata(value, name, mod))
Tim Peters28355492001-09-23 21:29:55 +00001393 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001394
Tim Petersfa26f7c2001-09-24 08:05:11 +00001395 def spilldata(msg, attrs, predicate):
1396 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001397 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001398 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001399 push(msg)
1400 for name, kind, homecls, value in ok:
Serhiy Storchakafbf27862020-04-15 23:00:20 +03001401 doc = getdoc(value)
Serhiy Storchaka056eb022014-02-19 23:05:12 +02001402 try:
1403 obj = getattr(object, name)
1404 except AttributeError:
1405 obj = homecls.__dict__[name]
1406 push(self.docother(obj, name, mod, maxlen=70, doc=doc) +
1407 '\n')
Tim Peters28355492001-09-23 21:29:55 +00001408 return attrs
1409
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001410 attrs = [(name, kind, cls, value)
1411 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -07001412 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001413
Tim Petersfa26f7c2001-09-24 08:05:11 +00001414 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001415 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001416 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001417 else:
1418 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001419 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1420
Cheryl Sabellac95c93d2019-05-24 06:43:29 -04001421 if object is not builtins.object and thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001422 attrs = inherited
1423 continue
1424 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001425 tag = "defined here"
1426 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001427 tag = "inherited from %s" % classname(thisclass,
1428 object.__module__)
Raymond Hettinger95801bb2015-08-18 22:25:16 -07001429
1430 sort_attributes(attrs, object)
Tim Peters28355492001-09-23 21:29:55 +00001431
1432 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001433 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001434 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001435 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001436 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001437 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001438 lambda t: t[1] == 'static method')
Raymond Hettinger62be3382019-03-24 17:07:47 -07001439 attrs = spilldescriptors("Readonly properties %s:\n" % tag, attrs,
1440 lambda t: t[1] == 'readonly property')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001441 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1442 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001443 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1444 lambda t: t[1] == 'data')
Ethan Furmanb0c84cd2013-10-20 22:37:39 -07001445
Tim Peters28355492001-09-23 21:29:55 +00001446 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001447 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001448
1449 contents = '\n'.join(contents)
1450 if not contents:
1451 return title + '\n'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001452 return title + '\n' + self.indent(contents.rstrip(), ' | ') + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001453
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001454 def formatvalue(self, object):
1455 """Format an argument default value as text."""
1456 return '=' + self.repr(object)
1457
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001458 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001459 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001460 realname = object.__name__
1461 name = name or realname
1462 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001463 skipdocs = 0
Larry Hastings24a882b2014-02-20 23:34:46 -08001464 if _is_bound_method(object):
Christian Heimesff737952007-11-27 10:40:20 +00001465 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001466 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001467 if imclass is not cl:
1468 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001469 else:
Christian Heimesff737952007-11-27 10:40:20 +00001470 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001471 note = ' method of %s instance' % classname(
Christian Heimesff737952007-11-27 10:40:20 +00001472 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001473 else:
1474 note = ' unbound %s method' % classname(imclass,mod)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001475
Dan Rose2a37f8f2019-05-24 06:38:01 -05001476 if (inspect.iscoroutinefunction(object) or
1477 inspect.isasyncgenfunction(object)):
1478 asyncqualifier = 'async '
1479 else:
1480 asyncqualifier = ''
1481
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001482 if name == realname:
1483 title = self.bold(realname)
1484 else:
Serhiy Storchakaa44d34e2018-11-08 08:48:11 +02001485 if cl and inspect.getattr_static(cl, realname, []) is object:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001486 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001487 title = self.bold(name) + ' = ' + realname
Larry Hastings44e2eaa2013-11-23 15:37:55 -08001488 argspec = None
Larry Hastings5c661892014-01-24 06:17:25 -08001489
1490 if inspect.isroutine(object):
1491 try:
1492 signature = inspect.signature(object)
1493 except (ValueError, TypeError):
1494 signature = None
Larry Hastings44e2eaa2013-11-23 15:37:55 -08001495 if signature:
1496 argspec = str(signature)
1497 if realname == '<lambda>':
1498 title = self.bold(name) + ' lambda '
1499 # XXX lambda's won't usually have func_annotations['return']
1500 # since the syntax doesn't support but it is possible.
1501 # So removing parentheses isn't truly safe.
1502 argspec = argspec[1:-1] # remove parentheses
1503 if not argspec:
Tim Peters4bcfa312001-09-20 06:08:24 +00001504 argspec = '(...)'
Dan Rose2a37f8f2019-05-24 06:38:01 -05001505 decl = asyncqualifier + title + argspec + note
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001506
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001507 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001508 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001509 else:
1510 doc = getdoc(object) or ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001511 return decl + '\n' + (doc and self.indent(doc).rstrip() + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001512
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001513 def docdata(self, object, name=None, mod=None, cl=None):
1514 """Produce text documentation for a data descriptor."""
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001515 results = []
1516 push = results.append
1517
1518 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001519 push(self.bold(name))
1520 push('\n')
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001521 doc = getdoc(object) or ''
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001522 if doc:
1523 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001524 push('\n')
1525 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001526
Serhiy Storchakaefcf82f2019-01-15 10:53:18 +02001527 docproperty = docdata
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001528
Georg Brandl8b813db2005-10-01 16:32:31 +00001529 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001530 """Produce text documentation for a data object."""
1531 repr = self.repr(object)
1532 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001533 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001534 chop = maxlen - len(line)
1535 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001536 line = (name and self.bold(name) + ' = ' or '') + repr
Serhiy Storchakafbf27862020-04-15 23:00:20 +03001537 if not doc:
1538 doc = getdoc(object)
1539 if doc:
Serhiy Storchaka7e644142020-04-18 17:13:21 +03001540 line += '\n' + self.indent(str(doc)) + '\n'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001541 return line
1542
Georg Brandld80d5f42010-12-03 07:47:22 +00001543class _PlainTextDoc(TextDoc):
1544 """Subclass of TextDoc which overrides string styling"""
1545 def bold(self, text):
1546 return text
1547
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001548# --------------------------------------------------------- user interfaces
1549
1550def pager(text):
1551 """The first time this is called, determine what kind of pager to use."""
1552 global pager
1553 pager = getpager()
1554 pager(text)
1555
1556def getpager():
1557 """Decide what method to use for paging through text."""
Benjamin Peterson159824e2014-06-07 20:14:26 -07001558 if not hasattr(sys.stdin, "isatty"):
1559 return plainpager
Guido van Rossuma01a8b62007-05-27 09:20:14 +00001560 if not hasattr(sys.stdout, "isatty"):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001561 return plainpager
1562 if not sys.stdin.isatty() or not sys.stdout.isatty():
1563 return plainpager
doko@ubuntu.com96575452016-06-14 08:39:31 +02001564 use_pager = os.environ.get('MANPAGER') or os.environ.get('PAGER')
1565 if use_pager:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001566 if sys.platform == 'win32': # pipes completely broken in Windows
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001567 return lambda text: tempfilepager(plain(text), use_pager)
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001568 elif os.environ.get('TERM') in ('dumb', 'emacs'):
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001569 return lambda text: pipepager(plain(text), use_pager)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001570 else:
doko@ubuntu.comc8fd1922016-06-14 09:03:52 +02001571 return lambda text: pipepager(text, use_pager)
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001572 if os.environ.get('TERM') in ('dumb', 'emacs'):
1573 return plainpager
Jesus Cea4791a242012-10-05 03:15:39 +02001574 if sys.platform == 'win32':
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001575 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001576 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001577 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001578
1579 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001580 (fd, filename) = tempfile.mkstemp()
1581 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001582 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001583 if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001584 return lambda text: pipepager(text, 'more')
1585 else:
1586 return ttypager
1587 finally:
1588 os.unlink(filename)
1589
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001590def plain(text):
1591 """Remove boldface formatting from text."""
1592 return re.sub('.\b', '', text)
1593
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001594def pipepager(text, cmd):
1595 """Page through text by feeding it to another program."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001596 import subprocess
Inada Naoki9dfefbe2021-04-27 12:46:20 +09001597 proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE,
1598 errors='backslashreplace')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001599 try:
Inada Naoki9dfefbe2021-04-27 12:46:20 +09001600 with proc.stdin as pipe:
R David Murraye7f5e142015-03-30 10:14:47 -04001601 try:
1602 pipe.write(text)
1603 except KeyboardInterrupt:
1604 # We've hereby abandoned whatever text hasn't been written,
1605 # but the pager is still in control of the terminal.
1606 pass
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001607 except OSError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001608 pass # Ignore broken pipes caused by quitting the pager program.
R David Murray1058cda2015-03-29 15:15:40 -04001609 while True:
1610 try:
1611 proc.wait()
1612 break
1613 except KeyboardInterrupt:
1614 # Ignore ctl-c like the pager itself does. Otherwise the pager is
1615 # left running and the terminal is in raw mode and unusable.
1616 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001617
1618def tempfilepager(text, cmd):
1619 """Page through text by invoking a program on a temporary file."""
1620 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001621 filename = tempfile.mktemp()
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001622 with open(filename, 'w', errors='backslashreplace') as file:
Giampaolo Rodola'2f50aaf2013-02-12 02:04:27 +01001623 file.write(text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001624 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001625 os.system(cmd + ' "' + filename + '"')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001626 finally:
1627 os.unlink(filename)
1628
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001629def _escape_stdout(text):
1630 # Escape non-encodable characters to avoid encoding errors later
1631 encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8'
1632 return text.encode(encoding, 'backslashreplace').decode(encoding)
1633
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001634def ttypager(text):
1635 """Page through text on a text terminal."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001636 lines = plain(_escape_stdout(text)).split('\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001637 try:
1638 import tty
1639 fd = sys.stdin.fileno()
1640 old = tty.tcgetattr(fd)
1641 tty.setcbreak(fd)
1642 getchar = lambda: sys.stdin.read(1)
Serhiy Storchakaab5e9b92014-11-28 00:09:29 +02001643 except (ImportError, AttributeError, io.UnsupportedOperation):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001644 tty = None
1645 getchar = lambda: sys.stdin.readline()[:-1][:1]
1646
1647 try:
Serhiy Storchakaab5e9b92014-11-28 00:09:29 +02001648 try:
1649 h = int(os.environ.get('LINES', 0))
1650 except ValueError:
1651 h = 0
1652 if h <= 1:
1653 h = 25
1654 r = inc = h - 1
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001655 sys.stdout.write('\n'.join(lines[:inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001656 while lines[r:]:
1657 sys.stdout.write('-- more --')
1658 sys.stdout.flush()
1659 c = getchar()
1660
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001661 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001662 sys.stdout.write('\r \r')
1663 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001664 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001665 sys.stdout.write('\r \r' + lines[r] + '\n')
1666 r = r + 1
1667 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001668 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001669 r = r - inc - inc
1670 if r < 0: r = 0
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001671 sys.stdout.write('\n' + '\n'.join(lines[r:r+inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001672 r = r + inc
1673
1674 finally:
1675 if tty:
1676 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1677
1678def plainpager(text):
1679 """Simply print unformatted text. This is the ultimate fallback."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001680 sys.stdout.write(plain(_escape_stdout(text)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001681
1682def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001683 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001684 if inspect.ismodule(thing):
1685 if thing.__name__ in sys.builtin_module_names:
1686 return 'built-in module ' + thing.__name__
1687 if hasattr(thing, '__path__'):
1688 return 'package ' + thing.__name__
1689 else:
1690 return 'module ' + thing.__name__
1691 if inspect.isbuiltin(thing):
1692 return 'built-in function ' + thing.__name__
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001693 if inspect.isgetsetdescriptor(thing):
1694 return 'getset descriptor %s.%s.%s' % (
1695 thing.__objclass__.__module__, thing.__objclass__.__name__,
1696 thing.__name__)
1697 if inspect.ismemberdescriptor(thing):
1698 return 'member descriptor %s.%s.%s' % (
1699 thing.__objclass__.__module__, thing.__objclass__.__name__,
1700 thing.__name__)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001701 if inspect.isclass(thing):
1702 return 'class ' + thing.__name__
1703 if inspect.isfunction(thing):
1704 return 'function ' + thing.__name__
1705 if inspect.ismethod(thing):
1706 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001707 return type(thing).__name__
1708
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001709def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001710 """Locate an object by name or dotted path, importing as necessary."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001711 parts = [part for part in path.split('.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001712 module, n = None, 0
1713 while n < len(parts):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001714 nextmodule = safeimport('.'.join(parts[:n+1]), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001715 if nextmodule: module, n = nextmodule, n + 1
1716 else: break
1717 if module:
1718 object = module
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001719 else:
Éric Araujoe64e51b2011-07-29 17:03:55 +02001720 object = builtins
1721 for part in parts[n:]:
1722 try:
1723 object = getattr(object, part)
1724 except AttributeError:
1725 return None
1726 return object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001727
1728# --------------------------------------- interactive interpreter interface
1729
1730text = TextDoc()
Georg Brandld80d5f42010-12-03 07:47:22 +00001731plaintext = _PlainTextDoc()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001732html = HTMLDoc()
1733
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001734def resolve(thing, forceload=0):
1735 """Given an object or a path to an object, get the object and its name."""
1736 if isinstance(thing, str):
1737 object = locate(thing, forceload)
Serhiy Storchakab6076fb2015-04-21 21:09:48 +03001738 if object is None:
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001739 raise ImportError('''\
1740No Python documentation found for %r.
1741Use help() to get the interactive help utility.
1742Use help(str) for help on the str class.''' % thing)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001743 return object, thing
1744 else:
R David Murrayc43125a2012-04-23 13:23:57 -04001745 name = getattr(thing, '__name__', None)
1746 return thing, name if isinstance(name, str) else None
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001747
Georg Brandld80d5f42010-12-03 07:47:22 +00001748def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
1749 renderer=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001750 """Render text documentation, given an object or a path to an object."""
Georg Brandld80d5f42010-12-03 07:47:22 +00001751 if renderer is None:
1752 renderer = text
Guido van Rossumd8faa362007-04-27 19:54:29 +00001753 object, name = resolve(thing, forceload)
1754 desc = describe(object)
1755 module = inspect.getmodule(object)
1756 if name and '.' in name:
1757 desc += ' in ' + name[:name.rfind('.')]
1758 elif module and module is not object:
1759 desc += ' in module ' + module.__name__
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001760
1761 if not (inspect.ismodule(object) or
Guido van Rossumd8faa362007-04-27 19:54:29 +00001762 inspect.isclass(object) or
1763 inspect.isroutine(object) or
Serhiy Storchakafbf27862020-04-15 23:00:20 +03001764 inspect.isdatadescriptor(object) or
Serhiy Storchaka08b47c32020-05-18 20:25:07 +03001765 _getdoc(object)):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001766 # If the passed object is a piece of data or an instance,
1767 # document its available methods instead of its value.
Serhiy Storchaka7e644142020-04-18 17:13:21 +03001768 if hasattr(object, '__origin__'):
1769 object = object.__origin__
1770 else:
1771 object = type(object)
1772 desc += ' object'
Georg Brandld80d5f42010-12-03 07:47:22 +00001773 return title % desc + '\n\n' + renderer.document(object, name)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001774
Georg Brandld80d5f42010-12-03 07:47:22 +00001775def doc(thing, title='Python Library Documentation: %s', forceload=0,
1776 output=None):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001777 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001778 try:
Georg Brandld80d5f42010-12-03 07:47:22 +00001779 if output is None:
1780 pager(render_doc(thing, title, forceload))
1781 else:
1782 output.write(render_doc(thing, title, forceload, plaintext))
Guido van Rossumb940e112007-01-10 16:19:56 +00001783 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001784 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001785
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001786def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001787 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001788 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001789 object, name = resolve(thing, forceload)
1790 page = html.page(describe(object), html.document(object, name))
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +03001791 with open(name + '.html', 'w', encoding='utf-8') as file:
1792 file.write(page)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001793 print('wrote', name + '.html')
Guido van Rossumb940e112007-01-10 16:19:56 +00001794 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001795 print(value)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001796
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001797def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001798 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001799 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001800 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1801 writedoc(modname)
1802 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001803
1804class Helper:
Georg Brandl6b38daa2008-06-01 21:05:17 +00001805
1806 # These dictionaries map a topic name to either an alias, or a tuple
1807 # (label, seealso-items). The "label" is the label of the corresponding
1808 # section in the .rst file under Doc/ and an index into the dictionary
Georg Brandl5617db82009-04-27 16:28:57 +00001809 # in pydoc_data/topics.py.
Georg Brandl6b38daa2008-06-01 21:05:17 +00001810 #
1811 # CAUTION: if you change one of these dictionaries, be sure to adapt the
Jelle Zijlstraac317702017-10-05 20:24:46 -07001812 # list of needed labels in Doc/tools/extensions/pyspecific.py and
Georg Brandl5617db82009-04-27 16:28:57 +00001813 # regenerate the pydoc_data/topics.py file by running
Georg Brandl6b38daa2008-06-01 21:05:17 +00001814 # make pydoc-topics
1815 # in Doc/ and copying the output file into the Lib/ directory.
1816
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001817 keywords = {
Ezio Melottib185a042011-04-28 07:42:55 +03001818 'False': '',
1819 'None': '',
1820 'True': '',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001821 'and': 'BOOLEAN',
Guido van Rossumd8faa362007-04-27 19:54:29 +00001822 'as': 'with',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001823 'assert': ('assert', ''),
Jelle Zijlstraac317702017-10-05 20:24:46 -07001824 'async': ('async', ''),
1825 'await': ('await', ''),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001826 'break': ('break', 'while for'),
1827 'class': ('class', 'CLASSES SPECIALMETHODS'),
1828 'continue': ('continue', 'while for'),
1829 'def': ('function', ''),
1830 'del': ('del', 'BASICMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001831 'elif': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001832 'else': ('else', 'while for'),
Georg Brandl0d855392008-08-30 19:53:05 +00001833 'except': 'try',
1834 'finally': 'try',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001835 'for': ('for', 'break continue while'),
Georg Brandl0d855392008-08-30 19:53:05 +00001836 'from': 'import',
Georg Brandl74abf6f2010-11-20 19:54:36 +00001837 'global': ('global', 'nonlocal NAMESPACES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001838 'if': ('if', 'TRUTHVALUE'),
1839 'import': ('import', 'MODULES'),
Georg Brandl395ed242009-09-04 08:07:32 +00001840 'in': ('in', 'SEQUENCEMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001841 'is': 'COMPARISON',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001842 'lambda': ('lambda', 'FUNCTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001843 'nonlocal': ('nonlocal', 'global NAMESPACES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001844 'not': 'BOOLEAN',
1845 'or': 'BOOLEAN',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001846 'pass': ('pass', ''),
1847 'raise': ('raise', 'EXCEPTIONS'),
1848 'return': ('return', 'FUNCTIONS'),
1849 'try': ('try', 'EXCEPTIONS'),
1850 'while': ('while', 'break continue if TRUTHVALUE'),
1851 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1852 'yield': ('yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001853 }
Georg Brandldb7b6b92009-01-01 15:53:14 +00001854 # Either add symbols to this dictionary or to the symbols dictionary
1855 # directly: Whichever is easier. They are merged later.
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001856 _strprefixes = [p + q for p in ('b', 'f', 'r', 'u') for q in ("'", '"')]
Georg Brandldb7b6b92009-01-01 15:53:14 +00001857 _symbols_inverse = {
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001858 'STRINGS' : ("'", "'''", '"', '"""', *_strprefixes),
Georg Brandldb7b6b92009-01-01 15:53:14 +00001859 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1860 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1861 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1862 'UNARY' : ('-', '~'),
1863 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1864 '^=', '<<=', '>>=', '**=', '//='),
1865 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1866 'COMPLEX' : ('j', 'J')
1867 }
1868 symbols = {
1869 '%': 'OPERATORS FORMATTING',
1870 '**': 'POWER',
1871 ',': 'TUPLES LISTS FUNCTIONS',
1872 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1873 '...': 'ELLIPSIS',
1874 ':': 'SLICINGS DICTIONARYLITERALS',
1875 '@': 'def class',
1876 '\\': 'STRINGS',
1877 '_': 'PRIVATENAMES',
1878 '__': 'PRIVATENAMES SPECIALMETHODS',
1879 '`': 'BACKQUOTES',
1880 '(': 'TUPLES FUNCTIONS CALLS',
1881 ')': 'TUPLES FUNCTIONS CALLS',
1882 '[': 'LISTS SUBSCRIPTS SLICINGS',
1883 ']': 'LISTS SUBSCRIPTS SLICINGS'
1884 }
1885 for topic, symbols_ in _symbols_inverse.items():
1886 for symbol in symbols_:
1887 topics = symbols.get(symbol, topic)
1888 if topic not in topics:
1889 topics = topics + ' ' + topic
1890 symbols[symbol] = topics
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001891
1892 topics = {
Georg Brandl6b38daa2008-06-01 21:05:17 +00001893 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1894 'FUNCTIONS CLASSES MODULES FILES inspect'),
1895 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
1896 'FORMATTING TYPES'),
1897 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1898 'FORMATTING': ('formatstrings', 'OPERATORS'),
1899 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1900 'FORMATTING TYPES'),
1901 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1902 'INTEGER': ('integers', 'int range'),
1903 'FLOAT': ('floating', 'float math'),
1904 'COMPLEX': ('imaginary', 'complex cmath'),
1905 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001906 'MAPPINGS': 'DICTIONARIES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001907 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1908 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1909 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1910 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001911 'FRAMEOBJECTS': 'TYPES',
1912 'TRACEBACKS': 'TYPES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001913 'NONE': ('bltin-null-object', ''),
1914 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001915 'SPECIALATTRIBUTES': ('specialattrs', ''),
1916 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1917 'MODULES': ('typesmodules', 'import'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001918 'PACKAGES': 'import',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001919 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1920 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1921 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1922 'LISTS DICTIONARIES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001923 'OPERATORS': 'EXPRESSIONS',
1924 'PRECEDENCE': 'EXPRESSIONS',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001925 'OBJECTS': ('objects', 'TYPES'),
1926 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
Georg Brandl395ed242009-09-04 08:07:32 +00001927 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
1928 'NUMBERMETHODS CLASSES'),
Mark Dickinsona56c4672009-01-27 18:17:45 +00001929 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001930 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1931 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001932 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
Georg Brandl6b38daa2008-06-01 21:05:17 +00001933 'SPECIALMETHODS'),
1934 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1935 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1936 'SPECIALMETHODS'),
1937 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001938 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001939 'DYNAMICFEATURES': ('dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001940 'SCOPING': 'NAMESPACES',
1941 'FRAMES': 'NAMESPACES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001942 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1943 'CONVERSIONS': ('conversions', ''),
1944 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1945 'SPECIALIDENTIFIERS': ('id-classes', ''),
1946 'PRIVATENAMES': ('atom-identifiers', ''),
1947 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
1948 'LISTLITERALS DICTIONARYLITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001949 'TUPLES': 'SEQUENCES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001950 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1951 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1952 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1953 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1954 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1955 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001956 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
1957 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001958 'CALLS': ('calls', 'EXPRESSIONS'),
1959 'POWER': ('power', 'EXPRESSIONS'),
1960 'UNARY': ('unary', 'EXPRESSIONS'),
1961 'BINARY': ('binary', 'EXPRESSIONS'),
1962 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1963 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1964 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1965 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001966 'ASSERTION': 'assert',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001967 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1968 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001969 'DELETION': 'del',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001970 'RETURNING': 'return',
1971 'IMPORTING': 'import',
1972 'CONDITIONAL': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001973 'LOOPING': ('compound', 'for while break continue'),
1974 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1975 'DEBUGGING': ('debugger', 'pdb'),
1976 'CONTEXTMANAGERS': ('context-managers', 'with'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001977 }
1978
Georg Brandl78aa3962010-07-31 21:51:48 +00001979 def __init__(self, input=None, output=None):
1980 self._input = input
1981 self._output = output
1982
Serhiy Storchakabdf6b912017-03-19 08:40:32 +02001983 @property
1984 def input(self):
1985 return self._input or sys.stdin
1986
1987 @property
1988 def output(self):
1989 return self._output or sys.stdout
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001990
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001991 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001992 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001993 self()
1994 return ''
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001995 return '<%s.%s instance>' % (self.__class__.__module__,
1996 self.__class__.__qualname__)
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001997
Alexander Belopolsky2e733c92010-07-04 17:00:20 +00001998 _GoInteractive = object()
1999 def __call__(self, request=_GoInteractive):
2000 if request is not self._GoInteractive:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002001 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002002 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002003 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002004 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002005 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00002006You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002007If you want to ask for help on a particular object directly from the
2008interpreter, you can type "help(object)". Executing "help('string')"
2009has the same effect as typing a particular string at the help> prompt.
2010''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002011
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002012 def interact(self):
2013 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002014 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002015 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00002016 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002017 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00002018 except (KeyboardInterrupt, EOFError):
2019 break
Andrés Delfinob2043bb2018-05-05 13:07:32 -03002020 request = request.strip()
2021
2022 # Make sure significant trailing quoting marks of literals don't
2023 # get deleted while cleaning input
2024 if (len(request) > 2 and request[0] == request[-1] in ("'", '"')
2025 and request[0] not in request[1:-1]):
2026 request = request[1:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002027 if request.lower() in ('q', 'quit'): break
Serhiy Storchaka1c205512015-03-01 00:42:54 +02002028 if request == 'help':
2029 self.intro()
2030 else:
2031 self.help(request)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002032
Johannes Gijsberse7691d32004-08-17 13:21:53 +00002033 def getline(self, prompt):
Guido van Rossum7c086c02008-01-02 03:52:38 +00002034 """Read one line, using input() when appropriate."""
Johannes Gijsberse7691d32004-08-17 13:21:53 +00002035 if self.input is sys.stdin:
Guido van Rossum7c086c02008-01-02 03:52:38 +00002036 return input(prompt)
Johannes Gijsberse7691d32004-08-17 13:21:53 +00002037 else:
2038 self.output.write(prompt)
2039 self.output.flush()
2040 return self.input.readline()
2041
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002042 def help(self, request):
2043 if type(request) is type(''):
R. David Murray1f1b9d32009-05-27 20:56:59 +00002044 request = request.strip()
Serhiy Storchaka1c205512015-03-01 00:42:54 +02002045 if request == 'keywords': self.listkeywords()
Georg Brandldb7b6b92009-01-01 15:53:14 +00002046 elif request == 'symbols': self.listsymbols()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002047 elif request == 'topics': self.listtopics()
2048 elif request == 'modules': self.listmodules()
2049 elif request[:8] == 'modules ':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002050 self.listmodules(request.split()[1])
Georg Brandldb7b6b92009-01-01 15:53:14 +00002051 elif request in self.symbols: self.showsymbol(request)
Ezio Melottib185a042011-04-28 07:42:55 +03002052 elif request in ['True', 'False', 'None']:
2053 # special case these keywords since they are objects too
2054 doc(eval(request), 'Help on %s:')
Raymond Hettinger54f02222002-06-01 14:18:47 +00002055 elif request in self.keywords: self.showtopic(request)
2056 elif request in self.topics: self.showtopic(request)
Georg Brandld80d5f42010-12-03 07:47:22 +00002057 elif request: doc(request, 'Help on %s:', output=self._output)
Serhiy Storchaka1c205512015-03-01 00:42:54 +02002058 else: doc(str, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002059 elif isinstance(request, Helper): self()
Georg Brandld80d5f42010-12-03 07:47:22 +00002060 else: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002061 self.output.write('\n')
2062
2063 def intro(self):
2064 self.output.write('''
Serhiy Storchaka885bdc42016-02-11 13:10:36 +02002065Welcome to Python {0}'s help utility!
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002066
2067If this is your first time using Python, you should definitely check out
oldke5681b92017-12-28 22:37:46 +08002068the tutorial on the Internet at https://docs.python.org/{0}/tutorial/.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002069
2070Enter the name of any module, keyword, or topic to get help on writing
2071Python programs and using Python modules. To quit this help utility and
2072return to the interpreter, just type "quit".
2073
Terry Jan Reedy34200572013-02-11 02:23:13 -05002074To get a list of available modules, keywords, symbols, or topics, type
2075"modules", "keywords", "symbols", or "topics". Each module also comes
2076with a one-line summary of what it does; to list the modules whose name
2077or summary contain a given string such as "spam", type "modules spam".
Serhiy Storchaka885bdc42016-02-11 13:10:36 +02002078'''.format('%d.%d' % sys.version_info[:2]))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002079
2080 def list(self, items, columns=4, width=80):
Guido van Rossum486364b2007-06-30 05:01:58 +00002081 items = list(sorted(items))
2082 colw = width // columns
2083 rows = (len(items) + columns - 1) // columns
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002084 for row in range(rows):
2085 for col in range(columns):
2086 i = col * rows + row
2087 if i < len(items):
2088 self.output.write(items[i])
2089 if col < columns - 1:
Guido van Rossum486364b2007-06-30 05:01:58 +00002090 self.output.write(' ' + ' ' * (colw - 1 - len(items[i])))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002091 self.output.write('\n')
2092
2093 def listkeywords(self):
2094 self.output.write('''
2095Here is a list of the Python keywords. Enter any keyword to get more help.
2096
2097''')
2098 self.list(self.keywords.keys())
2099
Georg Brandldb7b6b92009-01-01 15:53:14 +00002100 def listsymbols(self):
2101 self.output.write('''
2102Here is a list of the punctuation symbols which Python assigns special meaning
2103to. Enter any symbol to get more help.
2104
2105''')
2106 self.list(self.symbols.keys())
2107
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002108 def listtopics(self):
2109 self.output.write('''
2110Here is a list of available topics. Enter any topic name to get more help.
2111
2112''')
2113 self.list(self.topics.keys())
2114
Georg Brandldb7b6b92009-01-01 15:53:14 +00002115 def showtopic(self, topic, more_xrefs=''):
Georg Brandl6b38daa2008-06-01 21:05:17 +00002116 try:
Georg Brandl5617db82009-04-27 16:28:57 +00002117 import pydoc_data.topics
Brett Cannoncd171c82013-07-04 17:43:24 -04002118 except ImportError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002119 self.output.write('''
Georg Brandl6b38daa2008-06-01 21:05:17 +00002120Sorry, topic and keyword documentation is not available because the
Georg Brandl5617db82009-04-27 16:28:57 +00002121module "pydoc_data.topics" could not be found.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002122''')
2123 return
2124 target = self.topics.get(topic, self.keywords.get(topic))
2125 if not target:
2126 self.output.write('no documentation found for %s\n' % repr(topic))
2127 return
2128 if type(target) is type(''):
Georg Brandldb7b6b92009-01-01 15:53:14 +00002129 return self.showtopic(target, more_xrefs)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002130
Georg Brandl6b38daa2008-06-01 21:05:17 +00002131 label, xrefs = target
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002132 try:
Georg Brandl5617db82009-04-27 16:28:57 +00002133 doc = pydoc_data.topics.topics[label]
Georg Brandl6b38daa2008-06-01 21:05:17 +00002134 except KeyError:
2135 self.output.write('no documentation found for %s\n' % repr(topic))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002136 return
Berker Peksagd04f46c2018-07-23 08:37:47 +03002137 doc = doc.strip() + '\n'
Georg Brandldb7b6b92009-01-01 15:53:14 +00002138 if more_xrefs:
2139 xrefs = (xrefs or '') + ' ' + more_xrefs
Ka-Ping Yeeda793892001-04-13 11:02:51 +00002140 if xrefs:
Brett Cannon1448ecf2013-10-04 11:38:59 -04002141 import textwrap
2142 text = 'Related help topics: ' + ', '.join(xrefs.split()) + '\n'
2143 wrapped_text = textwrap.wrap(text, 72)
Berker Peksagd04f46c2018-07-23 08:37:47 +03002144 doc += '\n%s\n' % '\n'.join(wrapped_text)
2145 pager(doc)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002146
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002147 def _gettopic(self, topic, more_xrefs=''):
2148 """Return unbuffered tuple of (topic, xrefs).
2149
Georg Brandld2f38572011-01-30 08:37:19 +00002150 If an error occurs here, the exception is caught and displayed by
2151 the url handler.
2152
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002153 This function duplicates the showtopic method but returns its
2154 result directly so it can be formatted for display in an html page.
2155 """
2156 try:
2157 import pydoc_data.topics
Brett Cannoncd171c82013-07-04 17:43:24 -04002158 except ImportError:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002159 return('''
2160Sorry, topic and keyword documentation is not available because the
2161module "pydoc_data.topics" could not be found.
2162''' , '')
2163 target = self.topics.get(topic, self.keywords.get(topic))
2164 if not target:
Georg Brandld2f38572011-01-30 08:37:19 +00002165 raise ValueError('could not find topic')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002166 if isinstance(target, str):
2167 return self._gettopic(target, more_xrefs)
2168 label, xrefs = target
Georg Brandld2f38572011-01-30 08:37:19 +00002169 doc = pydoc_data.topics.topics[label]
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002170 if more_xrefs:
2171 xrefs = (xrefs or '') + ' ' + more_xrefs
2172 return doc, xrefs
2173
Georg Brandldb7b6b92009-01-01 15:53:14 +00002174 def showsymbol(self, symbol):
2175 target = self.symbols[symbol]
2176 topic, _, xrefs = target.partition(' ')
2177 self.showtopic(topic, xrefs)
2178
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002179 def listmodules(self, key=''):
2180 if key:
2181 self.output.write('''
Terry Jan Reedy34200572013-02-11 02:23:13 -05002182Here is a list of modules whose name or summary contains '{}'.
2183If there are any, enter a module name to get more help.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002184
Terry Jan Reedy34200572013-02-11 02:23:13 -05002185'''.format(key))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002186 apropos(key)
2187 else:
2188 self.output.write('''
2189Please wait a moment while I gather a list of all available modules...
2190
2191''')
2192 modules = {}
2193 def callback(path, modname, desc, modules=modules):
2194 if modname and modname[-9:] == '.__init__':
2195 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002196 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002197 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002198 def onerror(modname):
2199 callback(None, modname, None)
2200 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002201 self.list(modules.keys())
2202 self.output.write('''
2203Enter any module name to get more help. Or, type "modules spam" to search
Terry Jan Reedy34200572013-02-11 02:23:13 -05002204for modules whose name or summary contain the string "spam".
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002205''')
2206
Georg Brandl78aa3962010-07-31 21:51:48 +00002207help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002208
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002209class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002210 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002211
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002212 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002213 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002214 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002215 seen = {}
2216
2217 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002218 if modname != '__main__':
2219 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00002220 if key is None:
2221 callback(None, modname, '')
2222 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002223 name = __import__(modname).__doc__ or ''
2224 desc = name.split('\n')[0]
2225 name = modname + ' - ' + desc
2226 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002227 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002228
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002229 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002230 if self.quit:
2231 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002232
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002233 if key is None:
2234 callback(None, modname, '')
2235 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002236 try:
Eric Snow3a62d142014-01-06 20:42:59 -07002237 spec = pkgutil._get_spec(importer, modname)
Georg Brandl126c8792009-04-05 15:05:48 +00002238 except SyntaxError:
2239 # raised by tests for bad coding cookies or BOM
2240 continue
Eric Snow3a62d142014-01-06 20:42:59 -07002241 loader = spec.loader
Georg Brandl126c8792009-04-05 15:05:48 +00002242 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002243 try:
2244 source = loader.get_source(modname)
Nick Coghlan2824cb52012-07-15 22:12:14 +10002245 except Exception:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002246 if onerror:
2247 onerror(modname)
2248 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002249 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002250 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002251 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002252 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002253 path = None
2254 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002255 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -04002256 module = importlib._bootstrap._load(spec)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002257 except ImportError:
2258 if onerror:
2259 onerror(modname)
2260 continue
Benjamin Peterson54237f92015-02-16 19:45:01 -05002261 desc = module.__doc__.splitlines()[0] if module.__doc__ else ''
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002262 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002263 name = modname + ' - ' + desc
2264 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002265 callback(path, modname, desc)
2266
2267 if completer:
2268 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002269
2270def apropos(key):
2271 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002272 def callback(path, modname, desc):
2273 if modname[-9:] == '.__init__':
2274 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002275 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002276 def onerror(modname):
2277 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002278 with warnings.catch_warnings():
2279 warnings.filterwarnings('ignore') # ignore problems during import
2280 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002281
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002282# --------------------------------------- enhanced Web browser interface
2283
Feanil Patel6a396c92017-09-14 17:54:09 -04002284def _start_server(urlhandler, hostname, port):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002285 """Start an HTTP server thread on a specific port.
2286
2287 Start an HTML/text server thread, so HTML or text documents can be
2288 browsed dynamically and interactively with a Web browser. Example use:
2289
2290 >>> import time
2291 >>> import pydoc
2292
2293 Define a URL handler. To determine what the client is asking
2294 for, check the URL and content_type.
2295
2296 Then get or generate some text or HTML code and return it.
2297
2298 >>> def my_url_handler(url, content_type):
2299 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2300 ... return text
2301
2302 Start server thread on port 0.
2303 If you use port 0, the server will pick a random port number.
2304 You can then use serverthread.port to get the port number.
2305
2306 >>> port = 0
2307 >>> serverthread = pydoc._start_server(my_url_handler, port)
2308
2309 Check that the server is really started. If it is, open browser
2310 and get first page. Use serverthread.url as the starting page.
2311
2312 >>> if serverthread.serving:
2313 ... import webbrowser
2314
2315 The next two lines are commented out so a browser doesn't open if
2316 doctest is run on this module.
2317
2318 #... webbrowser.open(serverthread.url)
2319 #True
2320
2321 Let the server do its thing. We just need to monitor its status.
2322 Use time.sleep so the loop doesn't hog the CPU.
2323
Victor Stinner2cf4c202018-12-17 09:36:36 +01002324 >>> starttime = time.monotonic()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002325 >>> timeout = 1 #seconds
2326
2327 This is a short timeout for testing purposes.
2328
2329 >>> while serverthread.serving:
2330 ... time.sleep(.01)
Victor Stinner2cf4c202018-12-17 09:36:36 +01002331 ... if serverthread.serving and time.monotonic() - starttime > timeout:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002332 ... serverthread.stop()
2333 ... break
2334
2335 Print any errors that may have occurred.
2336
2337 >>> print(serverthread.error)
2338 None
2339 """
2340 import http.server
2341 import email.message
2342 import select
2343 import threading
2344
2345 class DocHandler(http.server.BaseHTTPRequestHandler):
2346
2347 def do_GET(self):
2348 """Process a request from an HTML browser.
2349
2350 The URL received is in self.path.
2351 Get an HTML page from self.urlhandler and send it.
2352 """
2353 if self.path.endswith('.css'):
2354 content_type = 'text/css'
2355 else:
2356 content_type = 'text/html'
2357 self.send_response(200)
Georg Brandld2f38572011-01-30 08:37:19 +00002358 self.send_header('Content-Type', '%s; charset=UTF-8' % content_type)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002359 self.end_headers()
2360 self.wfile.write(self.urlhandler(
2361 self.path, content_type).encode('utf-8'))
2362
2363 def log_message(self, *args):
2364 # Don't log messages.
2365 pass
2366
2367 class DocServer(http.server.HTTPServer):
2368
Feanil Patel6a396c92017-09-14 17:54:09 -04002369 def __init__(self, host, port, callback):
2370 self.host = host
Senthil Kumaran2a42a0b2014-09-17 13:17:58 +08002371 self.address = (self.host, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002372 self.callback = callback
2373 self.base.__init__(self, self.address, self.handler)
2374 self.quit = False
2375
2376 def serve_until_quit(self):
2377 while not self.quit:
2378 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2379 if rd:
2380 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002381 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002382
2383 def server_activate(self):
2384 self.base.server_activate(self)
2385 if self.callback:
2386 self.callback(self)
2387
2388 class ServerThread(threading.Thread):
2389
Feanil Patel6a396c92017-09-14 17:54:09 -04002390 def __init__(self, urlhandler, host, port):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002391 self.urlhandler = urlhandler
Feanil Patel6a396c92017-09-14 17:54:09 -04002392 self.host = host
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002393 self.port = int(port)
2394 threading.Thread.__init__(self)
2395 self.serving = False
2396 self.error = None
2397
2398 def run(self):
2399 """Start the server."""
2400 try:
2401 DocServer.base = http.server.HTTPServer
2402 DocServer.handler = DocHandler
2403 DocHandler.MessageClass = email.message.Message
2404 DocHandler.urlhandler = staticmethod(self.urlhandler)
Feanil Patel6a396c92017-09-14 17:54:09 -04002405 docsvr = DocServer(self.host, self.port, self.ready)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002406 self.docserver = docsvr
2407 docsvr.serve_until_quit()
2408 except Exception as e:
2409 self.error = e
2410
2411 def ready(self, server):
2412 self.serving = True
2413 self.host = server.host
2414 self.port = server.server_port
2415 self.url = 'http://%s:%d/' % (self.host, self.port)
2416
2417 def stop(self):
2418 """Stop the server and this thread nicely"""
2419 self.docserver.quit = True
Victor Stinner4cab2cd2017-08-21 23:24:40 +02002420 self.join()
2421 # explicitly break a reference cycle: DocServer.callback
2422 # has indirectly a reference to ServerThread.
2423 self.docserver = None
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002424 self.serving = False
2425 self.url = None
2426
Feanil Patel6a396c92017-09-14 17:54:09 -04002427 thread = ServerThread(urlhandler, hostname, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002428 thread.start()
2429 # Wait until thread.serving is True to make sure we are
2430 # really up before returning.
2431 while not thread.error and not thread.serving:
2432 time.sleep(.01)
2433 return thread
2434
2435
2436def _url_handler(url, content_type="text/html"):
2437 """The pydoc url handler for use with the pydoc server.
2438
2439 If the content_type is 'text/css', the _pydoc.css style
2440 sheet is read and returned if it exits.
2441
2442 If the content_type is 'text/html', then the result of
2443 get_html_page(url) is returned.
2444 """
2445 class _HTMLDoc(HTMLDoc):
2446
2447 def page(self, title, contents):
2448 """Format an HTML page."""
2449 css_path = "pydoc_data/_pydoc.css"
2450 css_link = (
2451 '<link rel="stylesheet" type="text/css" href="%s">' %
2452 css_path)
2453 return '''\
2454<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Georg Brandld2f38572011-01-30 08:37:19 +00002455<html><head><title>Pydoc: %s</title>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002456<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Georg Brandld2f38572011-01-30 08:37:19 +00002457%s</head><body bgcolor="#f0f0f8">%s<div style="clear:both;padding-top:.5em;">%s</div>
2458</body></html>''' % (title, css_link, html_navbar(), contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002459
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002460
2461 html = _HTMLDoc()
2462
2463 def html_navbar():
Georg Brandld2f38572011-01-30 08:37:19 +00002464 version = html.escape("%s [%s, %s]" % (platform.python_version(),
2465 platform.python_build()[0],
2466 platform.python_compiler()))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002467 return """
2468 <div style='float:left'>
Georg Brandld2f38572011-01-30 08:37:19 +00002469 Python %s<br>%s
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002470 </div>
2471 <div style='float:right'>
2472 <div style='text-align:center'>
2473 <a href="index.html">Module Index</a>
2474 : <a href="topics.html">Topics</a>
2475 : <a href="keywords.html">Keywords</a>
2476 </div>
2477 <div>
Georg Brandld2f38572011-01-30 08:37:19 +00002478 <form action="get" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002479 <input type=text name=key size=15>
2480 <input type=submit value="Get">
Georg Brandld2f38572011-01-30 08:37:19 +00002481 </form>&nbsp;
2482 <form action="search" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002483 <input type=text name=key size=15>
2484 <input type=submit value="Search">
2485 </form>
2486 </div>
2487 </div>
Georg Brandld2f38572011-01-30 08:37:19 +00002488 """ % (version, html.escape(platform.platform(terse=True)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002489
2490 def html_index():
2491 """Module Index page."""
2492
2493 def bltinlink(name):
2494 return '<a href="%s.html">%s</a>' % (name, name)
2495
2496 heading = html.heading(
2497 '<big><big><strong>Index of Modules</strong></big></big>',
2498 '#ffffff', '#7799ee')
2499 names = [name for name in sys.builtin_module_names
2500 if name != '__main__']
2501 contents = html.multicolumn(names, bltinlink)
2502 contents = [heading, '<p>' + html.bigsection(
2503 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2504
2505 seen = {}
2506 for dir in sys.path:
2507 contents.append(html.index(dir, seen))
2508
2509 contents.append(
2510 '<p align=right><font color="#909090" face="helvetica,'
2511 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2512 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002513 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002514
2515 def html_search(key):
2516 """Search results page."""
2517 # scan for modules
2518 search_result = []
2519
2520 def callback(path, modname, desc):
2521 if modname[-9:] == '.__init__':
2522 modname = modname[:-9] + ' (package)'
2523 search_result.append((modname, desc and '- ' + desc))
2524
2525 with warnings.catch_warnings():
2526 warnings.filterwarnings('ignore') # ignore problems during import
Martin Panter9ad0aae2015-11-06 00:27:14 +00002527 def onerror(modname):
2528 pass
2529 ModuleScanner().run(callback, key, onerror=onerror)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002530
2531 # format page
2532 def bltinlink(name):
2533 return '<a href="%s.html">%s</a>' % (name, name)
2534
2535 results = []
2536 heading = html.heading(
2537 '<big><big><strong>Search Results</strong></big></big>',
2538 '#ffffff', '#7799ee')
2539 for name, desc in search_result:
2540 results.append(bltinlink(name) + desc)
2541 contents = heading + html.bigsection(
2542 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002543 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002544
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002545 def html_topics():
2546 """Index of topic texts available."""
2547
2548 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002549 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002550
2551 heading = html.heading(
2552 '<big><big><strong>INDEX</strong></big></big>',
2553 '#ffffff', '#7799ee')
2554 names = sorted(Helper.topics.keys())
2555
2556 contents = html.multicolumn(names, bltinlink)
2557 contents = heading + html.bigsection(
2558 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002559 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002560
2561 def html_keywords():
2562 """Index of keywords."""
2563 heading = html.heading(
2564 '<big><big><strong>INDEX</strong></big></big>',
2565 '#ffffff', '#7799ee')
2566 names = sorted(Helper.keywords.keys())
2567
2568 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002569 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002570
2571 contents = html.multicolumn(names, bltinlink)
2572 contents = heading + html.bigsection(
2573 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002574 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002575
2576 def html_topicpage(topic):
2577 """Topic or keyword help page."""
2578 buf = io.StringIO()
2579 htmlhelp = Helper(buf, buf)
2580 contents, xrefs = htmlhelp._gettopic(topic)
2581 if topic in htmlhelp.keywords:
2582 title = 'KEYWORD'
2583 else:
2584 title = 'TOPIC'
2585 heading = html.heading(
2586 '<big><big><strong>%s</strong></big></big>' % title,
2587 '#ffffff', '#7799ee')
Georg Brandld2f38572011-01-30 08:37:19 +00002588 contents = '<pre>%s</pre>' % html.markup(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002589 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
Georg Brandld2f38572011-01-30 08:37:19 +00002590 if xrefs:
2591 xrefs = sorted(xrefs.split())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002592
Georg Brandld2f38572011-01-30 08:37:19 +00002593 def bltinlink(name):
2594 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002595
Georg Brandld2f38572011-01-30 08:37:19 +00002596 xrefs = html.multicolumn(xrefs, bltinlink)
2597 xrefs = html.section('Related help topics: ',
2598 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002599 return ('%s %s' % (title, topic),
2600 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002601
Georg Brandld2f38572011-01-30 08:37:19 +00002602 def html_getobj(url):
2603 obj = locate(url, forceload=1)
2604 if obj is None and url != 'None':
2605 raise ValueError('could not find object')
2606 title = describe(obj)
2607 content = html.document(obj, url)
2608 return title, content
2609
2610 def html_error(url, exc):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002611 heading = html.heading(
2612 '<big><big><strong>Error</strong></big></big>',
Georg Brandld2f38572011-01-30 08:37:19 +00002613 '#ffffff', '#7799ee')
2614 contents = '<br>'.join(html.escape(line) for line in
2615 format_exception_only(type(exc), exc))
2616 contents = heading + html.bigsection(url, '#ffffff', '#bb0000',
2617 contents)
2618 return "Error - %s" % url, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002619
2620 def get_html_page(url):
2621 """Generate an HTML page for url."""
Georg Brandld2f38572011-01-30 08:37:19 +00002622 complete_url = url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002623 if url.endswith('.html'):
2624 url = url[:-5]
Georg Brandld2f38572011-01-30 08:37:19 +00002625 try:
2626 if url in ("", "index"):
2627 title, content = html_index()
2628 elif url == "topics":
2629 title, content = html_topics()
2630 elif url == "keywords":
2631 title, content = html_keywords()
2632 elif '=' in url:
2633 op, _, url = url.partition('=')
2634 if op == "search?key":
2635 title, content = html_search(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002636 elif op == "topic?key":
2637 # try topics first, then objects.
2638 try:
2639 title, content = html_topicpage(url)
2640 except ValueError:
2641 title, content = html_getobj(url)
2642 elif op == "get?key":
2643 # try objects first, then topics.
2644 if url in ("", "index"):
2645 title, content = html_index()
2646 else:
2647 try:
2648 title, content = html_getobj(url)
2649 except ValueError:
2650 title, content = html_topicpage(url)
2651 else:
2652 raise ValueError('bad pydoc url')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002653 else:
Georg Brandld2f38572011-01-30 08:37:19 +00002654 title, content = html_getobj(url)
2655 except Exception as exc:
2656 # Catch any errors and display them in an error page.
2657 title, content = html_error(complete_url, exc)
2658 return html.page(title, content)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002659
2660 if url.startswith('/'):
2661 url = url[1:]
2662 if content_type == 'text/css':
2663 path_here = os.path.dirname(os.path.realpath(__file__))
Georg Brandld2f38572011-01-30 08:37:19 +00002664 css_path = os.path.join(path_here, url)
2665 with open(css_path) as fp:
2666 return ''.join(fp.readlines())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002667 elif content_type == 'text/html':
2668 return get_html_page(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002669 # Errors outside the url handler are caught by the server.
2670 raise TypeError('unknown content type %r for url %s' % (content_type, url))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002671
2672
Feanil Patel6a396c92017-09-14 17:54:09 -04002673def browse(port=0, *, open_browser=True, hostname='localhost'):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002674 """Start the enhanced pydoc Web server and open a Web browser.
2675
2676 Use port '0' to start the server on an arbitrary port.
2677 Set open_browser to False to suppress opening a browser.
2678 """
2679 import webbrowser
Feanil Patel6a396c92017-09-14 17:54:09 -04002680 serverthread = _start_server(_url_handler, hostname, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002681 if serverthread.error:
2682 print(serverthread.error)
2683 return
2684 if serverthread.serving:
2685 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2686 if open_browser:
2687 webbrowser.open(serverthread.url)
2688 try:
2689 print('Server ready at', serverthread.url)
2690 print(server_help_msg)
2691 while serverthread.serving:
2692 cmd = input('server> ')
2693 cmd = cmd.lower()
2694 if cmd == 'q':
2695 break
2696 elif cmd == 'b':
2697 webbrowser.open(serverthread.url)
2698 else:
2699 print(server_help_msg)
2700 except (KeyboardInterrupt, EOFError):
2701 print()
2702 finally:
2703 if serverthread.serving:
2704 serverthread.stop()
2705 print('Server stopped')
2706
2707
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002708# -------------------------------------------------- command-line interface
2709
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002710def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002711 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002712
Nick Coghlan82a94812018-04-15 21:52:57 +10002713def _get_revised_path(given_path, argv0):
2714 """Ensures current directory is on returned path, and argv0 directory is not
2715
2716 Exception: argv0 dir is left alone if it's also pydoc's directory.
2717
2718 Returns a new path entry list, or None if no adjustment is needed.
2719 """
2720 # Scripts may get the current directory in their path by default if they're
2721 # run with the -m switch, or directly from the current directory.
2722 # The interactive prompt also allows imports from the current directory.
2723
2724 # Accordingly, if the current directory is already present, don't make
2725 # any changes to the given_path
2726 if '' in given_path or os.curdir in given_path or os.getcwd() in given_path:
2727 return None
2728
2729 # Otherwise, add the current directory to the given path, and remove the
2730 # script directory (as long as the latter isn't also pydoc's directory.
2731 stdlib_dir = os.path.dirname(__file__)
2732 script_dir = os.path.dirname(argv0)
2733 revised_path = given_path.copy()
2734 if script_dir in given_path and not os.path.samefile(script_dir, stdlib_dir):
2735 revised_path.remove(script_dir)
2736 revised_path.insert(0, os.getcwd())
2737 return revised_path
2738
2739
2740# Note: the tests only cover _get_revised_path, not _adjust_cli_path itself
2741def _adjust_cli_sys_path():
Nick Coghlan1a5c4bd2018-04-15 23:32:05 +10002742 """Ensures current directory is on sys.path, and __main__ directory is not.
Nick Coghlan82a94812018-04-15 21:52:57 +10002743
2744 Exception: __main__ dir is left alone if it's also pydoc's directory.
2745 """
2746 revised_path = _get_revised_path(sys.path, sys.argv[0])
2747 if revised_path is not None:
2748 sys.path[:] = revised_path
2749
2750
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002751def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002752 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002753 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002754 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002755
Nick Coghlan82a94812018-04-15 21:52:57 +10002756 _adjust_cli_sys_path()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002757
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002758 try:
Feanil Patel6a396c92017-09-14 17:54:09 -04002759 opts, args = getopt.getopt(sys.argv[1:], 'bk:n:p:w')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002760 writing = False
2761 start_server = False
2762 open_browser = False
Feanil Patel6a396c92017-09-14 17:54:09 -04002763 port = 0
2764 hostname = 'localhost'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002765 for opt, val in opts:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002766 if opt == '-b':
2767 start_server = True
2768 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002769 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002770 apropos(val)
2771 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002772 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002773 start_server = True
2774 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002775 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002776 writing = True
Feanil Patel6a396c92017-09-14 17:54:09 -04002777 if opt == '-n':
2778 start_server = True
2779 hostname = val
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002780
Benjamin Petersonb29614e2012-10-09 11:16:03 -04002781 if start_server:
Feanil Patel6a396c92017-09-14 17:54:09 -04002782 browse(port, hostname=hostname, open_browser=open_browser)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002783 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002784
2785 if not args: raise BadUsage
2786 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002787 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002788 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002789 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002790 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002791 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002792 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002793 if writing:
2794 if ispath(arg) and os.path.isdir(arg):
2795 writedocs(arg)
2796 else:
2797 writedoc(arg)
2798 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002799 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002800 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002801 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002802
2803 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002804 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002805 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002806
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002807{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002808 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002809 Python keyword, topic, function, module, or package, or a dotted
2810 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002811 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002812 Python source file to document. If name is 'keywords', 'topics',
2813 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002814
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002815{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002816 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002817
Feanil Patel6a396c92017-09-14 17:54:09 -04002818{cmd} -n <hostname>
2819 Start an HTTP server with the given hostname (default: localhost).
2820
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002821{cmd} -p <port>
2822 Start an HTTP server on the given port on the local machine. Port
2823 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002824
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002825{cmd} -b
2826 Start an HTTP server on an arbitrary unused port and open a Web browser
Feanil Patel6a396c92017-09-14 17:54:09 -04002827 to interactively browse documentation. This option can be used in
2828 combination with -n and/or -p.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002829
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002830{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002831 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002832 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002833 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002834""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002835
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002836if __name__ == '__main__':
2837 cli()