blob: 8581d63d079f7af9f47f6bf127191e1190fd7769 [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
Ka-Ping Yeedd175342001-02-27 14:43:46 +00004In the Python interpreter, do "from pydoc import help" to provide online
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00005help. Calling help(thing) on a Python object documents the object.
6
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00007Or, at the shell command line outside of Python:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00008
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00009Run "pydoc <name>" to show documentation on something. <name> may be
10the name of a function, module, package, or a dotted reference to a
11class or function within a module or module in a package. If the
12argument contains a path segment delimiter (e.g. slash on Unix,
13backslash on Windows) it is treated as the path to a Python source file.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000014
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000015Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
16of all available modules.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000017
Nick Coghlan7bb30b72010-12-03 09:29:11 +000018Run "pydoc -p <port>" to start an HTTP server on the given port on the
19local machine. Port number 0 can be used to get an arbitrary unused port.
20
21Run "pydoc -b" to start an HTTP server on an arbitrary unused port and
22open a Web browser to interactively browse documentation. The -p option
23can be used with the -b option to explicitly specify the server port.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000024
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000025For platforms without a command line, "pydoc -g" starts the HTTP server
Nick Coghlan7bb30b72010-12-03 09:29:11 +000026and also pops up a little window for controlling it. This option is
27deprecated, since the server can now be controlled directly from HTTP
28clients.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +000029
30Run "pydoc -w <name>" to write out the HTML documentation for a module
31to a file named "<name>.html".
Skip Montanaro4997a692003-09-10 16:47:51 +000032
33Module docs for core modules are assumed to be in
34
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000035 http://docs.python.org/X.Y/library/
Skip Montanaro4997a692003-09-10 16:47:51 +000036
37This can be overridden by setting the PYTHONDOCS environment variable
38to a different URL or to a local directory containing the Library
39Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000040"""
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000041__all__ = ['help']
Ka-Ping Yeedd175342001-02-27 14:43:46 +000042__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000043__date__ = "26 February 2001"
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000044
Ka-Ping Yee09d7d9a2001-02-27 22:43:48 +000045__version__ = "$Revision$"
Martin v. Löwis6fe8f192004-11-14 10:21:04 +000046__credits__ = """Guido van Rossum, for an excellent programming language.
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000047Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000048Paul Prescod, for all his work on onlinehelp.
49Richard Chamberlain, for the first implementation of textdoc.
Raymond Hettingered2dbe32005-01-01 07:51:01 +000050"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000051
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000052# Known bugs that can't be fixed here:
53# - imp.load_module() cannot be prevented from clobbering existing
54# loaded modules, so calling synopsis() on a binary module file
55# changes the contents of any existing module with the same name.
56# - If the __file__ attribute on a module is a relative path and
57# the current directory is changed with os.chdir(), an incorrect
58# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000059
Nick Coghlan7bb30b72010-12-03 09:29:11 +000060import os
61import sys
62import builtins
63import imp
64import io
65import inspect
66import pkgutil
67import platform
68import re
69import time
70import warnings
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000071from collections import deque
Nick Coghlan7bb30b72010-12-03 09:29:11 +000072from reprlib import Repr
Georg Brandld2f38572011-01-30 08:37:19 +000073from traceback import extract_tb, format_exception_only
Nick Coghlan7bb30b72010-12-03 09:29:11 +000074
75
Ka-Ping Yeedd175342001-02-27 14:43:46 +000076# --------------------------------------------------------- common routines
77
Ka-Ping Yeedd175342001-02-27 14:43:46 +000078def pathdirs():
79 """Convert sys.path into a list of absolute, existing, unique paths."""
80 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000081 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000082 for dir in sys.path:
83 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000084 normdir = os.path.normcase(dir)
85 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000086 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000087 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000088 return dirs
89
90def getdoc(object):
91 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000092 result = inspect.getdoc(object) or inspect.getcomments(object)
Neal Norwitz9d72bb42007-04-17 08:48:32 +000093 return result and re.sub('^ *\n', '', result.rstrip()) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000094
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000095def splitdoc(doc):
96 """Split a doc string into a synopsis line (if any) and the rest."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +000097 lines = doc.strip().split('\n')
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000098 if len(lines) == 1:
99 return lines[0], ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000100 elif len(lines) >= 2 and not lines[1].rstrip():
101 return lines[0], '\n'.join(lines[2:])
102 return '', '\n'.join(lines)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000103
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000104def classname(object, modname):
105 """Get a class name and qualify it with a module name if necessary."""
106 name = object.__name__
107 if object.__module__ != modname:
108 name = object.__module__ + '.' + name
109 return name
110
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000111def isdata(object):
Georg Brandl94432422005-07-22 21:52:25 +0000112 """Check if an object is of a type that probably means it's data."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000113 return not (inspect.ismodule(object) or inspect.isclass(object) or
114 inspect.isroutine(object) or inspect.isframe(object) or
115 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000116
117def replace(text, *pairs):
118 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000119 while pairs:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000120 text = pairs[1].join(text.split(pairs[0]))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000121 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000122 return text
123
124def cram(text, maxlen):
125 """Omit part of a string if needed to make it fit in a maximum length."""
126 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000127 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000128 post = max(0, maxlen-3-pre)
129 return text[:pre] + '...' + text[len(text)-post:]
130 return text
131
Brett Cannon84601f12004-06-19 01:22:48 +0000132_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000133def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000134 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000135 # The behaviour of %p is implementation-dependent in terms of case.
Ezio Melotti412c95a2010-02-16 23:31:04 +0000136 return _re_stripid.sub(r'\1', text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000137
Brett Cannonc6c1f472004-06-19 01:02:51 +0000138def _is_some_method(obj):
139 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000140
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000141def allmethods(cl):
142 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000143 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000144 methods[key] = 1
145 for base in cl.__bases__:
146 methods.update(allmethods(base)) # all your base are belong to us
147 for key in methods.keys():
148 methods[key] = getattr(cl, key)
149 return methods
150
Tim Petersfa26f7c2001-09-24 08:05:11 +0000151def _split_list(s, predicate):
152 """Split sequence s via predicate, and return pair ([true], [false]).
153
154 The return value is a 2-tuple of lists,
155 ([x for x in s if predicate(x)],
156 [x for x in s if not predicate(x)])
157 """
158
Tim Peters28355492001-09-23 21:29:55 +0000159 yes = []
160 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000161 for x in s:
162 if predicate(x):
163 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000164 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000165 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000166 return yes, no
167
Raymond Hettinger1103d052011-03-25 14:15:24 -0700168def visiblename(name, all=None, obj=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000169 """Decide whether to show documentation on a variable."""
170 # Certain special names are redundant.
Raymond Hettinger68272942011-03-18 02:22:15 -0700171 if name in {'__builtins__', '__doc__', '__file__', '__path__',
Barry Warsaw28a691b2010-04-17 00:19:56 +0000172 '__module__', '__name__', '__slots__', '__package__',
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000173 '__cached__', '__author__', '__credits__', '__date__',
Raymond Hettinger68272942011-03-18 02:22:15 -0700174 '__version__'}:
175 return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000176 # Private names are hidden, but special names are displayed.
177 if name.startswith('__') and name.endswith('__'): return 1
Raymond Hettinger1103d052011-03-25 14:15:24 -0700178 # Namedtuples have public fields and methods with a single leading underscore
179 if name.startswith('_') and hasattr(obj, '_fields'):
180 return True
Skip Montanaroa5616d22004-06-11 04:46:12 +0000181 if all is not None:
182 # only document that which the programmer exported in __all__
183 return name in all
184 else:
185 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000186
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000187def classify_class_attrs(object):
188 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000189 results = []
190 for (name, kind, cls, value) in inspect.classify_class_attrs(object):
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000191 if inspect.isdatadescriptor(value):
192 kind = 'data descriptor'
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000193 results.append((name, kind, cls, value))
194 return results
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000195
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000196# ----------------------------------------------------- module manipulation
197
198def ispackage(path):
199 """Guess whether a path refers to a package directory."""
200 if os.path.isdir(path):
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000201 for ext in ('.py', '.pyc', '.pyo'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000202 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000203 return True
204 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000205
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000206def source_synopsis(file):
207 line = file.readline()
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000208 while line[:1] == '#' or not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000209 line = file.readline()
210 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000211 line = line.strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000212 if line[:4] == 'r"""': line = line[1:]
213 if line[:3] == '"""':
214 line = line[3:]
215 if line[-1:] == '\\': line = line[:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000216 while not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000217 line = file.readline()
218 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000219 result = line.split('"""')[0].strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000220 else: result = None
221 return result
222
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000223def synopsis(filename, cache={}):
224 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000225 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000226 lastupdate, result = cache.get(filename, (0, None))
227 if lastupdate < mtime:
228 info = inspect.getmoduleinfo(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000229 try:
230 file = open(filename)
231 except IOError:
232 # module can't be opened, so skip it
233 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000234 if info and 'b' in info[2]: # binary modules have to be imported
235 try: module = imp.load_module('__temp__', file, filename, info[1:])
236 except: return None
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000237 result = (module.__doc__ or '').splitlines()[0]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000238 del sys.modules['__temp__']
239 else: # text modules can be directly examined
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000240 result = source_synopsis(file)
241 file.close()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000242 cache[filename] = (mtime, result)
243 return result
244
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000245class ErrorDuringImport(Exception):
246 """Errors that occurred while trying to import something to document it."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000247 def __init__(self, filename, exc_info):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000248 self.filename = filename
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000249 self.exc, self.value, self.tb = exc_info
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000250
251 def __str__(self):
Guido van Rossuma01a8b62007-05-27 09:20:14 +0000252 exc = self.exc.__name__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000253 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000254
255def importfile(path):
256 """Import a Python source file or compiled file given its path."""
257 magic = imp.get_magic()
258 file = open(path, 'r')
259 if file.read(len(magic)) == magic:
260 kind = imp.PY_COMPILED
261 else:
262 kind = imp.PY_SOURCE
263 file.close()
264 filename = os.path.basename(path)
265 name, ext = os.path.splitext(filename)
266 file = open(path, 'r')
267 try:
268 module = imp.load_module(name, file, path, (ext, 'r', kind))
269 except:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000270 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000271 file.close()
272 return module
273
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000274def safeimport(path, forceload=0, cache={}):
275 """Import a module; handle errors; return None if the module isn't found.
276
277 If the module *is* found but an exception occurs, it's wrapped in an
278 ErrorDuringImport exception and reraised. Unlike __import__, if a
279 package path is specified, the module at the end of the path is returned,
280 not the package at the beginning. If the optional 'forceload' argument
281 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000282 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000283 # If forceload is 1 and the module has been previously loaded from
284 # disk, we always have to reload the module. Checking the file's
285 # mtime isn't good enough (e.g. the module could contain a class
286 # that inherits from another module that has changed).
287 if forceload and path in sys.modules:
288 if path not in sys.builtin_module_names:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000289 # Remove the module from sys.modules and re-import to try
290 # and avoid problems with partially loaded modules.
291 # Also remove any submodules because they won't appear
292 # in the newly loaded module's namespace if they're already
293 # in sys.modules.
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000294 subs = [m for m in sys.modules if m.startswith(path + '.')]
295 for key in [path] + subs:
296 # Prevent garbage collection.
297 cache[key] = sys.modules[key]
298 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000299 module = __import__(path)
300 except:
301 # Did the error occur before or after the module was found?
302 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000303 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000304 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000305 raise ErrorDuringImport(sys.modules[path].__file__, info)
306 elif exc is SyntaxError:
307 # A SyntaxError occurred before we could execute the module.
308 raise ErrorDuringImport(value.filename, info)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000309 elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport':
Benjamin Peterson0289b152009-06-28 17:22:03 +0000310 # The import error occurred directly in this function,
311 # which means there is no such module in the path.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000312 return None
313 else:
314 # Some other error occurred during the importing process.
315 raise ErrorDuringImport(path, sys.exc_info())
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000316 for part in path.split('.')[1:]:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000317 try: module = getattr(module, part)
318 except AttributeError: return None
319 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000320
321# ---------------------------------------------------- formatter base class
322
323class Doc:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000324
325 PYTHONDOCS = os.environ.get("PYTHONDOCS",
326 "http://docs.python.org/%d.%d/library"
327 % sys.version_info[:2])
328
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000329 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000330 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000331 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000332 # 'try' clause is to attempt to handle the possibility that inspect
333 # identifies something in a way that pydoc itself has issues handling;
334 # think 'super' and how it is a descriptor (which raises the exception
335 # by lacking a __name__ attribute) and an instance.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000336 if inspect.isgetsetdescriptor(object): return self.docdata(*args)
337 if inspect.ismemberdescriptor(object): return self.docdata(*args)
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000338 try:
339 if inspect.ismodule(object): return self.docmodule(*args)
340 if inspect.isclass(object): return self.docclass(*args)
341 if inspect.isroutine(object): return self.docroutine(*args)
342 except AttributeError:
343 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000344 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000345 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000346
347 def fail(self, object, name=None, *args):
348 """Raise an exception for unimplemented types."""
349 message = "don't know how to document object%s of type %s" % (
350 name and ' ' + repr(name), type(object).__name__)
Collin Winterce36ad82007-08-30 01:19:48 +0000351 raise TypeError(message)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000352
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000353 docmodule = docclass = docroutine = docother = docproperty = docdata = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000354
Skip Montanaro4997a692003-09-10 16:47:51 +0000355 def getdocloc(self, object):
356 """Return the location of module docs or None"""
357
358 try:
359 file = inspect.getabsfile(object)
360 except TypeError:
361 file = '(built-in)'
362
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000363 docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
364
Skip Montanaro4997a692003-09-10 16:47:51 +0000365 basedir = os.path.join(sys.exec_prefix, "lib",
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000366 "python%d.%d" % sys.version_info[:2])
Skip Montanaro4997a692003-09-10 16:47:51 +0000367 if (isinstance(object, type(os)) and
368 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
369 'marshal', 'posix', 'signal', 'sys',
Georg Brandl2067bfd2008-05-25 13:05:15 +0000370 '_thread', 'zipimport') or
Skip Montanaro4997a692003-09-10 16:47:51 +0000371 (file.startswith(basedir) and
Brian Curtin49c284c2010-03-31 03:19:28 +0000372 not file.startswith(os.path.join(basedir, 'site-packages')))) and
Brian Curtinedef05b2010-04-01 04:05:25 +0000373 object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
Skip Montanaro4997a692003-09-10 16:47:51 +0000374 if docloc.startswith("http://"):
Georg Brandl86def6c2008-01-21 20:36:10 +0000375 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__)
Skip Montanaro4997a692003-09-10 16:47:51 +0000376 else:
Georg Brandl86def6c2008-01-21 20:36:10 +0000377 docloc = os.path.join(docloc, object.__name__ + ".html")
Skip Montanaro4997a692003-09-10 16:47:51 +0000378 else:
379 docloc = None
380 return docloc
381
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000382# -------------------------------------------- HTML documentation generator
383
384class HTMLRepr(Repr):
385 """Class for safely making an HTML representation of a Python object."""
386 def __init__(self):
387 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000388 self.maxlist = self.maxtuple = 20
389 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000390 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000391
392 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000393 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000394
395 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000396 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000397
398 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000399 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000400 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000401 if hasattr(self, methodname):
402 return getattr(self, methodname)(x, level)
403 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000404
405 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000406 test = cram(x, self.maxstring)
407 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000408 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000409 # Backslashes are only literal in the string and are never
410 # needed to make any special characters, so show a raw string.
411 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000412 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000413 r'<font color="#c040c0">\1</font>',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000414 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000415
Skip Montanarodf708782002-03-07 22:58:02 +0000416 repr_str = repr_string
417
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000418 def repr_instance(self, x, level):
419 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000420 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000421 except:
422 return self.escape('<%s instance>' % x.__class__.__name__)
423
424 repr_unicode = repr_string
425
426class HTMLDoc(Doc):
427 """Formatter class for HTML documentation."""
428
429 # ------------------------------------------- HTML formatting utilities
430
431 _repr_instance = HTMLRepr()
432 repr = _repr_instance.repr
433 escape = _repr_instance.escape
434
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000435 def page(self, title, contents):
436 """Format an HTML page."""
Georg Brandl388faac2009-04-10 08:31:48 +0000437 return '''\
Georg Brandle6066942009-04-10 08:28:28 +0000438<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000439<html><head><title>Python: %s</title>
Georg Brandl388faac2009-04-10 08:31:48 +0000440<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000441</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000442%s
443</body></html>''' % (title, contents)
444
445 def heading(self, title, fgcol, bgcol, extras=''):
446 """Format a page heading."""
447 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000448<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000449<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000450<td valign=bottom>&nbsp;<br>
451<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000452><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000453><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000454 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
455
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000456 def section(self, title, fgcol, bgcol, contents, width=6,
457 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000458 """Format a section with a heading."""
459 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000460 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000461 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000462<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000463<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000464<td colspan=3 valign=bottom>&nbsp;<br>
465<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000466 ''' % (bgcol, fgcol, title)
467 if prelude:
468 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000469<tr bgcolor="%s"><td rowspan=2>%s</td>
470<td colspan=2>%s</td></tr>
471<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
472 else:
473 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000474<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000475
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000476 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000477
478 def bigsection(self, title, *args):
479 """Format a section with a big heading."""
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000480 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000481 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000482
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000483 def preformat(self, text):
484 """Format literal preformatted text."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000485 text = self.escape(text.expandtabs())
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000486 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
487 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000488
489 def multicolumn(self, list, format, cols=4):
490 """Format a list of items into a multi-column list."""
491 result = ''
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000492 rows = (len(list)+cols-1)//cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000493 for col in range(cols):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000494 result = result + '<td width="%d%%" valign=top>' % (100//cols)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000495 for i in range(rows*col, rows*col+rows):
496 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000497 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000498 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000499 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000500
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000501 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000502
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000503 def namelink(self, name, *dicts):
504 """Make a link for an identifier, given name-to-URL mappings."""
505 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000506 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000507 return '<a href="%s">%s</a>' % (dict[name], name)
508 return name
509
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000510 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000511 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000512 name, module = object.__name__, sys.modules.get(object.__module__)
513 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000514 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000515 module.__name__, name, classname(object, modname))
516 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000517
518 def modulelink(self, object):
519 """Make a link for a module."""
520 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
521
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000522 def modpkglink(self, modpkginfo):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000523 """Make a link for a module or package to display in an index."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000524 name, path, ispackage, shadowed = modpkginfo
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000525 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000526 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000527 if path:
528 url = '%s.%s.html' % (path, name)
529 else:
530 url = '%s.html' % name
531 if ispackage:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000532 text = '<strong>%s</strong>&nbsp;(package)' % name
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000533 else:
534 text = name
535 return '<a href="%s">%s</a>' % (url, text)
536
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000537 def filelink(self, url, path):
538 """Make a link to source file."""
539 return '<a href="file:%s">%s</a>' % (url, path)
540
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000541 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
542 """Mark up some plain text, given a context of symbols to look for.
543 Each context dictionary maps object names to anchor names."""
544 escape = escape or self.escape
545 results = []
546 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000547 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
548 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000549 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000550 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000551 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000552 match = pattern.search(text, here)
553 if not match: break
554 start, end = match.span()
555 results.append(escape(text[here:start]))
556
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000557 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000558 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000559 url = escape(all).replace('"', '&quot;')
560 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000561 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000562 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
563 results.append('<a href="%s">%s</a>' % (url, escape(all)))
564 elif pep:
Christian Heimes2202f872008-02-06 14:31:34 +0000565 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000566 results.append('<a href="%s">%s</a>' % (url, escape(all)))
567 elif text[end:end+1] == '(':
568 results.append(self.namelink(name, methods, funcs, classes))
569 elif selfdot:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000570 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000571 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000572 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000573 here = end
574 results.append(escape(text[here:]))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000575 return ''.join(results)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000576
577 # ---------------------------------------------- type-specific routines
578
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000579 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000580 """Produce HTML for a class tree as given by inspect.getclasstree()."""
581 result = ''
582 for entry in tree:
583 if type(entry) is type(()):
584 c, bases = entry
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000585 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000586 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000587 if bases and bases != (parent,):
588 parents = []
589 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000590 parents.append(self.classlink(base, modname))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000591 result = result + '(' + ', '.join(parents) + ')'
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000592 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000593 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000594 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000595 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000596 return '<dl>\n%s</dl>\n' % result
597
Tim Peters8dd7ade2001-10-18 19:56:17 +0000598 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000599 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000600 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000601 try:
602 all = object.__all__
603 except AttributeError:
604 all = None
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000605 parts = name.split('.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000606 links = []
607 for i in range(len(parts)-1):
608 links.append(
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000609 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000610 ('.'.join(parts[:i+1]), parts[i]))
611 linkedname = '.'.join(links + parts[-1:])
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000612 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000613 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000614 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000615 url = path
616 if sys.platform == 'win32':
617 import nturl2path
618 url = nturl2path.pathname2url(path)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000619 filelink = self.filelink(url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000620 except TypeError:
621 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000622 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000623 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000624 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000625 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000626 version = version[11:-1].strip()
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000627 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000628 if hasattr(object, '__date__'):
629 info.append(self.escape(str(object.__date__)))
630 if info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000631 head = head + ' (%s)' % ', '.join(info)
Skip Montanaro4997a692003-09-10 16:47:51 +0000632 docloc = self.getdocloc(object)
633 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000634 docloc = '<br><a href="%(docloc)s">Module Reference</a>' % locals()
Skip Montanaro4997a692003-09-10 16:47:51 +0000635 else:
636 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000637 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000638 head, '#ffffff', '#7799ee',
639 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000640
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000641 modules = inspect.getmembers(object, inspect.ismodule)
642
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000643 classes, cdict = [], {}
644 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000645 # if __all__ exists, believe it. Otherwise use old heuristic.
646 if (all is not None or
647 (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700648 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000649 classes.append((key, value))
650 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000651 for key, value in classes:
652 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000653 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000654 module = sys.modules.get(modname)
655 if modname != name and module and hasattr(module, key):
656 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000657 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000658 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000659 funcs, fdict = [], {}
660 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000661 # if __all__ exists, believe it. Otherwise use old heuristic.
662 if (all is not None or
663 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700664 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000665 funcs.append((key, value))
666 fdict[key] = '#-' + key
667 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000668 data = []
669 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700670 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000671 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000672
673 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
674 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000675 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000676
677 if hasattr(object, '__path__'):
678 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000679 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
680 modpkgs.append((modname, name, ispkg, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000681 modpkgs.sort()
682 contents = self.multicolumn(modpkgs, self.modpkglink)
683 result = result + self.bigsection(
684 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000685 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000686 contents = self.multicolumn(
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000687 modules, lambda t: self.modulelink(t[1]))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000688 result = result + self.bigsection(
Christian Heimes7131fd92008-02-19 14:21:46 +0000689 'Modules', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000690
691 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000692 classlist = [value for (key, value) in classes]
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000693 contents = [
694 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000695 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000696 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000697 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000698 'Classes', '#ffffff', '#ee77aa', ' '.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000699 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000700 contents = []
701 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000702 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000703 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000704 'Functions', '#ffffff', '#eeaa77', ' '.join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000705 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000706 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000707 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000708 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000709 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000710 'Data', '#ffffff', '#55aa55', '<br>\n'.join(contents))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000711 if hasattr(object, '__author__'):
712 contents = self.markup(str(object.__author__), self.preformat)
713 result = result + self.bigsection(
714 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000715 if hasattr(object, '__credits__'):
716 contents = self.markup(str(object.__credits__), self.preformat)
717 result = result + self.bigsection(
718 'Credits', '#ffffff', '#7799ee', contents)
719
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000720 return result
721
Tim Peters8dd7ade2001-10-18 19:56:17 +0000722 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
723 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000724 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000725 realname = object.__name__
726 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000727 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000728
Tim Petersb47879b2001-09-24 04:47:19 +0000729 contents = []
730 push = contents.append
731
Tim Petersfa26f7c2001-09-24 08:05:11 +0000732 # Cute little class to pump out a horizontal rule between sections.
733 class HorizontalRule:
734 def __init__(self):
735 self.needone = 0
736 def maybe(self):
737 if self.needone:
738 push('<hr>\n')
739 self.needone = 1
740 hr = HorizontalRule()
741
Tim Petersc86f6ca2001-09-26 21:31:51 +0000742 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000743 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000744 if len(mro) > 2:
745 hr.maybe()
746 push('<dl><dt>Method resolution order:</dt>\n')
747 for base in mro:
748 push('<dd>%s</dd>\n' % self.classlink(base,
749 object.__module__))
750 push('</dl>\n')
751
Tim Petersb47879b2001-09-24 04:47:19 +0000752 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000753 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000754 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000755 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000756 push(msg)
757 for name, kind, homecls, value in ok:
758 push(self.document(getattr(object, name), name, mod,
759 funcs, classes, mdict, object))
760 push('\n')
761 return attrs
762
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000763 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000764 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000765 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000766 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000767 push(msg)
768 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000769 push(self._docdescriptor(name, value, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000770 return attrs
771
Tim Petersfa26f7c2001-09-24 08:05:11 +0000772 def spilldata(msg, attrs, predicate):
773 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000774 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000775 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000776 push(msg)
777 for name, kind, homecls, value in ok:
778 base = self.docother(getattr(object, name), name, mod)
Guido van Rossumd59da4b2007-05-22 18:11:13 +0000779 if hasattr(value, '__call__') or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000780 doc = getattr(value, "__doc__", None)
781 else:
782 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000783 if doc is None:
784 push('<dl><dt>%s</dl>\n' % base)
785 else:
786 doc = self.markup(getdoc(value), self.preformat,
787 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000788 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000789 push('<dl><dt>%s%s</dl>\n' % (base, doc))
790 push('\n')
791 return attrs
792
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000793 attrs = [(name, kind, cls, value)
794 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -0700795 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000796
Tim Petersb47879b2001-09-24 04:47:19 +0000797 mdict = {}
798 for key, kind, homecls, value in attrs:
799 mdict[key] = anchor = '#' + name + '-' + key
800 value = getattr(object, key)
801 try:
802 # The value may not be hashable (e.g., a data attr with
803 # a dict or list value).
804 mdict[value] = anchor
805 except TypeError:
806 pass
807
Tim Petersfa26f7c2001-09-24 08:05:11 +0000808 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000809 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000810 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000811 else:
812 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000813 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
814
Georg Brandl1a3284e2007-12-02 09:40:06 +0000815 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000816 attrs = inherited
817 continue
818 elif thisclass is object:
819 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000820 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000821 tag = 'inherited from %s' % self.classlink(thisclass,
822 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000823 tag += ':<br>\n'
824
825 # Sort attrs by name.
Raymond Hettingerd4cb56d2008-01-30 02:55:10 +0000826 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000827
828 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000829 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000830 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000831 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000832 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000833 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000834 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000835 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
836 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000837 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000838 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000839 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000840 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000841
842 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000843
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000844 if name == realname:
845 title = '<a name="%s">class <strong>%s</strong></a>' % (
846 name, realname)
847 else:
848 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
849 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000850 if bases:
851 parents = []
852 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000853 parents.append(self.classlink(base, object.__module__))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000854 title = title + '(%s)' % ', '.join(parents)
Tim Peters2306d242001-09-25 03:18:32 +0000855 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000856 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000857
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000858 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000859
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000860 def formatvalue(self, object):
861 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000862 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000863
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000864 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000865 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000866 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000867 realname = object.__name__
868 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000869 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000870 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000871 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000872 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +0000873 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000874 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000875 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000876 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000877 else:
Christian Heimesff737952007-11-27 10:40:20 +0000878 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000879 note = ' method of %s instance' % self.classlink(
Christian Heimesff737952007-11-27 10:40:20 +0000880 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000881 else:
882 note = ' unbound %s method' % self.classlink(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +0000883 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000884
885 if name == realname:
886 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
887 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000888 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000889 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000890 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000891 cl.__name__ + '-' + realname, realname)
892 skipdocs = 1
893 else:
894 reallink = realname
895 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
896 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000897 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +0000898 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann = \
899 inspect.getfullargspec(object)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000900 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +0000901 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann,
902 formatvalue=self.formatvalue,
903 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000904 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000905 title = '<strong>%s</strong> <em>lambda</em> ' % name
Guido van Rossum2e65f892007-02-28 22:03:49 +0000906 # XXX lambda's won't usually have func_annotations['return']
907 # since the syntax doesn't support but it is possible.
908 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000909 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000910 else:
911 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000912
Tim Peters2306d242001-09-25 03:18:32 +0000913 decl = title + argspec + (note and self.grey(
914 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000915
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000916 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000917 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000918 else:
919 doc = self.markup(
920 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000921 doc = doc and '<dd><tt>%s</tt></dd>' % doc
922 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000923
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000924 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000925 results = []
926 push = results.append
927
928 if name:
929 push('<dl><dt><strong>%s</strong></dt>\n' % name)
930 if value.__doc__ is not None:
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +0000931 doc = self.markup(getdoc(value), self.preformat)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000932 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000933 push('</dl>\n')
934
935 return ''.join(results)
936
937 def docproperty(self, object, name=None, mod=None, cl=None):
938 """Produce html documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000939 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000940
Tim Peters8dd7ade2001-10-18 19:56:17 +0000941 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000942 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000943 lhs = name and '<strong>%s</strong> = ' % name or ''
944 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000945
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000946 def docdata(self, object, name=None, mod=None, cl=None):
947 """Produce html documentation for a data descriptor."""
948 return self._docdescriptor(name, object, mod)
949
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000950 def index(self, dir, shadowed=None):
951 """Generate an HTML index for a directory of modules."""
952 modpkgs = []
953 if shadowed is None: shadowed = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000954 for importer, name, ispkg in pkgutil.iter_modules([dir]):
Victor Stinner4d652242011-04-12 23:41:50 +0200955 if any((0xD800 <= ord(ch) <= 0xDFFF) for ch in name):
956 # ignore a module if its name contains a surrogate character
957 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000958 modpkgs.append((name, '', ispkg, name in shadowed))
959 shadowed[name] = 1
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000960
961 modpkgs.sort()
962 contents = self.multicolumn(modpkgs, self.modpkglink)
963 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
964
965# -------------------------------------------- text documentation generator
966
967class TextRepr(Repr):
968 """Class for safely making a text representation of a Python object."""
969 def __init__(self):
970 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000971 self.maxlist = self.maxtuple = 20
972 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000973 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000974
975 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000976 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000977 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000978 if hasattr(self, methodname):
979 return getattr(self, methodname)(x, level)
980 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000981
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000982 def repr_string(self, x, level):
983 test = cram(x, self.maxstring)
984 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000985 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000986 # Backslashes are only literal in the string and are never
987 # needed to make any special characters, so show a raw string.
988 return 'r' + testrepr[0] + test + testrepr[0]
989 return testrepr
990
Skip Montanarodf708782002-03-07 22:58:02 +0000991 repr_str = repr_string
992
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000993 def repr_instance(self, x, level):
994 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000995 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000996 except:
997 return '<%s instance>' % x.__class__.__name__
998
999class TextDoc(Doc):
1000 """Formatter class for text documentation."""
1001
1002 # ------------------------------------------- text formatting utilities
1003
1004 _repr_instance = TextRepr()
1005 repr = _repr_instance.repr
1006
1007 def bold(self, text):
1008 """Format a string in bold by overstriking."""
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001009 return ''.join(ch + '\b' + ch for ch in text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001010
1011 def indent(self, text, prefix=' '):
1012 """Indent text by prepending a given prefix to each line."""
1013 if not text: return ''
Collin Winter72e110c2007-07-17 00:27:30 +00001014 lines = [prefix + line for line in text.split('\n')]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001015 if lines: lines[-1] = lines[-1].rstrip()
1016 return '\n'.join(lines)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001017
1018 def section(self, title, contents):
1019 """Format a section with a given heading."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001020 clean_contents = self.indent(contents).rstrip()
1021 return self.bold(title) + '\n' + clean_contents + '\n\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001022
1023 # ---------------------------------------------- type-specific routines
1024
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001025 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001026 """Render in text a class tree as returned by inspect.getclasstree()."""
1027 result = ''
1028 for entry in tree:
1029 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001030 c, bases = entry
1031 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001032 if bases and bases != (parent,):
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001033 parents = (classname(c, modname) for c in bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001034 result = result + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001035 result = result + '\n'
1036 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001037 result = result + self.formattree(
1038 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001039 return result
1040
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001041 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001042 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001043 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001044 synop, desc = splitdoc(getdoc(object))
1045 result = self.section('NAME', name + (synop and ' - ' + synop))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001046 all = getattr(object, '__all__', None)
Skip Montanaro4997a692003-09-10 16:47:51 +00001047 docloc = self.getdocloc(object)
1048 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001049 result = result + self.section('MODULE REFERENCE', docloc + """
1050
1051The following documentation is automatically generated from the Python source
1052files. It may be incomplete, incorrect or include features that are considered
1053implementation detail and may vary between Python implementations. When in
1054doubt, consult the module reference at the location listed above.
1055""")
Skip Montanaro4997a692003-09-10 16:47:51 +00001056
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001057 if desc:
1058 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001059
1060 classes = []
1061 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001062 # if __all__ exists, believe it. Otherwise use old heuristic.
1063 if (all is not None
1064 or (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001065 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001066 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001067 funcs = []
1068 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001069 # if __all__ exists, believe it. Otherwise use old heuristic.
1070 if (all is not None or
1071 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001072 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001073 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001074 data = []
1075 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001076 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001077 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001078
Christian Heimes1af737c2008-01-23 08:24:23 +00001079 modpkgs = []
1080 modpkgs_names = set()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001081 if hasattr(object, '__path__'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001082 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
Christian Heimes1af737c2008-01-23 08:24:23 +00001083 modpkgs_names.add(modname)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001084 if ispkg:
1085 modpkgs.append(modname + ' (package)')
1086 else:
1087 modpkgs.append(modname)
1088
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001089 modpkgs.sort()
1090 result = result + self.section(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001091 'PACKAGE CONTENTS', '\n'.join(modpkgs))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001092
Christian Heimes1af737c2008-01-23 08:24:23 +00001093 # Detect submodules as sometimes created by C extensions
1094 submodules = []
1095 for key, value in inspect.getmembers(object, inspect.ismodule):
1096 if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1097 submodules.append(key)
1098 if submodules:
1099 submodules.sort()
1100 result = result + self.section(
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001101 'SUBMODULES', '\n'.join(submodules))
Christian Heimes1af737c2008-01-23 08:24:23 +00001102
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001103 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001104 classlist = [value for key, value in classes]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001105 contents = [self.formattree(
1106 inspect.getclasstree(classlist, 1), name)]
1107 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001108 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001109 result = result + self.section('CLASSES', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001110
1111 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001112 contents = []
1113 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001114 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001115 result = result + self.section('FUNCTIONS', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001116
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001117 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001118 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001119 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001120 contents.append(self.docother(value, key, name, maxlen=70))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001121 result = result + self.section('DATA', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001122
1123 if hasattr(object, '__version__'):
1124 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001125 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001126 version = version[11:-1].strip()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001127 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001128 if hasattr(object, '__date__'):
1129 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001130 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001131 result = result + self.section('AUTHOR', str(object.__author__))
1132 if hasattr(object, '__credits__'):
1133 result = result + self.section('CREDITS', str(object.__credits__))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001134 try:
1135 file = inspect.getabsfile(object)
1136 except TypeError:
1137 file = '(built-in)'
1138 result = result + self.section('FILE', file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001139 return result
1140
Georg Brandl9bd45f992010-12-03 09:58:38 +00001141 def docclass(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001142 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001143 realname = object.__name__
1144 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001145 bases = object.__bases__
1146
Tim Petersc86f6ca2001-09-26 21:31:51 +00001147 def makename(c, m=object.__module__):
1148 return classname(c, m)
1149
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001150 if name == realname:
1151 title = 'class ' + self.bold(realname)
1152 else:
1153 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001154 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001155 parents = map(makename, bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001156 title = title + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001157
1158 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001159 contents = doc and [doc + '\n'] or []
1160 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001161
Tim Petersc86f6ca2001-09-26 21:31:51 +00001162 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001163 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001164 if len(mro) > 2:
1165 push("Method resolution order:")
1166 for base in mro:
1167 push(' ' + makename(base))
1168 push('')
1169
Tim Petersf4aad8e2001-09-24 22:40:47 +00001170 # Cute little class to pump out a horizontal rule between sections.
1171 class HorizontalRule:
1172 def __init__(self):
1173 self.needone = 0
1174 def maybe(self):
1175 if self.needone:
1176 push('-' * 70)
1177 self.needone = 1
1178 hr = HorizontalRule()
1179
Tim Peters28355492001-09-23 21:29:55 +00001180 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001181 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001182 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001183 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001184 push(msg)
1185 for name, kind, homecls, value in ok:
1186 push(self.document(getattr(object, name),
1187 name, mod, object))
1188 return attrs
1189
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001190 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001191 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001192 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001193 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001194 push(msg)
1195 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001196 push(self._docdescriptor(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001197 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001198
Tim Petersfa26f7c2001-09-24 08:05:11 +00001199 def spilldata(msg, attrs, predicate):
1200 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001201 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001202 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001203 push(msg)
1204 for name, kind, homecls, value in ok:
Guido van Rossumd59da4b2007-05-22 18:11:13 +00001205 if hasattr(value, '__call__') or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001206 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001207 else:
1208 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001209 push(self.docother(getattr(object, name),
Georg Brandl8b813db2005-10-01 16:32:31 +00001210 name, mod, maxlen=70, doc=doc) + '\n')
Tim Peters28355492001-09-23 21:29:55 +00001211 return attrs
1212
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001213 attrs = [(name, kind, cls, value)
1214 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -07001215 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001216
Tim Petersfa26f7c2001-09-24 08:05:11 +00001217 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001218 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001219 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001220 else:
1221 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001222 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1223
Georg Brandl1a3284e2007-12-02 09:40:06 +00001224 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001225 attrs = inherited
1226 continue
1227 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001228 tag = "defined here"
1229 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001230 tag = "inherited from %s" % classname(thisclass,
1231 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001232
1233 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001234 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001235
1236 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001237 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001238 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001239 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001240 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001241 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001242 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001243 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1244 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001245 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1246 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001247 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001248 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001249
1250 contents = '\n'.join(contents)
1251 if not contents:
1252 return title + '\n'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001253 return title + '\n' + self.indent(contents.rstrip(), ' | ') + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001254
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001255 def formatvalue(self, object):
1256 """Format an argument default value as text."""
1257 return '=' + self.repr(object)
1258
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001259 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001260 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001261 realname = object.__name__
1262 name = name or realname
1263 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001264 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001265 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +00001266 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001267 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001268 if imclass is not cl:
1269 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001270 else:
Christian Heimesff737952007-11-27 10:40:20 +00001271 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001272 note = ' method of %s instance' % classname(
Christian Heimesff737952007-11-27 10:40:20 +00001273 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001274 else:
1275 note = ' unbound %s method' % classname(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +00001276 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001277
1278 if name == realname:
1279 title = self.bold(realname)
1280 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001281 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001282 cl.__dict__[realname] is object):
1283 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001284 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001285 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +00001286 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann = \
1287 inspect.getfullargspec(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001288 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +00001289 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann,
1290 formatvalue=self.formatvalue,
1291 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001292 if realname == '<lambda>':
Georg Brandl501dd0d2006-02-17 09:45:40 +00001293 title = self.bold(name) + ' lambda '
Guido van Rossum2e65f892007-02-28 22:03:49 +00001294 # XXX lambda's won't usually have func_annotations['return']
1295 # since the syntax doesn't support but it is possible.
1296 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001297 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001298 else:
1299 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001300 decl = title + argspec + note
1301
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001302 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001303 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001304 else:
1305 doc = getdoc(object) or ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001306 return decl + '\n' + (doc and self.indent(doc).rstrip() + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001307
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001308 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001309 results = []
1310 push = results.append
1311
1312 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001313 push(self.bold(name))
1314 push('\n')
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001315 doc = getdoc(value) or ''
1316 if doc:
1317 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001318 push('\n')
1319 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001320
1321 def docproperty(self, object, name=None, mod=None, cl=None):
1322 """Produce text documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001323 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001324
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001325 def docdata(self, object, name=None, mod=None, cl=None):
1326 """Produce text documentation for a data descriptor."""
1327 return self._docdescriptor(name, object, mod)
1328
Georg Brandl8b813db2005-10-01 16:32:31 +00001329 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001330 """Produce text documentation for a data object."""
1331 repr = self.repr(object)
1332 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001333 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001334 chop = maxlen - len(line)
1335 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001336 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001337 if doc is not None:
1338 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001339 return line
1340
Georg Brandld80d5f42010-12-03 07:47:22 +00001341class _PlainTextDoc(TextDoc):
1342 """Subclass of TextDoc which overrides string styling"""
1343 def bold(self, text):
1344 return text
1345
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001346# --------------------------------------------------------- user interfaces
1347
1348def pager(text):
1349 """The first time this is called, determine what kind of pager to use."""
1350 global pager
1351 pager = getpager()
1352 pager(text)
1353
1354def getpager():
1355 """Decide what method to use for paging through text."""
Guido van Rossuma01a8b62007-05-27 09:20:14 +00001356 if not hasattr(sys.stdout, "isatty"):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001357 return plainpager
1358 if not sys.stdin.isatty() or not sys.stdout.isatty():
1359 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001360 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001361 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001362 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001363 elif os.environ.get('TERM') in ('dumb', 'emacs'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001364 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001365 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001366 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001367 if os.environ.get('TERM') in ('dumb', 'emacs'):
1368 return plainpager
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001369 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001370 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001371 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001372 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001373
1374 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001375 (fd, filename) = tempfile.mkstemp()
1376 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001377 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001378 if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001379 return lambda text: pipepager(text, 'more')
1380 else:
1381 return ttypager
1382 finally:
1383 os.unlink(filename)
1384
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001385def plain(text):
1386 """Remove boldface formatting from text."""
1387 return re.sub('.\b', '', text)
1388
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001389def pipepager(text, cmd):
1390 """Page through text by feeding it to another program."""
1391 pipe = os.popen(cmd, 'w')
1392 try:
1393 pipe.write(text)
1394 pipe.close()
1395 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001396 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001397
1398def tempfilepager(text, cmd):
1399 """Page through text by invoking a program on a temporary file."""
1400 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001401 filename = tempfile.mktemp()
1402 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001403 file.write(text)
1404 file.close()
1405 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001406 os.system(cmd + ' "' + filename + '"')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001407 finally:
1408 os.unlink(filename)
1409
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001410def ttypager(text):
1411 """Page through text on a text terminal."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001412 lines = plain(text).split('\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001413 try:
1414 import tty
1415 fd = sys.stdin.fileno()
1416 old = tty.tcgetattr(fd)
1417 tty.setcbreak(fd)
1418 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001419 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001420 tty = None
1421 getchar = lambda: sys.stdin.readline()[:-1][:1]
1422
1423 try:
1424 r = inc = os.environ.get('LINES', 25) - 1
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001425 sys.stdout.write('\n'.join(lines[:inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001426 while lines[r:]:
1427 sys.stdout.write('-- more --')
1428 sys.stdout.flush()
1429 c = getchar()
1430
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001431 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001432 sys.stdout.write('\r \r')
1433 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001434 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001435 sys.stdout.write('\r \r' + lines[r] + '\n')
1436 r = r + 1
1437 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001438 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001439 r = r - inc - inc
1440 if r < 0: r = 0
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001441 sys.stdout.write('\n' + '\n'.join(lines[r:r+inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001442 r = r + inc
1443
1444 finally:
1445 if tty:
1446 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1447
1448def plainpager(text):
1449 """Simply print unformatted text. This is the ultimate fallback."""
1450 sys.stdout.write(plain(text))
1451
1452def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001453 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001454 if inspect.ismodule(thing):
1455 if thing.__name__ in sys.builtin_module_names:
1456 return 'built-in module ' + thing.__name__
1457 if hasattr(thing, '__path__'):
1458 return 'package ' + thing.__name__
1459 else:
1460 return 'module ' + thing.__name__
1461 if inspect.isbuiltin(thing):
1462 return 'built-in function ' + thing.__name__
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001463 if inspect.isgetsetdescriptor(thing):
1464 return 'getset descriptor %s.%s.%s' % (
1465 thing.__objclass__.__module__, thing.__objclass__.__name__,
1466 thing.__name__)
1467 if inspect.ismemberdescriptor(thing):
1468 return 'member descriptor %s.%s.%s' % (
1469 thing.__objclass__.__module__, thing.__objclass__.__name__,
1470 thing.__name__)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001471 if inspect.isclass(thing):
1472 return 'class ' + thing.__name__
1473 if inspect.isfunction(thing):
1474 return 'function ' + thing.__name__
1475 if inspect.ismethod(thing):
1476 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001477 return type(thing).__name__
1478
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001479def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001480 """Locate an object by name or dotted path, importing as necessary."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001481 parts = [part for part in path.split('.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001482 module, n = None, 0
1483 while n < len(parts):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001484 nextmodule = safeimport('.'.join(parts[:n+1]), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001485 if nextmodule: module, n = nextmodule, n + 1
1486 else: break
1487 if module:
1488 object = module
1489 for part in parts[n:]:
1490 try: object = getattr(object, part)
1491 except AttributeError: return None
1492 return object
1493 else:
Georg Brandl1a3284e2007-12-02 09:40:06 +00001494 if hasattr(builtins, path):
1495 return getattr(builtins, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001496
1497# --------------------------------------- interactive interpreter interface
1498
1499text = TextDoc()
Georg Brandld80d5f42010-12-03 07:47:22 +00001500plaintext = _PlainTextDoc()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001501html = HTMLDoc()
1502
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001503def resolve(thing, forceload=0):
1504 """Given an object or a path to an object, get the object and its name."""
1505 if isinstance(thing, str):
1506 object = locate(thing, forceload)
1507 if not object:
Collin Winterce36ad82007-08-30 01:19:48 +00001508 raise ImportError('no Python documentation found for %r' % thing)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001509 return object, thing
1510 else:
1511 return thing, getattr(thing, '__name__', None)
1512
Georg Brandld80d5f42010-12-03 07:47:22 +00001513def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
1514 renderer=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001515 """Render text documentation, given an object or a path to an object."""
Georg Brandld80d5f42010-12-03 07:47:22 +00001516 if renderer is None:
1517 renderer = text
Guido van Rossumd8faa362007-04-27 19:54:29 +00001518 object, name = resolve(thing, forceload)
1519 desc = describe(object)
1520 module = inspect.getmodule(object)
1521 if name and '.' in name:
1522 desc += ' in ' + name[:name.rfind('.')]
1523 elif module and module is not object:
1524 desc += ' in module ' + module.__name__
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001525
1526 if not (inspect.ismodule(object) or
Guido van Rossumd8faa362007-04-27 19:54:29 +00001527 inspect.isclass(object) or
1528 inspect.isroutine(object) or
1529 inspect.isgetsetdescriptor(object) or
1530 inspect.ismemberdescriptor(object) or
1531 isinstance(object, property)):
1532 # If the passed object is a piece of data or an instance,
1533 # document its available methods instead of its value.
1534 object = type(object)
1535 desc += ' object'
Georg Brandld80d5f42010-12-03 07:47:22 +00001536 return title % desc + '\n\n' + renderer.document(object, name)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001537
Georg Brandld80d5f42010-12-03 07:47:22 +00001538def doc(thing, title='Python Library Documentation: %s', forceload=0,
1539 output=None):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001540 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001541 try:
Georg Brandld80d5f42010-12-03 07:47:22 +00001542 if output is None:
1543 pager(render_doc(thing, title, forceload))
1544 else:
1545 output.write(render_doc(thing, title, forceload, plaintext))
Guido van Rossumb940e112007-01-10 16:19:56 +00001546 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001547 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001548
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001549def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001550 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001551 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001552 object, name = resolve(thing, forceload)
1553 page = html.page(describe(object), html.document(object, name))
Georg Brandl388faac2009-04-10 08:31:48 +00001554 file = open(name + '.html', 'w', encoding='utf-8')
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001555 file.write(page)
1556 file.close()
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001557 print('wrote', name + '.html')
Guido van Rossumb940e112007-01-10 16:19:56 +00001558 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001559 print(value)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001560
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001561def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001562 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001563 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001564 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1565 writedoc(modname)
1566 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001567
1568class Helper:
Georg Brandl6b38daa2008-06-01 21:05:17 +00001569
1570 # These dictionaries map a topic name to either an alias, or a tuple
1571 # (label, seealso-items). The "label" is the label of the corresponding
1572 # section in the .rst file under Doc/ and an index into the dictionary
Georg Brandl5617db82009-04-27 16:28:57 +00001573 # in pydoc_data/topics.py.
Georg Brandl6b38daa2008-06-01 21:05:17 +00001574 #
1575 # CAUTION: if you change one of these dictionaries, be sure to adapt the
1576 # list of needed labels in Doc/tools/sphinxext/pyspecific.py and
Georg Brandl5617db82009-04-27 16:28:57 +00001577 # regenerate the pydoc_data/topics.py file by running
Georg Brandl6b38daa2008-06-01 21:05:17 +00001578 # make pydoc-topics
1579 # in Doc/ and copying the output file into the Lib/ directory.
1580
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001581 keywords = {
Ezio Melottib185a042011-04-28 07:42:55 +03001582 'False': '',
1583 'None': '',
1584 'True': '',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001585 'and': 'BOOLEAN',
Guido van Rossumd8faa362007-04-27 19:54:29 +00001586 'as': 'with',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001587 'assert': ('assert', ''),
1588 'break': ('break', 'while for'),
1589 'class': ('class', 'CLASSES SPECIALMETHODS'),
1590 'continue': ('continue', 'while for'),
1591 'def': ('function', ''),
1592 'del': ('del', 'BASICMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001593 'elif': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001594 'else': ('else', 'while for'),
Georg Brandl0d855392008-08-30 19:53:05 +00001595 'except': 'try',
1596 'finally': 'try',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001597 'for': ('for', 'break continue while'),
Georg Brandl0d855392008-08-30 19:53:05 +00001598 'from': 'import',
Georg Brandl74abf6f2010-11-20 19:54:36 +00001599 'global': ('global', 'nonlocal NAMESPACES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001600 'if': ('if', 'TRUTHVALUE'),
1601 'import': ('import', 'MODULES'),
Georg Brandl395ed242009-09-04 08:07:32 +00001602 'in': ('in', 'SEQUENCEMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001603 'is': 'COMPARISON',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001604 'lambda': ('lambda', 'FUNCTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001605 'nonlocal': ('nonlocal', 'global NAMESPACES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001606 'not': 'BOOLEAN',
1607 'or': 'BOOLEAN',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001608 'pass': ('pass', ''),
1609 'raise': ('raise', 'EXCEPTIONS'),
1610 'return': ('return', 'FUNCTIONS'),
1611 'try': ('try', 'EXCEPTIONS'),
1612 'while': ('while', 'break continue if TRUTHVALUE'),
1613 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1614 'yield': ('yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001615 }
Georg Brandldb7b6b92009-01-01 15:53:14 +00001616 # Either add symbols to this dictionary or to the symbols dictionary
1617 # directly: Whichever is easier. They are merged later.
1618 _symbols_inverse = {
1619 'STRINGS' : ("'", "'''", "r'", "b'", '"""', '"', 'r"', 'b"'),
1620 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1621 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1622 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1623 'UNARY' : ('-', '~'),
1624 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1625 '^=', '<<=', '>>=', '**=', '//='),
1626 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1627 'COMPLEX' : ('j', 'J')
1628 }
1629 symbols = {
1630 '%': 'OPERATORS FORMATTING',
1631 '**': 'POWER',
1632 ',': 'TUPLES LISTS FUNCTIONS',
1633 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1634 '...': 'ELLIPSIS',
1635 ':': 'SLICINGS DICTIONARYLITERALS',
1636 '@': 'def class',
1637 '\\': 'STRINGS',
1638 '_': 'PRIVATENAMES',
1639 '__': 'PRIVATENAMES SPECIALMETHODS',
1640 '`': 'BACKQUOTES',
1641 '(': 'TUPLES FUNCTIONS CALLS',
1642 ')': 'TUPLES FUNCTIONS CALLS',
1643 '[': 'LISTS SUBSCRIPTS SLICINGS',
1644 ']': 'LISTS SUBSCRIPTS SLICINGS'
1645 }
1646 for topic, symbols_ in _symbols_inverse.items():
1647 for symbol in symbols_:
1648 topics = symbols.get(symbol, topic)
1649 if topic not in topics:
1650 topics = topics + ' ' + topic
1651 symbols[symbol] = topics
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001652
1653 topics = {
Georg Brandl6b38daa2008-06-01 21:05:17 +00001654 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1655 'FUNCTIONS CLASSES MODULES FILES inspect'),
1656 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
1657 'FORMATTING TYPES'),
1658 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1659 'FORMATTING': ('formatstrings', 'OPERATORS'),
1660 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1661 'FORMATTING TYPES'),
1662 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1663 'INTEGER': ('integers', 'int range'),
1664 'FLOAT': ('floating', 'float math'),
1665 'COMPLEX': ('imaginary', 'complex cmath'),
1666 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001667 'MAPPINGS': 'DICTIONARIES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001668 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1669 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1670 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1671 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001672 'FRAMEOBJECTS': 'TYPES',
1673 'TRACEBACKS': 'TYPES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001674 'NONE': ('bltin-null-object', ''),
1675 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
1676 'FILES': ('bltin-file-objects', ''),
1677 'SPECIALATTRIBUTES': ('specialattrs', ''),
1678 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1679 'MODULES': ('typesmodules', 'import'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001680 'PACKAGES': 'import',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001681 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1682 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1683 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1684 'LISTS DICTIONARIES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001685 'OPERATORS': 'EXPRESSIONS',
1686 'PRECEDENCE': 'EXPRESSIONS',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001687 'OBJECTS': ('objects', 'TYPES'),
1688 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
Georg Brandl395ed242009-09-04 08:07:32 +00001689 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
1690 'NUMBERMETHODS CLASSES'),
Mark Dickinsona56c4672009-01-27 18:17:45 +00001691 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001692 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1693 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001694 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
Georg Brandl6b38daa2008-06-01 21:05:17 +00001695 'SPECIALMETHODS'),
1696 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1697 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1698 'SPECIALMETHODS'),
1699 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001700 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001701 'DYNAMICFEATURES': ('dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001702 'SCOPING': 'NAMESPACES',
1703 'FRAMES': 'NAMESPACES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001704 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1705 'CONVERSIONS': ('conversions', ''),
1706 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1707 'SPECIALIDENTIFIERS': ('id-classes', ''),
1708 'PRIVATENAMES': ('atom-identifiers', ''),
1709 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
1710 'LISTLITERALS DICTIONARYLITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001711 'TUPLES': 'SEQUENCES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001712 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1713 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1714 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1715 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1716 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1717 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001718 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
1719 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001720 'CALLS': ('calls', 'EXPRESSIONS'),
1721 'POWER': ('power', 'EXPRESSIONS'),
1722 'UNARY': ('unary', 'EXPRESSIONS'),
1723 'BINARY': ('binary', 'EXPRESSIONS'),
1724 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1725 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1726 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1727 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001728 'ASSERTION': 'assert',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001729 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1730 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001731 'DELETION': 'del',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001732 'RETURNING': 'return',
1733 'IMPORTING': 'import',
1734 'CONDITIONAL': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001735 'LOOPING': ('compound', 'for while break continue'),
1736 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1737 'DEBUGGING': ('debugger', 'pdb'),
1738 'CONTEXTMANAGERS': ('context-managers', 'with'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001739 }
1740
Georg Brandl78aa3962010-07-31 21:51:48 +00001741 def __init__(self, input=None, output=None):
1742 self._input = input
1743 self._output = output
1744
Georg Brandl76ae3972010-08-01 06:32:55 +00001745 input = property(lambda self: self._input or sys.stdin)
1746 output = property(lambda self: self._output or sys.stdout)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001747
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001748 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001749 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001750 self()
1751 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001752 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001753
Alexander Belopolsky2e733c92010-07-04 17:00:20 +00001754 _GoInteractive = object()
1755 def __call__(self, request=_GoInteractive):
1756 if request is not self._GoInteractive:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001757 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001758 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001759 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001760 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001761 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001762You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001763If you want to ask for help on a particular object directly from the
1764interpreter, you can type "help(object)". Executing "help('string')"
1765has the same effect as typing a particular string at the help> prompt.
1766''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001767
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001768 def interact(self):
1769 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001770 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001771 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001772 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001773 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001774 except (KeyboardInterrupt, EOFError):
1775 break
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001776 request = replace(request, '"', '', "'", '').strip()
1777 if request.lower() in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001778 self.help(request)
1779
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001780 def getline(self, prompt):
Guido van Rossum7c086c02008-01-02 03:52:38 +00001781 """Read one line, using input() when appropriate."""
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001782 if self.input is sys.stdin:
Guido van Rossum7c086c02008-01-02 03:52:38 +00001783 return input(prompt)
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001784 else:
1785 self.output.write(prompt)
1786 self.output.flush()
1787 return self.input.readline()
1788
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001789 def help(self, request):
1790 if type(request) is type(''):
R. David Murray1f1b9d32009-05-27 20:56:59 +00001791 request = request.strip()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001792 if request == 'help': self.intro()
1793 elif request == 'keywords': self.listkeywords()
Georg Brandldb7b6b92009-01-01 15:53:14 +00001794 elif request == 'symbols': self.listsymbols()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001795 elif request == 'topics': self.listtopics()
1796 elif request == 'modules': self.listmodules()
1797 elif request[:8] == 'modules ':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001798 self.listmodules(request.split()[1])
Georg Brandldb7b6b92009-01-01 15:53:14 +00001799 elif request in self.symbols: self.showsymbol(request)
Ezio Melottib185a042011-04-28 07:42:55 +03001800 elif request in ['True', 'False', 'None']:
1801 # special case these keywords since they are objects too
1802 doc(eval(request), 'Help on %s:')
Raymond Hettinger54f02222002-06-01 14:18:47 +00001803 elif request in self.keywords: self.showtopic(request)
1804 elif request in self.topics: self.showtopic(request)
Georg Brandld80d5f42010-12-03 07:47:22 +00001805 elif request: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001806 elif isinstance(request, Helper): self()
Georg Brandld80d5f42010-12-03 07:47:22 +00001807 else: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001808 self.output.write('\n')
1809
1810 def intro(self):
1811 self.output.write('''
1812Welcome to Python %s! This is the online help utility.
1813
1814If this is your first time using Python, you should definitely check out
Georg Brandl86def6c2008-01-21 20:36:10 +00001815the tutorial on the Internet at http://docs.python.org/tutorial/.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001816
1817Enter the name of any module, keyword, or topic to get help on writing
1818Python programs and using Python modules. To quit this help utility and
1819return to the interpreter, just type "quit".
1820
1821To get a list of available modules, keywords, or topics, type "modules",
1822"keywords", or "topics". Each module also comes with a one-line summary
1823of what it does; to list the modules whose summaries contain a given word
1824such as "spam", type "modules spam".
1825''' % sys.version[:3])
1826
1827 def list(self, items, columns=4, width=80):
Guido van Rossum486364b2007-06-30 05:01:58 +00001828 items = list(sorted(items))
1829 colw = width // columns
1830 rows = (len(items) + columns - 1) // columns
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001831 for row in range(rows):
1832 for col in range(columns):
1833 i = col * rows + row
1834 if i < len(items):
1835 self.output.write(items[i])
1836 if col < columns - 1:
Guido van Rossum486364b2007-06-30 05:01:58 +00001837 self.output.write(' ' + ' ' * (colw - 1 - len(items[i])))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001838 self.output.write('\n')
1839
1840 def listkeywords(self):
1841 self.output.write('''
1842Here is a list of the Python keywords. Enter any keyword to get more help.
1843
1844''')
1845 self.list(self.keywords.keys())
1846
Georg Brandldb7b6b92009-01-01 15:53:14 +00001847 def listsymbols(self):
1848 self.output.write('''
1849Here is a list of the punctuation symbols which Python assigns special meaning
1850to. Enter any symbol to get more help.
1851
1852''')
1853 self.list(self.symbols.keys())
1854
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001855 def listtopics(self):
1856 self.output.write('''
1857Here is a list of available topics. Enter any topic name to get more help.
1858
1859''')
1860 self.list(self.topics.keys())
1861
Georg Brandldb7b6b92009-01-01 15:53:14 +00001862 def showtopic(self, topic, more_xrefs=''):
Georg Brandl6b38daa2008-06-01 21:05:17 +00001863 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001864 import pydoc_data.topics
Georg Brandl6b38daa2008-06-01 21:05:17 +00001865 except ImportError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001866 self.output.write('''
Georg Brandl6b38daa2008-06-01 21:05:17 +00001867Sorry, topic and keyword documentation is not available because the
Georg Brandl5617db82009-04-27 16:28:57 +00001868module "pydoc_data.topics" could not be found.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001869''')
1870 return
1871 target = self.topics.get(topic, self.keywords.get(topic))
1872 if not target:
1873 self.output.write('no documentation found for %s\n' % repr(topic))
1874 return
1875 if type(target) is type(''):
Georg Brandldb7b6b92009-01-01 15:53:14 +00001876 return self.showtopic(target, more_xrefs)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001877
Georg Brandl6b38daa2008-06-01 21:05:17 +00001878 label, xrefs = target
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001879 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001880 doc = pydoc_data.topics.topics[label]
Georg Brandl6b38daa2008-06-01 21:05:17 +00001881 except KeyError:
1882 self.output.write('no documentation found for %s\n' % repr(topic))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001883 return
Georg Brandl6b38daa2008-06-01 21:05:17 +00001884 pager(doc.strip() + '\n')
Georg Brandldb7b6b92009-01-01 15:53:14 +00001885 if more_xrefs:
1886 xrefs = (xrefs or '') + ' ' + more_xrefs
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001887 if xrefs:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001888 import formatter
Guido van Rossum34d19282007-08-09 01:03:29 +00001889 buffer = io.StringIO()
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001890 formatter.DumbWriter(buffer).send_flowing_data(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001891 'Related help topics: ' + ', '.join(xrefs.split()) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001892 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001893
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001894 def _gettopic(self, topic, more_xrefs=''):
1895 """Return unbuffered tuple of (topic, xrefs).
1896
Georg Brandld2f38572011-01-30 08:37:19 +00001897 If an error occurs here, the exception is caught and displayed by
1898 the url handler.
1899
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001900 This function duplicates the showtopic method but returns its
1901 result directly so it can be formatted for display in an html page.
1902 """
1903 try:
1904 import pydoc_data.topics
1905 except ImportError:
1906 return('''
1907Sorry, topic and keyword documentation is not available because the
1908module "pydoc_data.topics" could not be found.
1909''' , '')
1910 target = self.topics.get(topic, self.keywords.get(topic))
1911 if not target:
Georg Brandld2f38572011-01-30 08:37:19 +00001912 raise ValueError('could not find topic')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001913 if isinstance(target, str):
1914 return self._gettopic(target, more_xrefs)
1915 label, xrefs = target
Georg Brandld2f38572011-01-30 08:37:19 +00001916 doc = pydoc_data.topics.topics[label]
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001917 if more_xrefs:
1918 xrefs = (xrefs or '') + ' ' + more_xrefs
1919 return doc, xrefs
1920
Georg Brandldb7b6b92009-01-01 15:53:14 +00001921 def showsymbol(self, symbol):
1922 target = self.symbols[symbol]
1923 topic, _, xrefs = target.partition(' ')
1924 self.showtopic(topic, xrefs)
1925
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001926 def listmodules(self, key=''):
1927 if key:
1928 self.output.write('''
1929Here is a list of matching modules. Enter any module name to get more help.
1930
1931''')
1932 apropos(key)
1933 else:
1934 self.output.write('''
1935Please wait a moment while I gather a list of all available modules...
1936
1937''')
1938 modules = {}
1939 def callback(path, modname, desc, modules=modules):
1940 if modname and modname[-9:] == '.__init__':
1941 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001942 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001943 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001944 def onerror(modname):
1945 callback(None, modname, None)
1946 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001947 self.list(modules.keys())
1948 self.output.write('''
1949Enter any module name to get more help. Or, type "modules spam" to search
1950for modules whose descriptions contain the word "spam".
1951''')
1952
Georg Brandl78aa3962010-07-31 21:51:48 +00001953help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001954
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001955class Scanner:
1956 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001957 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001958 self.roots = roots[:]
1959 self.state = []
1960 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001961 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001962
1963 def next(self):
1964 if not self.state:
1965 if not self.roots:
1966 return None
1967 root = self.roots.pop(0)
1968 self.state = [(root, self.children(root))]
1969 node, children = self.state[-1]
1970 if not children:
1971 self.state.pop()
1972 return self.next()
1973 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001974 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001975 self.state.append((child, self.children(child)))
1976 return child
1977
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001978
1979class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001980 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001981
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001982 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001983 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001984 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001985 seen = {}
1986
1987 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001988 if modname != '__main__':
1989 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001990 if key is None:
1991 callback(None, modname, '')
1992 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001993 name = __import__(modname).__doc__ or ''
1994 desc = name.split('\n')[0]
1995 name = modname + ' - ' + desc
1996 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001997 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001998
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001999 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002000 if self.quit:
2001 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002002
2003 # XXX Skipping this file is a workaround for a bug
2004 # that causes python to crash with a segfault.
2005 # http://bugs.python.org/issue9319
2006 #
2007 # TODO Remove this once the bug is fixed.
2008 if modname in {'test.badsyntax_pep3120', 'badsyntax_pep3120'}:
2009 continue
2010
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002011 if key is None:
2012 callback(None, modname, '')
2013 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002014 try:
2015 loader = importer.find_module(modname)
2016 except SyntaxError:
2017 # raised by tests for bad coding cookies or BOM
2018 continue
2019 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002020 try:
2021 source = loader.get_source(modname)
2022 except UnicodeDecodeError:
2023 if onerror:
2024 onerror(modname)
2025 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002026 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002027 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002028 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002029 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002030 path = None
2031 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002032 try:
2033 module = loader.load_module(modname)
2034 except ImportError:
2035 if onerror:
2036 onerror(modname)
2037 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002038 desc = (module.__doc__ or '').splitlines()[0]
2039 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002040 name = modname + ' - ' + desc
2041 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002042 callback(path, modname, desc)
2043
2044 if completer:
2045 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002046
2047def apropos(key):
2048 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002049 def callback(path, modname, desc):
2050 if modname[-9:] == '.__init__':
2051 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002052 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002053 def onerror(modname):
2054 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002055 with warnings.catch_warnings():
2056 warnings.filterwarnings('ignore') # ignore problems during import
2057 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002058
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002059# --------------------------------------------------- Web browser interface
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002060
Ka-Ping Yee66246962001-04-12 11:59:50 +00002061def serve(port, callback=None, completer=None):
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002062 import http.server, email.message, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002063
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002064 msg = 'the pydoc.serve() function is deprecated'
2065 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2066
Georg Brandl24420152008-05-26 16:32:26 +00002067 class DocHandler(http.server.BaseHTTPRequestHandler):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002068 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002069 try:
2070 self.send_response(200)
Georg Brandl825fc8b2008-01-19 20:44:32 +00002071 self.send_header('Content-Type', 'text/html; charset=UTF-8')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002072 self.end_headers()
Georg Brandl825fc8b2008-01-19 20:44:32 +00002073 self.wfile.write(html.page(title, contents).encode('utf-8'))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002074 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002075
2076 def do_GET(self):
2077 path = self.path
2078 if path[-5:] == '.html': path = path[:-5]
2079 if path[:1] == '/': path = path[1:]
2080 if path and path != '.':
2081 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002082 obj = locate(path, forceload=1)
Guido van Rossumb940e112007-01-10 16:19:56 +00002083 except ErrorDuringImport as value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002084 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002085 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002086 if obj:
2087 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002088 else:
2089 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002090'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002091 else:
2092 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002093'<big><big><strong>Python: Index of Modules</strong></big></big>',
2094'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002095 def bltinlink(name):
2096 return '<a href="%s.html">%s</a>' % (name, name)
Georg Brandl661b0a12008-01-27 18:16:00 +00002097 names = [x for x in sys.builtin_module_names if x != '__main__']
2098 contents = html.multicolumn(names, bltinlink)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002099 indices = ['<p>' + html.bigsection(
2100 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2101
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002102 seen = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002103 for dir in sys.path:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002104 indices.append(html.index(dir, seen))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002105 contents = heading + ' '.join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00002106<font color="#909090" face="helvetica, arial"><strong>
2107pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002108 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002109
2110 def log_message(self, *args): pass
2111
Georg Brandl24420152008-05-26 16:32:26 +00002112 class DocServer(http.server.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002113 def __init__(self, port, callback):
Ronald Oussoren94f25282010-05-05 19:11:21 +00002114 host = 'localhost'
Senthil Kumaran7ff59132010-08-18 19:32:21 +00002115 self.address = (host, port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00002116 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002117 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002118 self.base.__init__(self, self.address, self.handler)
2119
2120 def serve_until_quit(self):
2121 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002122 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002123 while not self.quit:
2124 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2125 if rd: self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002126 self.server_close()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002127
2128 def server_activate(self):
2129 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002130 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002131
Georg Brandl24420152008-05-26 16:32:26 +00002132 DocServer.base = http.server.HTTPServer
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002133 DocServer.handler = DocHandler
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002134 DocHandler.MessageClass = email.message.Message
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002135 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002136 try:
2137 DocServer(port, callback).serve_until_quit()
2138 except (KeyboardInterrupt, select.error):
2139 pass
2140 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002141 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002142
2143# ----------------------------------------------------- graphical interface
2144
2145def gui():
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002146 """Graphical interface (starts Web server and pops up a control window)."""
2147
2148 msg = ('the pydoc.gui() function and "pydoc -g" option are deprecated\n',
2149 'use "pydoc.browse() function and "pydoc -b" option instead.')
2150 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2151
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002152 class GUI:
2153 def __init__(self, window, port=7464):
2154 self.window = window
2155 self.server = None
2156 self.scanner = None
2157
Georg Brandl14fc4272008-05-17 18:39:55 +00002158 import tkinter
2159 self.server_frm = tkinter.Frame(window)
2160 self.title_lbl = tkinter.Label(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002161 text='Starting server...\n ')
Georg Brandl14fc4272008-05-17 18:39:55 +00002162 self.open_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002163 text='open browser', command=self.open, state='disabled')
Georg Brandl14fc4272008-05-17 18:39:55 +00002164 self.quit_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002165 text='quit serving', command=self.quit, state='disabled')
2166
Georg Brandl14fc4272008-05-17 18:39:55 +00002167 self.search_frm = tkinter.Frame(window)
2168 self.search_lbl = tkinter.Label(self.search_frm, text='Search for')
2169 self.search_ent = tkinter.Entry(self.search_frm)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002170 self.search_ent.bind('<Return>', self.search)
Georg Brandl14fc4272008-05-17 18:39:55 +00002171 self.stop_btn = tkinter.Button(self.search_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002172 text='stop', pady=0, command=self.stop, state='disabled')
2173 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002174 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002175 self.stop_btn.pack(side='right')
2176
2177 self.window.title('pydoc')
2178 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2179 self.title_lbl.pack(side='top', fill='x')
2180 self.open_btn.pack(side='left', fill='x', expand=1)
2181 self.quit_btn.pack(side='right', fill='x', expand=1)
2182 self.server_frm.pack(side='top', fill='x')
2183
2184 self.search_lbl.pack(side='left')
2185 self.search_ent.pack(side='right', fill='x', expand=1)
2186 self.search_frm.pack(side='top', fill='x')
2187 self.search_ent.focus_set()
2188
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002189 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Georg Brandl14fc4272008-05-17 18:39:55 +00002190 self.result_lst = tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002191 self.result_lst.bind('<Button-1>', self.select)
2192 self.result_lst.bind('<Double-Button-1>', self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002193 self.result_scr = tkinter.Scrollbar(window,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002194 orient='vertical', command=self.result_lst.yview)
2195 self.result_lst.config(yscrollcommand=self.result_scr.set)
2196
Georg Brandl14fc4272008-05-17 18:39:55 +00002197 self.result_frm = tkinter.Frame(window)
2198 self.goto_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002199 text='go to selected', command=self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002200 self.hide_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002201 text='hide results', command=self.hide)
2202 self.goto_btn.pack(side='left', fill='x', expand=1)
2203 self.hide_btn.pack(side='right', fill='x', expand=1)
2204
2205 self.window.update()
2206 self.minwidth = self.window.winfo_width()
2207 self.minheight = self.window.winfo_height()
2208 self.bigminheight = (self.server_frm.winfo_reqheight() +
2209 self.search_frm.winfo_reqheight() +
2210 self.result_lst.winfo_reqheight() +
2211 self.result_frm.winfo_reqheight())
2212 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2213 self.expanded = 0
2214 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2215 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002216 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002217
2218 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002219 threading.Thread(
2220 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002221
2222 def ready(self, server):
2223 self.server = server
2224 self.title_lbl.config(
2225 text='Python documentation server at\n' + server.url)
2226 self.open_btn.config(state='normal')
2227 self.quit_btn.config(state='normal')
2228
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002229 def open(self, event=None, url=None):
2230 url = url or self.server.url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002231 import webbrowser
2232 webbrowser.open(url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002233
2234 def quit(self, event=None):
2235 if self.server:
2236 self.server.quit = 1
2237 self.window.quit()
2238
2239 def search(self, event=None):
2240 key = self.search_ent.get()
2241 self.stop_btn.pack(side='right')
2242 self.stop_btn.config(state='normal')
2243 self.search_lbl.config(text='Searching for "%s"...' % key)
2244 self.search_ent.forget()
2245 self.search_lbl.pack(side='left')
2246 self.result_lst.delete(0, 'end')
2247 self.goto_btn.config(state='disabled')
2248 self.expand()
2249
2250 import threading
2251 if self.scanner:
2252 self.scanner.quit = 1
2253 self.scanner = ModuleScanner()
2254 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002255 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002256
2257 def update(self, path, modname, desc):
2258 if modname[-9:] == '.__init__':
2259 modname = modname[:-9] + ' (package)'
2260 self.result_lst.insert('end',
2261 modname + ' - ' + (desc or '(no description)'))
2262
2263 def stop(self, event=None):
2264 if self.scanner:
2265 self.scanner.quit = 1
2266 self.scanner = None
2267
2268 def done(self):
2269 self.scanner = None
2270 self.search_lbl.config(text='Search for')
2271 self.search_lbl.pack(side='left')
2272 self.search_ent.pack(side='right', fill='x', expand=1)
2273 if sys.platform != 'win32': self.stop_btn.forget()
2274 self.stop_btn.config(state='disabled')
2275
2276 def select(self, event=None):
2277 self.goto_btn.config(state='normal')
2278
2279 def goto(self, event=None):
2280 selection = self.result_lst.curselection()
2281 if selection:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002282 modname = self.result_lst.get(selection[0]).split()[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002283 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002284
2285 def collapse(self):
2286 if not self.expanded: return
2287 self.result_frm.forget()
2288 self.result_scr.forget()
2289 self.result_lst.forget()
2290 self.bigwidth = self.window.winfo_width()
2291 self.bigheight = self.window.winfo_height()
2292 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2293 self.window.wm_minsize(self.minwidth, self.minheight)
2294 self.expanded = 0
2295
2296 def expand(self):
2297 if self.expanded: return
2298 self.result_frm.pack(side='bottom', fill='x')
2299 self.result_scr.pack(side='right', fill='y')
2300 self.result_lst.pack(side='top', fill='both', expand=1)
2301 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2302 self.window.wm_minsize(self.minwidth, self.bigminheight)
2303 self.expanded = 1
2304
2305 def hide(self, event=None):
2306 self.stop()
2307 self.collapse()
2308
Georg Brandl14fc4272008-05-17 18:39:55 +00002309 import tkinter
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002310 try:
Georg Brandl14fc4272008-05-17 18:39:55 +00002311 root = tkinter.Tk()
Martin v. Löwise09bd932004-08-22 16:13:26 +00002312 # Tk will crash if pythonw.exe has an XP .manifest
2313 # file and the root has is not destroyed explicitly.
2314 # If the problem is ever fixed in Tk, the explicit
2315 # destroy can go.
2316 try:
2317 gui = GUI(root)
2318 root.mainloop()
2319 finally:
2320 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002321 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002322 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002323
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002324
2325# --------------------------------------- enhanced Web browser interface
2326
2327def _start_server(urlhandler, port):
2328 """Start an HTTP server thread on a specific port.
2329
2330 Start an HTML/text server thread, so HTML or text documents can be
2331 browsed dynamically and interactively with a Web browser. Example use:
2332
2333 >>> import time
2334 >>> import pydoc
2335
2336 Define a URL handler. To determine what the client is asking
2337 for, check the URL and content_type.
2338
2339 Then get or generate some text or HTML code and return it.
2340
2341 >>> def my_url_handler(url, content_type):
2342 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2343 ... return text
2344
2345 Start server thread on port 0.
2346 If you use port 0, the server will pick a random port number.
2347 You can then use serverthread.port to get the port number.
2348
2349 >>> port = 0
2350 >>> serverthread = pydoc._start_server(my_url_handler, port)
2351
2352 Check that the server is really started. If it is, open browser
2353 and get first page. Use serverthread.url as the starting page.
2354
2355 >>> if serverthread.serving:
2356 ... import webbrowser
2357
2358 The next two lines are commented out so a browser doesn't open if
2359 doctest is run on this module.
2360
2361 #... webbrowser.open(serverthread.url)
2362 #True
2363
2364 Let the server do its thing. We just need to monitor its status.
2365 Use time.sleep so the loop doesn't hog the CPU.
2366
2367 >>> starttime = time.time()
2368 >>> timeout = 1 #seconds
2369
2370 This is a short timeout for testing purposes.
2371
2372 >>> while serverthread.serving:
2373 ... time.sleep(.01)
2374 ... if serverthread.serving and time.time() - starttime > timeout:
2375 ... serverthread.stop()
2376 ... break
2377
2378 Print any errors that may have occurred.
2379
2380 >>> print(serverthread.error)
2381 None
2382 """
2383 import http.server
2384 import email.message
2385 import select
2386 import threading
2387
2388 class DocHandler(http.server.BaseHTTPRequestHandler):
2389
2390 def do_GET(self):
2391 """Process a request from an HTML browser.
2392
2393 The URL received is in self.path.
2394 Get an HTML page from self.urlhandler and send it.
2395 """
2396 if self.path.endswith('.css'):
2397 content_type = 'text/css'
2398 else:
2399 content_type = 'text/html'
2400 self.send_response(200)
Georg Brandld2f38572011-01-30 08:37:19 +00002401 self.send_header('Content-Type', '%s; charset=UTF-8' % content_type)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002402 self.end_headers()
2403 self.wfile.write(self.urlhandler(
2404 self.path, content_type).encode('utf-8'))
2405
2406 def log_message(self, *args):
2407 # Don't log messages.
2408 pass
2409
2410 class DocServer(http.server.HTTPServer):
2411
2412 def __init__(self, port, callback):
2413 self.host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
2414 self.address = ('', port)
2415 self.callback = callback
2416 self.base.__init__(self, self.address, self.handler)
2417 self.quit = False
2418
2419 def serve_until_quit(self):
2420 while not self.quit:
2421 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2422 if rd:
2423 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002424 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002425
2426 def server_activate(self):
2427 self.base.server_activate(self)
2428 if self.callback:
2429 self.callback(self)
2430
2431 class ServerThread(threading.Thread):
2432
2433 def __init__(self, urlhandler, port):
2434 self.urlhandler = urlhandler
2435 self.port = int(port)
2436 threading.Thread.__init__(self)
2437 self.serving = False
2438 self.error = None
2439
2440 def run(self):
2441 """Start the server."""
2442 try:
2443 DocServer.base = http.server.HTTPServer
2444 DocServer.handler = DocHandler
2445 DocHandler.MessageClass = email.message.Message
2446 DocHandler.urlhandler = staticmethod(self.urlhandler)
2447 docsvr = DocServer(self.port, self.ready)
2448 self.docserver = docsvr
2449 docsvr.serve_until_quit()
2450 except Exception as e:
2451 self.error = e
2452
2453 def ready(self, server):
2454 self.serving = True
2455 self.host = server.host
2456 self.port = server.server_port
2457 self.url = 'http://%s:%d/' % (self.host, self.port)
2458
2459 def stop(self):
2460 """Stop the server and this thread nicely"""
2461 self.docserver.quit = True
2462 self.serving = False
2463 self.url = None
2464
2465 thread = ServerThread(urlhandler, port)
2466 thread.start()
2467 # Wait until thread.serving is True to make sure we are
2468 # really up before returning.
2469 while not thread.error and not thread.serving:
2470 time.sleep(.01)
2471 return thread
2472
2473
2474def _url_handler(url, content_type="text/html"):
2475 """The pydoc url handler for use with the pydoc server.
2476
2477 If the content_type is 'text/css', the _pydoc.css style
2478 sheet is read and returned if it exits.
2479
2480 If the content_type is 'text/html', then the result of
2481 get_html_page(url) is returned.
2482 """
2483 class _HTMLDoc(HTMLDoc):
2484
2485 def page(self, title, contents):
2486 """Format an HTML page."""
2487 css_path = "pydoc_data/_pydoc.css"
2488 css_link = (
2489 '<link rel="stylesheet" type="text/css" href="%s">' %
2490 css_path)
2491 return '''\
2492<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Georg Brandld2f38572011-01-30 08:37:19 +00002493<html><head><title>Pydoc: %s</title>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002494<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Georg Brandld2f38572011-01-30 08:37:19 +00002495%s</head><body bgcolor="#f0f0f8">%s<div style="clear:both;padding-top:.5em;">%s</div>
2496</body></html>''' % (title, css_link, html_navbar(), contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002497
2498 def filelink(self, url, path):
2499 return '<a href="getfile?key=%s">%s</a>' % (url, path)
2500
2501
2502 html = _HTMLDoc()
2503
2504 def html_navbar():
Georg Brandld2f38572011-01-30 08:37:19 +00002505 version = html.escape("%s [%s, %s]" % (platform.python_version(),
2506 platform.python_build()[0],
2507 platform.python_compiler()))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002508 return """
2509 <div style='float:left'>
Georg Brandld2f38572011-01-30 08:37:19 +00002510 Python %s<br>%s
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002511 </div>
2512 <div style='float:right'>
2513 <div style='text-align:center'>
2514 <a href="index.html">Module Index</a>
2515 : <a href="topics.html">Topics</a>
2516 : <a href="keywords.html">Keywords</a>
2517 </div>
2518 <div>
Georg Brandld2f38572011-01-30 08:37:19 +00002519 <form action="get" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002520 <input type=text name=key size=15>
2521 <input type=submit value="Get">
Georg Brandld2f38572011-01-30 08:37:19 +00002522 </form>&nbsp;
2523 <form action="search" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002524 <input type=text name=key size=15>
2525 <input type=submit value="Search">
2526 </form>
2527 </div>
2528 </div>
Georg Brandld2f38572011-01-30 08:37:19 +00002529 """ % (version, html.escape(platform.platform(terse=True)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002530
2531 def html_index():
2532 """Module Index page."""
2533
2534 def bltinlink(name):
2535 return '<a href="%s.html">%s</a>' % (name, name)
2536
2537 heading = html.heading(
2538 '<big><big><strong>Index of Modules</strong></big></big>',
2539 '#ffffff', '#7799ee')
2540 names = [name for name in sys.builtin_module_names
2541 if name != '__main__']
2542 contents = html.multicolumn(names, bltinlink)
2543 contents = [heading, '<p>' + html.bigsection(
2544 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2545
2546 seen = {}
2547 for dir in sys.path:
2548 contents.append(html.index(dir, seen))
2549
2550 contents.append(
2551 '<p align=right><font color="#909090" face="helvetica,'
2552 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2553 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002554 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002555
2556 def html_search(key):
2557 """Search results page."""
2558 # scan for modules
2559 search_result = []
2560
2561 def callback(path, modname, desc):
2562 if modname[-9:] == '.__init__':
2563 modname = modname[:-9] + ' (package)'
2564 search_result.append((modname, desc and '- ' + desc))
2565
2566 with warnings.catch_warnings():
2567 warnings.filterwarnings('ignore') # ignore problems during import
2568 ModuleScanner().run(callback, key)
2569
2570 # format page
2571 def bltinlink(name):
2572 return '<a href="%s.html">%s</a>' % (name, name)
2573
2574 results = []
2575 heading = html.heading(
2576 '<big><big><strong>Search Results</strong></big></big>',
2577 '#ffffff', '#7799ee')
2578 for name, desc in search_result:
2579 results.append(bltinlink(name) + desc)
2580 contents = heading + html.bigsection(
2581 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002582 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002583
2584 def html_getfile(path):
2585 """Get and display a source file listing safely."""
Nick Coghlanecace282010-12-03 16:08:46 +00002586 path = path.replace('%20', ' ')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002587 with open(path, 'r') as fp:
2588 lines = html.escape(fp.read())
2589 body = '<pre>%s</pre>' % lines
2590 heading = html.heading(
2591 '<big><big><strong>File Listing</strong></big></big>',
2592 '#ffffff', '#7799ee')
2593 contents = heading + html.bigsection(
2594 'File: %s' % path, '#ffffff', '#ee77aa', body)
Nick Coghlanecace282010-12-03 16:08:46 +00002595 return 'getfile %s' % path, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002596
2597 def html_topics():
2598 """Index of topic texts available."""
2599
2600 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002601 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002602
2603 heading = html.heading(
2604 '<big><big><strong>INDEX</strong></big></big>',
2605 '#ffffff', '#7799ee')
2606 names = sorted(Helper.topics.keys())
2607
2608 contents = html.multicolumn(names, bltinlink)
2609 contents = heading + html.bigsection(
2610 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002611 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002612
2613 def html_keywords():
2614 """Index of keywords."""
2615 heading = html.heading(
2616 '<big><big><strong>INDEX</strong></big></big>',
2617 '#ffffff', '#7799ee')
2618 names = sorted(Helper.keywords.keys())
2619
2620 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002621 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002622
2623 contents = html.multicolumn(names, bltinlink)
2624 contents = heading + html.bigsection(
2625 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002626 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002627
2628 def html_topicpage(topic):
2629 """Topic or keyword help page."""
2630 buf = io.StringIO()
2631 htmlhelp = Helper(buf, buf)
2632 contents, xrefs = htmlhelp._gettopic(topic)
2633 if topic in htmlhelp.keywords:
2634 title = 'KEYWORD'
2635 else:
2636 title = 'TOPIC'
2637 heading = html.heading(
2638 '<big><big><strong>%s</strong></big></big>' % title,
2639 '#ffffff', '#7799ee')
Georg Brandld2f38572011-01-30 08:37:19 +00002640 contents = '<pre>%s</pre>' % html.markup(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002641 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
Georg Brandld2f38572011-01-30 08:37:19 +00002642 if xrefs:
2643 xrefs = sorted(xrefs.split())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002644
Georg Brandld2f38572011-01-30 08:37:19 +00002645 def bltinlink(name):
2646 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002647
Georg Brandld2f38572011-01-30 08:37:19 +00002648 xrefs = html.multicolumn(xrefs, bltinlink)
2649 xrefs = html.section('Related help topics: ',
2650 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002651 return ('%s %s' % (title, topic),
2652 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002653
Georg Brandld2f38572011-01-30 08:37:19 +00002654 def html_getobj(url):
2655 obj = locate(url, forceload=1)
2656 if obj is None and url != 'None':
2657 raise ValueError('could not find object')
2658 title = describe(obj)
2659 content = html.document(obj, url)
2660 return title, content
2661
2662 def html_error(url, exc):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002663 heading = html.heading(
2664 '<big><big><strong>Error</strong></big></big>',
Georg Brandld2f38572011-01-30 08:37:19 +00002665 '#ffffff', '#7799ee')
2666 contents = '<br>'.join(html.escape(line) for line in
2667 format_exception_only(type(exc), exc))
2668 contents = heading + html.bigsection(url, '#ffffff', '#bb0000',
2669 contents)
2670 return "Error - %s" % url, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002671
2672 def get_html_page(url):
2673 """Generate an HTML page for url."""
Georg Brandld2f38572011-01-30 08:37:19 +00002674 complete_url = url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002675 if url.endswith('.html'):
2676 url = url[:-5]
Georg Brandld2f38572011-01-30 08:37:19 +00002677 try:
2678 if url in ("", "index"):
2679 title, content = html_index()
2680 elif url == "topics":
2681 title, content = html_topics()
2682 elif url == "keywords":
2683 title, content = html_keywords()
2684 elif '=' in url:
2685 op, _, url = url.partition('=')
2686 if op == "search?key":
2687 title, content = html_search(url)
2688 elif op == "getfile?key":
2689 title, content = html_getfile(url)
2690 elif op == "topic?key":
2691 # try topics first, then objects.
2692 try:
2693 title, content = html_topicpage(url)
2694 except ValueError:
2695 title, content = html_getobj(url)
2696 elif op == "get?key":
2697 # try objects first, then topics.
2698 if url in ("", "index"):
2699 title, content = html_index()
2700 else:
2701 try:
2702 title, content = html_getobj(url)
2703 except ValueError:
2704 title, content = html_topicpage(url)
2705 else:
2706 raise ValueError('bad pydoc url')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002707 else:
Georg Brandld2f38572011-01-30 08:37:19 +00002708 title, content = html_getobj(url)
2709 except Exception as exc:
2710 # Catch any errors and display them in an error page.
2711 title, content = html_error(complete_url, exc)
2712 return html.page(title, content)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002713
2714 if url.startswith('/'):
2715 url = url[1:]
2716 if content_type == 'text/css':
2717 path_here = os.path.dirname(os.path.realpath(__file__))
Georg Brandld2f38572011-01-30 08:37:19 +00002718 css_path = os.path.join(path_here, url)
2719 with open(css_path) as fp:
2720 return ''.join(fp.readlines())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002721 elif content_type == 'text/html':
2722 return get_html_page(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002723 # Errors outside the url handler are caught by the server.
2724 raise TypeError('unknown content type %r for url %s' % (content_type, url))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002725
2726
2727def browse(port=0, *, open_browser=True):
2728 """Start the enhanced pydoc Web server and open a Web browser.
2729
2730 Use port '0' to start the server on an arbitrary port.
2731 Set open_browser to False to suppress opening a browser.
2732 """
2733 import webbrowser
2734 serverthread = _start_server(_url_handler, port)
2735 if serverthread.error:
2736 print(serverthread.error)
2737 return
2738 if serverthread.serving:
2739 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2740 if open_browser:
2741 webbrowser.open(serverthread.url)
2742 try:
2743 print('Server ready at', serverthread.url)
2744 print(server_help_msg)
2745 while serverthread.serving:
2746 cmd = input('server> ')
2747 cmd = cmd.lower()
2748 if cmd == 'q':
2749 break
2750 elif cmd == 'b':
2751 webbrowser.open(serverthread.url)
2752 else:
2753 print(server_help_msg)
2754 except (KeyboardInterrupt, EOFError):
2755 print()
2756 finally:
2757 if serverthread.serving:
2758 serverthread.stop()
2759 print('Server stopped')
2760
2761
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002762# -------------------------------------------------- command-line interface
2763
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002764def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002765 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002766
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002767def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002768 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002769 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002770 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002771
Nick Coghlan106274b2009-11-15 23:04:33 +00002772 # Scripts don't get the current directory in their path by default
2773 # unless they are run with the '-m' switch
2774 if '' not in sys.path:
2775 scriptdir = os.path.dirname(sys.argv[0])
2776 if scriptdir in sys.path:
2777 sys.path.remove(scriptdir)
2778 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002779
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002780 try:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002781 opts, args = getopt.getopt(sys.argv[1:], 'bgk:p:w')
2782 writing = False
2783 start_server = False
2784 open_browser = False
2785 port = None
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002786 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002787 if opt == '-g':
2788 gui()
2789 return
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002790 if opt == '-b':
2791 start_server = True
2792 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002793 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002794 apropos(val)
2795 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002796 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002797 start_server = True
2798 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002799 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002800 writing = True
2801
2802 if start_server == True:
2803 if port == None:
2804 port = 0
2805 browse(port, open_browser=open_browser)
2806 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002807
2808 if not args: raise BadUsage
2809 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002810 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002811 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002812 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002813 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002814 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002815 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002816 if writing:
2817 if ispath(arg) and os.path.isdir(arg):
2818 writedocs(arg)
2819 else:
2820 writedoc(arg)
2821 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002822 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002823 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002824 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002825
2826 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002827 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002828 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002829
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002830{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002831 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002832 Python keyword, topic, function, module, or package, or a dotted
2833 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002834 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002835 Python source file to document. If name is 'keywords', 'topics',
2836 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002837
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002838{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002839 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002840
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002841{cmd} -p <port>
2842 Start an HTTP server on the given port on the local machine. Port
2843 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002844
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002845{cmd} -b
2846 Start an HTTP server on an arbitrary unused port and open a Web browser
2847 to interactively browse documentation. The -p option can be used with
2848 the -b option to explicitly specify the server port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002849
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002850{cmd} -g
2851 Deprecated.
2852
2853{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002854 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002855 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002856 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002857""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002858
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002859if __name__ == '__main__':
2860 cli()