blob: 282a9179983407a4610a195320ee95812c2c4476 [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
1597 proc = subprocess.Popen(cmd, shell=True, stdin=subprocess.PIPE)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001598 try:
R David Murray1058cda2015-03-29 15:15:40 -04001599 with io.TextIOWrapper(proc.stdin, errors='backslashreplace') as pipe:
R David Murraye7f5e142015-03-30 10:14:47 -04001600 try:
1601 pipe.write(text)
1602 except KeyboardInterrupt:
1603 # We've hereby abandoned whatever text hasn't been written,
1604 # but the pager is still in control of the terminal.
1605 pass
Andrew Svetlovf7a17b42012-12-25 16:47:37 +02001606 except OSError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001607 pass # Ignore broken pipes caused by quitting the pager program.
R David Murray1058cda2015-03-29 15:15:40 -04001608 while True:
1609 try:
1610 proc.wait()
1611 break
1612 except KeyboardInterrupt:
1613 # Ignore ctl-c like the pager itself does. Otherwise the pager is
1614 # left running and the terminal is in raw mode and unusable.
1615 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001616
1617def tempfilepager(text, cmd):
1618 """Page through text by invoking a program on a temporary file."""
1619 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001620 filename = tempfile.mktemp()
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001621 with open(filename, 'w', errors='backslashreplace') as file:
Giampaolo Rodola'2f50aaf2013-02-12 02:04:27 +01001622 file.write(text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001623 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001624 os.system(cmd + ' "' + filename + '"')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001625 finally:
1626 os.unlink(filename)
1627
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001628def _escape_stdout(text):
1629 # Escape non-encodable characters to avoid encoding errors later
1630 encoding = getattr(sys.stdout, 'encoding', None) or 'utf-8'
1631 return text.encode(encoding, 'backslashreplace').decode(encoding)
1632
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001633def ttypager(text):
1634 """Page through text on a text terminal."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001635 lines = plain(_escape_stdout(text)).split('\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001636 try:
1637 import tty
1638 fd = sys.stdin.fileno()
1639 old = tty.tcgetattr(fd)
1640 tty.setcbreak(fd)
1641 getchar = lambda: sys.stdin.read(1)
Serhiy Storchakaab5e9b92014-11-28 00:09:29 +02001642 except (ImportError, AttributeError, io.UnsupportedOperation):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001643 tty = None
1644 getchar = lambda: sys.stdin.readline()[:-1][:1]
1645
1646 try:
Serhiy Storchakaab5e9b92014-11-28 00:09:29 +02001647 try:
1648 h = int(os.environ.get('LINES', 0))
1649 except ValueError:
1650 h = 0
1651 if h <= 1:
1652 h = 25
1653 r = inc = h - 1
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001654 sys.stdout.write('\n'.join(lines[:inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001655 while lines[r:]:
1656 sys.stdout.write('-- more --')
1657 sys.stdout.flush()
1658 c = getchar()
1659
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001660 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001661 sys.stdout.write('\r \r')
1662 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001663 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001664 sys.stdout.write('\r \r' + lines[r] + '\n')
1665 r = r + 1
1666 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001667 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001668 r = r - inc - inc
1669 if r < 0: r = 0
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001670 sys.stdout.write('\n' + '\n'.join(lines[r:r+inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001671 r = r + inc
1672
1673 finally:
1674 if tty:
1675 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1676
1677def plainpager(text):
1678 """Simply print unformatted text. This is the ultimate fallback."""
Serhiy Storchaka5e3d7a42015-02-20 23:46:06 +02001679 sys.stdout.write(plain(_escape_stdout(text)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001680
1681def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001682 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001683 if inspect.ismodule(thing):
1684 if thing.__name__ in sys.builtin_module_names:
1685 return 'built-in module ' + thing.__name__
1686 if hasattr(thing, '__path__'):
1687 return 'package ' + thing.__name__
1688 else:
1689 return 'module ' + thing.__name__
1690 if inspect.isbuiltin(thing):
1691 return 'built-in function ' + thing.__name__
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001692 if inspect.isgetsetdescriptor(thing):
1693 return 'getset descriptor %s.%s.%s' % (
1694 thing.__objclass__.__module__, thing.__objclass__.__name__,
1695 thing.__name__)
1696 if inspect.ismemberdescriptor(thing):
1697 return 'member descriptor %s.%s.%s' % (
1698 thing.__objclass__.__module__, thing.__objclass__.__name__,
1699 thing.__name__)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001700 if inspect.isclass(thing):
1701 return 'class ' + thing.__name__
1702 if inspect.isfunction(thing):
1703 return 'function ' + thing.__name__
1704 if inspect.ismethod(thing):
1705 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001706 return type(thing).__name__
1707
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001708def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001709 """Locate an object by name or dotted path, importing as necessary."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001710 parts = [part for part in path.split('.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001711 module, n = None, 0
1712 while n < len(parts):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001713 nextmodule = safeimport('.'.join(parts[:n+1]), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001714 if nextmodule: module, n = nextmodule, n + 1
1715 else: break
1716 if module:
1717 object = module
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001718 else:
Éric Araujoe64e51b2011-07-29 17:03:55 +02001719 object = builtins
1720 for part in parts[n:]:
1721 try:
1722 object = getattr(object, part)
1723 except AttributeError:
1724 return None
1725 return object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001726
1727# --------------------------------------- interactive interpreter interface
1728
1729text = TextDoc()
Georg Brandld80d5f42010-12-03 07:47:22 +00001730plaintext = _PlainTextDoc()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001731html = HTMLDoc()
1732
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001733def resolve(thing, forceload=0):
1734 """Given an object or a path to an object, get the object and its name."""
1735 if isinstance(thing, str):
1736 object = locate(thing, forceload)
Serhiy Storchakab6076fb2015-04-21 21:09:48 +03001737 if object is None:
Serhiy Storchaka1c205512015-03-01 00:42:54 +02001738 raise ImportError('''\
1739No Python documentation found for %r.
1740Use help() to get the interactive help utility.
1741Use help(str) for help on the str class.''' % thing)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001742 return object, thing
1743 else:
R David Murrayc43125a2012-04-23 13:23:57 -04001744 name = getattr(thing, '__name__', None)
1745 return thing, name if isinstance(name, str) else None
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001746
Georg Brandld80d5f42010-12-03 07:47:22 +00001747def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
1748 renderer=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001749 """Render text documentation, given an object or a path to an object."""
Georg Brandld80d5f42010-12-03 07:47:22 +00001750 if renderer is None:
1751 renderer = text
Guido van Rossumd8faa362007-04-27 19:54:29 +00001752 object, name = resolve(thing, forceload)
1753 desc = describe(object)
1754 module = inspect.getmodule(object)
1755 if name and '.' in name:
1756 desc += ' in ' + name[:name.rfind('.')]
1757 elif module and module is not object:
1758 desc += ' in module ' + module.__name__
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001759
1760 if not (inspect.ismodule(object) or
Guido van Rossumd8faa362007-04-27 19:54:29 +00001761 inspect.isclass(object) or
1762 inspect.isroutine(object) or
Serhiy Storchakafbf27862020-04-15 23:00:20 +03001763 inspect.isdatadescriptor(object) or
Serhiy Storchaka08b47c32020-05-18 20:25:07 +03001764 _getdoc(object)):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001765 # If the passed object is a piece of data or an instance,
1766 # document its available methods instead of its value.
Serhiy Storchaka7e644142020-04-18 17:13:21 +03001767 if hasattr(object, '__origin__'):
1768 object = object.__origin__
1769 else:
1770 object = type(object)
1771 desc += ' object'
Georg Brandld80d5f42010-12-03 07:47:22 +00001772 return title % desc + '\n\n' + renderer.document(object, name)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001773
Georg Brandld80d5f42010-12-03 07:47:22 +00001774def doc(thing, title='Python Library Documentation: %s', forceload=0,
1775 output=None):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001776 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001777 try:
Georg Brandld80d5f42010-12-03 07:47:22 +00001778 if output is None:
1779 pager(render_doc(thing, title, forceload))
1780 else:
1781 output.write(render_doc(thing, title, forceload, plaintext))
Guido van Rossumb940e112007-01-10 16:19:56 +00001782 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001783 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001784
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001785def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001786 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001787 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001788 object, name = resolve(thing, forceload)
1789 page = html.page(describe(object), html.document(object, name))
Serhiy Storchaka46ba6c82015-04-04 11:01:02 +03001790 with open(name + '.html', 'w', encoding='utf-8') as file:
1791 file.write(page)
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001792 print('wrote', name + '.html')
Guido van Rossumb940e112007-01-10 16:19:56 +00001793 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001794 print(value)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001795
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001796def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001797 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001798 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001799 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1800 writedoc(modname)
1801 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001802
1803class Helper:
Georg Brandl6b38daa2008-06-01 21:05:17 +00001804
1805 # These dictionaries map a topic name to either an alias, or a tuple
1806 # (label, seealso-items). The "label" is the label of the corresponding
1807 # section in the .rst file under Doc/ and an index into the dictionary
Georg Brandl5617db82009-04-27 16:28:57 +00001808 # in pydoc_data/topics.py.
Georg Brandl6b38daa2008-06-01 21:05:17 +00001809 #
1810 # CAUTION: if you change one of these dictionaries, be sure to adapt the
Jelle Zijlstraac317702017-10-05 20:24:46 -07001811 # list of needed labels in Doc/tools/extensions/pyspecific.py and
Georg Brandl5617db82009-04-27 16:28:57 +00001812 # regenerate the pydoc_data/topics.py file by running
Georg Brandl6b38daa2008-06-01 21:05:17 +00001813 # make pydoc-topics
1814 # in Doc/ and copying the output file into the Lib/ directory.
1815
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001816 keywords = {
Ezio Melottib185a042011-04-28 07:42:55 +03001817 'False': '',
1818 'None': '',
1819 'True': '',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001820 'and': 'BOOLEAN',
Guido van Rossumd8faa362007-04-27 19:54:29 +00001821 'as': 'with',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001822 'assert': ('assert', ''),
Jelle Zijlstraac317702017-10-05 20:24:46 -07001823 'async': ('async', ''),
1824 'await': ('await', ''),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001825 'break': ('break', 'while for'),
1826 'class': ('class', 'CLASSES SPECIALMETHODS'),
1827 'continue': ('continue', 'while for'),
1828 'def': ('function', ''),
1829 'del': ('del', 'BASICMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001830 'elif': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001831 'else': ('else', 'while for'),
Georg Brandl0d855392008-08-30 19:53:05 +00001832 'except': 'try',
1833 'finally': 'try',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001834 'for': ('for', 'break continue while'),
Georg Brandl0d855392008-08-30 19:53:05 +00001835 'from': 'import',
Georg Brandl74abf6f2010-11-20 19:54:36 +00001836 'global': ('global', 'nonlocal NAMESPACES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001837 'if': ('if', 'TRUTHVALUE'),
1838 'import': ('import', 'MODULES'),
Georg Brandl395ed242009-09-04 08:07:32 +00001839 'in': ('in', 'SEQUENCEMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001840 'is': 'COMPARISON',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001841 'lambda': ('lambda', 'FUNCTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001842 'nonlocal': ('nonlocal', 'global NAMESPACES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001843 'not': 'BOOLEAN',
1844 'or': 'BOOLEAN',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001845 'pass': ('pass', ''),
1846 'raise': ('raise', 'EXCEPTIONS'),
1847 'return': ('return', 'FUNCTIONS'),
1848 'try': ('try', 'EXCEPTIONS'),
1849 'while': ('while', 'break continue if TRUTHVALUE'),
1850 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1851 'yield': ('yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001852 }
Georg Brandldb7b6b92009-01-01 15:53:14 +00001853 # Either add symbols to this dictionary or to the symbols dictionary
1854 # directly: Whichever is easier. They are merged later.
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001855 _strprefixes = [p + q for p in ('b', 'f', 'r', 'u') for q in ("'", '"')]
Georg Brandldb7b6b92009-01-01 15:53:14 +00001856 _symbols_inverse = {
Andrés Delfinob2043bb2018-05-05 13:07:32 -03001857 'STRINGS' : ("'", "'''", '"', '"""', *_strprefixes),
Georg Brandldb7b6b92009-01-01 15:53:14 +00001858 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1859 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1860 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1861 'UNARY' : ('-', '~'),
1862 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1863 '^=', '<<=', '>>=', '**=', '//='),
1864 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1865 'COMPLEX' : ('j', 'J')
1866 }
1867 symbols = {
1868 '%': 'OPERATORS FORMATTING',
1869 '**': 'POWER',
1870 ',': 'TUPLES LISTS FUNCTIONS',
1871 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1872 '...': 'ELLIPSIS',
1873 ':': 'SLICINGS DICTIONARYLITERALS',
1874 '@': 'def class',
1875 '\\': 'STRINGS',
1876 '_': 'PRIVATENAMES',
1877 '__': 'PRIVATENAMES SPECIALMETHODS',
1878 '`': 'BACKQUOTES',
1879 '(': 'TUPLES FUNCTIONS CALLS',
1880 ')': 'TUPLES FUNCTIONS CALLS',
1881 '[': 'LISTS SUBSCRIPTS SLICINGS',
1882 ']': 'LISTS SUBSCRIPTS SLICINGS'
1883 }
1884 for topic, symbols_ in _symbols_inverse.items():
1885 for symbol in symbols_:
1886 topics = symbols.get(symbol, topic)
1887 if topic not in topics:
1888 topics = topics + ' ' + topic
1889 symbols[symbol] = topics
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001890
1891 topics = {
Georg Brandl6b38daa2008-06-01 21:05:17 +00001892 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1893 'FUNCTIONS CLASSES MODULES FILES inspect'),
1894 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
1895 'FORMATTING TYPES'),
1896 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1897 'FORMATTING': ('formatstrings', 'OPERATORS'),
1898 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1899 'FORMATTING TYPES'),
1900 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1901 'INTEGER': ('integers', 'int range'),
1902 'FLOAT': ('floating', 'float math'),
1903 'COMPLEX': ('imaginary', 'complex cmath'),
1904 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001905 'MAPPINGS': 'DICTIONARIES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001906 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1907 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1908 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1909 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001910 'FRAMEOBJECTS': 'TYPES',
1911 'TRACEBACKS': 'TYPES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001912 'NONE': ('bltin-null-object', ''),
1913 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001914 'SPECIALATTRIBUTES': ('specialattrs', ''),
1915 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1916 'MODULES': ('typesmodules', 'import'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001917 'PACKAGES': 'import',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001918 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1919 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1920 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1921 'LISTS DICTIONARIES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001922 'OPERATORS': 'EXPRESSIONS',
1923 'PRECEDENCE': 'EXPRESSIONS',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001924 'OBJECTS': ('objects', 'TYPES'),
1925 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
Georg Brandl395ed242009-09-04 08:07:32 +00001926 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
1927 'NUMBERMETHODS CLASSES'),
Mark Dickinsona56c4672009-01-27 18:17:45 +00001928 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001929 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1930 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001931 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
Georg Brandl6b38daa2008-06-01 21:05:17 +00001932 'SPECIALMETHODS'),
1933 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1934 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1935 'SPECIALMETHODS'),
1936 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001937 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001938 'DYNAMICFEATURES': ('dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001939 'SCOPING': 'NAMESPACES',
1940 'FRAMES': 'NAMESPACES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001941 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1942 'CONVERSIONS': ('conversions', ''),
1943 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1944 'SPECIALIDENTIFIERS': ('id-classes', ''),
1945 'PRIVATENAMES': ('atom-identifiers', ''),
1946 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
1947 'LISTLITERALS DICTIONARYLITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001948 'TUPLES': 'SEQUENCES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001949 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1950 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1951 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1952 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1953 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1954 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001955 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
1956 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001957 'CALLS': ('calls', 'EXPRESSIONS'),
1958 'POWER': ('power', 'EXPRESSIONS'),
1959 'UNARY': ('unary', 'EXPRESSIONS'),
1960 'BINARY': ('binary', 'EXPRESSIONS'),
1961 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1962 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1963 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1964 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001965 'ASSERTION': 'assert',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001966 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1967 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001968 'DELETION': 'del',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001969 'RETURNING': 'return',
1970 'IMPORTING': 'import',
1971 'CONDITIONAL': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001972 'LOOPING': ('compound', 'for while break continue'),
1973 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1974 'DEBUGGING': ('debugger', 'pdb'),
1975 'CONTEXTMANAGERS': ('context-managers', 'with'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001976 }
1977
Georg Brandl78aa3962010-07-31 21:51:48 +00001978 def __init__(self, input=None, output=None):
1979 self._input = input
1980 self._output = output
1981
Serhiy Storchakabdf6b912017-03-19 08:40:32 +02001982 @property
1983 def input(self):
1984 return self._input or sys.stdin
1985
1986 @property
1987 def output(self):
1988 return self._output or sys.stdout
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001989
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001990 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001991 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001992 self()
1993 return ''
Serhiy Storchaka465e60e2014-07-25 23:36:00 +03001994 return '<%s.%s instance>' % (self.__class__.__module__,
1995 self.__class__.__qualname__)
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001996
Alexander Belopolsky2e733c92010-07-04 17:00:20 +00001997 _GoInteractive = object()
1998 def __call__(self, request=_GoInteractive):
1999 if request is not self._GoInteractive:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002000 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002001 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002002 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002003 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002004 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00002005You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002006If you want to ask for help on a particular object directly from the
2007interpreter, you can type "help(object)". Executing "help('string')"
2008has the same effect as typing a particular string at the help> prompt.
2009''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002010
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002011 def interact(self):
2012 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002013 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002014 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00002015 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002016 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00002017 except (KeyboardInterrupt, EOFError):
2018 break
Andrés Delfinob2043bb2018-05-05 13:07:32 -03002019 request = request.strip()
2020
2021 # Make sure significant trailing quoting marks of literals don't
2022 # get deleted while cleaning input
2023 if (len(request) > 2 and request[0] == request[-1] in ("'", '"')
2024 and request[0] not in request[1:-1]):
2025 request = request[1:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002026 if request.lower() in ('q', 'quit'): break
Serhiy Storchaka1c205512015-03-01 00:42:54 +02002027 if request == 'help':
2028 self.intro()
2029 else:
2030 self.help(request)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002031
Johannes Gijsberse7691d32004-08-17 13:21:53 +00002032 def getline(self, prompt):
Guido van Rossum7c086c02008-01-02 03:52:38 +00002033 """Read one line, using input() when appropriate."""
Johannes Gijsberse7691d32004-08-17 13:21:53 +00002034 if self.input is sys.stdin:
Guido van Rossum7c086c02008-01-02 03:52:38 +00002035 return input(prompt)
Johannes Gijsberse7691d32004-08-17 13:21:53 +00002036 else:
2037 self.output.write(prompt)
2038 self.output.flush()
2039 return self.input.readline()
2040
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002041 def help(self, request):
2042 if type(request) is type(''):
R. David Murray1f1b9d32009-05-27 20:56:59 +00002043 request = request.strip()
Serhiy Storchaka1c205512015-03-01 00:42:54 +02002044 if request == 'keywords': self.listkeywords()
Georg Brandldb7b6b92009-01-01 15:53:14 +00002045 elif request == 'symbols': self.listsymbols()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002046 elif request == 'topics': self.listtopics()
2047 elif request == 'modules': self.listmodules()
2048 elif request[:8] == 'modules ':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002049 self.listmodules(request.split()[1])
Georg Brandldb7b6b92009-01-01 15:53:14 +00002050 elif request in self.symbols: self.showsymbol(request)
Ezio Melottib185a042011-04-28 07:42:55 +03002051 elif request in ['True', 'False', 'None']:
2052 # special case these keywords since they are objects too
2053 doc(eval(request), 'Help on %s:')
Raymond Hettinger54f02222002-06-01 14:18:47 +00002054 elif request in self.keywords: self.showtopic(request)
2055 elif request in self.topics: self.showtopic(request)
Georg Brandld80d5f42010-12-03 07:47:22 +00002056 elif request: doc(request, 'Help on %s:', output=self._output)
Serhiy Storchaka1c205512015-03-01 00:42:54 +02002057 else: doc(str, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002058 elif isinstance(request, Helper): self()
Georg Brandld80d5f42010-12-03 07:47:22 +00002059 else: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002060 self.output.write('\n')
2061
2062 def intro(self):
2063 self.output.write('''
Serhiy Storchaka885bdc42016-02-11 13:10:36 +02002064Welcome to Python {0}'s help utility!
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002065
2066If this is your first time using Python, you should definitely check out
oldke5681b92017-12-28 22:37:46 +08002067the tutorial on the Internet at https://docs.python.org/{0}/tutorial/.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002068
2069Enter the name of any module, keyword, or topic to get help on writing
2070Python programs and using Python modules. To quit this help utility and
2071return to the interpreter, just type "quit".
2072
Terry Jan Reedy34200572013-02-11 02:23:13 -05002073To get a list of available modules, keywords, symbols, or topics, type
2074"modules", "keywords", "symbols", or "topics". Each module also comes
2075with a one-line summary of what it does; to list the modules whose name
2076or summary contain a given string such as "spam", type "modules spam".
Serhiy Storchaka885bdc42016-02-11 13:10:36 +02002077'''.format('%d.%d' % sys.version_info[:2]))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002078
2079 def list(self, items, columns=4, width=80):
Guido van Rossum486364b2007-06-30 05:01:58 +00002080 items = list(sorted(items))
2081 colw = width // columns
2082 rows = (len(items) + columns - 1) // columns
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002083 for row in range(rows):
2084 for col in range(columns):
2085 i = col * rows + row
2086 if i < len(items):
2087 self.output.write(items[i])
2088 if col < columns - 1:
Guido van Rossum486364b2007-06-30 05:01:58 +00002089 self.output.write(' ' + ' ' * (colw - 1 - len(items[i])))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002090 self.output.write('\n')
2091
2092 def listkeywords(self):
2093 self.output.write('''
2094Here is a list of the Python keywords. Enter any keyword to get more help.
2095
2096''')
2097 self.list(self.keywords.keys())
2098
Georg Brandldb7b6b92009-01-01 15:53:14 +00002099 def listsymbols(self):
2100 self.output.write('''
2101Here is a list of the punctuation symbols which Python assigns special meaning
2102to. Enter any symbol to get more help.
2103
2104''')
2105 self.list(self.symbols.keys())
2106
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002107 def listtopics(self):
2108 self.output.write('''
2109Here is a list of available topics. Enter any topic name to get more help.
2110
2111''')
2112 self.list(self.topics.keys())
2113
Georg Brandldb7b6b92009-01-01 15:53:14 +00002114 def showtopic(self, topic, more_xrefs=''):
Georg Brandl6b38daa2008-06-01 21:05:17 +00002115 try:
Georg Brandl5617db82009-04-27 16:28:57 +00002116 import pydoc_data.topics
Brett Cannoncd171c82013-07-04 17:43:24 -04002117 except ImportError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002118 self.output.write('''
Georg Brandl6b38daa2008-06-01 21:05:17 +00002119Sorry, topic and keyword documentation is not available because the
Georg Brandl5617db82009-04-27 16:28:57 +00002120module "pydoc_data.topics" could not be found.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002121''')
2122 return
2123 target = self.topics.get(topic, self.keywords.get(topic))
2124 if not target:
2125 self.output.write('no documentation found for %s\n' % repr(topic))
2126 return
2127 if type(target) is type(''):
Georg Brandldb7b6b92009-01-01 15:53:14 +00002128 return self.showtopic(target, more_xrefs)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002129
Georg Brandl6b38daa2008-06-01 21:05:17 +00002130 label, xrefs = target
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002131 try:
Georg Brandl5617db82009-04-27 16:28:57 +00002132 doc = pydoc_data.topics.topics[label]
Georg Brandl6b38daa2008-06-01 21:05:17 +00002133 except KeyError:
2134 self.output.write('no documentation found for %s\n' % repr(topic))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002135 return
Berker Peksagd04f46c2018-07-23 08:37:47 +03002136 doc = doc.strip() + '\n'
Georg Brandldb7b6b92009-01-01 15:53:14 +00002137 if more_xrefs:
2138 xrefs = (xrefs or '') + ' ' + more_xrefs
Ka-Ping Yeeda793892001-04-13 11:02:51 +00002139 if xrefs:
Brett Cannon1448ecf2013-10-04 11:38:59 -04002140 import textwrap
2141 text = 'Related help topics: ' + ', '.join(xrefs.split()) + '\n'
2142 wrapped_text = textwrap.wrap(text, 72)
Berker Peksagd04f46c2018-07-23 08:37:47 +03002143 doc += '\n%s\n' % '\n'.join(wrapped_text)
2144 pager(doc)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002145
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002146 def _gettopic(self, topic, more_xrefs=''):
2147 """Return unbuffered tuple of (topic, xrefs).
2148
Georg Brandld2f38572011-01-30 08:37:19 +00002149 If an error occurs here, the exception is caught and displayed by
2150 the url handler.
2151
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002152 This function duplicates the showtopic method but returns its
2153 result directly so it can be formatted for display in an html page.
2154 """
2155 try:
2156 import pydoc_data.topics
Brett Cannoncd171c82013-07-04 17:43:24 -04002157 except ImportError:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002158 return('''
2159Sorry, topic and keyword documentation is not available because the
2160module "pydoc_data.topics" could not be found.
2161''' , '')
2162 target = self.topics.get(topic, self.keywords.get(topic))
2163 if not target:
Georg Brandld2f38572011-01-30 08:37:19 +00002164 raise ValueError('could not find topic')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002165 if isinstance(target, str):
2166 return self._gettopic(target, more_xrefs)
2167 label, xrefs = target
Georg Brandld2f38572011-01-30 08:37:19 +00002168 doc = pydoc_data.topics.topics[label]
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002169 if more_xrefs:
2170 xrefs = (xrefs or '') + ' ' + more_xrefs
2171 return doc, xrefs
2172
Georg Brandldb7b6b92009-01-01 15:53:14 +00002173 def showsymbol(self, symbol):
2174 target = self.symbols[symbol]
2175 topic, _, xrefs = target.partition(' ')
2176 self.showtopic(topic, xrefs)
2177
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002178 def listmodules(self, key=''):
2179 if key:
2180 self.output.write('''
Terry Jan Reedy34200572013-02-11 02:23:13 -05002181Here is a list of modules whose name or summary contains '{}'.
2182If there are any, enter a module name to get more help.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002183
Terry Jan Reedy34200572013-02-11 02:23:13 -05002184'''.format(key))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002185 apropos(key)
2186 else:
2187 self.output.write('''
2188Please wait a moment while I gather a list of all available modules...
2189
2190''')
2191 modules = {}
2192 def callback(path, modname, desc, modules=modules):
2193 if modname and modname[-9:] == '.__init__':
2194 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002195 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002196 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002197 def onerror(modname):
2198 callback(None, modname, None)
2199 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002200 self.list(modules.keys())
2201 self.output.write('''
2202Enter any module name to get more help. Or, type "modules spam" to search
Terry Jan Reedy34200572013-02-11 02:23:13 -05002203for modules whose name or summary contain the string "spam".
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00002204''')
2205
Georg Brandl78aa3962010-07-31 21:51:48 +00002206help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002207
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002208class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002209 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002210
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002211 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002212 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002213 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002214 seen = {}
2215
2216 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002217 if modname != '__main__':
2218 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00002219 if key is None:
2220 callback(None, modname, '')
2221 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002222 name = __import__(modname).__doc__ or ''
2223 desc = name.split('\n')[0]
2224 name = modname + ' - ' + desc
2225 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002226 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002227
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002228 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002229 if self.quit:
2230 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002231
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002232 if key is None:
2233 callback(None, modname, '')
2234 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002235 try:
Eric Snow3a62d142014-01-06 20:42:59 -07002236 spec = pkgutil._get_spec(importer, modname)
Georg Brandl126c8792009-04-05 15:05:48 +00002237 except SyntaxError:
2238 # raised by tests for bad coding cookies or BOM
2239 continue
Eric Snow3a62d142014-01-06 20:42:59 -07002240 loader = spec.loader
Georg Brandl126c8792009-04-05 15:05:48 +00002241 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002242 try:
2243 source = loader.get_source(modname)
Nick Coghlan2824cb52012-07-15 22:12:14 +10002244 except Exception:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002245 if onerror:
2246 onerror(modname)
2247 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002248 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002249 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002250 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002251 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002252 path = None
2253 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002254 try:
Brett Cannon2a17bde2014-05-30 14:55:29 -04002255 module = importlib._bootstrap._load(spec)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002256 except ImportError:
2257 if onerror:
2258 onerror(modname)
2259 continue
Benjamin Peterson54237f92015-02-16 19:45:01 -05002260 desc = module.__doc__.splitlines()[0] if module.__doc__ else ''
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002261 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002262 name = modname + ' - ' + desc
2263 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002264 callback(path, modname, desc)
2265
2266 if completer:
2267 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002268
2269def apropos(key):
2270 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002271 def callback(path, modname, desc):
2272 if modname[-9:] == '.__init__':
2273 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002274 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002275 def onerror(modname):
2276 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002277 with warnings.catch_warnings():
2278 warnings.filterwarnings('ignore') # ignore problems during import
2279 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002280
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002281# --------------------------------------- enhanced Web browser interface
2282
Feanil Patel6a396c92017-09-14 17:54:09 -04002283def _start_server(urlhandler, hostname, port):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002284 """Start an HTTP server thread on a specific port.
2285
2286 Start an HTML/text server thread, so HTML or text documents can be
2287 browsed dynamically and interactively with a Web browser. Example use:
2288
2289 >>> import time
2290 >>> import pydoc
2291
2292 Define a URL handler. To determine what the client is asking
2293 for, check the URL and content_type.
2294
2295 Then get or generate some text or HTML code and return it.
2296
2297 >>> def my_url_handler(url, content_type):
2298 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2299 ... return text
2300
2301 Start server thread on port 0.
2302 If you use port 0, the server will pick a random port number.
2303 You can then use serverthread.port to get the port number.
2304
2305 >>> port = 0
2306 >>> serverthread = pydoc._start_server(my_url_handler, port)
2307
2308 Check that the server is really started. If it is, open browser
2309 and get first page. Use serverthread.url as the starting page.
2310
2311 >>> if serverthread.serving:
2312 ... import webbrowser
2313
2314 The next two lines are commented out so a browser doesn't open if
2315 doctest is run on this module.
2316
2317 #... webbrowser.open(serverthread.url)
2318 #True
2319
2320 Let the server do its thing. We just need to monitor its status.
2321 Use time.sleep so the loop doesn't hog the CPU.
2322
Victor Stinner2cf4c202018-12-17 09:36:36 +01002323 >>> starttime = time.monotonic()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002324 >>> timeout = 1 #seconds
2325
2326 This is a short timeout for testing purposes.
2327
2328 >>> while serverthread.serving:
2329 ... time.sleep(.01)
Victor Stinner2cf4c202018-12-17 09:36:36 +01002330 ... if serverthread.serving and time.monotonic() - starttime > timeout:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002331 ... serverthread.stop()
2332 ... break
2333
2334 Print any errors that may have occurred.
2335
2336 >>> print(serverthread.error)
2337 None
2338 """
2339 import http.server
2340 import email.message
2341 import select
2342 import threading
2343
2344 class DocHandler(http.server.BaseHTTPRequestHandler):
2345
2346 def do_GET(self):
2347 """Process a request from an HTML browser.
2348
2349 The URL received is in self.path.
2350 Get an HTML page from self.urlhandler and send it.
2351 """
2352 if self.path.endswith('.css'):
2353 content_type = 'text/css'
2354 else:
2355 content_type = 'text/html'
2356 self.send_response(200)
Georg Brandld2f38572011-01-30 08:37:19 +00002357 self.send_header('Content-Type', '%s; charset=UTF-8' % content_type)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002358 self.end_headers()
2359 self.wfile.write(self.urlhandler(
2360 self.path, content_type).encode('utf-8'))
2361
2362 def log_message(self, *args):
2363 # Don't log messages.
2364 pass
2365
2366 class DocServer(http.server.HTTPServer):
2367
Feanil Patel6a396c92017-09-14 17:54:09 -04002368 def __init__(self, host, port, callback):
2369 self.host = host
Senthil Kumaran2a42a0b2014-09-17 13:17:58 +08002370 self.address = (self.host, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002371 self.callback = callback
2372 self.base.__init__(self, self.address, self.handler)
2373 self.quit = False
2374
2375 def serve_until_quit(self):
2376 while not self.quit:
2377 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2378 if rd:
2379 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002380 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002381
2382 def server_activate(self):
2383 self.base.server_activate(self)
2384 if self.callback:
2385 self.callback(self)
2386
2387 class ServerThread(threading.Thread):
2388
Feanil Patel6a396c92017-09-14 17:54:09 -04002389 def __init__(self, urlhandler, host, port):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002390 self.urlhandler = urlhandler
Feanil Patel6a396c92017-09-14 17:54:09 -04002391 self.host = host
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002392 self.port = int(port)
2393 threading.Thread.__init__(self)
2394 self.serving = False
2395 self.error = None
2396
2397 def run(self):
2398 """Start the server."""
2399 try:
2400 DocServer.base = http.server.HTTPServer
2401 DocServer.handler = DocHandler
2402 DocHandler.MessageClass = email.message.Message
2403 DocHandler.urlhandler = staticmethod(self.urlhandler)
Feanil Patel6a396c92017-09-14 17:54:09 -04002404 docsvr = DocServer(self.host, self.port, self.ready)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002405 self.docserver = docsvr
2406 docsvr.serve_until_quit()
2407 except Exception as e:
2408 self.error = e
2409
2410 def ready(self, server):
2411 self.serving = True
2412 self.host = server.host
2413 self.port = server.server_port
2414 self.url = 'http://%s:%d/' % (self.host, self.port)
2415
2416 def stop(self):
2417 """Stop the server and this thread nicely"""
2418 self.docserver.quit = True
Victor Stinner4cab2cd2017-08-21 23:24:40 +02002419 self.join()
2420 # explicitly break a reference cycle: DocServer.callback
2421 # has indirectly a reference to ServerThread.
2422 self.docserver = None
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002423 self.serving = False
2424 self.url = None
2425
Feanil Patel6a396c92017-09-14 17:54:09 -04002426 thread = ServerThread(urlhandler, hostname, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002427 thread.start()
2428 # Wait until thread.serving is True to make sure we are
2429 # really up before returning.
2430 while not thread.error and not thread.serving:
2431 time.sleep(.01)
2432 return thread
2433
2434
2435def _url_handler(url, content_type="text/html"):
2436 """The pydoc url handler for use with the pydoc server.
2437
2438 If the content_type is 'text/css', the _pydoc.css style
2439 sheet is read and returned if it exits.
2440
2441 If the content_type is 'text/html', then the result of
2442 get_html_page(url) is returned.
2443 """
2444 class _HTMLDoc(HTMLDoc):
2445
2446 def page(self, title, contents):
2447 """Format an HTML page."""
2448 css_path = "pydoc_data/_pydoc.css"
2449 css_link = (
2450 '<link rel="stylesheet" type="text/css" href="%s">' %
2451 css_path)
2452 return '''\
2453<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Georg Brandld2f38572011-01-30 08:37:19 +00002454<html><head><title>Pydoc: %s</title>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002455<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Georg Brandld2f38572011-01-30 08:37:19 +00002456%s</head><body bgcolor="#f0f0f8">%s<div style="clear:both;padding-top:.5em;">%s</div>
2457</body></html>''' % (title, css_link, html_navbar(), contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002458
2459 def filelink(self, url, path):
2460 return '<a href="getfile?key=%s">%s</a>' % (url, path)
2461
2462
2463 html = _HTMLDoc()
2464
2465 def html_navbar():
Georg Brandld2f38572011-01-30 08:37:19 +00002466 version = html.escape("%s [%s, %s]" % (platform.python_version(),
2467 platform.python_build()[0],
2468 platform.python_compiler()))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002469 return """
2470 <div style='float:left'>
Georg Brandld2f38572011-01-30 08:37:19 +00002471 Python %s<br>%s
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002472 </div>
2473 <div style='float:right'>
2474 <div style='text-align:center'>
2475 <a href="index.html">Module Index</a>
2476 : <a href="topics.html">Topics</a>
2477 : <a href="keywords.html">Keywords</a>
2478 </div>
2479 <div>
Georg Brandld2f38572011-01-30 08:37:19 +00002480 <form action="get" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002481 <input type=text name=key size=15>
2482 <input type=submit value="Get">
Georg Brandld2f38572011-01-30 08:37:19 +00002483 </form>&nbsp;
2484 <form action="search" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002485 <input type=text name=key size=15>
2486 <input type=submit value="Search">
2487 </form>
2488 </div>
2489 </div>
Georg Brandld2f38572011-01-30 08:37:19 +00002490 """ % (version, html.escape(platform.platform(terse=True)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002491
2492 def html_index():
2493 """Module Index page."""
2494
2495 def bltinlink(name):
2496 return '<a href="%s.html">%s</a>' % (name, name)
2497
2498 heading = html.heading(
2499 '<big><big><strong>Index of Modules</strong></big></big>',
2500 '#ffffff', '#7799ee')
2501 names = [name for name in sys.builtin_module_names
2502 if name != '__main__']
2503 contents = html.multicolumn(names, bltinlink)
2504 contents = [heading, '<p>' + html.bigsection(
2505 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2506
2507 seen = {}
2508 for dir in sys.path:
2509 contents.append(html.index(dir, seen))
2510
2511 contents.append(
2512 '<p align=right><font color="#909090" face="helvetica,'
2513 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2514 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002515 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002516
2517 def html_search(key):
2518 """Search results page."""
2519 # scan for modules
2520 search_result = []
2521
2522 def callback(path, modname, desc):
2523 if modname[-9:] == '.__init__':
2524 modname = modname[:-9] + ' (package)'
2525 search_result.append((modname, desc and '- ' + desc))
2526
2527 with warnings.catch_warnings():
2528 warnings.filterwarnings('ignore') # ignore problems during import
Martin Panter9ad0aae2015-11-06 00:27:14 +00002529 def onerror(modname):
2530 pass
2531 ModuleScanner().run(callback, key, onerror=onerror)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002532
2533 # format page
2534 def bltinlink(name):
2535 return '<a href="%s.html">%s</a>' % (name, name)
2536
2537 results = []
2538 heading = html.heading(
2539 '<big><big><strong>Search Results</strong></big></big>',
2540 '#ffffff', '#7799ee')
2541 for name, desc in search_result:
2542 results.append(bltinlink(name) + desc)
2543 contents = heading + html.bigsection(
2544 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002545 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002546
2547 def html_getfile(path):
2548 """Get and display a source file listing safely."""
Zachary Wareeb432142014-07-10 11:18:00 -05002549 path = urllib.parse.unquote(path)
Victor Stinner91e08772011-07-05 14:30:41 +02002550 with tokenize.open(path) as fp:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002551 lines = html.escape(fp.read())
2552 body = '<pre>%s</pre>' % lines
2553 heading = html.heading(
2554 '<big><big><strong>File Listing</strong></big></big>',
2555 '#ffffff', '#7799ee')
2556 contents = heading + html.bigsection(
2557 'File: %s' % path, '#ffffff', '#ee77aa', body)
Nick Coghlanecace282010-12-03 16:08:46 +00002558 return 'getfile %s' % path, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002559
2560 def html_topics():
2561 """Index of topic texts available."""
2562
2563 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002564 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002565
2566 heading = html.heading(
2567 '<big><big><strong>INDEX</strong></big></big>',
2568 '#ffffff', '#7799ee')
2569 names = sorted(Helper.topics.keys())
2570
2571 contents = html.multicolumn(names, bltinlink)
2572 contents = heading + html.bigsection(
2573 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002574 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002575
2576 def html_keywords():
2577 """Index of keywords."""
2578 heading = html.heading(
2579 '<big><big><strong>INDEX</strong></big></big>',
2580 '#ffffff', '#7799ee')
2581 names = sorted(Helper.keywords.keys())
2582
2583 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002584 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002585
2586 contents = html.multicolumn(names, bltinlink)
2587 contents = heading + html.bigsection(
2588 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002589 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002590
2591 def html_topicpage(topic):
2592 """Topic or keyword help page."""
2593 buf = io.StringIO()
2594 htmlhelp = Helper(buf, buf)
2595 contents, xrefs = htmlhelp._gettopic(topic)
2596 if topic in htmlhelp.keywords:
2597 title = 'KEYWORD'
2598 else:
2599 title = 'TOPIC'
2600 heading = html.heading(
2601 '<big><big><strong>%s</strong></big></big>' % title,
2602 '#ffffff', '#7799ee')
Georg Brandld2f38572011-01-30 08:37:19 +00002603 contents = '<pre>%s</pre>' % html.markup(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002604 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
Georg Brandld2f38572011-01-30 08:37:19 +00002605 if xrefs:
2606 xrefs = sorted(xrefs.split())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002607
Georg Brandld2f38572011-01-30 08:37:19 +00002608 def bltinlink(name):
2609 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002610
Georg Brandld2f38572011-01-30 08:37:19 +00002611 xrefs = html.multicolumn(xrefs, bltinlink)
2612 xrefs = html.section('Related help topics: ',
2613 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002614 return ('%s %s' % (title, topic),
2615 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002616
Georg Brandld2f38572011-01-30 08:37:19 +00002617 def html_getobj(url):
2618 obj = locate(url, forceload=1)
2619 if obj is None and url != 'None':
2620 raise ValueError('could not find object')
2621 title = describe(obj)
2622 content = html.document(obj, url)
2623 return title, content
2624
2625 def html_error(url, exc):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002626 heading = html.heading(
2627 '<big><big><strong>Error</strong></big></big>',
Georg Brandld2f38572011-01-30 08:37:19 +00002628 '#ffffff', '#7799ee')
2629 contents = '<br>'.join(html.escape(line) for line in
2630 format_exception_only(type(exc), exc))
2631 contents = heading + html.bigsection(url, '#ffffff', '#bb0000',
2632 contents)
2633 return "Error - %s" % url, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002634
2635 def get_html_page(url):
2636 """Generate an HTML page for url."""
Georg Brandld2f38572011-01-30 08:37:19 +00002637 complete_url = url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002638 if url.endswith('.html'):
2639 url = url[:-5]
Georg Brandld2f38572011-01-30 08:37:19 +00002640 try:
2641 if url in ("", "index"):
2642 title, content = html_index()
2643 elif url == "topics":
2644 title, content = html_topics()
2645 elif url == "keywords":
2646 title, content = html_keywords()
2647 elif '=' in url:
2648 op, _, url = url.partition('=')
2649 if op == "search?key":
2650 title, content = html_search(url)
2651 elif op == "getfile?key":
2652 title, content = html_getfile(url)
2653 elif op == "topic?key":
2654 # try topics first, then objects.
2655 try:
2656 title, content = html_topicpage(url)
2657 except ValueError:
2658 title, content = html_getobj(url)
2659 elif op == "get?key":
2660 # try objects first, then topics.
2661 if url in ("", "index"):
2662 title, content = html_index()
2663 else:
2664 try:
2665 title, content = html_getobj(url)
2666 except ValueError:
2667 title, content = html_topicpage(url)
2668 else:
2669 raise ValueError('bad pydoc url')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002670 else:
Georg Brandld2f38572011-01-30 08:37:19 +00002671 title, content = html_getobj(url)
2672 except Exception as exc:
2673 # Catch any errors and display them in an error page.
2674 title, content = html_error(complete_url, exc)
2675 return html.page(title, content)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002676
2677 if url.startswith('/'):
2678 url = url[1:]
2679 if content_type == 'text/css':
2680 path_here = os.path.dirname(os.path.realpath(__file__))
Georg Brandld2f38572011-01-30 08:37:19 +00002681 css_path = os.path.join(path_here, url)
2682 with open(css_path) as fp:
2683 return ''.join(fp.readlines())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002684 elif content_type == 'text/html':
2685 return get_html_page(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002686 # Errors outside the url handler are caught by the server.
2687 raise TypeError('unknown content type %r for url %s' % (content_type, url))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002688
2689
Feanil Patel6a396c92017-09-14 17:54:09 -04002690def browse(port=0, *, open_browser=True, hostname='localhost'):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002691 """Start the enhanced pydoc Web server and open a Web browser.
2692
2693 Use port '0' to start the server on an arbitrary port.
2694 Set open_browser to False to suppress opening a browser.
2695 """
2696 import webbrowser
Feanil Patel6a396c92017-09-14 17:54:09 -04002697 serverthread = _start_server(_url_handler, hostname, port)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002698 if serverthread.error:
2699 print(serverthread.error)
2700 return
2701 if serverthread.serving:
2702 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2703 if open_browser:
2704 webbrowser.open(serverthread.url)
2705 try:
2706 print('Server ready at', serverthread.url)
2707 print(server_help_msg)
2708 while serverthread.serving:
2709 cmd = input('server> ')
2710 cmd = cmd.lower()
2711 if cmd == 'q':
2712 break
2713 elif cmd == 'b':
2714 webbrowser.open(serverthread.url)
2715 else:
2716 print(server_help_msg)
2717 except (KeyboardInterrupt, EOFError):
2718 print()
2719 finally:
2720 if serverthread.serving:
2721 serverthread.stop()
2722 print('Server stopped')
2723
2724
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002725# -------------------------------------------------- command-line interface
2726
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002727def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002728 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002729
Nick Coghlan82a94812018-04-15 21:52:57 +10002730def _get_revised_path(given_path, argv0):
2731 """Ensures current directory is on returned path, and argv0 directory is not
2732
2733 Exception: argv0 dir is left alone if it's also pydoc's directory.
2734
2735 Returns a new path entry list, or None if no adjustment is needed.
2736 """
2737 # Scripts may get the current directory in their path by default if they're
2738 # run with the -m switch, or directly from the current directory.
2739 # The interactive prompt also allows imports from the current directory.
2740
2741 # Accordingly, if the current directory is already present, don't make
2742 # any changes to the given_path
2743 if '' in given_path or os.curdir in given_path or os.getcwd() in given_path:
2744 return None
2745
2746 # Otherwise, add the current directory to the given path, and remove the
2747 # script directory (as long as the latter isn't also pydoc's directory.
2748 stdlib_dir = os.path.dirname(__file__)
2749 script_dir = os.path.dirname(argv0)
2750 revised_path = given_path.copy()
2751 if script_dir in given_path and not os.path.samefile(script_dir, stdlib_dir):
2752 revised_path.remove(script_dir)
2753 revised_path.insert(0, os.getcwd())
2754 return revised_path
2755
2756
2757# Note: the tests only cover _get_revised_path, not _adjust_cli_path itself
2758def _adjust_cli_sys_path():
Nick Coghlan1a5c4bd2018-04-15 23:32:05 +10002759 """Ensures current directory is on sys.path, and __main__ directory is not.
Nick Coghlan82a94812018-04-15 21:52:57 +10002760
2761 Exception: __main__ dir is left alone if it's also pydoc's directory.
2762 """
2763 revised_path = _get_revised_path(sys.path, sys.argv[0])
2764 if revised_path is not None:
2765 sys.path[:] = revised_path
2766
2767
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002768def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002769 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002770 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002771 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002772
Nick Coghlan82a94812018-04-15 21:52:57 +10002773 _adjust_cli_sys_path()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002774
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002775 try:
Feanil Patel6a396c92017-09-14 17:54:09 -04002776 opts, args = getopt.getopt(sys.argv[1:], 'bk:n:p:w')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002777 writing = False
2778 start_server = False
2779 open_browser = False
Feanil Patel6a396c92017-09-14 17:54:09 -04002780 port = 0
2781 hostname = 'localhost'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002782 for opt, val in opts:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002783 if opt == '-b':
2784 start_server = True
2785 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002786 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002787 apropos(val)
2788 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002789 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002790 start_server = True
2791 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002792 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002793 writing = True
Feanil Patel6a396c92017-09-14 17:54:09 -04002794 if opt == '-n':
2795 start_server = True
2796 hostname = val
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002797
Benjamin Petersonb29614e2012-10-09 11:16:03 -04002798 if start_server:
Feanil Patel6a396c92017-09-14 17:54:09 -04002799 browse(port, hostname=hostname, open_browser=open_browser)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002800 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002801
2802 if not args: raise BadUsage
2803 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002804 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002805 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002806 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002807 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002808 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002809 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002810 if writing:
2811 if ispath(arg) and os.path.isdir(arg):
2812 writedocs(arg)
2813 else:
2814 writedoc(arg)
2815 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002816 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002817 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002818 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002819
2820 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002821 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002822 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002823
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002824{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002825 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002826 Python keyword, topic, function, module, or package, or a dotted
2827 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002828 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002829 Python source file to document. If name is 'keywords', 'topics',
2830 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002831
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002832{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002833 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002834
Feanil Patel6a396c92017-09-14 17:54:09 -04002835{cmd} -n <hostname>
2836 Start an HTTP server with the given hostname (default: localhost).
2837
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002838{cmd} -p <port>
2839 Start an HTTP server on the given port on the local machine. Port
2840 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002841
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002842{cmd} -b
2843 Start an HTTP server on an arbitrary unused port and open a Web browser
Feanil Patel6a396c92017-09-14 17:54:09 -04002844 to interactively browse documentation. This option can be used in
2845 combination with -n and/or -p.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002846
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002847{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002848 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002849 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002850 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002851""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002852
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002853if __name__ == '__main__':
2854 cli()