blob: 2533226025ec6a391512ad78d894a89e032a647c [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 builtins
61import imp
Nick Coghlan7bb30b72010-12-03 09:29:11 +000062import inspect
Victor Stinnere6c910e2011-06-30 15:55:43 +020063import io
64import os
Nick Coghlan7bb30b72010-12-03 09:29:11 +000065import pkgutil
66import platform
67import re
Victor Stinnere6c910e2011-06-30 15:55:43 +020068import sys
Nick Coghlan7bb30b72010-12-03 09:29:11 +000069import time
Victor Stinnere6c910e2011-06-30 15:55:43 +020070import tokenize
Nick Coghlan7bb30b72010-12-03 09:29:11 +000071import warnings
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000072from collections import deque
Nick Coghlan7bb30b72010-12-03 09:29:11 +000073from reprlib import Repr
Georg Brandld2f38572011-01-30 08:37:19 +000074from traceback import extract_tb, format_exception_only
Nick Coghlan7bb30b72010-12-03 09:29:11 +000075
76
Ka-Ping Yeedd175342001-02-27 14:43:46 +000077# --------------------------------------------------------- common routines
78
Ka-Ping Yeedd175342001-02-27 14:43:46 +000079def pathdirs():
80 """Convert sys.path into a list of absolute, existing, unique paths."""
81 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000082 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000083 for dir in sys.path:
84 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000085 normdir = os.path.normcase(dir)
86 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000087 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000088 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000089 return dirs
90
91def getdoc(object):
92 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000093 result = inspect.getdoc(object) or inspect.getcomments(object)
Neal Norwitz9d72bb42007-04-17 08:48:32 +000094 return result and re.sub('^ *\n', '', result.rstrip()) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000095
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000096def splitdoc(doc):
97 """Split a doc string into a synopsis line (if any) and the rest."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +000098 lines = doc.strip().split('\n')
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000099 if len(lines) == 1:
100 return lines[0], ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000101 elif len(lines) >= 2 and not lines[1].rstrip():
102 return lines[0], '\n'.join(lines[2:])
103 return '', '\n'.join(lines)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000104
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000105def classname(object, modname):
106 """Get a class name and qualify it with a module name if necessary."""
107 name = object.__name__
108 if object.__module__ != modname:
109 name = object.__module__ + '.' + name
110 return name
111
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000112def isdata(object):
Georg Brandl94432422005-07-22 21:52:25 +0000113 """Check if an object is of a type that probably means it's data."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000114 return not (inspect.ismodule(object) or inspect.isclass(object) or
115 inspect.isroutine(object) or inspect.isframe(object) or
116 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000117
118def replace(text, *pairs):
119 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000120 while pairs:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000121 text = pairs[1].join(text.split(pairs[0]))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000122 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000123 return text
124
125def cram(text, maxlen):
126 """Omit part of a string if needed to make it fit in a maximum length."""
127 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000128 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000129 post = max(0, maxlen-3-pre)
130 return text[:pre] + '...' + text[len(text)-post:]
131 return text
132
Brett Cannon84601f12004-06-19 01:22:48 +0000133_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000134def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000135 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000136 # The behaviour of %p is implementation-dependent in terms of case.
Ezio Melotti412c95a2010-02-16 23:31:04 +0000137 return _re_stripid.sub(r'\1', text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000138
Brett Cannonc6c1f472004-06-19 01:02:51 +0000139def _is_some_method(obj):
140 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000141
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000142def allmethods(cl):
143 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000144 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000145 methods[key] = 1
146 for base in cl.__bases__:
147 methods.update(allmethods(base)) # all your base are belong to us
148 for key in methods.keys():
149 methods[key] = getattr(cl, key)
150 return methods
151
Tim Petersfa26f7c2001-09-24 08:05:11 +0000152def _split_list(s, predicate):
153 """Split sequence s via predicate, and return pair ([true], [false]).
154
155 The return value is a 2-tuple of lists,
156 ([x for x in s if predicate(x)],
157 [x for x in s if not predicate(x)])
158 """
159
Tim Peters28355492001-09-23 21:29:55 +0000160 yes = []
161 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000162 for x in s:
163 if predicate(x):
164 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000165 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000166 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000167 return yes, no
168
Raymond Hettinger1103d052011-03-25 14:15:24 -0700169def visiblename(name, all=None, obj=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000170 """Decide whether to show documentation on a variable."""
171 # Certain special names are redundant.
Benjamin Peterson41181742008-07-02 20:22:54 +0000172 _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__',
Barry Warsaw28a691b2010-04-17 00:19:56 +0000173 '__module__', '__name__', '__slots__', '__package__',
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000174 '__cached__', '__author__', '__credits__', '__date__',
175 '__version__')
Benjamin Peterson41181742008-07-02 20:22:54 +0000176 if name in _hidden_names: return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000177 # Private names are hidden, but special names are displayed.
178 if name.startswith('__') and name.endswith('__'): return 1
Raymond Hettinger1103d052011-03-25 14:15:24 -0700179 # Namedtuples have public fields and methods with a single leading underscore
180 if name.startswith('_') and hasattr(obj, '_fields'):
181 return True
Skip Montanaroa5616d22004-06-11 04:46:12 +0000182 if all is not None:
183 # only document that which the programmer exported in __all__
184 return name in all
185 else:
186 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000187
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000188def classify_class_attrs(object):
189 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000190 results = []
191 for (name, kind, cls, value) in inspect.classify_class_attrs(object):
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000192 if inspect.isdatadescriptor(value):
193 kind = 'data descriptor'
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000194 results.append((name, kind, cls, value))
195 return results
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000196
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000197# ----------------------------------------------------- module manipulation
198
199def ispackage(path):
200 """Guess whether a path refers to a package directory."""
201 if os.path.isdir(path):
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000202 for ext in ('.py', '.pyc', '.pyo'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000203 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000204 return True
205 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000206
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000207def source_synopsis(file):
208 line = file.readline()
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000209 while line[:1] == '#' or not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000210 line = file.readline()
211 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000212 line = line.strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000213 if line[:4] == 'r"""': line = line[1:]
214 if line[:3] == '"""':
215 line = line[3:]
216 if line[-1:] == '\\': line = line[:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000217 while not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000218 line = file.readline()
219 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000220 result = line.split('"""')[0].strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000221 else: result = None
222 return result
223
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000224def synopsis(filename, cache={}):
225 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000226 mtime = os.stat(filename).st_mtime
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000227 lastupdate, result = cache.get(filename, (0, None))
228 if lastupdate < mtime:
229 info = inspect.getmoduleinfo(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000230 try:
Victor Stinnere6c910e2011-06-30 15:55:43 +0200231 file = tokenize.open(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000232 except IOError:
233 # module can't be opened, so skip it
234 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000235 if info and 'b' in info[2]: # binary modules have to be imported
236 try: module = imp.load_module('__temp__', file, filename, info[1:])
237 except: return None
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000238 result = (module.__doc__ or '').splitlines()[0]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000239 del sys.modules['__temp__']
240 else: # text modules can be directly examined
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000241 result = source_synopsis(file)
242 file.close()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000243 cache[filename] = (mtime, result)
244 return result
245
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000246class ErrorDuringImport(Exception):
247 """Errors that occurred while trying to import something to document it."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000248 def __init__(self, filename, exc_info):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000249 self.filename = filename
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000250 self.exc, self.value, self.tb = exc_info
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000251
252 def __str__(self):
Guido van Rossuma01a8b62007-05-27 09:20:14 +0000253 exc = self.exc.__name__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000254 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000255
256def importfile(path):
257 """Import a Python source file or compiled file given its path."""
258 magic = imp.get_magic()
Victor Stinnere975af62011-07-04 02:08:50 +0200259 with open(path, 'rb') as file:
260 if file.read(len(magic)) == magic:
261 kind = imp.PY_COMPILED
262 else:
263 kind = imp.PY_SOURCE
264 file.seek(0)
265 filename = os.path.basename(path)
266 name, ext = os.path.splitext(filename)
267 try:
268 module = imp.load_module(name, file, path, (ext, 'r', kind))
269 except:
270 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000271 return module
272
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000273def safeimport(path, forceload=0, cache={}):
274 """Import a module; handle errors; return None if the module isn't found.
275
276 If the module *is* found but an exception occurs, it's wrapped in an
277 ErrorDuringImport exception and reraised. Unlike __import__, if a
278 package path is specified, the module at the end of the path is returned,
279 not the package at the beginning. If the optional 'forceload' argument
280 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000281 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000282 # If forceload is 1 and the module has been previously loaded from
283 # disk, we always have to reload the module. Checking the file's
284 # mtime isn't good enough (e.g. the module could contain a class
285 # that inherits from another module that has changed).
286 if forceload and path in sys.modules:
287 if path not in sys.builtin_module_names:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000288 # Remove the module from sys.modules and re-import to try
289 # and avoid problems with partially loaded modules.
290 # Also remove any submodules because they won't appear
291 # in the newly loaded module's namespace if they're already
292 # in sys.modules.
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000293 subs = [m for m in sys.modules if m.startswith(path + '.')]
294 for key in [path] + subs:
295 # Prevent garbage collection.
296 cache[key] = sys.modules[key]
297 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000298 module = __import__(path)
299 except:
300 # Did the error occur before or after the module was found?
301 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000302 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000303 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000304 raise ErrorDuringImport(sys.modules[path].__file__, info)
305 elif exc is SyntaxError:
306 # A SyntaxError occurred before we could execute the module.
307 raise ErrorDuringImport(value.filename, info)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000308 elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport':
Benjamin Peterson0289b152009-06-28 17:22:03 +0000309 # The import error occurred directly in this function,
310 # which means there is no such module in the path.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000311 return None
312 else:
313 # Some other error occurred during the importing process.
314 raise ErrorDuringImport(path, sys.exc_info())
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000315 for part in path.split('.')[1:]:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000316 try: module = getattr(module, part)
317 except AttributeError: return None
318 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000319
320# ---------------------------------------------------- formatter base class
321
322class Doc:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000323
324 PYTHONDOCS = os.environ.get("PYTHONDOCS",
325 "http://docs.python.org/%d.%d/library"
326 % sys.version_info[:2])
327
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000328 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000329 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000330 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000331 # 'try' clause is to attempt to handle the possibility that inspect
332 # identifies something in a way that pydoc itself has issues handling;
333 # think 'super' and how it is a descriptor (which raises the exception
334 # by lacking a __name__ attribute) and an instance.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000335 if inspect.isgetsetdescriptor(object): return self.docdata(*args)
336 if inspect.ismemberdescriptor(object): return self.docdata(*args)
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000337 try:
338 if inspect.ismodule(object): return self.docmodule(*args)
339 if inspect.isclass(object): return self.docclass(*args)
340 if inspect.isroutine(object): return self.docroutine(*args)
341 except AttributeError:
342 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000343 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000344 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000345
346 def fail(self, object, name=None, *args):
347 """Raise an exception for unimplemented types."""
348 message = "don't know how to document object%s of type %s" % (
349 name and ' ' + repr(name), type(object).__name__)
Collin Winterce36ad82007-08-30 01:19:48 +0000350 raise TypeError(message)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000351
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000352 docmodule = docclass = docroutine = docother = docproperty = docdata = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000353
Skip Montanaro4997a692003-09-10 16:47:51 +0000354 def getdocloc(self, object):
355 """Return the location of module docs or None"""
356
357 try:
358 file = inspect.getabsfile(object)
359 except TypeError:
360 file = '(built-in)'
361
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000362 docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
363
Skip Montanaro4997a692003-09-10 16:47:51 +0000364 basedir = os.path.join(sys.exec_prefix, "lib",
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000365 "python%d.%d" % sys.version_info[:2])
Skip Montanaro4997a692003-09-10 16:47:51 +0000366 if (isinstance(object, type(os)) and
367 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
368 'marshal', 'posix', 'signal', 'sys',
Georg Brandl2067bfd2008-05-25 13:05:15 +0000369 '_thread', 'zipimport') or
Skip Montanaro4997a692003-09-10 16:47:51 +0000370 (file.startswith(basedir) and
Brian Curtin49c284c2010-03-31 03:19:28 +0000371 not file.startswith(os.path.join(basedir, 'site-packages')))) and
Brian Curtinedef05b2010-04-01 04:05:25 +0000372 object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
Skip Montanaro4997a692003-09-10 16:47:51 +0000373 if docloc.startswith("http://"):
Georg Brandl86def6c2008-01-21 20:36:10 +0000374 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__)
Skip Montanaro4997a692003-09-10 16:47:51 +0000375 else:
Georg Brandl86def6c2008-01-21 20:36:10 +0000376 docloc = os.path.join(docloc, object.__name__ + ".html")
Skip Montanaro4997a692003-09-10 16:47:51 +0000377 else:
378 docloc = None
379 return docloc
380
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000381# -------------------------------------------- HTML documentation generator
382
383class HTMLRepr(Repr):
384 """Class for safely making an HTML representation of a Python object."""
385 def __init__(self):
386 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000387 self.maxlist = self.maxtuple = 20
388 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000389 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000390
391 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000392 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000393
394 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000395 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000396
397 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000398 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000399 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000400 if hasattr(self, methodname):
401 return getattr(self, methodname)(x, level)
402 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000403
404 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000405 test = cram(x, self.maxstring)
406 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000407 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000408 # Backslashes are only literal in the string and are never
409 # needed to make any special characters, so show a raw string.
410 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000411 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000412 r'<font color="#c040c0">\1</font>',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000413 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000414
Skip Montanarodf708782002-03-07 22:58:02 +0000415 repr_str = repr_string
416
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000417 def repr_instance(self, x, level):
418 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000419 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000420 except:
421 return self.escape('<%s instance>' % x.__class__.__name__)
422
423 repr_unicode = repr_string
424
425class HTMLDoc(Doc):
426 """Formatter class for HTML documentation."""
427
428 # ------------------------------------------- HTML formatting utilities
429
430 _repr_instance = HTMLRepr()
431 repr = _repr_instance.repr
432 escape = _repr_instance.escape
433
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000434 def page(self, title, contents):
435 """Format an HTML page."""
Georg Brandl388faac2009-04-10 08:31:48 +0000436 return '''\
Georg Brandle6066942009-04-10 08:28:28 +0000437<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000438<html><head><title>Python: %s</title>
Georg Brandl388faac2009-04-10 08:31:48 +0000439<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000440</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000441%s
442</body></html>''' % (title, contents)
443
444 def heading(self, title, fgcol, bgcol, extras=''):
445 """Format a page heading."""
446 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000447<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000448<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000449<td valign=bottom>&nbsp;<br>
450<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000451><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000452><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000453 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
454
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000455 def section(self, title, fgcol, bgcol, contents, width=6,
456 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000457 """Format a section with a heading."""
458 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000459 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000460 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000461<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000462<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000463<td colspan=3 valign=bottom>&nbsp;<br>
464<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000465 ''' % (bgcol, fgcol, title)
466 if prelude:
467 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000468<tr bgcolor="%s"><td rowspan=2>%s</td>
469<td colspan=2>%s</td></tr>
470<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
471 else:
472 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000473<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000474
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000475 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000476
477 def bigsection(self, title, *args):
478 """Format a section with a big heading."""
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000479 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000480 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000481
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000482 def preformat(self, text):
483 """Format literal preformatted text."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000484 text = self.escape(text.expandtabs())
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000485 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
486 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000487
488 def multicolumn(self, list, format, cols=4):
489 """Format a list of items into a multi-column list."""
490 result = ''
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000491 rows = (len(list)+cols-1)//cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000492 for col in range(cols):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000493 result = result + '<td width="%d%%" valign=top>' % (100//cols)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000494 for i in range(rows*col, rows*col+rows):
495 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000496 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000497 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000498 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000499
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000500 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000501
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000502 def namelink(self, name, *dicts):
503 """Make a link for an identifier, given name-to-URL mappings."""
504 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000505 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000506 return '<a href="%s">%s</a>' % (dict[name], name)
507 return name
508
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000509 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000510 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000511 name, module = object.__name__, sys.modules.get(object.__module__)
512 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000513 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000514 module.__name__, name, classname(object, modname))
515 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000516
517 def modulelink(self, object):
518 """Make a link for a module."""
519 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
520
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000521 def modpkglink(self, modpkginfo):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000522 """Make a link for a module or package to display in an index."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000523 name, path, ispackage, shadowed = modpkginfo
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000524 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000525 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000526 if path:
527 url = '%s.%s.html' % (path, name)
528 else:
529 url = '%s.html' % name
530 if ispackage:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000531 text = '<strong>%s</strong>&nbsp;(package)' % name
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000532 else:
533 text = name
534 return '<a href="%s">%s</a>' % (url, text)
535
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000536 def filelink(self, url, path):
537 """Make a link to source file."""
538 return '<a href="file:%s">%s</a>' % (url, path)
539
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000540 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
541 """Mark up some plain text, given a context of symbols to look for.
542 Each context dictionary maps object names to anchor names."""
543 escape = escape or self.escape
544 results = []
545 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000546 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
547 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000548 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000549 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000550 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000551 match = pattern.search(text, here)
552 if not match: break
553 start, end = match.span()
554 results.append(escape(text[here:start]))
555
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000556 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000557 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000558 url = escape(all).replace('"', '&quot;')
559 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000560 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000561 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
562 results.append('<a href="%s">%s</a>' % (url, escape(all)))
563 elif pep:
Christian Heimes2202f872008-02-06 14:31:34 +0000564 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000565 results.append('<a href="%s">%s</a>' % (url, escape(all)))
566 elif text[end:end+1] == '(':
567 results.append(self.namelink(name, methods, funcs, classes))
568 elif selfdot:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000569 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000570 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000571 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000572 here = end
573 results.append(escape(text[here:]))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000574 return ''.join(results)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000575
576 # ---------------------------------------------- type-specific routines
577
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000578 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000579 """Produce HTML for a class tree as given by inspect.getclasstree()."""
580 result = ''
581 for entry in tree:
582 if type(entry) is type(()):
583 c, bases = entry
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000584 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000585 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000586 if bases and bases != (parent,):
587 parents = []
588 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000589 parents.append(self.classlink(base, modname))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000590 result = result + '(' + ', '.join(parents) + ')'
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000591 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000592 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000593 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000594 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000595 return '<dl>\n%s</dl>\n' % result
596
Tim Peters8dd7ade2001-10-18 19:56:17 +0000597 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000598 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000599 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000600 try:
601 all = object.__all__
602 except AttributeError:
603 all = None
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000604 parts = name.split('.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000605 links = []
606 for i in range(len(parts)-1):
607 links.append(
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000608 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000609 ('.'.join(parts[:i+1]), parts[i]))
610 linkedname = '.'.join(links + parts[-1:])
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000611 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000612 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000613 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000614 url = path
615 if sys.platform == 'win32':
616 import nturl2path
617 url = nturl2path.pathname2url(path)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000618 filelink = self.filelink(url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000619 except TypeError:
620 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000621 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000622 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000623 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000624 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000625 version = version[11:-1].strip()
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000626 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000627 if hasattr(object, '__date__'):
628 info.append(self.escape(str(object.__date__)))
629 if info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000630 head = head + ' (%s)' % ', '.join(info)
Skip Montanaro4997a692003-09-10 16:47:51 +0000631 docloc = self.getdocloc(object)
632 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000633 docloc = '<br><a href="%(docloc)s">Module Reference</a>' % locals()
Skip Montanaro4997a692003-09-10 16:47:51 +0000634 else:
635 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000636 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000637 head, '#ffffff', '#7799ee',
638 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000639
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000640 modules = inspect.getmembers(object, inspect.ismodule)
641
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000642 classes, cdict = [], {}
643 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000644 # if __all__ exists, believe it. Otherwise use old heuristic.
645 if (all is not None or
646 (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700647 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000648 classes.append((key, value))
649 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000650 for key, value in classes:
651 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000652 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000653 module = sys.modules.get(modname)
654 if modname != name and module and hasattr(module, key):
655 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000656 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000657 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000658 funcs, fdict = [], {}
659 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000660 # if __all__ exists, believe it. Otherwise use old heuristic.
661 if (all is not None or
662 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700663 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000664 funcs.append((key, value))
665 fdict[key] = '#-' + key
666 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000667 data = []
668 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700669 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000670 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000671
672 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
673 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000674 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000675
676 if hasattr(object, '__path__'):
677 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000678 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
679 modpkgs.append((modname, name, ispkg, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000680 modpkgs.sort()
681 contents = self.multicolumn(modpkgs, self.modpkglink)
682 result = result + self.bigsection(
683 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000684 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000685 contents = self.multicolumn(
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000686 modules, lambda t: self.modulelink(t[1]))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000687 result = result + self.bigsection(
Christian Heimes7131fd92008-02-19 14:21:46 +0000688 'Modules', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000689
690 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000691 classlist = [value for (key, value) in classes]
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000692 contents = [
693 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000694 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000695 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000696 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000697 'Classes', '#ffffff', '#ee77aa', ' '.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000698 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000699 contents = []
700 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000701 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000702 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000703 'Functions', '#ffffff', '#eeaa77', ' '.join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000704 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000705 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000706 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000707 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000708 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000709 'Data', '#ffffff', '#55aa55', '<br>\n'.join(contents))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000710 if hasattr(object, '__author__'):
711 contents = self.markup(str(object.__author__), self.preformat)
712 result = result + self.bigsection(
713 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000714 if hasattr(object, '__credits__'):
715 contents = self.markup(str(object.__credits__), self.preformat)
716 result = result + self.bigsection(
717 'Credits', '#ffffff', '#7799ee', contents)
718
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000719 return result
720
Tim Peters8dd7ade2001-10-18 19:56:17 +0000721 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
722 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000723 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000724 realname = object.__name__
725 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000726 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000727
Tim Petersb47879b2001-09-24 04:47:19 +0000728 contents = []
729 push = contents.append
730
Tim Petersfa26f7c2001-09-24 08:05:11 +0000731 # Cute little class to pump out a horizontal rule between sections.
732 class HorizontalRule:
733 def __init__(self):
734 self.needone = 0
735 def maybe(self):
736 if self.needone:
737 push('<hr>\n')
738 self.needone = 1
739 hr = HorizontalRule()
740
Tim Petersc86f6ca2001-09-26 21:31:51 +0000741 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000742 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000743 if len(mro) > 2:
744 hr.maybe()
745 push('<dl><dt>Method resolution order:</dt>\n')
746 for base in mro:
747 push('<dd>%s</dd>\n' % self.classlink(base,
748 object.__module__))
749 push('</dl>\n')
750
Tim Petersb47879b2001-09-24 04:47:19 +0000751 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000752 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000753 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000754 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000755 push(msg)
756 for name, kind, homecls, value in ok:
757 push(self.document(getattr(object, name), name, mod,
758 funcs, classes, mdict, object))
759 push('\n')
760 return attrs
761
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000762 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000763 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000764 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000765 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000766 push(msg)
767 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000768 push(self._docdescriptor(name, value, mod))
Tim Petersb47879b2001-09-24 04:47:19 +0000769 return attrs
770
Tim Petersfa26f7c2001-09-24 08:05:11 +0000771 def spilldata(msg, attrs, predicate):
772 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000773 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000774 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000775 push(msg)
776 for name, kind, homecls, value in ok:
777 base = self.docother(getattr(object, name), name, mod)
Guido van Rossumd59da4b2007-05-22 18:11:13 +0000778 if hasattr(value, '__call__') or inspect.isdatadescriptor(value):
Guido van Rossum5e355b22002-05-21 20:56:15 +0000779 doc = getattr(value, "__doc__", None)
780 else:
781 doc = None
Tim Petersb47879b2001-09-24 04:47:19 +0000782 if doc is None:
783 push('<dl><dt>%s</dl>\n' % base)
784 else:
785 doc = self.markup(getdoc(value), self.preformat,
786 funcs, classes, mdict)
Tim Peters2306d242001-09-25 03:18:32 +0000787 doc = '<dd><tt>%s</tt>' % doc
Tim Petersb47879b2001-09-24 04:47:19 +0000788 push('<dl><dt>%s%s</dl>\n' % (base, doc))
789 push('\n')
790 return attrs
791
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000792 attrs = [(name, kind, cls, value)
793 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -0700794 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000795
Tim Petersb47879b2001-09-24 04:47:19 +0000796 mdict = {}
797 for key, kind, homecls, value in attrs:
798 mdict[key] = anchor = '#' + name + '-' + key
799 value = getattr(object, key)
800 try:
801 # The value may not be hashable (e.g., a data attr with
802 # a dict or list value).
803 mdict[value] = anchor
804 except TypeError:
805 pass
806
Tim Petersfa26f7c2001-09-24 08:05:11 +0000807 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000808 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000809 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000810 else:
811 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000812 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
813
Georg Brandl1a3284e2007-12-02 09:40:06 +0000814 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000815 attrs = inherited
816 continue
817 elif thisclass is object:
818 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000819 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000820 tag = 'inherited from %s' % self.classlink(thisclass,
821 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000822 tag += ':<br>\n'
823
824 # Sort attrs by name.
Raymond Hettingerd4cb56d2008-01-30 02:55:10 +0000825 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000826
827 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000828 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000829 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000830 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000831 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000832 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000833 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000834 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
835 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000836 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000837 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000838 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000839 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000840
841 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000842
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000843 if name == realname:
844 title = '<a name="%s">class <strong>%s</strong></a>' % (
845 name, realname)
846 else:
847 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
848 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000849 if bases:
850 parents = []
851 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000852 parents.append(self.classlink(base, object.__module__))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000853 title = title + '(%s)' % ', '.join(parents)
Tim Peters2306d242001-09-25 03:18:32 +0000854 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000855 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000856
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000857 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000858
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000859 def formatvalue(self, object):
860 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000861 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000862
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000863 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000864 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000865 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000866 realname = object.__name__
867 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000868 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000869 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000870 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000871 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +0000872 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000873 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000874 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000875 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000876 else:
Christian Heimesff737952007-11-27 10:40:20 +0000877 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000878 note = ' method of %s instance' % self.classlink(
Christian Heimesff737952007-11-27 10:40:20 +0000879 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000880 else:
881 note = ' unbound %s method' % self.classlink(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +0000882 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000883
884 if name == realname:
885 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
886 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000887 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000888 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000889 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000890 cl.__name__ + '-' + realname, realname)
891 skipdocs = 1
892 else:
893 reallink = realname
894 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
895 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000896 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +0000897 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann = \
898 inspect.getfullargspec(object)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000899 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +0000900 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann,
901 formatvalue=self.formatvalue,
902 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000903 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000904 title = '<strong>%s</strong> <em>lambda</em> ' % name
Guido van Rossum2e65f892007-02-28 22:03:49 +0000905 # XXX lambda's won't usually have func_annotations['return']
906 # since the syntax doesn't support but it is possible.
907 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000908 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000909 else:
910 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000911
Tim Peters2306d242001-09-25 03:18:32 +0000912 decl = title + argspec + (note and self.grey(
913 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000914
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000915 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000916 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000917 else:
918 doc = self.markup(
919 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000920 doc = doc and '<dd><tt>%s</tt></dd>' % doc
921 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000922
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000923 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000924 results = []
925 push = results.append
926
927 if name:
928 push('<dl><dt><strong>%s</strong></dt>\n' % name)
929 if value.__doc__ is not None:
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +0000930 doc = self.markup(getdoc(value), self.preformat)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000931 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000932 push('</dl>\n')
933
934 return ''.join(results)
935
936 def docproperty(self, object, name=None, mod=None, cl=None):
937 """Produce html documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000938 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000939
Tim Peters8dd7ade2001-10-18 19:56:17 +0000940 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000941 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000942 lhs = name and '<strong>%s</strong> = ' % name or ''
943 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000944
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000945 def docdata(self, object, name=None, mod=None, cl=None):
946 """Produce html documentation for a data descriptor."""
947 return self._docdescriptor(name, object, mod)
948
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000949 def index(self, dir, shadowed=None):
950 """Generate an HTML index for a directory of modules."""
951 modpkgs = []
952 if shadowed is None: shadowed = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000953 for importer, name, ispkg in pkgutil.iter_modules([dir]):
954 modpkgs.append((name, '', ispkg, name in shadowed))
955 shadowed[name] = 1
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000956
957 modpkgs.sort()
958 contents = self.multicolumn(modpkgs, self.modpkglink)
959 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
960
961# -------------------------------------------- text documentation generator
962
963class TextRepr(Repr):
964 """Class for safely making a text representation of a Python object."""
965 def __init__(self):
966 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000967 self.maxlist = self.maxtuple = 20
968 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000969 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000970
971 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000972 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000973 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000974 if hasattr(self, methodname):
975 return getattr(self, methodname)(x, level)
976 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000977
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000978 def repr_string(self, x, level):
979 test = cram(x, self.maxstring)
980 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000981 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000982 # Backslashes are only literal in the string and are never
983 # needed to make any special characters, so show a raw string.
984 return 'r' + testrepr[0] + test + testrepr[0]
985 return testrepr
986
Skip Montanarodf708782002-03-07 22:58:02 +0000987 repr_str = repr_string
988
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000989 def repr_instance(self, x, level):
990 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000991 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000992 except:
993 return '<%s instance>' % x.__class__.__name__
994
995class TextDoc(Doc):
996 """Formatter class for text documentation."""
997
998 # ------------------------------------------- text formatting utilities
999
1000 _repr_instance = TextRepr()
1001 repr = _repr_instance.repr
1002
1003 def bold(self, text):
1004 """Format a string in bold by overstriking."""
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001005 return ''.join(ch + '\b' + ch for ch in text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001006
1007 def indent(self, text, prefix=' '):
1008 """Indent text by prepending a given prefix to each line."""
1009 if not text: return ''
Collin Winter72e110c2007-07-17 00:27:30 +00001010 lines = [prefix + line for line in text.split('\n')]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001011 if lines: lines[-1] = lines[-1].rstrip()
1012 return '\n'.join(lines)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001013
1014 def section(self, title, contents):
1015 """Format a section with a given heading."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001016 clean_contents = self.indent(contents).rstrip()
1017 return self.bold(title) + '\n' + clean_contents + '\n\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001018
1019 # ---------------------------------------------- type-specific routines
1020
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001021 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001022 """Render in text a class tree as returned by inspect.getclasstree()."""
1023 result = ''
1024 for entry in tree:
1025 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001026 c, bases = entry
1027 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001028 if bases and bases != (parent,):
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001029 parents = (classname(c, modname) for c in bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001030 result = result + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001031 result = result + '\n'
1032 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001033 result = result + self.formattree(
1034 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001035 return result
1036
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001037 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001038 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001039 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001040 synop, desc = splitdoc(getdoc(object))
1041 result = self.section('NAME', name + (synop and ' - ' + synop))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001042 all = getattr(object, '__all__', None)
Skip Montanaro4997a692003-09-10 16:47:51 +00001043 docloc = self.getdocloc(object)
1044 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001045 result = result + self.section('MODULE REFERENCE', docloc + """
1046
1047The following documentation is automatically generated from the Python source
1048files. It may be incomplete, incorrect or include features that are considered
1049implementation detail and may vary between Python implementations. When in
1050doubt, consult the module reference at the location listed above.
1051""")
Skip Montanaro4997a692003-09-10 16:47:51 +00001052
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001053 if desc:
1054 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001055
1056 classes = []
1057 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001058 # if __all__ exists, believe it. Otherwise use old heuristic.
1059 if (all is not None
1060 or (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001061 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001062 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001063 funcs = []
1064 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001065 # if __all__ exists, believe it. Otherwise use old heuristic.
1066 if (all is not None or
1067 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001068 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001069 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001070 data = []
1071 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001072 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001073 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001074
Christian Heimes1af737c2008-01-23 08:24:23 +00001075 modpkgs = []
1076 modpkgs_names = set()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001077 if hasattr(object, '__path__'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001078 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
Christian Heimes1af737c2008-01-23 08:24:23 +00001079 modpkgs_names.add(modname)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001080 if ispkg:
1081 modpkgs.append(modname + ' (package)')
1082 else:
1083 modpkgs.append(modname)
1084
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001085 modpkgs.sort()
1086 result = result + self.section(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001087 'PACKAGE CONTENTS', '\n'.join(modpkgs))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001088
Christian Heimes1af737c2008-01-23 08:24:23 +00001089 # Detect submodules as sometimes created by C extensions
1090 submodules = []
1091 for key, value in inspect.getmembers(object, inspect.ismodule):
1092 if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1093 submodules.append(key)
1094 if submodules:
1095 submodules.sort()
1096 result = result + self.section(
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001097 'SUBMODULES', '\n'.join(submodules))
Christian Heimes1af737c2008-01-23 08:24:23 +00001098
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001099 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001100 classlist = [value for key, value in classes]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001101 contents = [self.formattree(
1102 inspect.getclasstree(classlist, 1), name)]
1103 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001104 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001105 result = result + self.section('CLASSES', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001106
1107 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001108 contents = []
1109 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001110 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001111 result = result + self.section('FUNCTIONS', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001112
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001113 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001114 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001115 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001116 contents.append(self.docother(value, key, name, maxlen=70))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001117 result = result + self.section('DATA', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001118
1119 if hasattr(object, '__version__'):
1120 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001121 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001122 version = version[11:-1].strip()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001123 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001124 if hasattr(object, '__date__'):
1125 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001126 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001127 result = result + self.section('AUTHOR', str(object.__author__))
1128 if hasattr(object, '__credits__'):
1129 result = result + self.section('CREDITS', str(object.__credits__))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001130 try:
1131 file = inspect.getabsfile(object)
1132 except TypeError:
1133 file = '(built-in)'
1134 result = result + self.section('FILE', file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001135 return result
1136
Georg Brandl9bd45f992010-12-03 09:58:38 +00001137 def docclass(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001138 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001139 realname = object.__name__
1140 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001141 bases = object.__bases__
1142
Tim Petersc86f6ca2001-09-26 21:31:51 +00001143 def makename(c, m=object.__module__):
1144 return classname(c, m)
1145
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001146 if name == realname:
1147 title = 'class ' + self.bold(realname)
1148 else:
1149 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001150 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001151 parents = map(makename, bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001152 title = title + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001153
1154 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001155 contents = doc and [doc + '\n'] or []
1156 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001157
Tim Petersc86f6ca2001-09-26 21:31:51 +00001158 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001159 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001160 if len(mro) > 2:
1161 push("Method resolution order:")
1162 for base in mro:
1163 push(' ' + makename(base))
1164 push('')
1165
Tim Petersf4aad8e2001-09-24 22:40:47 +00001166 # Cute little class to pump out a horizontal rule between sections.
1167 class HorizontalRule:
1168 def __init__(self):
1169 self.needone = 0
1170 def maybe(self):
1171 if self.needone:
1172 push('-' * 70)
1173 self.needone = 1
1174 hr = HorizontalRule()
1175
Tim Peters28355492001-09-23 21:29:55 +00001176 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001177 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001178 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001179 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001180 push(msg)
1181 for name, kind, homecls, value in ok:
1182 push(self.document(getattr(object, name),
1183 name, mod, object))
1184 return attrs
1185
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001186 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001187 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001188 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001189 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001190 push(msg)
1191 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001192 push(self._docdescriptor(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001193 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001194
Tim Petersfa26f7c2001-09-24 08:05:11 +00001195 def spilldata(msg, attrs, predicate):
1196 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001197 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001198 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001199 push(msg)
1200 for name, kind, homecls, value in ok:
Guido van Rossumd59da4b2007-05-22 18:11:13 +00001201 if hasattr(value, '__call__') or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001202 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001203 else:
1204 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001205 push(self.docother(getattr(object, name),
Georg Brandl8b813db2005-10-01 16:32:31 +00001206 name, mod, maxlen=70, doc=doc) + '\n')
Tim Peters28355492001-09-23 21:29:55 +00001207 return attrs
1208
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001209 attrs = [(name, kind, cls, value)
1210 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -07001211 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001212
Tim Petersfa26f7c2001-09-24 08:05:11 +00001213 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001214 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001215 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001216 else:
1217 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001218 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1219
Georg Brandl1a3284e2007-12-02 09:40:06 +00001220 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001221 attrs = inherited
1222 continue
1223 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001224 tag = "defined here"
1225 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001226 tag = "inherited from %s" % classname(thisclass,
1227 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001228
1229 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001230 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001231
1232 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001233 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001234 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001235 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001236 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001237 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001238 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001239 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1240 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001241 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1242 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001243 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001244 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001245
1246 contents = '\n'.join(contents)
1247 if not contents:
1248 return title + '\n'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001249 return title + '\n' + self.indent(contents.rstrip(), ' | ') + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001250
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001251 def formatvalue(self, object):
1252 """Format an argument default value as text."""
1253 return '=' + self.repr(object)
1254
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001255 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001256 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001257 realname = object.__name__
1258 name = name or realname
1259 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001260 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001261 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +00001262 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001263 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001264 if imclass is not cl:
1265 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001266 else:
Christian Heimesff737952007-11-27 10:40:20 +00001267 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001268 note = ' method of %s instance' % classname(
Christian Heimesff737952007-11-27 10:40:20 +00001269 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001270 else:
1271 note = ' unbound %s method' % classname(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +00001272 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001273
1274 if name == realname:
1275 title = self.bold(realname)
1276 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001277 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001278 cl.__dict__[realname] is object):
1279 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001280 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001281 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +00001282 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann = \
1283 inspect.getfullargspec(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001284 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +00001285 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann,
1286 formatvalue=self.formatvalue,
1287 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001288 if realname == '<lambda>':
Georg Brandl501dd0d2006-02-17 09:45:40 +00001289 title = self.bold(name) + ' lambda '
Guido van Rossum2e65f892007-02-28 22:03:49 +00001290 # XXX lambda's won't usually have func_annotations['return']
1291 # since the syntax doesn't support but it is possible.
1292 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001293 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001294 else:
1295 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001296 decl = title + argspec + note
1297
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001298 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001299 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001300 else:
1301 doc = getdoc(object) or ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001302 return decl + '\n' + (doc and self.indent(doc).rstrip() + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001303
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001304 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001305 results = []
1306 push = results.append
1307
1308 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001309 push(self.bold(name))
1310 push('\n')
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001311 doc = getdoc(value) or ''
1312 if doc:
1313 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001314 push('\n')
1315 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001316
1317 def docproperty(self, object, name=None, mod=None, cl=None):
1318 """Produce text documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001319 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001320
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001321 def docdata(self, object, name=None, mod=None, cl=None):
1322 """Produce text documentation for a data descriptor."""
1323 return self._docdescriptor(name, object, mod)
1324
Georg Brandl8b813db2005-10-01 16:32:31 +00001325 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001326 """Produce text documentation for a data object."""
1327 repr = self.repr(object)
1328 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001329 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001330 chop = maxlen - len(line)
1331 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001332 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001333 if doc is not None:
1334 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001335 return line
1336
Georg Brandld80d5f42010-12-03 07:47:22 +00001337class _PlainTextDoc(TextDoc):
1338 """Subclass of TextDoc which overrides string styling"""
1339 def bold(self, text):
1340 return text
1341
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001342# --------------------------------------------------------- user interfaces
1343
1344def pager(text):
1345 """The first time this is called, determine what kind of pager to use."""
1346 global pager
1347 pager = getpager()
1348 pager(text)
1349
1350def getpager():
1351 """Decide what method to use for paging through text."""
Guido van Rossuma01a8b62007-05-27 09:20:14 +00001352 if not hasattr(sys.stdout, "isatty"):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001353 return plainpager
1354 if not sys.stdin.isatty() or not sys.stdout.isatty():
1355 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001356 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001357 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001358 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001359 elif os.environ.get('TERM') in ('dumb', 'emacs'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001360 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001361 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001362 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001363 if os.environ.get('TERM') in ('dumb', 'emacs'):
1364 return plainpager
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001365 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001366 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001367 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001368 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001369
1370 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001371 (fd, filename) = tempfile.mkstemp()
1372 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001373 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001374 if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001375 return lambda text: pipepager(text, 'more')
1376 else:
1377 return ttypager
1378 finally:
1379 os.unlink(filename)
1380
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001381def plain(text):
1382 """Remove boldface formatting from text."""
1383 return re.sub('.\b', '', text)
1384
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001385def pipepager(text, cmd):
1386 """Page through text by feeding it to another program."""
1387 pipe = os.popen(cmd, 'w')
1388 try:
1389 pipe.write(text)
1390 pipe.close()
1391 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001392 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001393
1394def tempfilepager(text, cmd):
1395 """Page through text by invoking a program on a temporary file."""
1396 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001397 filename = tempfile.mktemp()
1398 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001399 file.write(text)
1400 file.close()
1401 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001402 os.system(cmd + ' "' + filename + '"')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001403 finally:
1404 os.unlink(filename)
1405
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001406def ttypager(text):
1407 """Page through text on a text terminal."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001408 lines = plain(text).split('\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001409 try:
1410 import tty
1411 fd = sys.stdin.fileno()
1412 old = tty.tcgetattr(fd)
1413 tty.setcbreak(fd)
1414 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001415 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001416 tty = None
1417 getchar = lambda: sys.stdin.readline()[:-1][:1]
1418
1419 try:
1420 r = inc = os.environ.get('LINES', 25) - 1
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001421 sys.stdout.write('\n'.join(lines[:inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001422 while lines[r:]:
1423 sys.stdout.write('-- more --')
1424 sys.stdout.flush()
1425 c = getchar()
1426
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001427 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001428 sys.stdout.write('\r \r')
1429 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001430 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001431 sys.stdout.write('\r \r' + lines[r] + '\n')
1432 r = r + 1
1433 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001434 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001435 r = r - inc - inc
1436 if r < 0: r = 0
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001437 sys.stdout.write('\n' + '\n'.join(lines[r:r+inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001438 r = r + inc
1439
1440 finally:
1441 if tty:
1442 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1443
1444def plainpager(text):
1445 """Simply print unformatted text. This is the ultimate fallback."""
1446 sys.stdout.write(plain(text))
1447
1448def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001449 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001450 if inspect.ismodule(thing):
1451 if thing.__name__ in sys.builtin_module_names:
1452 return 'built-in module ' + thing.__name__
1453 if hasattr(thing, '__path__'):
1454 return 'package ' + thing.__name__
1455 else:
1456 return 'module ' + thing.__name__
1457 if inspect.isbuiltin(thing):
1458 return 'built-in function ' + thing.__name__
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001459 if inspect.isgetsetdescriptor(thing):
1460 return 'getset descriptor %s.%s.%s' % (
1461 thing.__objclass__.__module__, thing.__objclass__.__name__,
1462 thing.__name__)
1463 if inspect.ismemberdescriptor(thing):
1464 return 'member descriptor %s.%s.%s' % (
1465 thing.__objclass__.__module__, thing.__objclass__.__name__,
1466 thing.__name__)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001467 if inspect.isclass(thing):
1468 return 'class ' + thing.__name__
1469 if inspect.isfunction(thing):
1470 return 'function ' + thing.__name__
1471 if inspect.ismethod(thing):
1472 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001473 return type(thing).__name__
1474
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001475def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001476 """Locate an object by name or dotted path, importing as necessary."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001477 parts = [part for part in path.split('.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001478 module, n = None, 0
1479 while n < len(parts):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001480 nextmodule = safeimport('.'.join(parts[:n+1]), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001481 if nextmodule: module, n = nextmodule, n + 1
1482 else: break
1483 if module:
1484 object = module
1485 for part in parts[n:]:
1486 try: object = getattr(object, part)
1487 except AttributeError: return None
1488 return object
1489 else:
Georg Brandl1a3284e2007-12-02 09:40:06 +00001490 if hasattr(builtins, path):
1491 return getattr(builtins, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001492
1493# --------------------------------------- interactive interpreter interface
1494
1495text = TextDoc()
Georg Brandld80d5f42010-12-03 07:47:22 +00001496plaintext = _PlainTextDoc()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001497html = HTMLDoc()
1498
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001499def resolve(thing, forceload=0):
1500 """Given an object or a path to an object, get the object and its name."""
1501 if isinstance(thing, str):
1502 object = locate(thing, forceload)
1503 if not object:
Collin Winterce36ad82007-08-30 01:19:48 +00001504 raise ImportError('no Python documentation found for %r' % thing)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001505 return object, thing
1506 else:
1507 return thing, getattr(thing, '__name__', None)
1508
Georg Brandld80d5f42010-12-03 07:47:22 +00001509def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
1510 renderer=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001511 """Render text documentation, given an object or a path to an object."""
Georg Brandld80d5f42010-12-03 07:47:22 +00001512 if renderer is None:
1513 renderer = text
Guido van Rossumd8faa362007-04-27 19:54:29 +00001514 object, name = resolve(thing, forceload)
1515 desc = describe(object)
1516 module = inspect.getmodule(object)
1517 if name and '.' in name:
1518 desc += ' in ' + name[:name.rfind('.')]
1519 elif module and module is not object:
1520 desc += ' in module ' + module.__name__
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001521
1522 if not (inspect.ismodule(object) or
Guido van Rossumd8faa362007-04-27 19:54:29 +00001523 inspect.isclass(object) or
1524 inspect.isroutine(object) or
1525 inspect.isgetsetdescriptor(object) or
1526 inspect.ismemberdescriptor(object) or
1527 isinstance(object, property)):
1528 # If the passed object is a piece of data or an instance,
1529 # document its available methods instead of its value.
1530 object = type(object)
1531 desc += ' object'
Georg Brandld80d5f42010-12-03 07:47:22 +00001532 return title % desc + '\n\n' + renderer.document(object, name)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001533
Georg Brandld80d5f42010-12-03 07:47:22 +00001534def doc(thing, title='Python Library Documentation: %s', forceload=0,
1535 output=None):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001536 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001537 try:
Georg Brandld80d5f42010-12-03 07:47:22 +00001538 if output is None:
1539 pager(render_doc(thing, title, forceload))
1540 else:
1541 output.write(render_doc(thing, title, forceload, plaintext))
Guido van Rossumb940e112007-01-10 16:19:56 +00001542 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001543 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001544
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001545def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001546 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001547 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001548 object, name = resolve(thing, forceload)
1549 page = html.page(describe(object), html.document(object, name))
Georg Brandl388faac2009-04-10 08:31:48 +00001550 file = open(name + '.html', 'w', encoding='utf-8')
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001551 file.write(page)
1552 file.close()
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001553 print('wrote', name + '.html')
Guido van Rossumb940e112007-01-10 16:19:56 +00001554 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001555 print(value)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001556
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001557def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001558 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001559 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001560 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1561 writedoc(modname)
1562 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001563
1564class Helper:
Georg Brandl6b38daa2008-06-01 21:05:17 +00001565
1566 # These dictionaries map a topic name to either an alias, or a tuple
1567 # (label, seealso-items). The "label" is the label of the corresponding
1568 # section in the .rst file under Doc/ and an index into the dictionary
Georg Brandl5617db82009-04-27 16:28:57 +00001569 # in pydoc_data/topics.py.
Georg Brandl6b38daa2008-06-01 21:05:17 +00001570 #
1571 # CAUTION: if you change one of these dictionaries, be sure to adapt the
1572 # list of needed labels in Doc/tools/sphinxext/pyspecific.py and
Georg Brandl5617db82009-04-27 16:28:57 +00001573 # regenerate the pydoc_data/topics.py file by running
Georg Brandl6b38daa2008-06-01 21:05:17 +00001574 # make pydoc-topics
1575 # in Doc/ and copying the output file into the Lib/ directory.
1576
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001577 keywords = {
Ezio Melottib185a042011-04-28 07:42:55 +03001578 'False': '',
1579 'None': '',
1580 'True': '',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001581 'and': 'BOOLEAN',
Guido van Rossumd8faa362007-04-27 19:54:29 +00001582 'as': 'with',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001583 'assert': ('assert', ''),
1584 'break': ('break', 'while for'),
1585 'class': ('class', 'CLASSES SPECIALMETHODS'),
1586 'continue': ('continue', 'while for'),
1587 'def': ('function', ''),
1588 'del': ('del', 'BASICMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001589 'elif': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001590 'else': ('else', 'while for'),
Georg Brandl0d855392008-08-30 19:53:05 +00001591 'except': 'try',
1592 'finally': 'try',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001593 'for': ('for', 'break continue while'),
Georg Brandl0d855392008-08-30 19:53:05 +00001594 'from': 'import',
Georg Brandl74abf6f2010-11-20 19:54:36 +00001595 'global': ('global', 'nonlocal NAMESPACES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001596 'if': ('if', 'TRUTHVALUE'),
1597 'import': ('import', 'MODULES'),
Georg Brandl395ed242009-09-04 08:07:32 +00001598 'in': ('in', 'SEQUENCEMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001599 'is': 'COMPARISON',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001600 'lambda': ('lambda', 'FUNCTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001601 'nonlocal': ('nonlocal', 'global NAMESPACES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001602 'not': 'BOOLEAN',
1603 'or': 'BOOLEAN',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001604 'pass': ('pass', ''),
1605 'raise': ('raise', 'EXCEPTIONS'),
1606 'return': ('return', 'FUNCTIONS'),
1607 'try': ('try', 'EXCEPTIONS'),
1608 'while': ('while', 'break continue if TRUTHVALUE'),
1609 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1610 'yield': ('yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001611 }
Georg Brandldb7b6b92009-01-01 15:53:14 +00001612 # Either add symbols to this dictionary or to the symbols dictionary
1613 # directly: Whichever is easier. They are merged later.
1614 _symbols_inverse = {
1615 'STRINGS' : ("'", "'''", "r'", "b'", '"""', '"', 'r"', 'b"'),
1616 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1617 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1618 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1619 'UNARY' : ('-', '~'),
1620 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1621 '^=', '<<=', '>>=', '**=', '//='),
1622 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1623 'COMPLEX' : ('j', 'J')
1624 }
1625 symbols = {
1626 '%': 'OPERATORS FORMATTING',
1627 '**': 'POWER',
1628 ',': 'TUPLES LISTS FUNCTIONS',
1629 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1630 '...': 'ELLIPSIS',
1631 ':': 'SLICINGS DICTIONARYLITERALS',
1632 '@': 'def class',
1633 '\\': 'STRINGS',
1634 '_': 'PRIVATENAMES',
1635 '__': 'PRIVATENAMES SPECIALMETHODS',
1636 '`': 'BACKQUOTES',
1637 '(': 'TUPLES FUNCTIONS CALLS',
1638 ')': 'TUPLES FUNCTIONS CALLS',
1639 '[': 'LISTS SUBSCRIPTS SLICINGS',
1640 ']': 'LISTS SUBSCRIPTS SLICINGS'
1641 }
1642 for topic, symbols_ in _symbols_inverse.items():
1643 for symbol in symbols_:
1644 topics = symbols.get(symbol, topic)
1645 if topic not in topics:
1646 topics = topics + ' ' + topic
1647 symbols[symbol] = topics
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001648
1649 topics = {
Georg Brandl6b38daa2008-06-01 21:05:17 +00001650 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1651 'FUNCTIONS CLASSES MODULES FILES inspect'),
1652 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
1653 'FORMATTING TYPES'),
1654 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1655 'FORMATTING': ('formatstrings', 'OPERATORS'),
1656 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1657 'FORMATTING TYPES'),
1658 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1659 'INTEGER': ('integers', 'int range'),
1660 'FLOAT': ('floating', 'float math'),
1661 'COMPLEX': ('imaginary', 'complex cmath'),
1662 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001663 'MAPPINGS': 'DICTIONARIES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001664 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1665 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1666 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1667 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001668 'FRAMEOBJECTS': 'TYPES',
1669 'TRACEBACKS': 'TYPES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001670 'NONE': ('bltin-null-object', ''),
1671 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
1672 'FILES': ('bltin-file-objects', ''),
1673 'SPECIALATTRIBUTES': ('specialattrs', ''),
1674 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1675 'MODULES': ('typesmodules', 'import'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001676 'PACKAGES': 'import',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001677 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1678 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1679 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1680 'LISTS DICTIONARIES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001681 'OPERATORS': 'EXPRESSIONS',
1682 'PRECEDENCE': 'EXPRESSIONS',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001683 'OBJECTS': ('objects', 'TYPES'),
1684 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
Georg Brandl395ed242009-09-04 08:07:32 +00001685 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
1686 'NUMBERMETHODS CLASSES'),
Mark Dickinsona56c4672009-01-27 18:17:45 +00001687 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001688 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1689 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001690 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
Georg Brandl6b38daa2008-06-01 21:05:17 +00001691 'SPECIALMETHODS'),
1692 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1693 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1694 'SPECIALMETHODS'),
1695 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001696 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001697 'DYNAMICFEATURES': ('dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001698 'SCOPING': 'NAMESPACES',
1699 'FRAMES': 'NAMESPACES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001700 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1701 'CONVERSIONS': ('conversions', ''),
1702 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1703 'SPECIALIDENTIFIERS': ('id-classes', ''),
1704 'PRIVATENAMES': ('atom-identifiers', ''),
1705 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
1706 'LISTLITERALS DICTIONARYLITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001707 'TUPLES': 'SEQUENCES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001708 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1709 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1710 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1711 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1712 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1713 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001714 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
1715 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001716 'CALLS': ('calls', 'EXPRESSIONS'),
1717 'POWER': ('power', 'EXPRESSIONS'),
1718 'UNARY': ('unary', 'EXPRESSIONS'),
1719 'BINARY': ('binary', 'EXPRESSIONS'),
1720 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1721 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1722 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1723 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001724 'ASSERTION': 'assert',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001725 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1726 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001727 'DELETION': 'del',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001728 'RETURNING': 'return',
1729 'IMPORTING': 'import',
1730 'CONDITIONAL': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001731 'LOOPING': ('compound', 'for while break continue'),
1732 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1733 'DEBUGGING': ('debugger', 'pdb'),
1734 'CONTEXTMANAGERS': ('context-managers', 'with'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001735 }
1736
Georg Brandl78aa3962010-07-31 21:51:48 +00001737 def __init__(self, input=None, output=None):
1738 self._input = input
1739 self._output = output
1740
Georg Brandl76ae3972010-08-01 06:32:55 +00001741 input = property(lambda self: self._input or sys.stdin)
1742 output = property(lambda self: self._output or sys.stdout)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001743
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001744 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001745 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001746 self()
1747 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001748 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001749
Alexander Belopolsky2e733c92010-07-04 17:00:20 +00001750 _GoInteractive = object()
1751 def __call__(self, request=_GoInteractive):
1752 if request is not self._GoInteractive:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001753 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001754 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001755 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001756 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001757 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001758You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001759If you want to ask for help on a particular object directly from the
1760interpreter, you can type "help(object)". Executing "help('string')"
1761has the same effect as typing a particular string at the help> prompt.
1762''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001763
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001764 def interact(self):
1765 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001766 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001767 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001768 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001769 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001770 except (KeyboardInterrupt, EOFError):
1771 break
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001772 request = replace(request, '"', '', "'", '').strip()
1773 if request.lower() in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001774 self.help(request)
1775
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001776 def getline(self, prompt):
Guido van Rossum7c086c02008-01-02 03:52:38 +00001777 """Read one line, using input() when appropriate."""
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001778 if self.input is sys.stdin:
Guido van Rossum7c086c02008-01-02 03:52:38 +00001779 return input(prompt)
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001780 else:
1781 self.output.write(prompt)
1782 self.output.flush()
1783 return self.input.readline()
1784
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001785 def help(self, request):
1786 if type(request) is type(''):
R. David Murray1f1b9d32009-05-27 20:56:59 +00001787 request = request.strip()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001788 if request == 'help': self.intro()
1789 elif request == 'keywords': self.listkeywords()
Georg Brandldb7b6b92009-01-01 15:53:14 +00001790 elif request == 'symbols': self.listsymbols()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001791 elif request == 'topics': self.listtopics()
1792 elif request == 'modules': self.listmodules()
1793 elif request[:8] == 'modules ':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001794 self.listmodules(request.split()[1])
Georg Brandldb7b6b92009-01-01 15:53:14 +00001795 elif request in self.symbols: self.showsymbol(request)
Ezio Melottib185a042011-04-28 07:42:55 +03001796 elif request in ['True', 'False', 'None']:
1797 # special case these keywords since they are objects too
1798 doc(eval(request), 'Help on %s:')
Raymond Hettinger54f02222002-06-01 14:18:47 +00001799 elif request in self.keywords: self.showtopic(request)
1800 elif request in self.topics: self.showtopic(request)
Georg Brandld80d5f42010-12-03 07:47:22 +00001801 elif request: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001802 elif isinstance(request, Helper): self()
Georg Brandld80d5f42010-12-03 07:47:22 +00001803 else: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001804 self.output.write('\n')
1805
1806 def intro(self):
1807 self.output.write('''
1808Welcome to Python %s! This is the online help utility.
1809
1810If this is your first time using Python, you should definitely check out
Georg Brandl86def6c2008-01-21 20:36:10 +00001811the tutorial on the Internet at http://docs.python.org/tutorial/.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001812
1813Enter the name of any module, keyword, or topic to get help on writing
1814Python programs and using Python modules. To quit this help utility and
1815return to the interpreter, just type "quit".
1816
1817To get a list of available modules, keywords, or topics, type "modules",
1818"keywords", or "topics". Each module also comes with a one-line summary
1819of what it does; to list the modules whose summaries contain a given word
1820such as "spam", type "modules spam".
1821''' % sys.version[:3])
1822
1823 def list(self, items, columns=4, width=80):
Guido van Rossum486364b2007-06-30 05:01:58 +00001824 items = list(sorted(items))
1825 colw = width // columns
1826 rows = (len(items) + columns - 1) // columns
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001827 for row in range(rows):
1828 for col in range(columns):
1829 i = col * rows + row
1830 if i < len(items):
1831 self.output.write(items[i])
1832 if col < columns - 1:
Guido van Rossum486364b2007-06-30 05:01:58 +00001833 self.output.write(' ' + ' ' * (colw - 1 - len(items[i])))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001834 self.output.write('\n')
1835
1836 def listkeywords(self):
1837 self.output.write('''
1838Here is a list of the Python keywords. Enter any keyword to get more help.
1839
1840''')
1841 self.list(self.keywords.keys())
1842
Georg Brandldb7b6b92009-01-01 15:53:14 +00001843 def listsymbols(self):
1844 self.output.write('''
1845Here is a list of the punctuation symbols which Python assigns special meaning
1846to. Enter any symbol to get more help.
1847
1848''')
1849 self.list(self.symbols.keys())
1850
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001851 def listtopics(self):
1852 self.output.write('''
1853Here is a list of available topics. Enter any topic name to get more help.
1854
1855''')
1856 self.list(self.topics.keys())
1857
Georg Brandldb7b6b92009-01-01 15:53:14 +00001858 def showtopic(self, topic, more_xrefs=''):
Georg Brandl6b38daa2008-06-01 21:05:17 +00001859 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001860 import pydoc_data.topics
Georg Brandl6b38daa2008-06-01 21:05:17 +00001861 except ImportError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001862 self.output.write('''
Georg Brandl6b38daa2008-06-01 21:05:17 +00001863Sorry, topic and keyword documentation is not available because the
Georg Brandl5617db82009-04-27 16:28:57 +00001864module "pydoc_data.topics" could not be found.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001865''')
1866 return
1867 target = self.topics.get(topic, self.keywords.get(topic))
1868 if not target:
1869 self.output.write('no documentation found for %s\n' % repr(topic))
1870 return
1871 if type(target) is type(''):
Georg Brandldb7b6b92009-01-01 15:53:14 +00001872 return self.showtopic(target, more_xrefs)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001873
Georg Brandl6b38daa2008-06-01 21:05:17 +00001874 label, xrefs = target
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001875 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001876 doc = pydoc_data.topics.topics[label]
Georg Brandl6b38daa2008-06-01 21:05:17 +00001877 except KeyError:
1878 self.output.write('no documentation found for %s\n' % repr(topic))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001879 return
Georg Brandl6b38daa2008-06-01 21:05:17 +00001880 pager(doc.strip() + '\n')
Georg Brandldb7b6b92009-01-01 15:53:14 +00001881 if more_xrefs:
1882 xrefs = (xrefs or '') + ' ' + more_xrefs
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001883 if xrefs:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001884 import formatter
Guido van Rossum34d19282007-08-09 01:03:29 +00001885 buffer = io.StringIO()
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001886 formatter.DumbWriter(buffer).send_flowing_data(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001887 'Related help topics: ' + ', '.join(xrefs.split()) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001888 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001889
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001890 def _gettopic(self, topic, more_xrefs=''):
1891 """Return unbuffered tuple of (topic, xrefs).
1892
Georg Brandld2f38572011-01-30 08:37:19 +00001893 If an error occurs here, the exception is caught and displayed by
1894 the url handler.
1895
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001896 This function duplicates the showtopic method but returns its
1897 result directly so it can be formatted for display in an html page.
1898 """
1899 try:
1900 import pydoc_data.topics
1901 except ImportError:
1902 return('''
1903Sorry, topic and keyword documentation is not available because the
1904module "pydoc_data.topics" could not be found.
1905''' , '')
1906 target = self.topics.get(topic, self.keywords.get(topic))
1907 if not target:
Georg Brandld2f38572011-01-30 08:37:19 +00001908 raise ValueError('could not find topic')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001909 if isinstance(target, str):
1910 return self._gettopic(target, more_xrefs)
1911 label, xrefs = target
Georg Brandld2f38572011-01-30 08:37:19 +00001912 doc = pydoc_data.topics.topics[label]
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001913 if more_xrefs:
1914 xrefs = (xrefs or '') + ' ' + more_xrefs
1915 return doc, xrefs
1916
Georg Brandldb7b6b92009-01-01 15:53:14 +00001917 def showsymbol(self, symbol):
1918 target = self.symbols[symbol]
1919 topic, _, xrefs = target.partition(' ')
1920 self.showtopic(topic, xrefs)
1921
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001922 def listmodules(self, key=''):
1923 if key:
1924 self.output.write('''
1925Here is a list of matching modules. Enter any module name to get more help.
1926
1927''')
1928 apropos(key)
1929 else:
1930 self.output.write('''
1931Please wait a moment while I gather a list of all available modules...
1932
1933''')
1934 modules = {}
1935 def callback(path, modname, desc, modules=modules):
1936 if modname and modname[-9:] == '.__init__':
1937 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001938 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001939 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001940 def onerror(modname):
1941 callback(None, modname, None)
1942 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001943 self.list(modules.keys())
1944 self.output.write('''
1945Enter any module name to get more help. Or, type "modules spam" to search
1946for modules whose descriptions contain the word "spam".
1947''')
1948
Georg Brandl78aa3962010-07-31 21:51:48 +00001949help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001950
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001951class Scanner:
1952 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001953 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001954 self.roots = roots[:]
1955 self.state = []
1956 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001957 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001958
1959 def next(self):
1960 if not self.state:
1961 if not self.roots:
1962 return None
1963 root = self.roots.pop(0)
1964 self.state = [(root, self.children(root))]
1965 node, children = self.state[-1]
1966 if not children:
1967 self.state.pop()
1968 return self.next()
1969 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001970 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001971 self.state.append((child, self.children(child)))
1972 return child
1973
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001974
1975class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001976 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001977
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001978 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001979 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001980 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001981 seen = {}
1982
1983 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00001984 if modname != '__main__':
1985 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00001986 if key is None:
1987 callback(None, modname, '')
1988 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001989 name = __import__(modname).__doc__ or ''
1990 desc = name.split('\n')[0]
1991 name = modname + ' - ' + desc
1992 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00001993 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001994
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001995 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001996 if self.quit:
1997 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001998
1999 # XXX Skipping this file is a workaround for a bug
2000 # that causes python to crash with a segfault.
2001 # http://bugs.python.org/issue9319
2002 #
2003 # TODO Remove this once the bug is fixed.
2004 if modname in {'test.badsyntax_pep3120', 'badsyntax_pep3120'}:
2005 continue
2006
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002007 if key is None:
2008 callback(None, modname, '')
2009 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002010 try:
2011 loader = importer.find_module(modname)
2012 except SyntaxError:
2013 # raised by tests for bad coding cookies or BOM
2014 continue
2015 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002016 try:
2017 source = loader.get_source(modname)
2018 except UnicodeDecodeError:
2019 if onerror:
2020 onerror(modname)
2021 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002022 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002023 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002024 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002025 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002026 path = None
2027 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002028 try:
2029 module = loader.load_module(modname)
2030 except ImportError:
2031 if onerror:
2032 onerror(modname)
2033 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002034 desc = (module.__doc__ or '').splitlines()[0]
2035 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002036 name = modname + ' - ' + desc
2037 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002038 callback(path, modname, desc)
2039
2040 if completer:
2041 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002042
2043def apropos(key):
2044 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002045 def callback(path, modname, desc):
2046 if modname[-9:] == '.__init__':
2047 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002048 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002049 def onerror(modname):
2050 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002051 with warnings.catch_warnings():
2052 warnings.filterwarnings('ignore') # ignore problems during import
2053 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002054
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002055# --------------------------------------------------- Web browser interface
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002056
Ka-Ping Yee66246962001-04-12 11:59:50 +00002057def serve(port, callback=None, completer=None):
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002058 import http.server, email.message, select
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002059
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002060 msg = 'the pydoc.serve() function is deprecated'
2061 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2062
Georg Brandl24420152008-05-26 16:32:26 +00002063 class DocHandler(http.server.BaseHTTPRequestHandler):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002064 def send_document(self, title, contents):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002065 try:
2066 self.send_response(200)
Georg Brandl825fc8b2008-01-19 20:44:32 +00002067 self.send_header('Content-Type', 'text/html; charset=UTF-8')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002068 self.end_headers()
Georg Brandl825fc8b2008-01-19 20:44:32 +00002069 self.wfile.write(html.page(title, contents).encode('utf-8'))
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002070 except IOError: pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002071
2072 def do_GET(self):
2073 path = self.path
2074 if path[-5:] == '.html': path = path[:-5]
2075 if path[:1] == '/': path = path[1:]
2076 if path and path != '.':
2077 try:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00002078 obj = locate(path, forceload=1)
Guido van Rossumb940e112007-01-10 16:19:56 +00002079 except ErrorDuringImport as value:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002080 self.send_document(path, html.escape(str(value)))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002081 return
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002082 if obj:
2083 self.send_document(describe(obj), html.document(obj, path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002084 else:
2085 self.send_document(path,
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002086'no Python documentation found for %s' % repr(path))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002087 else:
2088 heading = html.heading(
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002089'<big><big><strong>Python: Index of Modules</strong></big></big>',
2090'#ffffff', '#7799ee')
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002091 def bltinlink(name):
2092 return '<a href="%s.html">%s</a>' % (name, name)
Georg Brandl661b0a12008-01-27 18:16:00 +00002093 names = [x for x in sys.builtin_module_names if x != '__main__']
2094 contents = html.multicolumn(names, bltinlink)
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002095 indices = ['<p>' + html.bigsection(
2096 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2097
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002098 seen = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002099 for dir in sys.path:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002100 indices.append(html.index(dir, seen))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002101 contents = heading + ' '.join(indices) + '''<p align=right>
Tim Peters2306d242001-09-25 03:18:32 +00002102<font color="#909090" face="helvetica, arial"><strong>
2103pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002104 self.send_document('Index of Modules', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002105
2106 def log_message(self, *args): pass
2107
Georg Brandl24420152008-05-26 16:32:26 +00002108 class DocServer(http.server.HTTPServer):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002109 def __init__(self, port, callback):
Ronald Oussoren94f25282010-05-05 19:11:21 +00002110 host = 'localhost'
Senthil Kumaran7ff59132010-08-18 19:32:21 +00002111 self.address = (host, port)
Ka-Ping Yeedb8ed152001-03-02 05:58:17 +00002112 self.url = 'http://%s:%d/' % (host, port)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002113 self.callback = callback
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002114 self.base.__init__(self, self.address, self.handler)
2115
2116 def serve_until_quit(self):
2117 import select
Guido van Rossum8ca162f2002-04-07 06:36:23 +00002118 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002119 while not self.quit:
2120 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2121 if rd: self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002122 self.server_close()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002123
2124 def server_activate(self):
2125 self.base.server_activate(self)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002126 if self.callback: self.callback(self)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002127
Georg Brandl24420152008-05-26 16:32:26 +00002128 DocServer.base = http.server.HTTPServer
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002129 DocServer.handler = DocHandler
Georg Brandl83e9f4c2008-06-12 18:52:31 +00002130 DocHandler.MessageClass = email.message.Message
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002131 try:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002132 try:
2133 DocServer(port, callback).serve_until_quit()
2134 except (KeyboardInterrupt, select.error):
2135 pass
2136 finally:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002137 if completer: completer()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002138
2139# ----------------------------------------------------- graphical interface
2140
2141def gui():
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002142 """Graphical interface (starts Web server and pops up a control window)."""
2143
2144 msg = ('the pydoc.gui() function and "pydoc -g" option are deprecated\n',
2145 'use "pydoc.browse() function and "pydoc -b" option instead.')
2146 warnings.warn(msg, DeprecationWarning, stacklevel=2)
2147
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002148 class GUI:
2149 def __init__(self, window, port=7464):
2150 self.window = window
2151 self.server = None
2152 self.scanner = None
2153
Georg Brandl14fc4272008-05-17 18:39:55 +00002154 import tkinter
2155 self.server_frm = tkinter.Frame(window)
2156 self.title_lbl = tkinter.Label(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002157 text='Starting server...\n ')
Georg Brandl14fc4272008-05-17 18:39:55 +00002158 self.open_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002159 text='open browser', command=self.open, state='disabled')
Georg Brandl14fc4272008-05-17 18:39:55 +00002160 self.quit_btn = tkinter.Button(self.server_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002161 text='quit serving', command=self.quit, state='disabled')
2162
Georg Brandl14fc4272008-05-17 18:39:55 +00002163 self.search_frm = tkinter.Frame(window)
2164 self.search_lbl = tkinter.Label(self.search_frm, text='Search for')
2165 self.search_ent = tkinter.Entry(self.search_frm)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002166 self.search_ent.bind('<Return>', self.search)
Georg Brandl14fc4272008-05-17 18:39:55 +00002167 self.stop_btn = tkinter.Button(self.search_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002168 text='stop', pady=0, command=self.stop, state='disabled')
2169 if sys.platform == 'win32':
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002170 # Trying to hide and show this button crashes under Windows.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002171 self.stop_btn.pack(side='right')
2172
2173 self.window.title('pydoc')
2174 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2175 self.title_lbl.pack(side='top', fill='x')
2176 self.open_btn.pack(side='left', fill='x', expand=1)
2177 self.quit_btn.pack(side='right', fill='x', expand=1)
2178 self.server_frm.pack(side='top', fill='x')
2179
2180 self.search_lbl.pack(side='left')
2181 self.search_ent.pack(side='right', fill='x', expand=1)
2182 self.search_frm.pack(side='top', fill='x')
2183 self.search_ent.focus_set()
2184
Ka-Ping Yeec92cdf72001-03-02 05:54:35 +00002185 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
Georg Brandl14fc4272008-05-17 18:39:55 +00002186 self.result_lst = tkinter.Listbox(window, font=font, height=6)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002187 self.result_lst.bind('<Button-1>', self.select)
2188 self.result_lst.bind('<Double-Button-1>', self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002189 self.result_scr = tkinter.Scrollbar(window,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002190 orient='vertical', command=self.result_lst.yview)
2191 self.result_lst.config(yscrollcommand=self.result_scr.set)
2192
Georg Brandl14fc4272008-05-17 18:39:55 +00002193 self.result_frm = tkinter.Frame(window)
2194 self.goto_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002195 text='go to selected', command=self.goto)
Georg Brandl14fc4272008-05-17 18:39:55 +00002196 self.hide_btn = tkinter.Button(self.result_frm,
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002197 text='hide results', command=self.hide)
2198 self.goto_btn.pack(side='left', fill='x', expand=1)
2199 self.hide_btn.pack(side='right', fill='x', expand=1)
2200
2201 self.window.update()
2202 self.minwidth = self.window.winfo_width()
2203 self.minheight = self.window.winfo_height()
2204 self.bigminheight = (self.server_frm.winfo_reqheight() +
2205 self.search_frm.winfo_reqheight() +
2206 self.result_lst.winfo_reqheight() +
2207 self.result_frm.winfo_reqheight())
2208 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2209 self.expanded = 0
2210 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2211 self.window.wm_minsize(self.minwidth, self.minheight)
Martin v. Löwis5b26abb2002-12-28 09:23:09 +00002212 self.window.tk.willdispatch()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002213
2214 import threading
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00002215 threading.Thread(
2216 target=serve, args=(port, self.ready, self.quit)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002217
2218 def ready(self, server):
2219 self.server = server
2220 self.title_lbl.config(
2221 text='Python documentation server at\n' + server.url)
2222 self.open_btn.config(state='normal')
2223 self.quit_btn.config(state='normal')
2224
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002225 def open(self, event=None, url=None):
2226 url = url or self.server.url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002227 import webbrowser
2228 webbrowser.open(url)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002229
2230 def quit(self, event=None):
2231 if self.server:
2232 self.server.quit = 1
2233 self.window.quit()
2234
2235 def search(self, event=None):
2236 key = self.search_ent.get()
2237 self.stop_btn.pack(side='right')
2238 self.stop_btn.config(state='normal')
2239 self.search_lbl.config(text='Searching for "%s"...' % key)
2240 self.search_ent.forget()
2241 self.search_lbl.pack(side='left')
2242 self.result_lst.delete(0, 'end')
2243 self.goto_btn.config(state='disabled')
2244 self.expand()
2245
2246 import threading
2247 if self.scanner:
2248 self.scanner.quit = 1
2249 self.scanner = ModuleScanner()
2250 threading.Thread(target=self.scanner.run,
Ka-Ping Yee6dcfa382001-04-12 20:27:31 +00002251 args=(self.update, key, self.done)).start()
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002252
2253 def update(self, path, modname, desc):
2254 if modname[-9:] == '.__init__':
2255 modname = modname[:-9] + ' (package)'
2256 self.result_lst.insert('end',
2257 modname + ' - ' + (desc or '(no description)'))
2258
2259 def stop(self, event=None):
2260 if self.scanner:
2261 self.scanner.quit = 1
2262 self.scanner = None
2263
2264 def done(self):
2265 self.scanner = None
2266 self.search_lbl.config(text='Search for')
2267 self.search_lbl.pack(side='left')
2268 self.search_ent.pack(side='right', fill='x', expand=1)
2269 if sys.platform != 'win32': self.stop_btn.forget()
2270 self.stop_btn.config(state='disabled')
2271
2272 def select(self, event=None):
2273 self.goto_btn.config(state='normal')
2274
2275 def goto(self, event=None):
2276 selection = self.result_lst.curselection()
2277 if selection:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002278 modname = self.result_lst.get(selection[0]).split()[0]
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002279 self.open(url=self.server.url + modname + '.html')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002280
2281 def collapse(self):
2282 if not self.expanded: return
2283 self.result_frm.forget()
2284 self.result_scr.forget()
2285 self.result_lst.forget()
2286 self.bigwidth = self.window.winfo_width()
2287 self.bigheight = self.window.winfo_height()
2288 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2289 self.window.wm_minsize(self.minwidth, self.minheight)
2290 self.expanded = 0
2291
2292 def expand(self):
2293 if self.expanded: return
2294 self.result_frm.pack(side='bottom', fill='x')
2295 self.result_scr.pack(side='right', fill='y')
2296 self.result_lst.pack(side='top', fill='both', expand=1)
2297 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2298 self.window.wm_minsize(self.minwidth, self.bigminheight)
2299 self.expanded = 1
2300
2301 def hide(self, event=None):
2302 self.stop()
2303 self.collapse()
2304
Georg Brandl14fc4272008-05-17 18:39:55 +00002305 import tkinter
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002306 try:
Georg Brandl14fc4272008-05-17 18:39:55 +00002307 root = tkinter.Tk()
Martin v. Löwise09bd932004-08-22 16:13:26 +00002308 # Tk will crash if pythonw.exe has an XP .manifest
2309 # file and the root has is not destroyed explicitly.
2310 # If the problem is ever fixed in Tk, the explicit
2311 # destroy can go.
2312 try:
2313 gui = GUI(root)
2314 root.mainloop()
2315 finally:
2316 root.destroy()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002317 except KeyboardInterrupt:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002318 pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002319
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002320
2321# --------------------------------------- enhanced Web browser interface
2322
2323def _start_server(urlhandler, port):
2324 """Start an HTTP server thread on a specific port.
2325
2326 Start an HTML/text server thread, so HTML or text documents can be
2327 browsed dynamically and interactively with a Web browser. Example use:
2328
2329 >>> import time
2330 >>> import pydoc
2331
2332 Define a URL handler. To determine what the client is asking
2333 for, check the URL and content_type.
2334
2335 Then get or generate some text or HTML code and return it.
2336
2337 >>> def my_url_handler(url, content_type):
2338 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2339 ... return text
2340
2341 Start server thread on port 0.
2342 If you use port 0, the server will pick a random port number.
2343 You can then use serverthread.port to get the port number.
2344
2345 >>> port = 0
2346 >>> serverthread = pydoc._start_server(my_url_handler, port)
2347
2348 Check that the server is really started. If it is, open browser
2349 and get first page. Use serverthread.url as the starting page.
2350
2351 >>> if serverthread.serving:
2352 ... import webbrowser
2353
2354 The next two lines are commented out so a browser doesn't open if
2355 doctest is run on this module.
2356
2357 #... webbrowser.open(serverthread.url)
2358 #True
2359
2360 Let the server do its thing. We just need to monitor its status.
2361 Use time.sleep so the loop doesn't hog the CPU.
2362
2363 >>> starttime = time.time()
2364 >>> timeout = 1 #seconds
2365
2366 This is a short timeout for testing purposes.
2367
2368 >>> while serverthread.serving:
2369 ... time.sleep(.01)
2370 ... if serverthread.serving and time.time() - starttime > timeout:
2371 ... serverthread.stop()
2372 ... break
2373
2374 Print any errors that may have occurred.
2375
2376 >>> print(serverthread.error)
2377 None
2378 """
2379 import http.server
2380 import email.message
2381 import select
2382 import threading
2383
2384 class DocHandler(http.server.BaseHTTPRequestHandler):
2385
2386 def do_GET(self):
2387 """Process a request from an HTML browser.
2388
2389 The URL received is in self.path.
2390 Get an HTML page from self.urlhandler and send it.
2391 """
2392 if self.path.endswith('.css'):
2393 content_type = 'text/css'
2394 else:
2395 content_type = 'text/html'
2396 self.send_response(200)
Georg Brandld2f38572011-01-30 08:37:19 +00002397 self.send_header('Content-Type', '%s; charset=UTF-8' % content_type)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002398 self.end_headers()
2399 self.wfile.write(self.urlhandler(
2400 self.path, content_type).encode('utf-8'))
2401
2402 def log_message(self, *args):
2403 # Don't log messages.
2404 pass
2405
2406 class DocServer(http.server.HTTPServer):
2407
2408 def __init__(self, port, callback):
2409 self.host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
2410 self.address = ('', port)
2411 self.callback = callback
2412 self.base.__init__(self, self.address, self.handler)
2413 self.quit = False
2414
2415 def serve_until_quit(self):
2416 while not self.quit:
2417 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2418 if rd:
2419 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002420 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002421
2422 def server_activate(self):
2423 self.base.server_activate(self)
2424 if self.callback:
2425 self.callback(self)
2426
2427 class ServerThread(threading.Thread):
2428
2429 def __init__(self, urlhandler, port):
2430 self.urlhandler = urlhandler
2431 self.port = int(port)
2432 threading.Thread.__init__(self)
2433 self.serving = False
2434 self.error = None
2435
2436 def run(self):
2437 """Start the server."""
2438 try:
2439 DocServer.base = http.server.HTTPServer
2440 DocServer.handler = DocHandler
2441 DocHandler.MessageClass = email.message.Message
2442 DocHandler.urlhandler = staticmethod(self.urlhandler)
2443 docsvr = DocServer(self.port, self.ready)
2444 self.docserver = docsvr
2445 docsvr.serve_until_quit()
2446 except Exception as e:
2447 self.error = e
2448
2449 def ready(self, server):
2450 self.serving = True
2451 self.host = server.host
2452 self.port = server.server_port
2453 self.url = 'http://%s:%d/' % (self.host, self.port)
2454
2455 def stop(self):
2456 """Stop the server and this thread nicely"""
2457 self.docserver.quit = True
2458 self.serving = False
2459 self.url = None
2460
2461 thread = ServerThread(urlhandler, port)
2462 thread.start()
2463 # Wait until thread.serving is True to make sure we are
2464 # really up before returning.
2465 while not thread.error and not thread.serving:
2466 time.sleep(.01)
2467 return thread
2468
2469
2470def _url_handler(url, content_type="text/html"):
2471 """The pydoc url handler for use with the pydoc server.
2472
2473 If the content_type is 'text/css', the _pydoc.css style
2474 sheet is read and returned if it exits.
2475
2476 If the content_type is 'text/html', then the result of
2477 get_html_page(url) is returned.
2478 """
2479 class _HTMLDoc(HTMLDoc):
2480
2481 def page(self, title, contents):
2482 """Format an HTML page."""
2483 css_path = "pydoc_data/_pydoc.css"
2484 css_link = (
2485 '<link rel="stylesheet" type="text/css" href="%s">' %
2486 css_path)
2487 return '''\
2488<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Georg Brandld2f38572011-01-30 08:37:19 +00002489<html><head><title>Pydoc: %s</title>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002490<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Georg Brandld2f38572011-01-30 08:37:19 +00002491%s</head><body bgcolor="#f0f0f8">%s<div style="clear:both;padding-top:.5em;">%s</div>
2492</body></html>''' % (title, css_link, html_navbar(), contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002493
2494 def filelink(self, url, path):
2495 return '<a href="getfile?key=%s">%s</a>' % (url, path)
2496
2497
2498 html = _HTMLDoc()
2499
2500 def html_navbar():
Georg Brandld2f38572011-01-30 08:37:19 +00002501 version = html.escape("%s [%s, %s]" % (platform.python_version(),
2502 platform.python_build()[0],
2503 platform.python_compiler()))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002504 return """
2505 <div style='float:left'>
Georg Brandld2f38572011-01-30 08:37:19 +00002506 Python %s<br>%s
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002507 </div>
2508 <div style='float:right'>
2509 <div style='text-align:center'>
2510 <a href="index.html">Module Index</a>
2511 : <a href="topics.html">Topics</a>
2512 : <a href="keywords.html">Keywords</a>
2513 </div>
2514 <div>
Georg Brandld2f38572011-01-30 08:37:19 +00002515 <form action="get" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002516 <input type=text name=key size=15>
2517 <input type=submit value="Get">
Georg Brandld2f38572011-01-30 08:37:19 +00002518 </form>&nbsp;
2519 <form action="search" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002520 <input type=text name=key size=15>
2521 <input type=submit value="Search">
2522 </form>
2523 </div>
2524 </div>
Georg Brandld2f38572011-01-30 08:37:19 +00002525 """ % (version, html.escape(platform.platform(terse=True)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002526
2527 def html_index():
2528 """Module Index page."""
2529
2530 def bltinlink(name):
2531 return '<a href="%s.html">%s</a>' % (name, name)
2532
2533 heading = html.heading(
2534 '<big><big><strong>Index of Modules</strong></big></big>',
2535 '#ffffff', '#7799ee')
2536 names = [name for name in sys.builtin_module_names
2537 if name != '__main__']
2538 contents = html.multicolumn(names, bltinlink)
2539 contents = [heading, '<p>' + html.bigsection(
2540 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2541
2542 seen = {}
2543 for dir in sys.path:
2544 contents.append(html.index(dir, seen))
2545
2546 contents.append(
2547 '<p align=right><font color="#909090" face="helvetica,'
2548 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2549 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002550 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002551
2552 def html_search(key):
2553 """Search results page."""
2554 # scan for modules
2555 search_result = []
2556
2557 def callback(path, modname, desc):
2558 if modname[-9:] == '.__init__':
2559 modname = modname[:-9] + ' (package)'
2560 search_result.append((modname, desc and '- ' + desc))
2561
2562 with warnings.catch_warnings():
2563 warnings.filterwarnings('ignore') # ignore problems during import
2564 ModuleScanner().run(callback, key)
2565
2566 # format page
2567 def bltinlink(name):
2568 return '<a href="%s.html">%s</a>' % (name, name)
2569
2570 results = []
2571 heading = html.heading(
2572 '<big><big><strong>Search Results</strong></big></big>',
2573 '#ffffff', '#7799ee')
2574 for name, desc in search_result:
2575 results.append(bltinlink(name) + desc)
2576 contents = heading + html.bigsection(
2577 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002578 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002579
2580 def html_getfile(path):
2581 """Get and display a source file listing safely."""
Nick Coghlanecace282010-12-03 16:08:46 +00002582 path = path.replace('%20', ' ')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002583 with open(path, 'r') as fp:
2584 lines = html.escape(fp.read())
2585 body = '<pre>%s</pre>' % lines
2586 heading = html.heading(
2587 '<big><big><strong>File Listing</strong></big></big>',
2588 '#ffffff', '#7799ee')
2589 contents = heading + html.bigsection(
2590 'File: %s' % path, '#ffffff', '#ee77aa', body)
Nick Coghlanecace282010-12-03 16:08:46 +00002591 return 'getfile %s' % path, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002592
2593 def html_topics():
2594 """Index of topic texts available."""
2595
2596 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002597 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002598
2599 heading = html.heading(
2600 '<big><big><strong>INDEX</strong></big></big>',
2601 '#ffffff', '#7799ee')
2602 names = sorted(Helper.topics.keys())
2603
2604 contents = html.multicolumn(names, bltinlink)
2605 contents = heading + html.bigsection(
2606 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002607 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002608
2609 def html_keywords():
2610 """Index of keywords."""
2611 heading = html.heading(
2612 '<big><big><strong>INDEX</strong></big></big>',
2613 '#ffffff', '#7799ee')
2614 names = sorted(Helper.keywords.keys())
2615
2616 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002617 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002618
2619 contents = html.multicolumn(names, bltinlink)
2620 contents = heading + html.bigsection(
2621 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002622 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002623
2624 def html_topicpage(topic):
2625 """Topic or keyword help page."""
2626 buf = io.StringIO()
2627 htmlhelp = Helper(buf, buf)
2628 contents, xrefs = htmlhelp._gettopic(topic)
2629 if topic in htmlhelp.keywords:
2630 title = 'KEYWORD'
2631 else:
2632 title = 'TOPIC'
2633 heading = html.heading(
2634 '<big><big><strong>%s</strong></big></big>' % title,
2635 '#ffffff', '#7799ee')
Georg Brandld2f38572011-01-30 08:37:19 +00002636 contents = '<pre>%s</pre>' % html.markup(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002637 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
Georg Brandld2f38572011-01-30 08:37:19 +00002638 if xrefs:
2639 xrefs = sorted(xrefs.split())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002640
Georg Brandld2f38572011-01-30 08:37:19 +00002641 def bltinlink(name):
2642 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002643
Georg Brandld2f38572011-01-30 08:37:19 +00002644 xrefs = html.multicolumn(xrefs, bltinlink)
2645 xrefs = html.section('Related help topics: ',
2646 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002647 return ('%s %s' % (title, topic),
2648 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002649
Georg Brandld2f38572011-01-30 08:37:19 +00002650 def html_getobj(url):
2651 obj = locate(url, forceload=1)
2652 if obj is None and url != 'None':
2653 raise ValueError('could not find object')
2654 title = describe(obj)
2655 content = html.document(obj, url)
2656 return title, content
2657
2658 def html_error(url, exc):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002659 heading = html.heading(
2660 '<big><big><strong>Error</strong></big></big>',
Georg Brandld2f38572011-01-30 08:37:19 +00002661 '#ffffff', '#7799ee')
2662 contents = '<br>'.join(html.escape(line) for line in
2663 format_exception_only(type(exc), exc))
2664 contents = heading + html.bigsection(url, '#ffffff', '#bb0000',
2665 contents)
2666 return "Error - %s" % url, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002667
2668 def get_html_page(url):
2669 """Generate an HTML page for url."""
Georg Brandld2f38572011-01-30 08:37:19 +00002670 complete_url = url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002671 if url.endswith('.html'):
2672 url = url[:-5]
Georg Brandld2f38572011-01-30 08:37:19 +00002673 try:
2674 if url in ("", "index"):
2675 title, content = html_index()
2676 elif url == "topics":
2677 title, content = html_topics()
2678 elif url == "keywords":
2679 title, content = html_keywords()
2680 elif '=' in url:
2681 op, _, url = url.partition('=')
2682 if op == "search?key":
2683 title, content = html_search(url)
2684 elif op == "getfile?key":
2685 title, content = html_getfile(url)
2686 elif op == "topic?key":
2687 # try topics first, then objects.
2688 try:
2689 title, content = html_topicpage(url)
2690 except ValueError:
2691 title, content = html_getobj(url)
2692 elif op == "get?key":
2693 # try objects first, then topics.
2694 if url in ("", "index"):
2695 title, content = html_index()
2696 else:
2697 try:
2698 title, content = html_getobj(url)
2699 except ValueError:
2700 title, content = html_topicpage(url)
2701 else:
2702 raise ValueError('bad pydoc url')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002703 else:
Georg Brandld2f38572011-01-30 08:37:19 +00002704 title, content = html_getobj(url)
2705 except Exception as exc:
2706 # Catch any errors and display them in an error page.
2707 title, content = html_error(complete_url, exc)
2708 return html.page(title, content)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002709
2710 if url.startswith('/'):
2711 url = url[1:]
2712 if content_type == 'text/css':
2713 path_here = os.path.dirname(os.path.realpath(__file__))
Georg Brandld2f38572011-01-30 08:37:19 +00002714 css_path = os.path.join(path_here, url)
2715 with open(css_path) as fp:
2716 return ''.join(fp.readlines())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002717 elif content_type == 'text/html':
2718 return get_html_page(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002719 # Errors outside the url handler are caught by the server.
2720 raise TypeError('unknown content type %r for url %s' % (content_type, url))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002721
2722
2723def browse(port=0, *, open_browser=True):
2724 """Start the enhanced pydoc Web server and open a Web browser.
2725
2726 Use port '0' to start the server on an arbitrary port.
2727 Set open_browser to False to suppress opening a browser.
2728 """
2729 import webbrowser
2730 serverthread = _start_server(_url_handler, port)
2731 if serverthread.error:
2732 print(serverthread.error)
2733 return
2734 if serverthread.serving:
2735 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2736 if open_browser:
2737 webbrowser.open(serverthread.url)
2738 try:
2739 print('Server ready at', serverthread.url)
2740 print(server_help_msg)
2741 while serverthread.serving:
2742 cmd = input('server> ')
2743 cmd = cmd.lower()
2744 if cmd == 'q':
2745 break
2746 elif cmd == 'b':
2747 webbrowser.open(serverthread.url)
2748 else:
2749 print(server_help_msg)
2750 except (KeyboardInterrupt, EOFError):
2751 print()
2752 finally:
2753 if serverthread.serving:
2754 serverthread.stop()
2755 print('Server stopped')
2756
2757
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002758# -------------------------------------------------- command-line interface
2759
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002760def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002761 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002762
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002763def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002764 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002765 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002766 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002767
Nick Coghlan106274b2009-11-15 23:04:33 +00002768 # Scripts don't get the current directory in their path by default
2769 # unless they are run with the '-m' switch
2770 if '' not in sys.path:
2771 scriptdir = os.path.dirname(sys.argv[0])
2772 if scriptdir in sys.path:
2773 sys.path.remove(scriptdir)
2774 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002775
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002776 try:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002777 opts, args = getopt.getopt(sys.argv[1:], 'bgk:p:w')
2778 writing = False
2779 start_server = False
2780 open_browser = False
2781 port = None
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002782 for opt, val in opts:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002783 if opt == '-g':
2784 gui()
2785 return
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002786 if opt == '-b':
2787 start_server = True
2788 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002789 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002790 apropos(val)
2791 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002792 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002793 start_server = True
2794 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002795 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002796 writing = True
2797
2798 if start_server == True:
2799 if port == None:
2800 port = 0
2801 browse(port, open_browser=open_browser)
2802 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002803
2804 if not args: raise BadUsage
2805 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002806 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002807 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002808 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002809 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002810 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002811 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002812 if writing:
2813 if ispath(arg) and os.path.isdir(arg):
2814 writedocs(arg)
2815 else:
2816 writedoc(arg)
2817 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002818 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002819 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002820 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002821
2822 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002823 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002824 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002825
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002826{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002827 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002828 Python keyword, topic, function, module, or package, or a dotted
2829 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002830 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002831 Python source file to document. If name is 'keywords', 'topics',
2832 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002833
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002834{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002835 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002836
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002837{cmd} -p <port>
2838 Start an HTTP server on the given port on the local machine. Port
2839 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002840
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002841{cmd} -b
2842 Start an HTTP server on an arbitrary unused port and open a Web browser
2843 to interactively browse documentation. The -p option can be used with
2844 the -b option to explicitly specify the server port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002845
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002846{cmd} -g
2847 Deprecated.
2848
2849{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002850 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002851 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002852 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002853""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002854
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002855if __name__ == '__main__':
2856 cli()