blob: 8b94993928316cadf6b746daa38cd99e9b2327c8 [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 +000025Run "pydoc -w <name>" to write out the HTML documentation for a module
26to a file named "<name>.html".
Skip Montanaro4997a692003-09-10 16:47:51 +000027
28Module docs for core modules are assumed to be in
29
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000030 http://docs.python.org/X.Y/library/
Skip Montanaro4997a692003-09-10 16:47:51 +000031
32This can be overridden by setting the PYTHONDOCS environment variable
33to a different URL or to a local directory containing the Library
34Reference Manual pages.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000035"""
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000036__all__ = ['help']
Ka-Ping Yeedd175342001-02-27 14:43:46 +000037__author__ = "Ka-Ping Yee <ping@lfw.org>"
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000038__date__ = "26 February 2001"
Jeremy Hylton3e0055f2005-10-20 19:59:25 +000039
Martin v. Löwis6fe8f192004-11-14 10:21:04 +000040__credits__ = """Guido van Rossum, for an excellent programming language.
Ka-Ping Yee5e2b1732001-02-27 23:35:09 +000041Tommy Burnette, the original creator of manpy.
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +000042Paul Prescod, for all his work on onlinehelp.
43Richard Chamberlain, for the first implementation of textdoc.
Raymond Hettingered2dbe32005-01-01 07:51:01 +000044"""
Ka-Ping Yeedd175342001-02-27 14:43:46 +000045
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000046# Known bugs that can't be fixed here:
47# - imp.load_module() cannot be prevented from clobbering existing
48# loaded modules, so calling synopsis() on a binary module file
49# changes the contents of any existing module with the same name.
50# - If the __file__ attribute on a module is a relative path and
51# the current directory is changed with os.chdir(), an incorrect
52# path will be displayed.
Ka-Ping Yee66efbc72001-03-01 13:55:20 +000053
Nick Coghlan7bb30b72010-12-03 09:29:11 +000054import builtins
55import imp
Nick Coghlan7bb30b72010-12-03 09:29:11 +000056import inspect
Victor Stinnere6c910e2011-06-30 15:55:43 +020057import io
58import os
Nick Coghlan7bb30b72010-12-03 09:29:11 +000059import pkgutil
60import platform
61import re
Victor Stinnere6c910e2011-06-30 15:55:43 +020062import sys
Nick Coghlan7bb30b72010-12-03 09:29:11 +000063import time
Victor Stinnere6c910e2011-06-30 15:55:43 +020064import tokenize
Nick Coghlan7bb30b72010-12-03 09:29:11 +000065import warnings
Alexander Belopolskya47bbf52010-11-18 01:52:54 +000066from collections import deque
Nick Coghlan7bb30b72010-12-03 09:29:11 +000067from reprlib import Repr
Georg Brandld2f38572011-01-30 08:37:19 +000068from traceback import extract_tb, format_exception_only
Nick Coghlan7bb30b72010-12-03 09:29:11 +000069
70
Ka-Ping Yeedd175342001-02-27 14:43:46 +000071# --------------------------------------------------------- common routines
72
Ka-Ping Yeedd175342001-02-27 14:43:46 +000073def pathdirs():
74 """Convert sys.path into a list of absolute, existing, unique paths."""
75 dirs = []
Ka-Ping Yee1d384632001-03-01 00:24:32 +000076 normdirs = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +000077 for dir in sys.path:
78 dir = os.path.abspath(dir or '.')
Ka-Ping Yee1d384632001-03-01 00:24:32 +000079 normdir = os.path.normcase(dir)
80 if normdir not in normdirs and os.path.isdir(dir):
Ka-Ping Yeedd175342001-02-27 14:43:46 +000081 dirs.append(dir)
Ka-Ping Yee1d384632001-03-01 00:24:32 +000082 normdirs.append(normdir)
Ka-Ping Yeedd175342001-02-27 14:43:46 +000083 return dirs
84
85def getdoc(object):
86 """Get the doc string or comments for an object."""
Ka-Ping Yee3bda8792001-03-23 13:17:50 +000087 result = inspect.getdoc(object) or inspect.getcomments(object)
Neal Norwitz9d72bb42007-04-17 08:48:32 +000088 return result and re.sub('^ *\n', '', result.rstrip()) or ''
Ka-Ping Yeedd175342001-02-27 14:43:46 +000089
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000090def splitdoc(doc):
91 """Split a doc string into a synopsis line (if any) and the rest."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +000092 lines = doc.strip().split('\n')
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000093 if len(lines) == 1:
94 return lines[0], ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +000095 elif len(lines) >= 2 and not lines[1].rstrip():
96 return lines[0], '\n'.join(lines[2:])
97 return '', '\n'.join(lines)
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +000098
Ka-Ping Yeedd175342001-02-27 14:43:46 +000099def classname(object, modname):
100 """Get a class name and qualify it with a module name if necessary."""
101 name = object.__name__
102 if object.__module__ != modname:
103 name = object.__module__ + '.' + name
104 return name
105
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000106def isdata(object):
Georg Brandl94432422005-07-22 21:52:25 +0000107 """Check if an object is of a type that probably means it's data."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000108 return not (inspect.ismodule(object) or inspect.isclass(object) or
109 inspect.isroutine(object) or inspect.isframe(object) or
110 inspect.istraceback(object) or inspect.iscode(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000111
112def replace(text, *pairs):
113 """Do a series of global replacements on a string."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000114 while pairs:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000115 text = pairs[1].join(text.split(pairs[0]))
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000116 pairs = pairs[2:]
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000117 return text
118
119def cram(text, maxlen):
120 """Omit part of a string if needed to make it fit in a maximum length."""
121 if len(text) > maxlen:
Raymond Hettingerfca3bb62002-10-21 04:44:11 +0000122 pre = max(0, (maxlen-3)//2)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000123 post = max(0, maxlen-3-pre)
124 return text[:pre] + '...' + text[len(text)-post:]
125 return text
126
Brett Cannon84601f12004-06-19 01:22:48 +0000127_re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000128def stripid(text):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000129 """Remove the hexadecimal id from a Python object representation."""
Brett Cannonc6c1f472004-06-19 01:02:51 +0000130 # The behaviour of %p is implementation-dependent in terms of case.
Ezio Melotti412c95a2010-02-16 23:31:04 +0000131 return _re_stripid.sub(r'\1', text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000132
Brett Cannonc6c1f472004-06-19 01:02:51 +0000133def _is_some_method(obj):
134 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
Tim Peters536d2262001-09-20 05:13:38 +0000135
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000136def allmethods(cl):
137 methods = {}
Tim Peters536d2262001-09-20 05:13:38 +0000138 for key, value in inspect.getmembers(cl, _is_some_method):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000139 methods[key] = 1
140 for base in cl.__bases__:
141 methods.update(allmethods(base)) # all your base are belong to us
142 for key in methods.keys():
143 methods[key] = getattr(cl, key)
144 return methods
145
Tim Petersfa26f7c2001-09-24 08:05:11 +0000146def _split_list(s, predicate):
147 """Split sequence s via predicate, and return pair ([true], [false]).
148
149 The return value is a 2-tuple of lists,
150 ([x for x in s if predicate(x)],
151 [x for x in s if not predicate(x)])
152 """
153
Tim Peters28355492001-09-23 21:29:55 +0000154 yes = []
155 no = []
Tim Petersfa26f7c2001-09-24 08:05:11 +0000156 for x in s:
157 if predicate(x):
158 yes.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000159 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000160 no.append(x)
Tim Peters28355492001-09-23 21:29:55 +0000161 return yes, no
162
Raymond Hettinger1103d052011-03-25 14:15:24 -0700163def visiblename(name, all=None, obj=None):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000164 """Decide whether to show documentation on a variable."""
165 # Certain special names are redundant.
Raymond Hettinger68272942011-03-18 02:22:15 -0700166 if name in {'__builtins__', '__doc__', '__file__', '__path__',
Barry Warsaw28a691b2010-04-17 00:19:56 +0000167 '__module__', '__name__', '__slots__', '__package__',
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000168 '__cached__', '__author__', '__credits__', '__date__',
Antoine Pitrou86a36b52011-11-25 18:56:07 +0100169 '__version__', '__qualname__'}:
Raymond Hettinger68272942011-03-18 02:22:15 -0700170 return 0
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000171 # Private names are hidden, but special names are displayed.
172 if name.startswith('__') and name.endswith('__'): return 1
Raymond Hettinger1103d052011-03-25 14:15:24 -0700173 # Namedtuples have public fields and methods with a single leading underscore
174 if name.startswith('_') and hasattr(obj, '_fields'):
175 return True
Skip Montanaroa5616d22004-06-11 04:46:12 +0000176 if all is not None:
177 # only document that which the programmer exported in __all__
178 return name in all
179 else:
180 return not name.startswith('_')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000181
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000182def classify_class_attrs(object):
183 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000184 results = []
185 for (name, kind, cls, value) in inspect.classify_class_attrs(object):
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000186 if inspect.isdatadescriptor(value):
187 kind = 'data descriptor'
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000188 results.append((name, kind, cls, value))
189 return results
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000190
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000191# ----------------------------------------------------- module manipulation
192
193def ispackage(path):
194 """Guess whether a path refers to a package directory."""
195 if os.path.isdir(path):
Raymond Hettingerdbecd932005-02-06 06:57:08 +0000196 for ext in ('.py', '.pyc', '.pyo'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000197 if os.path.isfile(os.path.join(path, '__init__' + ext)):
Tim Petersbc0e9102002-04-04 22:55:58 +0000198 return True
199 return False
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000200
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000201def source_synopsis(file):
202 line = file.readline()
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000203 while line[:1] == '#' or not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000204 line = file.readline()
205 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000206 line = line.strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000207 if line[:4] == 'r"""': line = line[1:]
208 if line[:3] == '"""':
209 line = line[3:]
210 if line[-1:] == '\\': line = line[:-1]
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000211 while not line.strip():
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000212 line = file.readline()
213 if not line: break
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000214 result = line.split('"""')[0].strip()
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000215 else: result = None
216 return result
217
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000218def synopsis(filename, cache={}):
219 """Get the one-line summary out of a module file."""
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000220 mtime = os.stat(filename).st_mtime
Charles-François Natali27c4e882011-07-27 19:40:02 +0200221 lastupdate, result = cache.get(filename, (None, None))
222 if lastupdate is None or lastupdate < mtime:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000223 info = inspect.getmoduleinfo(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000224 try:
Victor Stinnere6c910e2011-06-30 15:55:43 +0200225 file = tokenize.open(filename)
Georg Brandl26fd2e12006-03-08 09:34:53 +0000226 except IOError:
227 # module can't be opened, so skip it
228 return None
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000229 if info and 'b' in info[2]: # binary modules have to be imported
230 try: module = imp.load_module('__temp__', file, filename, info[1:])
231 except: return None
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000232 result = (module.__doc__ or '').splitlines()[0]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000233 del sys.modules['__temp__']
234 else: # text modules can be directly examined
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000235 result = source_synopsis(file)
236 file.close()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000237 cache[filename] = (mtime, result)
238 return result
239
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000240class ErrorDuringImport(Exception):
241 """Errors that occurred while trying to import something to document it."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000242 def __init__(self, filename, exc_info):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000243 self.filename = filename
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000244 self.exc, self.value, self.tb = exc_info
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000245
246 def __str__(self):
Guido van Rossuma01a8b62007-05-27 09:20:14 +0000247 exc = self.exc.__name__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000248 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000249
250def importfile(path):
251 """Import a Python source file or compiled file given its path."""
252 magic = imp.get_magic()
Victor Stinnere975af62011-07-04 02:08:50 +0200253 with open(path, 'rb') as file:
254 if file.read(len(magic)) == magic:
255 kind = imp.PY_COMPILED
256 else:
257 kind = imp.PY_SOURCE
258 file.seek(0)
259 filename = os.path.basename(path)
260 name, ext = os.path.splitext(filename)
261 try:
262 module = imp.load_module(name, file, path, (ext, 'r', kind))
263 except:
264 raise ErrorDuringImport(path, sys.exc_info())
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000265 return module
266
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000267def safeimport(path, forceload=0, cache={}):
268 """Import a module; handle errors; return None if the module isn't found.
269
270 If the module *is* found but an exception occurs, it's wrapped in an
271 ErrorDuringImport exception and reraised. Unlike __import__, if a
272 package path is specified, the module at the end of the path is returned,
273 not the package at the beginning. If the optional 'forceload' argument
274 is 1, we reload the module from disk (unless it's a dynamic extension)."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000275 try:
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000276 # If forceload is 1 and the module has been previously loaded from
277 # disk, we always have to reload the module. Checking the file's
278 # mtime isn't good enough (e.g. the module could contain a class
279 # that inherits from another module that has changed).
280 if forceload and path in sys.modules:
281 if path not in sys.builtin_module_names:
Guido van Rossume7ba4952007-06-06 23:52:48 +0000282 # Remove the module from sys.modules and re-import to try
283 # and avoid problems with partially loaded modules.
284 # Also remove any submodules because they won't appear
285 # in the newly loaded module's namespace if they're already
286 # in sys.modules.
Ka-Ping Yee9a2dcf82005-11-05 05:04:41 +0000287 subs = [m for m in sys.modules if m.startswith(path + '.')]
288 for key in [path] + subs:
289 # Prevent garbage collection.
290 cache[key] = sys.modules[key]
291 del sys.modules[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000292 module = __import__(path)
293 except:
294 # Did the error occur before or after the module was found?
295 (exc, value, tb) = info = sys.exc_info()
Raymond Hettinger54f02222002-06-01 14:18:47 +0000296 if path in sys.modules:
Fred Drakedb390c12005-10-28 14:39:47 +0000297 # An error occurred while executing the imported module.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000298 raise ErrorDuringImport(sys.modules[path].__file__, info)
299 elif exc is SyntaxError:
300 # A SyntaxError occurred before we could execute the module.
301 raise ErrorDuringImport(value.filename, info)
Brett Cannonfd074152012-04-14 14:10:13 -0400302 elif exc is ImportError and value.name == path:
303 # No such module in the path.
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000304 return None
305 else:
306 # Some other error occurred during the importing process.
307 raise ErrorDuringImport(path, sys.exc_info())
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000308 for part in path.split('.')[1:]:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000309 try: module = getattr(module, part)
310 except AttributeError: return None
311 return module
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000312
313# ---------------------------------------------------- formatter base class
314
315class Doc:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000316
317 PYTHONDOCS = os.environ.get("PYTHONDOCS",
318 "http://docs.python.org/%d.%d/library"
319 % sys.version_info[:2])
320
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000321 def document(self, object, name=None, *args):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000322 """Generate documentation for an object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000323 args = (object, name) + args
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000324 # 'try' clause is to attempt to handle the possibility that inspect
325 # identifies something in a way that pydoc itself has issues handling;
326 # think 'super' and how it is a descriptor (which raises the exception
327 # by lacking a __name__ attribute) and an instance.
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000328 if inspect.isgetsetdescriptor(object): return self.docdata(*args)
329 if inspect.ismemberdescriptor(object): return self.docdata(*args)
Brett Cannon28a4f0f2003-06-11 23:38:55 +0000330 try:
331 if inspect.ismodule(object): return self.docmodule(*args)
332 if inspect.isclass(object): return self.docclass(*args)
333 if inspect.isroutine(object): return self.docroutine(*args)
334 except AttributeError:
335 pass
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000336 if isinstance(object, property): return self.docproperty(*args)
Guido van Rossum68468eb2003-02-27 20:14:51 +0000337 return self.docother(*args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000338
339 def fail(self, object, name=None, *args):
340 """Raise an exception for unimplemented types."""
341 message = "don't know how to document object%s of type %s" % (
342 name and ' ' + repr(name), type(object).__name__)
Collin Winterce36ad82007-08-30 01:19:48 +0000343 raise TypeError(message)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000344
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000345 docmodule = docclass = docroutine = docother = docproperty = docdata = fail
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000346
Skip Montanaro4997a692003-09-10 16:47:51 +0000347 def getdocloc(self, object):
348 """Return the location of module docs or None"""
349
350 try:
351 file = inspect.getabsfile(object)
352 except TypeError:
353 file = '(built-in)'
354
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000355 docloc = os.environ.get("PYTHONDOCS", self.PYTHONDOCS)
356
Skip Montanaro4997a692003-09-10 16:47:51 +0000357 basedir = os.path.join(sys.exec_prefix, "lib",
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000358 "python%d.%d" % sys.version_info[:2])
Skip Montanaro4997a692003-09-10 16:47:51 +0000359 if (isinstance(object, type(os)) and
360 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
361 'marshal', 'posix', 'signal', 'sys',
Georg Brandl2067bfd2008-05-25 13:05:15 +0000362 '_thread', 'zipimport') or
Skip Montanaro4997a692003-09-10 16:47:51 +0000363 (file.startswith(basedir) and
Brian Curtin49c284c2010-03-31 03:19:28 +0000364 not file.startswith(os.path.join(basedir, 'site-packages')))) and
Brian Curtinedef05b2010-04-01 04:05:25 +0000365 object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
Skip Montanaro4997a692003-09-10 16:47:51 +0000366 if docloc.startswith("http://"):
Georg Brandl86def6c2008-01-21 20:36:10 +0000367 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__)
Skip Montanaro4997a692003-09-10 16:47:51 +0000368 else:
Georg Brandl86def6c2008-01-21 20:36:10 +0000369 docloc = os.path.join(docloc, object.__name__ + ".html")
Skip Montanaro4997a692003-09-10 16:47:51 +0000370 else:
371 docloc = None
372 return docloc
373
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000374# -------------------------------------------- HTML documentation generator
375
376class HTMLRepr(Repr):
377 """Class for safely making an HTML representation of a Python object."""
378 def __init__(self):
379 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000380 self.maxlist = self.maxtuple = 20
381 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000382 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000383
384 def escape(self, text):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000385 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000386
387 def repr(self, object):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000388 return Repr.repr(self, object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000389
390 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000391 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000392 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000393 if hasattr(self, methodname):
394 return getattr(self, methodname)(x, level)
395 return self.escape(cram(stripid(repr(x)), self.maxother))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000396
397 def repr_string(self, x, level):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000398 test = cram(x, self.maxstring)
399 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000400 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000401 # Backslashes are only literal in the string and are never
402 # needed to make any special characters, so show a raw string.
403 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000404 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000405 r'<font color="#c040c0">\1</font>',
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000406 self.escape(testrepr))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000407
Skip Montanarodf708782002-03-07 22:58:02 +0000408 repr_str = repr_string
409
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000410 def repr_instance(self, x, level):
411 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000412 return self.escape(cram(stripid(repr(x)), self.maxstring))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000413 except:
414 return self.escape('<%s instance>' % x.__class__.__name__)
415
416 repr_unicode = repr_string
417
418class HTMLDoc(Doc):
419 """Formatter class for HTML documentation."""
420
421 # ------------------------------------------- HTML formatting utilities
422
423 _repr_instance = HTMLRepr()
424 repr = _repr_instance.repr
425 escape = _repr_instance.escape
426
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000427 def page(self, title, contents):
428 """Format an HTML page."""
Georg Brandl388faac2009-04-10 08:31:48 +0000429 return '''\
Georg Brandle6066942009-04-10 08:28:28 +0000430<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000431<html><head><title>Python: %s</title>
Georg Brandl388faac2009-04-10 08:31:48 +0000432<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000433</head><body bgcolor="#f0f0f8">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000434%s
435</body></html>''' % (title, contents)
436
437 def heading(self, title, fgcol, bgcol, extras=''):
438 """Format a page heading."""
439 return '''
Tim Peters59ed4482001-10-31 04:20:26 +0000440<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000441<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000442<td valign=bottom>&nbsp;<br>
443<font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000444><td align=right valign=bottom
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000445><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000446 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
447
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000448 def section(self, title, fgcol, bgcol, contents, width=6,
449 prelude='', marginalia=None, gap='&nbsp;'):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000450 """Format a section with a heading."""
451 if marginalia is None:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000452 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000453 result = '''<p>
Tim Peters59ed4482001-10-31 04:20:26 +0000454<table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000455<tr bgcolor="%s">
Tim Peters2306d242001-09-25 03:18:32 +0000456<td colspan=3 valign=bottom>&nbsp;<br>
457<font color="%s" face="helvetica, arial">%s</font></td></tr>
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000458 ''' % (bgcol, fgcol, title)
459 if prelude:
460 result = result + '''
Ka-Ping Yee987ec902001-03-23 13:35:45 +0000461<tr bgcolor="%s"><td rowspan=2>%s</td>
462<td colspan=2>%s</td></tr>
463<tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
464 else:
465 result = result + '''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000466<tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000467
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +0000468 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000469
470 def bigsection(self, title, *args):
471 """Format a section with a big heading."""
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000472 title = '<big><strong>%s</strong></big>' % title
Guido van Rossum68468eb2003-02-27 20:14:51 +0000473 return self.section(title, *args)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000474
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000475 def preformat(self, text):
476 """Format literal preformatted text."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000477 text = self.escape(text.expandtabs())
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000478 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
479 ' ', '&nbsp;', '\n', '<br>\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000480
481 def multicolumn(self, list, format, cols=4):
482 """Format a list of items into a multi-column list."""
483 result = ''
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000484 rows = (len(list)+cols-1)//cols
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000485 for col in range(cols):
Guido van Rossumc1f779c2007-07-03 08:25:58 +0000486 result = result + '<td width="%d%%" valign=top>' % (100//cols)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000487 for i in range(rows*col, rows*col+rows):
488 if i < len(list):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000489 result = result + format(list[i]) + '<br>\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000490 result = result + '</td>'
Tim Peters59ed4482001-10-31 04:20:26 +0000491 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000492
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000493 def grey(self, text): return '<font color="#909090">%s</font>' % text
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000494
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000495 def namelink(self, name, *dicts):
496 """Make a link for an identifier, given name-to-URL mappings."""
497 for dict in dicts:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000498 if name in dict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000499 return '<a href="%s">%s</a>' % (dict[name], name)
500 return name
501
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000502 def classlink(self, object, modname):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000503 """Make a link for a class."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000504 name, module = object.__name__, sys.modules.get(object.__module__)
505 if hasattr(module, name) and getattr(module, name) is object:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000506 return '<a href="%s.html#%s">%s</a>' % (
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000507 module.__name__, name, classname(object, modname))
508 return classname(object, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000509
510 def modulelink(self, object):
511 """Make a link for a module."""
512 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
513
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000514 def modpkglink(self, modpkginfo):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000515 """Make a link for a module or package to display in an index."""
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000516 name, path, ispackage, shadowed = modpkginfo
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000517 if shadowed:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000518 return self.grey(name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000519 if path:
520 url = '%s.%s.html' % (path, name)
521 else:
522 url = '%s.html' % name
523 if ispackage:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000524 text = '<strong>%s</strong>&nbsp;(package)' % name
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000525 else:
526 text = name
527 return '<a href="%s">%s</a>' % (url, text)
528
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000529 def filelink(self, url, path):
530 """Make a link to source file."""
531 return '<a href="file:%s">%s</a>' % (url, path)
532
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000533 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
534 """Mark up some plain text, given a context of symbols to look for.
535 Each context dictionary maps object names to anchor names."""
536 escape = escape or self.escape
537 results = []
538 here = 0
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000539 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
540 r'RFC[- ]?(\d+)|'
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000541 r'PEP[- ]?(\d+)|'
Neil Schemenauerd69711c2002-03-24 23:02:07 +0000542 r'(self\.)?(\w+))')
Guido van Rossum8ca162f2002-04-07 06:36:23 +0000543 while True:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000544 match = pattern.search(text, here)
545 if not match: break
546 start, end = match.span()
547 results.append(escape(text[here:start]))
548
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000549 all, scheme, rfc, pep, selfdot, name = match.groups()
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000550 if scheme:
Neil Schemenauercddc1a02002-03-24 23:11:21 +0000551 url = escape(all).replace('"', '&quot;')
552 results.append('<a href="%s">%s</a>' % (url, url))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000553 elif rfc:
Ka-Ping Yeef78a81b2001-03-27 08:13:42 +0000554 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
555 results.append('<a href="%s">%s</a>' % (url, escape(all)))
556 elif pep:
Christian Heimes2202f872008-02-06 14:31:34 +0000557 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000558 results.append('<a href="%s">%s</a>' % (url, escape(all)))
559 elif text[end:end+1] == '(':
560 results.append(self.namelink(name, methods, funcs, classes))
561 elif selfdot:
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000562 results.append('self.<strong>%s</strong>' % name)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000563 else:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000564 results.append(self.namelink(name, classes))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000565 here = end
566 results.append(escape(text[here:]))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000567 return ''.join(results)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000568
569 # ---------------------------------------------- type-specific routines
570
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000571 def formattree(self, tree, modname, parent=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000572 """Produce HTML for a class tree as given by inspect.getclasstree()."""
573 result = ''
574 for entry in tree:
575 if type(entry) is type(()):
576 c, bases = entry
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000577 result = result + '<dt><font face="helvetica, arial">'
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000578 result = result + self.classlink(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000579 if bases and bases != (parent,):
580 parents = []
581 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000582 parents.append(self.classlink(base, modname))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000583 result = result + '(' + ', '.join(parents) + ')'
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000584 result = result + '\n</font></dt>'
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000585 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000586 result = result + '<dd>\n%s</dd>\n' % self.formattree(
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000587 entry, modname, c)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000588 return '<dl>\n%s</dl>\n' % result
589
Tim Peters8dd7ade2001-10-18 19:56:17 +0000590 def docmodule(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000591 """Produce HTML documentation for a module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000592 name = object.__name__ # ignore the passed-in name
Skip Montanaroa5616d22004-06-11 04:46:12 +0000593 try:
594 all = object.__all__
595 except AttributeError:
596 all = None
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000597 parts = name.split('.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000598 links = []
599 for i in range(len(parts)-1):
600 links.append(
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000601 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000602 ('.'.join(parts[:i+1]), parts[i]))
603 linkedname = '.'.join(links + parts[-1:])
Raymond Hettinger95f285c2009-02-24 23:41:47 +0000604 head = '<big><big><strong>%s</strong></big></big>' % linkedname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000605 try:
Ka-Ping Yee239432a2001-03-02 02:45:08 +0000606 path = inspect.getabsfile(object)
Ka-Ping Yee6191a232001-04-13 15:00:27 +0000607 url = path
608 if sys.platform == 'win32':
609 import nturl2path
610 url = nturl2path.pathname2url(path)
Nick Coghlan7bb30b72010-12-03 09:29:11 +0000611 filelink = self.filelink(url, path)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000612 except TypeError:
613 filelink = '(built-in)'
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000614 info = []
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000615 if hasattr(object, '__version__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000616 version = str(object.__version__)
Ka-Ping Yee40c49912001-02-27 22:46:01 +0000617 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000618 version = version[11:-1].strip()
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000619 info.append('version %s' % self.escape(version))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000620 if hasattr(object, '__date__'):
621 info.append(self.escape(str(object.__date__)))
622 if info:
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000623 head = head + ' (%s)' % ', '.join(info)
Skip Montanaro4997a692003-09-10 16:47:51 +0000624 docloc = self.getdocloc(object)
625 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +0000626 docloc = '<br><a href="%(docloc)s">Module Reference</a>' % locals()
Skip Montanaro4997a692003-09-10 16:47:51 +0000627 else:
628 docloc = ''
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000629 result = self.heading(
Skip Montanaro4997a692003-09-10 16:47:51 +0000630 head, '#ffffff', '#7799ee',
631 '<a href=".">index</a><br>' + filelink + docloc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000632
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000633 modules = inspect.getmembers(object, inspect.ismodule)
634
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000635 classes, cdict = [], {}
636 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000637 # if __all__ exists, believe it. Otherwise use old heuristic.
638 if (all is not None or
639 (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700640 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000641 classes.append((key, value))
642 cdict[key] = cdict[value] = '#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000643 for key, value in classes:
644 for base in value.__bases__:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000645 key, modname = base.__name__, base.__module__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000646 module = sys.modules.get(modname)
647 if modname != name and module and hasattr(module, key):
648 if getattr(module, key) is base:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000649 if not key in cdict:
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000650 cdict[key] = cdict[base] = modname + '.html#' + key
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000651 funcs, fdict = [], {}
652 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +0000653 # if __all__ exists, believe it. Otherwise use old heuristic.
654 if (all is not None or
655 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700656 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000657 funcs.append((key, value))
658 fdict[key] = '#-' + key
659 if inspect.isfunction(value): fdict[value] = fdict[key]
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000660 data = []
661 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -0700662 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000663 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000664
665 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
666 doc = doc and '<tt>%s</tt>' % doc
Tim Peters2306d242001-09-25 03:18:32 +0000667 result = result + '<p>%s</p>\n' % doc
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000668
669 if hasattr(object, '__path__'):
670 modpkgs = []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000671 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
672 modpkgs.append((modname, name, ispkg, 0))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000673 modpkgs.sort()
674 contents = self.multicolumn(modpkgs, self.modpkglink)
675 result = result + self.bigsection(
676 'Package Contents', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000677 elif modules:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000678 contents = self.multicolumn(
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000679 modules, lambda t: self.modulelink(t[1]))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000680 result = result + self.bigsection(
Christian Heimes7131fd92008-02-19 14:21:46 +0000681 'Modules', '#ffffff', '#aa55cc', contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000682
683 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +0000684 classlist = [value for (key, value) in classes]
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000685 contents = [
686 self.formattree(inspect.getclasstree(classlist, 1), name)]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000687 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000688 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000689 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000690 'Classes', '#ffffff', '#ee77aa', ' '.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000691 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000692 contents = []
693 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000694 contents.append(self.document(value, key, name, fdict, cdict))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000695 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000696 'Functions', '#ffffff', '#eeaa77', ' '.join(contents))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000697 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000698 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000699 for key, value in data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000700 contents.append(self.document(value, key))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000701 result = result + self.bigsection(
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000702 'Data', '#ffffff', '#55aa55', '<br>\n'.join(contents))
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000703 if hasattr(object, '__author__'):
704 contents = self.markup(str(object.__author__), self.preformat)
705 result = result + self.bigsection(
706 'Author', '#ffffff', '#7799ee', contents)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +0000707 if hasattr(object, '__credits__'):
708 contents = self.markup(str(object.__credits__), self.preformat)
709 result = result + self.bigsection(
710 'Credits', '#ffffff', '#7799ee', contents)
711
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000712 return result
713
Tim Peters8dd7ade2001-10-18 19:56:17 +0000714 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
715 *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000716 """Produce HTML documentation for a class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000717 realname = object.__name__
718 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000719 bases = object.__bases__
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000720
Tim Petersb47879b2001-09-24 04:47:19 +0000721 contents = []
722 push = contents.append
723
Tim Petersfa26f7c2001-09-24 08:05:11 +0000724 # Cute little class to pump out a horizontal rule between sections.
725 class HorizontalRule:
726 def __init__(self):
727 self.needone = 0
728 def maybe(self):
729 if self.needone:
730 push('<hr>\n')
731 self.needone = 1
732 hr = HorizontalRule()
733
Tim Petersc86f6ca2001-09-26 21:31:51 +0000734 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000735 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +0000736 if len(mro) > 2:
737 hr.maybe()
738 push('<dl><dt>Method resolution order:</dt>\n')
739 for base in mro:
740 push('<dd>%s</dd>\n' % self.classlink(base,
741 object.__module__))
742 push('</dl>\n')
743
Tim Petersb47879b2001-09-24 04:47:19 +0000744 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +0000745 ok, attrs = _split_list(attrs, predicate)
Tim Petersb47879b2001-09-24 04:47:19 +0000746 if ok:
Tim Petersfa26f7c2001-09-24 08:05:11 +0000747 hr.maybe()
Tim Petersb47879b2001-09-24 04:47:19 +0000748 push(msg)
749 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100750 try:
751 value = getattr(object, name)
752 except Exception:
753 # Some descriptors may meet a failure in their __get__.
754 # (bug #1785)
755 push(self._docdescriptor(name, value, mod))
756 else:
757 push(self.document(value, name, mod,
758 funcs, classes, mdict, object))
Tim Petersb47879b2001-09-24 04:47:19 +0000759 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)
Florent Xicluna5d1155c2011-10-28 14:45:05 +0200778 if callable(value) 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
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +0100799 try:
800 value = getattr(object, name)
801 except Exception:
802 # Some descriptors may meet a failure in their __get__.
803 # (bug #1785)
804 pass
Tim Petersb47879b2001-09-24 04:47:19 +0000805 try:
806 # The value may not be hashable (e.g., a data attr with
807 # a dict or list value).
808 mdict[value] = anchor
809 except TypeError:
810 pass
811
Tim Petersfa26f7c2001-09-24 08:05:11 +0000812 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +0000813 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +0000814 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +0000815 else:
816 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +0000817 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
818
Georg Brandl1a3284e2007-12-02 09:40:06 +0000819 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000820 attrs = inherited
821 continue
822 elif thisclass is object:
823 tag = 'defined here'
Tim Petersb47879b2001-09-24 04:47:19 +0000824 else:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000825 tag = 'inherited from %s' % self.classlink(thisclass,
826 object.__module__)
Tim Petersb47879b2001-09-24 04:47:19 +0000827 tag += ':<br>\n'
828
829 # Sort attrs by name.
Raymond Hettingerd4cb56d2008-01-30 02:55:10 +0000830 attrs.sort(key=lambda t: t[0])
Tim Petersb47879b2001-09-24 04:47:19 +0000831
832 # Pump out the attrs, segregated by kind.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000833 attrs = spill('Methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000834 lambda t: t[1] == 'method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000835 attrs = spill('Class methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000836 lambda t: t[1] == 'class method')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000837 attrs = spill('Static methods %s' % tag, attrs,
Tim Petersb47879b2001-09-24 04:47:19 +0000838 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000839 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
840 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000841 attrs = spilldata('Data and other attributes %s' % tag, attrs,
Tim Petersfa26f7c2001-09-24 08:05:11 +0000842 lambda t: t[1] == 'data')
Tim Petersb47879b2001-09-24 04:47:19 +0000843 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +0000844 attrs = inherited
Tim Petersb47879b2001-09-24 04:47:19 +0000845
846 contents = ''.join(contents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000847
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000848 if name == realname:
849 title = '<a name="%s">class <strong>%s</strong></a>' % (
850 name, realname)
851 else:
852 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
853 name, name, realname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000854 if bases:
855 parents = []
856 for base in bases:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000857 parents.append(self.classlink(base, object.__module__))
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000858 title = title + '(%s)' % ', '.join(parents)
Tim Peters2306d242001-09-25 03:18:32 +0000859 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000860 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
Tim Petersc86f6ca2001-09-26 21:31:51 +0000861
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +0000862 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000863
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000864 def formatvalue(self, object):
865 """Format an argument default value as text."""
Tim Peters2306d242001-09-25 03:18:32 +0000866 return self.grey('=' + self.repr(object))
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000867
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000868 def docroutine(self, object, name=None, mod=None,
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000869 funcs={}, classes={}, methods={}, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000870 """Produce HTML documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000871 realname = object.__name__
872 name = name or realname
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000873 anchor = (cl and cl.__name__ or '') + '-' + name
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000874 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000875 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000876 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +0000877 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000878 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000879 if imclass is not cl:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000880 note = ' from ' + self.classlink(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000881 else:
Christian Heimesff737952007-11-27 10:40:20 +0000882 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000883 note = ' method of %s instance' % self.classlink(
Christian Heimesff737952007-11-27 10:40:20 +0000884 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +0000885 else:
886 note = ' unbound %s method' % self.classlink(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +0000887 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000888
889 if name == realname:
890 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
891 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +0000892 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000893 cl.__dict__[realname] is object):
Ka-Ping Yeee280c062001-03-23 14:05:53 +0000894 reallink = '<a href="#%s">%s</a>' % (
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000895 cl.__name__ + '-' + realname, realname)
896 skipdocs = 1
897 else:
898 reallink = realname
899 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
900 anchor, name, reallink)
Tim Peters4bcfa312001-09-20 06:08:24 +0000901 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +0000902 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann = \
903 inspect.getfullargspec(object)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000904 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +0000905 args, varargs, kwonlyargs, kwdefaults, varkw, defaults, ann,
906 formatvalue=self.formatvalue,
907 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000908 if realname == '<lambda>':
Tim Peters59ed4482001-10-31 04:20:26 +0000909 title = '<strong>%s</strong> <em>lambda</em> ' % name
Guido van Rossum2e65f892007-02-28 22:03:49 +0000910 # XXX lambda's won't usually have func_annotations['return']
911 # since the syntax doesn't support but it is possible.
912 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000913 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +0000914 else:
915 argspec = '(...)'
Ka-Ping Yee66efbc72001-03-01 13:55:20 +0000916
Tim Peters2306d242001-09-25 03:18:32 +0000917 decl = title + argspec + (note and self.grey(
918 '<font face="helvetica, arial">%s</font>' % note))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000919
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000920 if skipdocs:
Tim Peters2306d242001-09-25 03:18:32 +0000921 return '<dl><dt>%s</dt></dl>\n' % decl
Ka-Ping Yee3bda8792001-03-23 13:17:50 +0000922 else:
923 doc = self.markup(
924 getdoc(object), self.preformat, funcs, classes, methods)
Tim Peters2306d242001-09-25 03:18:32 +0000925 doc = doc and '<dd><tt>%s</tt></dd>' % doc
926 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000927
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000928 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000929 results = []
930 push = results.append
931
932 if name:
933 push('<dl><dt><strong>%s</strong></dt>\n' % name)
934 if value.__doc__ is not None:
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +0000935 doc = self.markup(getdoc(value), self.preformat)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000936 push('<dd><tt>%s</tt></dd>\n' % doc)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000937 push('</dl>\n')
938
939 return ''.join(results)
940
941 def docproperty(self, object, name=None, mod=None, cl=None):
942 """Produce html documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +0000943 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +0000944
Tim Peters8dd7ade2001-10-18 19:56:17 +0000945 def docother(self, object, name=None, mod=None, *ignored):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000946 """Produce HTML documentation for a data object."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000947 lhs = name and '<strong>%s</strong> = ' % name or ''
948 return lhs + self.repr(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000949
Thomas Wouters0e3f5912006-08-11 14:57:12 +0000950 def docdata(self, object, name=None, mod=None, cl=None):
951 """Produce html documentation for a data descriptor."""
952 return self._docdescriptor(name, object, mod)
953
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000954 def index(self, dir, shadowed=None):
955 """Generate an HTML index for a directory of modules."""
956 modpkgs = []
957 if shadowed is None: shadowed = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000958 for importer, name, ispkg in pkgutil.iter_modules([dir]):
Victor Stinner4d652242011-04-12 23:41:50 +0200959 if any((0xD800 <= ord(ch) <= 0xDFFF) for ch in name):
960 # ignore a module if its name contains a surrogate character
961 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000962 modpkgs.append((name, '', ispkg, name in shadowed))
963 shadowed[name] = 1
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000964
965 modpkgs.sort()
966 contents = self.multicolumn(modpkgs, self.modpkglink)
967 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
968
969# -------------------------------------------- text documentation generator
970
971class TextRepr(Repr):
972 """Class for safely making a text representation of a Python object."""
973 def __init__(self):
974 Repr.__init__(self)
Ka-Ping Yeedec96e92001-04-13 09:55:49 +0000975 self.maxlist = self.maxtuple = 20
976 self.maxdict = 10
Ka-Ping Yee37f7b382001-03-23 00:12:53 +0000977 self.maxstring = self.maxother = 100
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000978
979 def repr1(self, x, level):
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000980 if hasattr(type(x), '__name__'):
Neal Norwitz9d72bb42007-04-17 08:48:32 +0000981 methodname = 'repr_' + '_'.join(type(x).__name__.split())
Skip Montanaro0fe8fce2003-06-27 15:45:41 +0000982 if hasattr(self, methodname):
983 return getattr(self, methodname)(x, level)
984 return cram(stripid(repr(x)), self.maxother)
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000985
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000986 def repr_string(self, x, level):
987 test = cram(x, self.maxstring)
988 testrepr = repr(test)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +0000989 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
Ka-Ping Yeea2fe1032001-03-02 01:19:14 +0000990 # Backslashes are only literal in the string and are never
991 # needed to make any special characters, so show a raw string.
992 return 'r' + testrepr[0] + test + testrepr[0]
993 return testrepr
994
Skip Montanarodf708782002-03-07 22:58:02 +0000995 repr_str = repr_string
996
Ka-Ping Yeedd175342001-02-27 14:43:46 +0000997 def repr_instance(self, x, level):
998 try:
Ka-Ping Yee1d384632001-03-01 00:24:32 +0000999 return cram(stripid(repr(x)), self.maxstring)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001000 except:
1001 return '<%s instance>' % x.__class__.__name__
1002
1003class TextDoc(Doc):
1004 """Formatter class for text documentation."""
1005
1006 # ------------------------------------------- text formatting utilities
1007
1008 _repr_instance = TextRepr()
1009 repr = _repr_instance.repr
1010
1011 def bold(self, text):
1012 """Format a string in bold by overstriking."""
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001013 return ''.join(ch + '\b' + ch for ch in text)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001014
1015 def indent(self, text, prefix=' '):
1016 """Indent text by prepending a given prefix to each line."""
1017 if not text: return ''
Collin Winter72e110c2007-07-17 00:27:30 +00001018 lines = [prefix + line for line in text.split('\n')]
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001019 if lines: lines[-1] = lines[-1].rstrip()
1020 return '\n'.join(lines)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001021
1022 def section(self, title, contents):
1023 """Format a section with a given heading."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001024 clean_contents = self.indent(contents).rstrip()
1025 return self.bold(title) + '\n' + clean_contents + '\n\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001026
1027 # ---------------------------------------------- type-specific routines
1028
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001029 def formattree(self, tree, modname, parent=None, prefix=''):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001030 """Render in text a class tree as returned by inspect.getclasstree()."""
1031 result = ''
1032 for entry in tree:
1033 if type(entry) is type(()):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001034 c, bases = entry
1035 result = result + prefix + classname(c, modname)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001036 if bases and bases != (parent,):
Georg Brandlcbd2ab12010-12-04 10:39:14 +00001037 parents = (classname(c, modname) for c in bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001038 result = result + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001039 result = result + '\n'
1040 elif type(entry) is type([]):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001041 result = result + self.formattree(
1042 entry, modname, c, prefix + ' ')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001043 return result
1044
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001045 def docmodule(self, object, name=None, mod=None):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001046 """Produce text documentation for a given module object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001047 name = object.__name__ # ignore the passed-in name
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001048 synop, desc = splitdoc(getdoc(object))
1049 result = self.section('NAME', name + (synop and ' - ' + synop))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001050 all = getattr(object, '__all__', None)
Skip Montanaro4997a692003-09-10 16:47:51 +00001051 docloc = self.getdocloc(object)
1052 if docloc is not None:
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001053 result = result + self.section('MODULE REFERENCE', docloc + """
1054
Éric Araujo647ef8c2011-09-11 00:43:20 +02001055The following documentation is automatically generated from the Python
1056source files. It may be incomplete, incorrect or include features that
1057are considered implementation detail and may vary between Python
1058implementations. When in doubt, consult the module reference at the
1059location listed above.
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001060""")
Skip Montanaro4997a692003-09-10 16:47:51 +00001061
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001062 if desc:
1063 result = result + self.section('DESCRIPTION', desc)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001064
1065 classes = []
1066 for key, value in inspect.getmembers(object, inspect.isclass):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001067 # if __all__ exists, believe it. Otherwise use old heuristic.
1068 if (all is not None
1069 or (inspect.getmodule(value) or object) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001070 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001071 classes.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001072 funcs = []
1073 for key, value in inspect.getmembers(object, inspect.isroutine):
Johannes Gijsbers4c11f602004-08-30 14:13:04 +00001074 # if __all__ exists, believe it. Otherwise use old heuristic.
1075 if (all is not None or
1076 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001077 if visiblename(key, all, object):
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001078 funcs.append((key, value))
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001079 data = []
1080 for key, value in inspect.getmembers(object, isdata):
Raymond Hettinger1103d052011-03-25 14:15:24 -07001081 if visiblename(key, all, object):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001082 data.append((key, value))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001083
Christian Heimes1af737c2008-01-23 08:24:23 +00001084 modpkgs = []
1085 modpkgs_names = set()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001086 if hasattr(object, '__path__'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001087 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
Christian Heimes1af737c2008-01-23 08:24:23 +00001088 modpkgs_names.add(modname)
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001089 if ispkg:
1090 modpkgs.append(modname + ' (package)')
1091 else:
1092 modpkgs.append(modname)
1093
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001094 modpkgs.sort()
1095 result = result + self.section(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001096 'PACKAGE CONTENTS', '\n'.join(modpkgs))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001097
Christian Heimes1af737c2008-01-23 08:24:23 +00001098 # Detect submodules as sometimes created by C extensions
1099 submodules = []
1100 for key, value in inspect.getmembers(object, inspect.ismodule):
1101 if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1102 submodules.append(key)
1103 if submodules:
1104 submodules.sort()
1105 result = result + self.section(
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001106 'SUBMODULES', '\n'.join(submodules))
Christian Heimes1af737c2008-01-23 08:24:23 +00001107
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001108 if classes:
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001109 classlist = [value for key, value in classes]
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001110 contents = [self.formattree(
1111 inspect.getclasstree(classlist, 1), name)]
1112 for key, value in classes:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001113 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001114 result = result + self.section('CLASSES', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001115
1116 if funcs:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001117 contents = []
1118 for key, value in funcs:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001119 contents.append(self.document(value, key, name))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001120 result = result + self.section('FUNCTIONS', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001121
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001122 if data:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001123 contents = []
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001124 for key, value in data:
Georg Brandl8b813db2005-10-01 16:32:31 +00001125 contents.append(self.docother(value, key, name, maxlen=70))
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001126 result = result + self.section('DATA', '\n'.join(contents))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001127
1128 if hasattr(object, '__version__'):
1129 version = str(object.__version__)
Ka-Ping Yee1d384632001-03-01 00:24:32 +00001130 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001131 version = version[11:-1].strip()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001132 result = result + self.section('VERSION', version)
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001133 if hasattr(object, '__date__'):
1134 result = result + self.section('DATE', str(object.__date__))
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001135 if hasattr(object, '__author__'):
Ka-Ping Yee6f3f9a42001-02-27 22:42:36 +00001136 result = result + self.section('AUTHOR', str(object.__author__))
1137 if hasattr(object, '__credits__'):
1138 result = result + self.section('CREDITS', str(object.__credits__))
Alexander Belopolskya47bbf52010-11-18 01:52:54 +00001139 try:
1140 file = inspect.getabsfile(object)
1141 except TypeError:
1142 file = '(built-in)'
1143 result = result + self.section('FILE', file)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001144 return result
1145
Georg Brandl9bd45f992010-12-03 09:58:38 +00001146 def docclass(self, object, name=None, mod=None, *ignored):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001147 """Produce text documentation for a given class object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001148 realname = object.__name__
1149 name = name or realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001150 bases = object.__bases__
1151
Tim Petersc86f6ca2001-09-26 21:31:51 +00001152 def makename(c, m=object.__module__):
1153 return classname(c, m)
1154
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001155 if name == realname:
1156 title = 'class ' + self.bold(realname)
1157 else:
1158 title = self.bold(name) + ' = class ' + realname
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001159 if bases:
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001160 parents = map(makename, bases)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001161 title = title + '(%s)' % ', '.join(parents)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001162
1163 doc = getdoc(object)
Tim Peters28355492001-09-23 21:29:55 +00001164 contents = doc and [doc + '\n'] or []
1165 push = contents.append
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001166
Tim Petersc86f6ca2001-09-26 21:31:51 +00001167 # List the mro, if non-trivial.
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001168 mro = deque(inspect.getmro(object))
Tim Petersc86f6ca2001-09-26 21:31:51 +00001169 if len(mro) > 2:
1170 push("Method resolution order:")
1171 for base in mro:
1172 push(' ' + makename(base))
1173 push('')
1174
Tim Petersf4aad8e2001-09-24 22:40:47 +00001175 # Cute little class to pump out a horizontal rule between sections.
1176 class HorizontalRule:
1177 def __init__(self):
1178 self.needone = 0
1179 def maybe(self):
1180 if self.needone:
1181 push('-' * 70)
1182 self.needone = 1
1183 hr = HorizontalRule()
1184
Tim Peters28355492001-09-23 21:29:55 +00001185 def spill(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001186 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001187 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001188 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001189 push(msg)
1190 for name, kind, homecls, value in ok:
Antoine Pitrou86a8a9a2011-12-21 09:57:40 +01001191 try:
1192 value = getattr(object, name)
1193 except Exception:
1194 # Some descriptors may meet a failure in their __get__.
1195 # (bug #1785)
1196 push(self._docdescriptor(name, value, mod))
1197 else:
1198 push(self.document(value,
1199 name, mod, object))
Tim Peters28355492001-09-23 21:29:55 +00001200 return attrs
1201
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001202 def spilldescriptors(msg, attrs, predicate):
Tim Petersfa26f7c2001-09-24 08:05:11 +00001203 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001204 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001205 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001206 push(msg)
1207 for name, kind, homecls, value in ok:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001208 push(self._docdescriptor(name, value, mod))
Tim Peters28355492001-09-23 21:29:55 +00001209 return attrs
Tim Petersb47879b2001-09-24 04:47:19 +00001210
Tim Petersfa26f7c2001-09-24 08:05:11 +00001211 def spilldata(msg, attrs, predicate):
1212 ok, attrs = _split_list(attrs, predicate)
Tim Peters28355492001-09-23 21:29:55 +00001213 if ok:
Tim Petersf4aad8e2001-09-24 22:40:47 +00001214 hr.maybe()
Tim Peters28355492001-09-23 21:29:55 +00001215 push(msg)
1216 for name, kind, homecls, value in ok:
Florent Xicluna5d1155c2011-10-28 14:45:05 +02001217 if callable(value) or inspect.isdatadescriptor(value):
Ka-Ping Yeebba6acc2005-02-19 22:58:26 +00001218 doc = getdoc(value)
Guido van Rossum5e355b22002-05-21 20:56:15 +00001219 else:
1220 doc = None
Tim Peters28355492001-09-23 21:29:55 +00001221 push(self.docother(getattr(object, name),
Georg Brandl8b813db2005-10-01 16:32:31 +00001222 name, mod, maxlen=70, doc=doc) + '\n')
Tim Peters28355492001-09-23 21:29:55 +00001223 return attrs
1224
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001225 attrs = [(name, kind, cls, value)
1226 for name, kind, cls, value in classify_class_attrs(object)
Raymond Hettinger1103d052011-03-25 14:15:24 -07001227 if visiblename(name, obj=object)]
Guido van Rossum1bc535d2007-05-15 18:46:22 +00001228
Tim Petersfa26f7c2001-09-24 08:05:11 +00001229 while attrs:
Tim Peters351e3622001-09-27 03:29:51 +00001230 if mro:
Raymond Hettinger756b3f32004-01-29 06:37:52 +00001231 thisclass = mro.popleft()
Tim Peters351e3622001-09-27 03:29:51 +00001232 else:
1233 thisclass = attrs[0][2]
Tim Petersfa26f7c2001-09-24 08:05:11 +00001234 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1235
Georg Brandl1a3284e2007-12-02 09:40:06 +00001236 if thisclass is builtins.object:
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001237 attrs = inherited
1238 continue
1239 elif thisclass is object:
Tim Peters28355492001-09-23 21:29:55 +00001240 tag = "defined here"
1241 else:
Tim Petersfa26f7c2001-09-24 08:05:11 +00001242 tag = "inherited from %s" % classname(thisclass,
1243 object.__module__)
Tim Peters28355492001-09-23 21:29:55 +00001244
1245 # Sort attrs by name.
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001246 attrs.sort()
Tim Peters28355492001-09-23 21:29:55 +00001247
1248 # Pump out the attrs, segregated by kind.
Tim Petersf4aad8e2001-09-24 22:40:47 +00001249 attrs = spill("Methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001250 lambda t: t[1] == 'method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001251 attrs = spill("Class methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001252 lambda t: t[1] == 'class method')
Tim Petersf4aad8e2001-09-24 22:40:47 +00001253 attrs = spill("Static methods %s:\n" % tag, attrs,
Tim Peters28355492001-09-23 21:29:55 +00001254 lambda t: t[1] == 'static method')
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001255 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1256 lambda t: t[1] == 'data descriptor')
Ka-Ping Yeed9e213e2003-03-28 16:35:51 +00001257 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1258 lambda t: t[1] == 'data')
Tim Peters28355492001-09-23 21:29:55 +00001259 assert attrs == []
Tim Peters351e3622001-09-27 03:29:51 +00001260 attrs = inherited
Tim Peters28355492001-09-23 21:29:55 +00001261
1262 contents = '\n'.join(contents)
1263 if not contents:
1264 return title + '\n'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001265 return title + '\n' + self.indent(contents.rstrip(), ' | ') + '\n'
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001266
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001267 def formatvalue(self, object):
1268 """Format an argument default value as text."""
1269 return '=' + self.repr(object)
1270
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001271 def docroutine(self, object, name=None, mod=None, cl=None):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001272 """Produce text documentation for a function or method object."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001273 realname = object.__name__
1274 name = name or realname
1275 note = ''
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001276 skipdocs = 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001277 if inspect.ismethod(object):
Christian Heimesff737952007-11-27 10:40:20 +00001278 imclass = object.__self__.__class__
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001279 if cl:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001280 if imclass is not cl:
1281 note = ' from ' + classname(imclass, mod)
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001282 else:
Christian Heimesff737952007-11-27 10:40:20 +00001283 if object.__self__ is not None:
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001284 note = ' method of %s instance' % classname(
Christian Heimesff737952007-11-27 10:40:20 +00001285 object.__self__.__class__, mod)
Ka-Ping Yeeb7a48302001-04-12 20:39:14 +00001286 else:
1287 note = ' unbound %s method' % classname(imclass,mod)
Christian Heimesff737952007-11-27 10:40:20 +00001288 object = object.__func__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001289
1290 if name == realname:
1291 title = self.bold(realname)
1292 else:
Raymond Hettinger54f02222002-06-01 14:18:47 +00001293 if (cl and realname in cl.__dict__ and
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001294 cl.__dict__[realname] is object):
1295 skipdocs = 1
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001296 title = self.bold(name) + ' = ' + realname
Tim Peters4bcfa312001-09-20 06:08:24 +00001297 if inspect.isfunction(object):
Guido van Rossum2e65f892007-02-28 22:03:49 +00001298 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann = \
1299 inspect.getfullargspec(object)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001300 argspec = inspect.formatargspec(
Guido van Rossum2e65f892007-02-28 22:03:49 +00001301 args, varargs, varkw, defaults, kwonlyargs, kwdefaults, ann,
1302 formatvalue=self.formatvalue,
1303 formatannotation=inspect.formatannotationrelativeto(object))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001304 if realname == '<lambda>':
Georg Brandl501dd0d2006-02-17 09:45:40 +00001305 title = self.bold(name) + ' lambda '
Guido van Rossum2e65f892007-02-28 22:03:49 +00001306 # XXX lambda's won't usually have func_annotations['return']
1307 # since the syntax doesn't support but it is possible.
1308 # So removing parentheses isn't truly safe.
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001309 argspec = argspec[1:-1] # remove parentheses
Tim Peters4bcfa312001-09-20 06:08:24 +00001310 else:
1311 argspec = '(...)'
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001312 decl = title + argspec + note
1313
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001314 if skipdocs:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001315 return decl + '\n'
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001316 else:
1317 doc = getdoc(object) or ''
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001318 return decl + '\n' + (doc and self.indent(doc).rstrip() + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001319
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001320 def _docdescriptor(self, name, value, mod):
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001321 results = []
1322 push = results.append
1323
1324 if name:
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001325 push(self.bold(name))
1326 push('\n')
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001327 doc = getdoc(value) or ''
1328 if doc:
1329 push(self.indent(doc))
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001330 push('\n')
1331 return ''.join(results)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001332
1333 def docproperty(self, object, name=None, mod=None, cl=None):
1334 """Produce text documentation for a property."""
Johannes Gijsbers9ddb3002005-01-08 20:16:43 +00001335 return self._docdescriptor(name, object, mod)
Johannes Gijsbers8de645a2004-11-07 19:16:05 +00001336
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001337 def docdata(self, object, name=None, mod=None, cl=None):
1338 """Produce text documentation for a data descriptor."""
1339 return self._docdescriptor(name, object, mod)
1340
Georg Brandl8b813db2005-10-01 16:32:31 +00001341 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001342 """Produce text documentation for a data object."""
1343 repr = self.repr(object)
1344 if maxlen:
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001345 line = (name and name + ' = ' or '') + repr
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001346 chop = maxlen - len(line)
1347 if chop < 0: repr = repr[:chop] + '...'
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001348 line = (name and self.bold(name) + ' = ' or '') + repr
Tim Peters28355492001-09-23 21:29:55 +00001349 if doc is not None:
1350 line += '\n' + self.indent(str(doc))
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001351 return line
1352
Georg Brandld80d5f42010-12-03 07:47:22 +00001353class _PlainTextDoc(TextDoc):
1354 """Subclass of TextDoc which overrides string styling"""
1355 def bold(self, text):
1356 return text
1357
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001358# --------------------------------------------------------- user interfaces
1359
1360def pager(text):
1361 """The first time this is called, determine what kind of pager to use."""
1362 global pager
1363 pager = getpager()
1364 pager(text)
1365
1366def getpager():
1367 """Decide what method to use for paging through text."""
Guido van Rossuma01a8b62007-05-27 09:20:14 +00001368 if not hasattr(sys.stdout, "isatty"):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001369 return plainpager
1370 if not sys.stdin.isatty() or not sys.stdout.isatty():
1371 return plainpager
Raymond Hettinger54f02222002-06-01 14:18:47 +00001372 if 'PAGER' in os.environ:
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001373 if sys.platform == 'win32': # pipes completely broken in Windows
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001374 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001375 elif os.environ.get('TERM') in ('dumb', 'emacs'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001376 return lambda text: pipepager(plain(text), os.environ['PAGER'])
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00001377 else:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001378 return lambda text: pipepager(text, os.environ['PAGER'])
Ka-Ping Yeea487e4e2005-11-05 04:49:18 +00001379 if os.environ.get('TERM') in ('dumb', 'emacs'):
1380 return plainpager
Andrew MacIntyre54e0eab2002-03-03 03:12:30 +00001381 if sys.platform == 'win32' or sys.platform.startswith('os2'):
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001382 return lambda text: tempfilepager(plain(text), 'more <')
Skip Montanarod404bee2002-09-26 21:44:57 +00001383 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001384 return lambda text: pipepager(text, 'less')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001385
1386 import tempfile
Guido van Rossum3b0a3292002-08-09 16:38:32 +00001387 (fd, filename) = tempfile.mkstemp()
1388 os.close(fd)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001389 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001390 if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001391 return lambda text: pipepager(text, 'more')
1392 else:
1393 return ttypager
1394 finally:
1395 os.unlink(filename)
1396
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001397def plain(text):
1398 """Remove boldface formatting from text."""
1399 return re.sub('.\b', '', text)
1400
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001401def pipepager(text, cmd):
1402 """Page through text by feeding it to another program."""
1403 pipe = os.popen(cmd, 'w')
1404 try:
1405 pipe.write(text)
1406 pipe.close()
1407 except IOError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001408 pass # Ignore broken pipes caused by quitting the pager program.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001409
1410def tempfilepager(text, cmd):
1411 """Page through text by invoking a program on a temporary file."""
1412 import tempfile
Tim Peters550e4e52003-02-07 01:53:46 +00001413 filename = tempfile.mktemp()
1414 file = open(filename, 'w')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001415 file.write(text)
1416 file.close()
1417 try:
Georg Brandl3dbca812008-07-23 16:10:53 +00001418 os.system(cmd + ' "' + filename + '"')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001419 finally:
1420 os.unlink(filename)
1421
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001422def ttypager(text):
1423 """Page through text on a text terminal."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001424 lines = plain(text).split('\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001425 try:
1426 import tty
1427 fd = sys.stdin.fileno()
1428 old = tty.tcgetattr(fd)
1429 tty.setcbreak(fd)
1430 getchar = lambda: sys.stdin.read(1)
Ka-Ping Yee457aab22001-02-27 23:36:29 +00001431 except (ImportError, AttributeError):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001432 tty = None
1433 getchar = lambda: sys.stdin.readline()[:-1][:1]
1434
1435 try:
1436 r = inc = os.environ.get('LINES', 25) - 1
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001437 sys.stdout.write('\n'.join(lines[:inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001438 while lines[r:]:
1439 sys.stdout.write('-- more --')
1440 sys.stdout.flush()
1441 c = getchar()
1442
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001443 if c in ('q', 'Q'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001444 sys.stdout.write('\r \r')
1445 break
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001446 elif c in ('\r', '\n'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001447 sys.stdout.write('\r \r' + lines[r] + '\n')
1448 r = r + 1
1449 continue
Raymond Hettingerdbecd932005-02-06 06:57:08 +00001450 if c in ('b', 'B', '\x1b'):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001451 r = r - inc - inc
1452 if r < 0: r = 0
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001453 sys.stdout.write('\n' + '\n'.join(lines[r:r+inc]) + '\n')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001454 r = r + inc
1455
1456 finally:
1457 if tty:
1458 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1459
1460def plainpager(text):
1461 """Simply print unformatted text. This is the ultimate fallback."""
1462 sys.stdout.write(plain(text))
1463
1464def describe(thing):
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00001465 """Produce a short description of the given thing."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001466 if inspect.ismodule(thing):
1467 if thing.__name__ in sys.builtin_module_names:
1468 return 'built-in module ' + thing.__name__
1469 if hasattr(thing, '__path__'):
1470 return 'package ' + thing.__name__
1471 else:
1472 return 'module ' + thing.__name__
1473 if inspect.isbuiltin(thing):
1474 return 'built-in function ' + thing.__name__
Thomas Wouters0e3f5912006-08-11 14:57:12 +00001475 if inspect.isgetsetdescriptor(thing):
1476 return 'getset descriptor %s.%s.%s' % (
1477 thing.__objclass__.__module__, thing.__objclass__.__name__,
1478 thing.__name__)
1479 if inspect.ismemberdescriptor(thing):
1480 return 'member descriptor %s.%s.%s' % (
1481 thing.__objclass__.__module__, thing.__objclass__.__name__,
1482 thing.__name__)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001483 if inspect.isclass(thing):
1484 return 'class ' + thing.__name__
1485 if inspect.isfunction(thing):
1486 return 'function ' + thing.__name__
1487 if inspect.ismethod(thing):
1488 return 'method ' + thing.__name__
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001489 return type(thing).__name__
1490
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001491def locate(path, forceload=0):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001492 """Locate an object by name or dotted path, importing as necessary."""
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001493 parts = [part for part in path.split('.') if part]
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001494 module, n = None, 0
1495 while n < len(parts):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001496 nextmodule = safeimport('.'.join(parts[:n+1]), forceload)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001497 if nextmodule: module, n = nextmodule, n + 1
1498 else: break
1499 if module:
1500 object = module
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001501 else:
Éric Araujoe64e51b2011-07-29 17:03:55 +02001502 object = builtins
1503 for part in parts[n:]:
1504 try:
1505 object = getattr(object, part)
1506 except AttributeError:
1507 return None
1508 return object
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001509
1510# --------------------------------------- interactive interpreter interface
1511
1512text = TextDoc()
Georg Brandld80d5f42010-12-03 07:47:22 +00001513plaintext = _PlainTextDoc()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001514html = HTMLDoc()
1515
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001516def resolve(thing, forceload=0):
1517 """Given an object or a path to an object, get the object and its name."""
1518 if isinstance(thing, str):
1519 object = locate(thing, forceload)
1520 if not object:
Collin Winterce36ad82007-08-30 01:19:48 +00001521 raise ImportError('no Python documentation found for %r' % thing)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001522 return object, thing
1523 else:
1524 return thing, getattr(thing, '__name__', None)
1525
Georg Brandld80d5f42010-12-03 07:47:22 +00001526def render_doc(thing, title='Python Library Documentation: %s', forceload=0,
1527 renderer=None):
Guido van Rossumd8faa362007-04-27 19:54:29 +00001528 """Render text documentation, given an object or a path to an object."""
Georg Brandld80d5f42010-12-03 07:47:22 +00001529 if renderer is None:
1530 renderer = text
Guido van Rossumd8faa362007-04-27 19:54:29 +00001531 object, name = resolve(thing, forceload)
1532 desc = describe(object)
1533 module = inspect.getmodule(object)
1534 if name and '.' in name:
1535 desc += ' in ' + name[:name.rfind('.')]
1536 elif module and module is not object:
1537 desc += ' in module ' + module.__name__
Amaury Forgeot d'Arc768db922008-04-24 21:00:04 +00001538
1539 if not (inspect.ismodule(object) or
Guido van Rossumd8faa362007-04-27 19:54:29 +00001540 inspect.isclass(object) or
1541 inspect.isroutine(object) or
1542 inspect.isgetsetdescriptor(object) or
1543 inspect.ismemberdescriptor(object) or
1544 isinstance(object, property)):
1545 # If the passed object is a piece of data or an instance,
1546 # document its available methods instead of its value.
1547 object = type(object)
1548 desc += ' object'
Georg Brandld80d5f42010-12-03 07:47:22 +00001549 return title % desc + '\n\n' + renderer.document(object, name)
Guido van Rossumd8faa362007-04-27 19:54:29 +00001550
Georg Brandld80d5f42010-12-03 07:47:22 +00001551def doc(thing, title='Python Library Documentation: %s', forceload=0,
1552 output=None):
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001553 """Display text documentation, given an object or a path to an object."""
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001554 try:
Georg Brandld80d5f42010-12-03 07:47:22 +00001555 if output is None:
1556 pager(render_doc(thing, title, forceload))
1557 else:
1558 output.write(render_doc(thing, title, forceload, plaintext))
Guido van Rossumb940e112007-01-10 16:19:56 +00001559 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001560 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001561
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001562def writedoc(thing, forceload=0):
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001563 """Write HTML documentation to a file in the current directory."""
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001564 try:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001565 object, name = resolve(thing, forceload)
1566 page = html.page(describe(object), html.document(object, name))
Georg Brandl388faac2009-04-10 08:31:48 +00001567 file = open(name + '.html', 'w', encoding='utf-8')
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00001568 file.write(page)
1569 file.close()
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001570 print('wrote', name + '.html')
Guido van Rossumb940e112007-01-10 16:19:56 +00001571 except (ImportError, ErrorDuringImport) as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00001572 print(value)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001573
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001574def writedocs(dir, pkgpath='', done=None):
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00001575 """Write out HTML documentation for all modules in a directory tree."""
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001576 if done is None: done = {}
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001577 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1578 writedoc(modname)
1579 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001580
1581class Helper:
Georg Brandl6b38daa2008-06-01 21:05:17 +00001582
1583 # These dictionaries map a topic name to either an alias, or a tuple
1584 # (label, seealso-items). The "label" is the label of the corresponding
1585 # section in the .rst file under Doc/ and an index into the dictionary
Georg Brandl5617db82009-04-27 16:28:57 +00001586 # in pydoc_data/topics.py.
Georg Brandl6b38daa2008-06-01 21:05:17 +00001587 #
1588 # CAUTION: if you change one of these dictionaries, be sure to adapt the
1589 # list of needed labels in Doc/tools/sphinxext/pyspecific.py and
Georg Brandl5617db82009-04-27 16:28:57 +00001590 # regenerate the pydoc_data/topics.py file by running
Georg Brandl6b38daa2008-06-01 21:05:17 +00001591 # make pydoc-topics
1592 # in Doc/ and copying the output file into the Lib/ directory.
1593
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001594 keywords = {
Ezio Melottib185a042011-04-28 07:42:55 +03001595 'False': '',
1596 'None': '',
1597 'True': '',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001598 'and': 'BOOLEAN',
Guido van Rossumd8faa362007-04-27 19:54:29 +00001599 'as': 'with',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001600 'assert': ('assert', ''),
1601 'break': ('break', 'while for'),
1602 'class': ('class', 'CLASSES SPECIALMETHODS'),
1603 'continue': ('continue', 'while for'),
1604 'def': ('function', ''),
1605 'del': ('del', 'BASICMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001606 'elif': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001607 'else': ('else', 'while for'),
Georg Brandl0d855392008-08-30 19:53:05 +00001608 'except': 'try',
1609 'finally': 'try',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001610 'for': ('for', 'break continue while'),
Georg Brandl0d855392008-08-30 19:53:05 +00001611 'from': 'import',
Georg Brandl74abf6f2010-11-20 19:54:36 +00001612 'global': ('global', 'nonlocal NAMESPACES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001613 'if': ('if', 'TRUTHVALUE'),
1614 'import': ('import', 'MODULES'),
Georg Brandl395ed242009-09-04 08:07:32 +00001615 'in': ('in', 'SEQUENCEMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001616 'is': 'COMPARISON',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001617 'lambda': ('lambda', 'FUNCTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001618 'nonlocal': ('nonlocal', 'global NAMESPACES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001619 'not': 'BOOLEAN',
1620 'or': 'BOOLEAN',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001621 'pass': ('pass', ''),
1622 'raise': ('raise', 'EXCEPTIONS'),
1623 'return': ('return', 'FUNCTIONS'),
1624 'try': ('try', 'EXCEPTIONS'),
1625 'while': ('while', 'break continue if TRUTHVALUE'),
1626 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1627 'yield': ('yield', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001628 }
Georg Brandldb7b6b92009-01-01 15:53:14 +00001629 # Either add symbols to this dictionary or to the symbols dictionary
1630 # directly: Whichever is easier. They are merged later.
1631 _symbols_inverse = {
1632 'STRINGS' : ("'", "'''", "r'", "b'", '"""', '"', 'r"', 'b"'),
1633 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1634 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1635 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1636 'UNARY' : ('-', '~'),
1637 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1638 '^=', '<<=', '>>=', '**=', '//='),
1639 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1640 'COMPLEX' : ('j', 'J')
1641 }
1642 symbols = {
1643 '%': 'OPERATORS FORMATTING',
1644 '**': 'POWER',
1645 ',': 'TUPLES LISTS FUNCTIONS',
1646 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1647 '...': 'ELLIPSIS',
1648 ':': 'SLICINGS DICTIONARYLITERALS',
1649 '@': 'def class',
1650 '\\': 'STRINGS',
1651 '_': 'PRIVATENAMES',
1652 '__': 'PRIVATENAMES SPECIALMETHODS',
1653 '`': 'BACKQUOTES',
1654 '(': 'TUPLES FUNCTIONS CALLS',
1655 ')': 'TUPLES FUNCTIONS CALLS',
1656 '[': 'LISTS SUBSCRIPTS SLICINGS',
1657 ']': 'LISTS SUBSCRIPTS SLICINGS'
1658 }
1659 for topic, symbols_ in _symbols_inverse.items():
1660 for symbol in symbols_:
1661 topics = symbols.get(symbol, topic)
1662 if topic not in topics:
1663 topics = topics + ' ' + topic
1664 symbols[symbol] = topics
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001665
1666 topics = {
Georg Brandl6b38daa2008-06-01 21:05:17 +00001667 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1668 'FUNCTIONS CLASSES MODULES FILES inspect'),
1669 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS '
1670 'FORMATTING TYPES'),
1671 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1672 'FORMATTING': ('formatstrings', 'OPERATORS'),
1673 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1674 'FORMATTING TYPES'),
1675 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1676 'INTEGER': ('integers', 'int range'),
1677 'FLOAT': ('floating', 'float math'),
1678 'COMPLEX': ('imaginary', 'complex cmath'),
1679 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING range LISTS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001680 'MAPPINGS': 'DICTIONARIES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001681 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1682 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1683 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1684 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001685 'FRAMEOBJECTS': 'TYPES',
1686 'TRACEBACKS': 'TYPES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001687 'NONE': ('bltin-null-object', ''),
1688 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
1689 'FILES': ('bltin-file-objects', ''),
1690 'SPECIALATTRIBUTES': ('specialattrs', ''),
1691 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1692 'MODULES': ('typesmodules', 'import'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001693 'PACKAGES': 'import',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001694 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1695 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1696 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1697 'LISTS DICTIONARIES'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001698 'OPERATORS': 'EXPRESSIONS',
1699 'PRECEDENCE': 'EXPRESSIONS',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001700 'OBJECTS': ('objects', 'TYPES'),
1701 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
Georg Brandl395ed242009-09-04 08:07:32 +00001702 'CALLABLEMETHODS SEQUENCEMETHODS MAPPINGMETHODS '
1703 'NUMBERMETHODS CLASSES'),
Mark Dickinsona56c4672009-01-27 18:17:45 +00001704 'BASICMETHODS': ('customization', 'hash repr str SPECIALMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001705 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1706 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001707 'SEQUENCEMETHODS': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS '
Georg Brandl6b38daa2008-06-01 21:05:17 +00001708 'SPECIALMETHODS'),
1709 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1710 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1711 'SPECIALMETHODS'),
1712 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
Georg Brandl74abf6f2010-11-20 19:54:36 +00001713 'NAMESPACES': ('naming', 'global nonlocal ASSIGNMENT DELETION DYNAMICFEATURES'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001714 'DYNAMICFEATURES': ('dynamic-features', ''),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001715 'SCOPING': 'NAMESPACES',
1716 'FRAMES': 'NAMESPACES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001717 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1718 'CONVERSIONS': ('conversions', ''),
1719 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1720 'SPECIALIDENTIFIERS': ('id-classes', ''),
1721 'PRIVATENAMES': ('atom-identifiers', ''),
1722 'LITERALS': ('atom-literals', 'STRINGS NUMBERS TUPLELITERALS '
1723 'LISTLITERALS DICTIONARYLITERALS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001724 'TUPLES': 'SEQUENCES',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001725 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1726 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1727 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1728 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1729 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1730 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
Georg Brandl395ed242009-09-04 08:07:32 +00001731 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS'),
1732 'SLICINGS': ('slicings', 'SEQUENCEMETHODS'),
Georg Brandl6b38daa2008-06-01 21:05:17 +00001733 'CALLS': ('calls', 'EXPRESSIONS'),
1734 'POWER': ('power', 'EXPRESSIONS'),
1735 'UNARY': ('unary', 'EXPRESSIONS'),
1736 'BINARY': ('binary', 'EXPRESSIONS'),
1737 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1738 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1739 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1740 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001741 'ASSERTION': 'assert',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001742 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1743 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001744 'DELETION': 'del',
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001745 'RETURNING': 'return',
1746 'IMPORTING': 'import',
1747 'CONDITIONAL': 'if',
Georg Brandl6b38daa2008-06-01 21:05:17 +00001748 'LOOPING': ('compound', 'for while break continue'),
1749 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1750 'DEBUGGING': ('debugger', 'pdb'),
1751 'CONTEXTMANAGERS': ('context-managers', 'with'),
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001752 }
1753
Georg Brandl78aa3962010-07-31 21:51:48 +00001754 def __init__(self, input=None, output=None):
1755 self._input = input
1756 self._output = output
1757
Georg Brandl76ae3972010-08-01 06:32:55 +00001758 input = property(lambda self: self._input or sys.stdin)
1759 output = property(lambda self: self._output or sys.stdout)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001760
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001761 def __repr__(self):
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001762 if inspect.stack()[1][3] == '?':
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001763 self()
1764 return ''
Ka-Ping Yee9bc576b2001-04-13 13:57:31 +00001765 return '<pydoc.Helper instance>'
Ka-Ping Yee79c009d2001-04-13 10:53:25 +00001766
Alexander Belopolsky2e733c92010-07-04 17:00:20 +00001767 _GoInteractive = object()
1768 def __call__(self, request=_GoInteractive):
1769 if request is not self._GoInteractive:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001770 self.help(request)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001771 else:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001772 self.intro()
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001773 self.interact()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001774 self.output.write('''
Fred Drakee61967f2001-05-10 18:41:02 +00001775You are now leaving help and returning to the Python interpreter.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001776If you want to ask for help on a particular object directly from the
1777interpreter, you can type "help(object)". Executing "help('string')"
1778has the same effect as typing a particular string at the help> prompt.
1779''')
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001780
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001781 def interact(self):
1782 self.output.write('\n')
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001783 while True:
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001784 try:
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001785 request = self.getline('help> ')
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001786 if not request: break
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001787 except (KeyboardInterrupt, EOFError):
1788 break
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001789 request = replace(request, '"', '', "'", '').strip()
1790 if request.lower() in ('q', 'quit'): break
Ka-Ping Yeedec96e92001-04-13 09:55:49 +00001791 self.help(request)
1792
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001793 def getline(self, prompt):
Guido van Rossum7c086c02008-01-02 03:52:38 +00001794 """Read one line, using input() when appropriate."""
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001795 if self.input is sys.stdin:
Guido van Rossum7c086c02008-01-02 03:52:38 +00001796 return input(prompt)
Johannes Gijsberse7691d32004-08-17 13:21:53 +00001797 else:
1798 self.output.write(prompt)
1799 self.output.flush()
1800 return self.input.readline()
1801
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001802 def help(self, request):
1803 if type(request) is type(''):
R. David Murray1f1b9d32009-05-27 20:56:59 +00001804 request = request.strip()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001805 if request == 'help': self.intro()
1806 elif request == 'keywords': self.listkeywords()
Georg Brandldb7b6b92009-01-01 15:53:14 +00001807 elif request == 'symbols': self.listsymbols()
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001808 elif request == 'topics': self.listtopics()
1809 elif request == 'modules': self.listmodules()
1810 elif request[:8] == 'modules ':
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001811 self.listmodules(request.split()[1])
Georg Brandldb7b6b92009-01-01 15:53:14 +00001812 elif request in self.symbols: self.showsymbol(request)
Ezio Melottib185a042011-04-28 07:42:55 +03001813 elif request in ['True', 'False', 'None']:
1814 # special case these keywords since they are objects too
1815 doc(eval(request), 'Help on %s:')
Raymond Hettinger54f02222002-06-01 14:18:47 +00001816 elif request in self.keywords: self.showtopic(request)
1817 elif request in self.topics: self.showtopic(request)
Georg Brandld80d5f42010-12-03 07:47:22 +00001818 elif request: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001819 elif isinstance(request, Helper): self()
Georg Brandld80d5f42010-12-03 07:47:22 +00001820 else: doc(request, 'Help on %s:', output=self._output)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001821 self.output.write('\n')
1822
1823 def intro(self):
1824 self.output.write('''
1825Welcome to Python %s! This is the online help utility.
1826
1827If this is your first time using Python, you should definitely check out
R David Murrayde0f6292012-03-31 12:06:35 -04001828the tutorial on the Internet at http://docs.python.org/%s/tutorial/.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001829
1830Enter the name of any module, keyword, or topic to get help on writing
1831Python programs and using Python modules. To quit this help utility and
1832return to the interpreter, just type "quit".
1833
1834To get a list of available modules, keywords, or topics, type "modules",
1835"keywords", or "topics". Each module also comes with a one-line summary
1836of what it does; to list the modules whose summaries contain a given word
1837such as "spam", type "modules spam".
R David Murrayde0f6292012-03-31 12:06:35 -04001838''' % tuple([sys.version[:3]]*2))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001839
1840 def list(self, items, columns=4, width=80):
Guido van Rossum486364b2007-06-30 05:01:58 +00001841 items = list(sorted(items))
1842 colw = width // columns
1843 rows = (len(items) + columns - 1) // columns
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001844 for row in range(rows):
1845 for col in range(columns):
1846 i = col * rows + row
1847 if i < len(items):
1848 self.output.write(items[i])
1849 if col < columns - 1:
Guido van Rossum486364b2007-06-30 05:01:58 +00001850 self.output.write(' ' + ' ' * (colw - 1 - len(items[i])))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001851 self.output.write('\n')
1852
1853 def listkeywords(self):
1854 self.output.write('''
1855Here is a list of the Python keywords. Enter any keyword to get more help.
1856
1857''')
1858 self.list(self.keywords.keys())
1859
Georg Brandldb7b6b92009-01-01 15:53:14 +00001860 def listsymbols(self):
1861 self.output.write('''
1862Here is a list of the punctuation symbols which Python assigns special meaning
1863to. Enter any symbol to get more help.
1864
1865''')
1866 self.list(self.symbols.keys())
1867
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001868 def listtopics(self):
1869 self.output.write('''
1870Here is a list of available topics. Enter any topic name to get more help.
1871
1872''')
1873 self.list(self.topics.keys())
1874
Georg Brandldb7b6b92009-01-01 15:53:14 +00001875 def showtopic(self, topic, more_xrefs=''):
Georg Brandl6b38daa2008-06-01 21:05:17 +00001876 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001877 import pydoc_data.topics
Georg Brandl6b38daa2008-06-01 21:05:17 +00001878 except ImportError:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001879 self.output.write('''
Georg Brandl6b38daa2008-06-01 21:05:17 +00001880Sorry, topic and keyword documentation is not available because the
Georg Brandl5617db82009-04-27 16:28:57 +00001881module "pydoc_data.topics" could not be found.
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001882''')
1883 return
1884 target = self.topics.get(topic, self.keywords.get(topic))
1885 if not target:
1886 self.output.write('no documentation found for %s\n' % repr(topic))
1887 return
1888 if type(target) is type(''):
Georg Brandldb7b6b92009-01-01 15:53:14 +00001889 return self.showtopic(target, more_xrefs)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001890
Georg Brandl6b38daa2008-06-01 21:05:17 +00001891 label, xrefs = target
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001892 try:
Georg Brandl5617db82009-04-27 16:28:57 +00001893 doc = pydoc_data.topics.topics[label]
Georg Brandl6b38daa2008-06-01 21:05:17 +00001894 except KeyError:
1895 self.output.write('no documentation found for %s\n' % repr(topic))
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001896 return
Georg Brandl6b38daa2008-06-01 21:05:17 +00001897 pager(doc.strip() + '\n')
Georg Brandldb7b6b92009-01-01 15:53:14 +00001898 if more_xrefs:
1899 xrefs = (xrefs or '') + ' ' + more_xrefs
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001900 if xrefs:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001901 import formatter
Guido van Rossum34d19282007-08-09 01:03:29 +00001902 buffer = io.StringIO()
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001903 formatter.DumbWriter(buffer).send_flowing_data(
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001904 'Related help topics: ' + ', '.join(xrefs.split()) + '\n')
Ka-Ping Yeeda793892001-04-13 11:02:51 +00001905 self.output.write('\n%s\n' % buffer.getvalue())
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001906
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001907 def _gettopic(self, topic, more_xrefs=''):
1908 """Return unbuffered tuple of (topic, xrefs).
1909
Georg Brandld2f38572011-01-30 08:37:19 +00001910 If an error occurs here, the exception is caught and displayed by
1911 the url handler.
1912
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001913 This function duplicates the showtopic method but returns its
1914 result directly so it can be formatted for display in an html page.
1915 """
1916 try:
1917 import pydoc_data.topics
1918 except ImportError:
1919 return('''
1920Sorry, topic and keyword documentation is not available because the
1921module "pydoc_data.topics" could not be found.
1922''' , '')
1923 target = self.topics.get(topic, self.keywords.get(topic))
1924 if not target:
Georg Brandld2f38572011-01-30 08:37:19 +00001925 raise ValueError('could not find topic')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001926 if isinstance(target, str):
1927 return self._gettopic(target, more_xrefs)
1928 label, xrefs = target
Georg Brandld2f38572011-01-30 08:37:19 +00001929 doc = pydoc_data.topics.topics[label]
Nick Coghlan7bb30b72010-12-03 09:29:11 +00001930 if more_xrefs:
1931 xrefs = (xrefs or '') + ' ' + more_xrefs
1932 return doc, xrefs
1933
Georg Brandldb7b6b92009-01-01 15:53:14 +00001934 def showsymbol(self, symbol):
1935 target = self.symbols[symbol]
1936 topic, _, xrefs = target.partition(' ')
1937 self.showtopic(topic, xrefs)
1938
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001939 def listmodules(self, key=''):
1940 if key:
1941 self.output.write('''
1942Here is a list of matching modules. Enter any module name to get more help.
1943
1944''')
1945 apropos(key)
1946 else:
1947 self.output.write('''
1948Please wait a moment while I gather a list of all available modules...
1949
1950''')
1951 modules = {}
1952 def callback(path, modname, desc, modules=modules):
1953 if modname and modname[-9:] == '.__init__':
1954 modname = modname[:-9] + ' (package)'
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001955 if modname.find('.') < 0:
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001956 modules[modname] = 1
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001957 def onerror(modname):
1958 callback(None, modname, None)
1959 ModuleScanner().run(callback, onerror=onerror)
Ka-Ping Yee35cf0a32001-04-12 19:53:52 +00001960 self.list(modules.keys())
1961 self.output.write('''
1962Enter any module name to get more help. Or, type "modules spam" to search
1963for modules whose descriptions contain the word "spam".
1964''')
1965
Georg Brandl78aa3962010-07-31 21:51:48 +00001966help = Helper()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00001967
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001968class Scanner:
1969 """A generic tree iterator."""
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001970 def __init__(self, roots, children, descendp):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001971 self.roots = roots[:]
1972 self.state = []
1973 self.children = children
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001974 self.descendp = descendp
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001975
1976 def next(self):
1977 if not self.state:
1978 if not self.roots:
1979 return None
1980 root = self.roots.pop(0)
1981 self.state = [(root, self.children(root))]
1982 node, children = self.state[-1]
1983 if not children:
1984 self.state.pop()
1985 return self.next()
1986 child = children.pop(0)
Ka-Ping Yee9aa0d902001-04-12 10:50:23 +00001987 if self.descendp(child):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001988 self.state.append((child, self.children(child)))
1989 return child
1990
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00001991
1992class ModuleScanner:
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001993 """An interruptible scanner that searches module synopses."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001994
Christian Heimesd32ed6f2008-01-14 18:49:24 +00001995 def run(self, callback, key=None, completer=None, onerror=None):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00001996 if key: key = key.lower()
Guido van Rossum8ca162f2002-04-07 06:36:23 +00001997 self.quit = False
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00001998 seen = {}
1999
2000 for modname in sys.builtin_module_names:
Ka-Ping Yee239432a2001-03-02 02:45:08 +00002001 if modname != '__main__':
2002 seen[modname] = 1
Ka-Ping Yee66246962001-04-12 11:59:50 +00002003 if key is None:
2004 callback(None, modname, '')
2005 else:
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002006 name = __import__(modname).__doc__ or ''
2007 desc = name.split('\n')[0]
2008 name = modname + ' - ' + desc
2009 if name.lower().find(key) >= 0:
Ka-Ping Yee66246962001-04-12 11:59:50 +00002010 callback(None, modname, desc)
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002011
Christian Heimesd32ed6f2008-01-14 18:49:24 +00002012 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002013 if self.quit:
2014 break
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002015
2016 # XXX Skipping this file is a workaround for a bug
2017 # that causes python to crash with a segfault.
2018 # http://bugs.python.org/issue9319
2019 #
2020 # TODO Remove this once the bug is fixed.
2021 if modname in {'test.badsyntax_pep3120', 'badsyntax_pep3120'}:
2022 continue
2023
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002024 if key is None:
2025 callback(None, modname, '')
2026 else:
Georg Brandl126c8792009-04-05 15:05:48 +00002027 try:
2028 loader = importer.find_module(modname)
2029 except SyntaxError:
2030 # raised by tests for bad coding cookies or BOM
2031 continue
2032 if hasattr(loader, 'get_source'):
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002033 try:
2034 source = loader.get_source(modname)
2035 except UnicodeDecodeError:
2036 if onerror:
2037 onerror(modname)
2038 continue
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002039 desc = source_synopsis(io.StringIO(source)) or ''
Georg Brandl126c8792009-04-05 15:05:48 +00002040 if hasattr(loader, 'get_filename'):
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002041 path = loader.get_filename(modname)
Ka-Ping Yee66246962001-04-12 11:59:50 +00002042 else:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002043 path = None
2044 else:
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002045 try:
2046 module = loader.load_module(modname)
2047 except ImportError:
2048 if onerror:
2049 onerror(modname)
2050 continue
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002051 desc = (module.__doc__ or '').splitlines()[0]
2052 path = getattr(module,'__file__',None)
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002053 name = modname + ' - ' + desc
2054 if name.lower().find(key) >= 0:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +00002055 callback(path, modname, desc)
2056
2057 if completer:
2058 completer()
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002059
2060def apropos(key):
2061 """Print all the one-line module summaries that contain a substring."""
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002062 def callback(path, modname, desc):
2063 if modname[-9:] == '.__init__':
2064 modname = modname[:-9] + ' (package)'
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002065 print(modname, desc and '- ' + desc)
Amaury Forgeot d'Arc9196dc62008-06-19 20:54:32 +00002066 def onerror(modname):
2067 pass
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002068 with warnings.catch_warnings():
2069 warnings.filterwarnings('ignore') # ignore problems during import
2070 ModuleScanner().run(callback, key, onerror=onerror)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002071
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002072# --------------------------------------- enhanced Web browser interface
2073
2074def _start_server(urlhandler, port):
2075 """Start an HTTP server thread on a specific port.
2076
2077 Start an HTML/text server thread, so HTML or text documents can be
2078 browsed dynamically and interactively with a Web browser. Example use:
2079
2080 >>> import time
2081 >>> import pydoc
2082
2083 Define a URL handler. To determine what the client is asking
2084 for, check the URL and content_type.
2085
2086 Then get or generate some text or HTML code and return it.
2087
2088 >>> def my_url_handler(url, content_type):
2089 ... text = 'the URL sent was: (%s, %s)' % (url, content_type)
2090 ... return text
2091
2092 Start server thread on port 0.
2093 If you use port 0, the server will pick a random port number.
2094 You can then use serverthread.port to get the port number.
2095
2096 >>> port = 0
2097 >>> serverthread = pydoc._start_server(my_url_handler, port)
2098
2099 Check that the server is really started. If it is, open browser
2100 and get first page. Use serverthread.url as the starting page.
2101
2102 >>> if serverthread.serving:
2103 ... import webbrowser
2104
2105 The next two lines are commented out so a browser doesn't open if
2106 doctest is run on this module.
2107
2108 #... webbrowser.open(serverthread.url)
2109 #True
2110
2111 Let the server do its thing. We just need to monitor its status.
2112 Use time.sleep so the loop doesn't hog the CPU.
2113
2114 >>> starttime = time.time()
2115 >>> timeout = 1 #seconds
2116
2117 This is a short timeout for testing purposes.
2118
2119 >>> while serverthread.serving:
2120 ... time.sleep(.01)
2121 ... if serverthread.serving and time.time() - starttime > timeout:
2122 ... serverthread.stop()
2123 ... break
2124
2125 Print any errors that may have occurred.
2126
2127 >>> print(serverthread.error)
2128 None
2129 """
2130 import http.server
2131 import email.message
2132 import select
2133 import threading
2134
2135 class DocHandler(http.server.BaseHTTPRequestHandler):
2136
2137 def do_GET(self):
2138 """Process a request from an HTML browser.
2139
2140 The URL received is in self.path.
2141 Get an HTML page from self.urlhandler and send it.
2142 """
2143 if self.path.endswith('.css'):
2144 content_type = 'text/css'
2145 else:
2146 content_type = 'text/html'
2147 self.send_response(200)
Georg Brandld2f38572011-01-30 08:37:19 +00002148 self.send_header('Content-Type', '%s; charset=UTF-8' % content_type)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002149 self.end_headers()
2150 self.wfile.write(self.urlhandler(
2151 self.path, content_type).encode('utf-8'))
2152
2153 def log_message(self, *args):
2154 # Don't log messages.
2155 pass
2156
2157 class DocServer(http.server.HTTPServer):
2158
2159 def __init__(self, port, callback):
2160 self.host = (sys.platform == 'mac') and '127.0.0.1' or 'localhost'
2161 self.address = ('', port)
2162 self.callback = callback
2163 self.base.__init__(self, self.address, self.handler)
2164 self.quit = False
2165
2166 def serve_until_quit(self):
2167 while not self.quit:
2168 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2169 if rd:
2170 self.handle_request()
Victor Stinnera3abd1d2011-01-03 16:12:39 +00002171 self.server_close()
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002172
2173 def server_activate(self):
2174 self.base.server_activate(self)
2175 if self.callback:
2176 self.callback(self)
2177
2178 class ServerThread(threading.Thread):
2179
2180 def __init__(self, urlhandler, port):
2181 self.urlhandler = urlhandler
2182 self.port = int(port)
2183 threading.Thread.__init__(self)
2184 self.serving = False
2185 self.error = None
2186
2187 def run(self):
2188 """Start the server."""
2189 try:
2190 DocServer.base = http.server.HTTPServer
2191 DocServer.handler = DocHandler
2192 DocHandler.MessageClass = email.message.Message
2193 DocHandler.urlhandler = staticmethod(self.urlhandler)
2194 docsvr = DocServer(self.port, self.ready)
2195 self.docserver = docsvr
2196 docsvr.serve_until_quit()
2197 except Exception as e:
2198 self.error = e
2199
2200 def ready(self, server):
2201 self.serving = True
2202 self.host = server.host
2203 self.port = server.server_port
2204 self.url = 'http://%s:%d/' % (self.host, self.port)
2205
2206 def stop(self):
2207 """Stop the server and this thread nicely"""
2208 self.docserver.quit = True
2209 self.serving = False
2210 self.url = None
2211
2212 thread = ServerThread(urlhandler, port)
2213 thread.start()
2214 # Wait until thread.serving is True to make sure we are
2215 # really up before returning.
2216 while not thread.error and not thread.serving:
2217 time.sleep(.01)
2218 return thread
2219
2220
2221def _url_handler(url, content_type="text/html"):
2222 """The pydoc url handler for use with the pydoc server.
2223
2224 If the content_type is 'text/css', the _pydoc.css style
2225 sheet is read and returned if it exits.
2226
2227 If the content_type is 'text/html', then the result of
2228 get_html_page(url) is returned.
2229 """
2230 class _HTMLDoc(HTMLDoc):
2231
2232 def page(self, title, contents):
2233 """Format an HTML page."""
2234 css_path = "pydoc_data/_pydoc.css"
2235 css_link = (
2236 '<link rel="stylesheet" type="text/css" href="%s">' %
2237 css_path)
2238 return '''\
2239<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
Georg Brandld2f38572011-01-30 08:37:19 +00002240<html><head><title>Pydoc: %s</title>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002241<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
Georg Brandld2f38572011-01-30 08:37:19 +00002242%s</head><body bgcolor="#f0f0f8">%s<div style="clear:both;padding-top:.5em;">%s</div>
2243</body></html>''' % (title, css_link, html_navbar(), contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002244
2245 def filelink(self, url, path):
2246 return '<a href="getfile?key=%s">%s</a>' % (url, path)
2247
2248
2249 html = _HTMLDoc()
2250
2251 def html_navbar():
Georg Brandld2f38572011-01-30 08:37:19 +00002252 version = html.escape("%s [%s, %s]" % (platform.python_version(),
2253 platform.python_build()[0],
2254 platform.python_compiler()))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002255 return """
2256 <div style='float:left'>
Georg Brandld2f38572011-01-30 08:37:19 +00002257 Python %s<br>%s
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002258 </div>
2259 <div style='float:right'>
2260 <div style='text-align:center'>
2261 <a href="index.html">Module Index</a>
2262 : <a href="topics.html">Topics</a>
2263 : <a href="keywords.html">Keywords</a>
2264 </div>
2265 <div>
Georg Brandld2f38572011-01-30 08:37:19 +00002266 <form action="get" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002267 <input type=text name=key size=15>
2268 <input type=submit value="Get">
Georg Brandld2f38572011-01-30 08:37:19 +00002269 </form>&nbsp;
2270 <form action="search" style='display:inline;'>
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002271 <input type=text name=key size=15>
2272 <input type=submit value="Search">
2273 </form>
2274 </div>
2275 </div>
Georg Brandld2f38572011-01-30 08:37:19 +00002276 """ % (version, html.escape(platform.platform(terse=True)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002277
2278 def html_index():
2279 """Module Index page."""
2280
2281 def bltinlink(name):
2282 return '<a href="%s.html">%s</a>' % (name, name)
2283
2284 heading = html.heading(
2285 '<big><big><strong>Index of Modules</strong></big></big>',
2286 '#ffffff', '#7799ee')
2287 names = [name for name in sys.builtin_module_names
2288 if name != '__main__']
2289 contents = html.multicolumn(names, bltinlink)
2290 contents = [heading, '<p>' + html.bigsection(
2291 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2292
2293 seen = {}
2294 for dir in sys.path:
2295 contents.append(html.index(dir, seen))
2296
2297 contents.append(
2298 '<p align=right><font color="#909090" face="helvetica,'
2299 'arial"><strong>pydoc</strong> by Ka-Ping Yee'
2300 '&lt;ping@lfw.org&gt;</font>')
Nick Coghlanecace282010-12-03 16:08:46 +00002301 return 'Index of Modules', ''.join(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002302
2303 def html_search(key):
2304 """Search results page."""
2305 # scan for modules
2306 search_result = []
2307
2308 def callback(path, modname, desc):
2309 if modname[-9:] == '.__init__':
2310 modname = modname[:-9] + ' (package)'
2311 search_result.append((modname, desc and '- ' + desc))
2312
2313 with warnings.catch_warnings():
2314 warnings.filterwarnings('ignore') # ignore problems during import
2315 ModuleScanner().run(callback, key)
2316
2317 # format page
2318 def bltinlink(name):
2319 return '<a href="%s.html">%s</a>' % (name, name)
2320
2321 results = []
2322 heading = html.heading(
2323 '<big><big><strong>Search Results</strong></big></big>',
2324 '#ffffff', '#7799ee')
2325 for name, desc in search_result:
2326 results.append(bltinlink(name) + desc)
2327 contents = heading + html.bigsection(
2328 'key = %s' % key, '#ffffff', '#ee77aa', '<br>'.join(results))
Nick Coghlanecace282010-12-03 16:08:46 +00002329 return 'Search Results', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002330
2331 def html_getfile(path):
2332 """Get and display a source file listing safely."""
Nick Coghlanecace282010-12-03 16:08:46 +00002333 path = path.replace('%20', ' ')
Victor Stinner91e08772011-07-05 14:30:41 +02002334 with tokenize.open(path) as fp:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002335 lines = html.escape(fp.read())
2336 body = '<pre>%s</pre>' % lines
2337 heading = html.heading(
2338 '<big><big><strong>File Listing</strong></big></big>',
2339 '#ffffff', '#7799ee')
2340 contents = heading + html.bigsection(
2341 'File: %s' % path, '#ffffff', '#ee77aa', body)
Nick Coghlanecace282010-12-03 16:08:46 +00002342 return 'getfile %s' % path, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002343
2344 def html_topics():
2345 """Index of topic texts available."""
2346
2347 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002348 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002349
2350 heading = html.heading(
2351 '<big><big><strong>INDEX</strong></big></big>',
2352 '#ffffff', '#7799ee')
2353 names = sorted(Helper.topics.keys())
2354
2355 contents = html.multicolumn(names, bltinlink)
2356 contents = heading + html.bigsection(
2357 'Topics', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002358 return 'Topics', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002359
2360 def html_keywords():
2361 """Index of keywords."""
2362 heading = html.heading(
2363 '<big><big><strong>INDEX</strong></big></big>',
2364 '#ffffff', '#7799ee')
2365 names = sorted(Helper.keywords.keys())
2366
2367 def bltinlink(name):
Georg Brandld2f38572011-01-30 08:37:19 +00002368 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002369
2370 contents = html.multicolumn(names, bltinlink)
2371 contents = heading + html.bigsection(
2372 'Keywords', '#ffffff', '#ee77aa', contents)
Nick Coghlanecace282010-12-03 16:08:46 +00002373 return 'Keywords', contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002374
2375 def html_topicpage(topic):
2376 """Topic or keyword help page."""
2377 buf = io.StringIO()
2378 htmlhelp = Helper(buf, buf)
2379 contents, xrefs = htmlhelp._gettopic(topic)
2380 if topic in htmlhelp.keywords:
2381 title = 'KEYWORD'
2382 else:
2383 title = 'TOPIC'
2384 heading = html.heading(
2385 '<big><big><strong>%s</strong></big></big>' % title,
2386 '#ffffff', '#7799ee')
Georg Brandld2f38572011-01-30 08:37:19 +00002387 contents = '<pre>%s</pre>' % html.markup(contents)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002388 contents = html.bigsection(topic , '#ffffff','#ee77aa', contents)
Georg Brandld2f38572011-01-30 08:37:19 +00002389 if xrefs:
2390 xrefs = sorted(xrefs.split())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002391
Georg Brandld2f38572011-01-30 08:37:19 +00002392 def bltinlink(name):
2393 return '<a href="topic?key=%s">%s</a>' % (name, name)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002394
Georg Brandld2f38572011-01-30 08:37:19 +00002395 xrefs = html.multicolumn(xrefs, bltinlink)
2396 xrefs = html.section('Related help topics: ',
2397 '#ffffff', '#ee77aa', xrefs)
Nick Coghlanecace282010-12-03 16:08:46 +00002398 return ('%s %s' % (title, topic),
2399 ''.join((heading, contents, xrefs)))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002400
Georg Brandld2f38572011-01-30 08:37:19 +00002401 def html_getobj(url):
2402 obj = locate(url, forceload=1)
2403 if obj is None and url != 'None':
2404 raise ValueError('could not find object')
2405 title = describe(obj)
2406 content = html.document(obj, url)
2407 return title, content
2408
2409 def html_error(url, exc):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002410 heading = html.heading(
2411 '<big><big><strong>Error</strong></big></big>',
Georg Brandld2f38572011-01-30 08:37:19 +00002412 '#ffffff', '#7799ee')
2413 contents = '<br>'.join(html.escape(line) for line in
2414 format_exception_only(type(exc), exc))
2415 contents = heading + html.bigsection(url, '#ffffff', '#bb0000',
2416 contents)
2417 return "Error - %s" % url, contents
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002418
2419 def get_html_page(url):
2420 """Generate an HTML page for url."""
Georg Brandld2f38572011-01-30 08:37:19 +00002421 complete_url = url
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002422 if url.endswith('.html'):
2423 url = url[:-5]
Georg Brandld2f38572011-01-30 08:37:19 +00002424 try:
2425 if url in ("", "index"):
2426 title, content = html_index()
2427 elif url == "topics":
2428 title, content = html_topics()
2429 elif url == "keywords":
2430 title, content = html_keywords()
2431 elif '=' in url:
2432 op, _, url = url.partition('=')
2433 if op == "search?key":
2434 title, content = html_search(url)
2435 elif op == "getfile?key":
2436 title, content = html_getfile(url)
2437 elif op == "topic?key":
2438 # try topics first, then objects.
2439 try:
2440 title, content = html_topicpage(url)
2441 except ValueError:
2442 title, content = html_getobj(url)
2443 elif op == "get?key":
2444 # try objects first, then topics.
2445 if url in ("", "index"):
2446 title, content = html_index()
2447 else:
2448 try:
2449 title, content = html_getobj(url)
2450 except ValueError:
2451 title, content = html_topicpage(url)
2452 else:
2453 raise ValueError('bad pydoc url')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002454 else:
Georg Brandld2f38572011-01-30 08:37:19 +00002455 title, content = html_getobj(url)
2456 except Exception as exc:
2457 # Catch any errors and display them in an error page.
2458 title, content = html_error(complete_url, exc)
2459 return html.page(title, content)
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002460
2461 if url.startswith('/'):
2462 url = url[1:]
2463 if content_type == 'text/css':
2464 path_here = os.path.dirname(os.path.realpath(__file__))
Georg Brandld2f38572011-01-30 08:37:19 +00002465 css_path = os.path.join(path_here, url)
2466 with open(css_path) as fp:
2467 return ''.join(fp.readlines())
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002468 elif content_type == 'text/html':
2469 return get_html_page(url)
Georg Brandld2f38572011-01-30 08:37:19 +00002470 # Errors outside the url handler are caught by the server.
2471 raise TypeError('unknown content type %r for url %s' % (content_type, url))
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002472
2473
2474def browse(port=0, *, open_browser=True):
2475 """Start the enhanced pydoc Web server and open a Web browser.
2476
2477 Use port '0' to start the server on an arbitrary port.
2478 Set open_browser to False to suppress opening a browser.
2479 """
2480 import webbrowser
2481 serverthread = _start_server(_url_handler, port)
2482 if serverthread.error:
2483 print(serverthread.error)
2484 return
2485 if serverthread.serving:
2486 server_help_msg = 'Server commands: [b]rowser, [q]uit'
2487 if open_browser:
2488 webbrowser.open(serverthread.url)
2489 try:
2490 print('Server ready at', serverthread.url)
2491 print(server_help_msg)
2492 while serverthread.serving:
2493 cmd = input('server> ')
2494 cmd = cmd.lower()
2495 if cmd == 'q':
2496 break
2497 elif cmd == 'b':
2498 webbrowser.open(serverthread.url)
2499 else:
2500 print(server_help_msg)
2501 except (KeyboardInterrupt, EOFError):
2502 print()
2503 finally:
2504 if serverthread.serving:
2505 serverthread.stop()
2506 print('Server stopped')
2507
2508
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002509# -------------------------------------------------- command-line interface
2510
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002511def ispath(x):
Neal Norwitz9d72bb42007-04-17 08:48:32 +00002512 return isinstance(x, str) and x.find(os.sep) >= 0
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002513
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002514def cli():
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002515 """Command-line interface (looks at sys.argv to decide what to do)."""
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002516 import getopt
Guido van Rossum756aa932007-04-07 03:04:01 +00002517 class BadUsage(Exception): pass
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002518
Nick Coghlan106274b2009-11-15 23:04:33 +00002519 # Scripts don't get the current directory in their path by default
2520 # unless they are run with the '-m' switch
2521 if '' not in sys.path:
2522 scriptdir = os.path.dirname(sys.argv[0])
2523 if scriptdir in sys.path:
2524 sys.path.remove(scriptdir)
2525 sys.path.insert(0, '.')
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002526
Ka-Ping Yee3bda8792001-03-23 13:17:50 +00002527 try:
Victor Stinner383c3fc2011-05-25 01:35:05 +02002528 opts, args = getopt.getopt(sys.argv[1:], 'bk:p:w')
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002529 writing = False
2530 start_server = False
2531 open_browser = False
2532 port = None
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002533 for opt, val in opts:
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002534 if opt == '-b':
2535 start_server = True
2536 open_browser = True
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002537 if opt == '-k':
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002538 apropos(val)
2539 return
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002540 if opt == '-p':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002541 start_server = True
2542 port = val
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002543 if opt == '-w':
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002544 writing = True
2545
2546 if start_server == True:
2547 if port == None:
2548 port = 0
2549 browse(port, open_browser=open_browser)
2550 return
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002551
2552 if not args: raise BadUsage
2553 for arg in args:
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002554 if ispath(arg) and not os.path.exists(arg):
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002555 print('file %r does not exist' % arg)
Ka-Ping Yee45daeb02002-08-11 15:11:33 +00002556 break
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002557 try:
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002558 if ispath(arg) and os.path.isfile(arg):
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002559 arg = importfile(arg)
Ka-Ping Yee37f7b382001-03-23 00:12:53 +00002560 if writing:
2561 if ispath(arg) and os.path.isdir(arg):
2562 writedocs(arg)
2563 else:
2564 writedoc(arg)
2565 else:
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002566 help.help(arg)
Guido van Rossumb940e112007-01-10 16:19:56 +00002567 except ErrorDuringImport as value:
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002568 print(value)
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002569
2570 except (getopt.error, BadUsage):
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002571 cmd = os.path.splitext(os.path.basename(sys.argv[0]))[0]
Guido van Rossumbe19ed72007-02-09 05:37:30 +00002572 print("""pydoc - the Python documentation tool
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002573
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002574{cmd} <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002575 Show text documentation on something. <name> may be the name of a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002576 Python keyword, topic, function, module, or package, or a dotted
2577 reference to a class or function within a module or module in a
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002578 package. If <name> contains a '{sep}', it is used as the path to a
Martin v. Löwisb8c084e2003-06-14 09:03:46 +00002579 Python source file to document. If name is 'keywords', 'topics',
2580 or 'modules', a listing of these things is displayed.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002581
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002582{cmd} -k <keyword>
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002583 Search for a keyword in the synopsis lines of all available modules.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002584
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002585{cmd} -p <port>
2586 Start an HTTP server on the given port on the local machine. Port
2587 number 0 can be used to get an arbitrary unused port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002588
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002589{cmd} -b
2590 Start an HTTP server on an arbitrary unused port and open a Web browser
2591 to interactively browse documentation. The -p option can be used with
2592 the -b option to explicitly specify the server port.
Ka-Ping Yeedd175342001-02-27 14:43:46 +00002593
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002594{cmd} -w <name> ...
Ka-Ping Yee66efbc72001-03-01 13:55:20 +00002595 Write out the HTML documentation for a module to a file in the current
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002596 directory. If <name> contains a '{sep}', it is treated as a filename; if
Ka-Ping Yee5a804ed2001-04-10 11:46:02 +00002597 it names a directory, documentation is written for all the contents.
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002598""".format(cmd=cmd, sep=os.sep))
Ka-Ping Yee1d384632001-03-01 00:24:32 +00002599
Nick Coghlan7bb30b72010-12-03 09:29:11 +00002600if __name__ == '__main__':
2601 cli()