]> git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Lib/pydoc.py
4b5b387a60f41e916675b26bfd6ecf33f416ff55
[mirror_edk2.git] / AppPkg / Applications / Python / Python-2.7.2 / Lib / pydoc.py
1 #!/usr/bin/env python
2 # -*- coding: latin-1 -*-
3 """Generate Python documentation in HTML or text for interactive use.
4
5 In the Python interpreter, do "from pydoc import help" to provide online
6 help. Calling help(thing) on a Python object documents the object.
7
8 Or, at the shell command line outside of Python:
9
10 Run "pydoc <name>" to show documentation on something. <name> may be
11 the name of a function, module, package, or a dotted reference to a
12 class or function within a module or module in a package. If the
13 argument contains a path segment delimiter (e.g. slash on Unix,
14 backslash on Windows) it is treated as the path to a Python source file.
15
16 Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17 of all available modules.
18
19 Run "pydoc -p <port>" to start an HTTP server on a given port on the
20 local machine to generate documentation web pages.
21
22 For platforms without a command line, "pydoc -g" starts the HTTP server
23 and also pops up a little window for controlling it.
24
25 Run "pydoc -w <name>" to write out the HTML documentation for a module
26 to a file named "<name>.html".
27
28 Module docs for core modules are assumed to be in
29
30 http://docs.python.org/library/
31
32 This can be overridden by setting the PYTHONDOCS environment variable
33 to a different URL or to a local directory containing the Library
34 Reference Manual pages.
35 """
36
37 __author__ = "Ka-Ping Yee <ping@lfw.org>"
38 __date__ = "26 February 2001"
39
40 __version__ = "$Revision$"
41 __credits__ = """Guido van Rossum, for an excellent programming language.
42 Tommy Burnette, the original creator of manpy.
43 Paul Prescod, for all his work on onlinehelp.
44 Richard Chamberlain, for the first implementation of textdoc.
45 """
46
47 # Known bugs that can't be fixed here:
48 # - imp.load_module() cannot be prevented from clobbering existing
49 # loaded modules, so calling synopsis() on a binary module file
50 # changes the contents of any existing module with the same name.
51 # - If the __file__ attribute on a module is a relative path and
52 # the current directory is changed with os.chdir(), an incorrect
53 # path will be displayed.
54
55 import sys, imp, os, re, types, inspect, __builtin__, pkgutil
56 from repr import Repr
57 from string import expandtabs, find, join, lower, split, strip, rfind, rstrip
58 from traceback import extract_tb
59 try:
60 from collections import deque
61 except ImportError:
62 # Python 2.3 compatibility
63 class deque(list):
64 def popleft(self):
65 return self.pop(0)
66
67 # --------------------------------------------------------- common routines
68
69 def pathdirs():
70 """Convert sys.path into a list of absolute, existing, unique paths."""
71 dirs = []
72 normdirs = []
73 for dir in sys.path:
74 dir = os.path.abspath(dir or '.')
75 normdir = os.path.normcase(dir)
76 if normdir not in normdirs and os.path.isdir(dir):
77 dirs.append(dir)
78 normdirs.append(normdir)
79 return dirs
80
81 def getdoc(object):
82 """Get the doc string or comments for an object."""
83 result = inspect.getdoc(object) or inspect.getcomments(object)
84 return result and re.sub('^ *\n', '', rstrip(result)) or ''
85
86 def splitdoc(doc):
87 """Split a doc string into a synopsis line (if any) and the rest."""
88 lines = split(strip(doc), '\n')
89 if len(lines) == 1:
90 return lines[0], ''
91 elif len(lines) >= 2 and not rstrip(lines[1]):
92 return lines[0], join(lines[2:], '\n')
93 return '', join(lines, '\n')
94
95 def classname(object, modname):
96 """Get a class name and qualify it with a module name if necessary."""
97 name = object.__name__
98 if object.__module__ != modname:
99 name = object.__module__ + '.' + name
100 return name
101
102 def isdata(object):
103 """Check if an object is of a type that probably means it's data."""
104 return not (inspect.ismodule(object) or inspect.isclass(object) or
105 inspect.isroutine(object) or inspect.isframe(object) or
106 inspect.istraceback(object) or inspect.iscode(object))
107
108 def replace(text, *pairs):
109 """Do a series of global replacements on a string."""
110 while pairs:
111 text = join(split(text, pairs[0]), pairs[1])
112 pairs = pairs[2:]
113 return text
114
115 def cram(text, maxlen):
116 """Omit part of a string if needed to make it fit in a maximum length."""
117 if len(text) > maxlen:
118 pre = max(0, (maxlen-3)//2)
119 post = max(0, maxlen-3-pre)
120 return text[:pre] + '...' + text[len(text)-post:]
121 return text
122
123 _re_stripid = re.compile(r' at 0x[0-9a-f]{6,16}(>+)$', re.IGNORECASE)
124 def stripid(text):
125 """Remove the hexadecimal id from a Python object representation."""
126 # The behaviour of %p is implementation-dependent in terms of case.
127 return _re_stripid.sub(r'\1', text)
128
129 def _is_some_method(obj):
130 return inspect.ismethod(obj) or inspect.ismethoddescriptor(obj)
131
132 def allmethods(cl):
133 methods = {}
134 for key, value in inspect.getmembers(cl, _is_some_method):
135 methods[key] = 1
136 for base in cl.__bases__:
137 methods.update(allmethods(base)) # all your base are belong to us
138 for key in methods.keys():
139 methods[key] = getattr(cl, key)
140 return methods
141
142 def _split_list(s, predicate):
143 """Split sequence s via predicate, and return pair ([true], [false]).
144
145 The return value is a 2-tuple of lists,
146 ([x for x in s if predicate(x)],
147 [x for x in s if not predicate(x)])
148 """
149
150 yes = []
151 no = []
152 for x in s:
153 if predicate(x):
154 yes.append(x)
155 else:
156 no.append(x)
157 return yes, no
158
159 def visiblename(name, all=None, obj=None):
160 """Decide whether to show documentation on a variable."""
161 # Certain special names are redundant.
162 _hidden_names = ('__builtins__', '__doc__', '__file__', '__path__',
163 '__module__', '__name__', '__slots__', '__package__')
164 if name in _hidden_names: return 0
165 # Private names are hidden, but special names are displayed.
166 if name.startswith('__') and name.endswith('__'): return 1
167 # Namedtuples have public fields and methods with a single leading underscore
168 if name.startswith('_') and hasattr(obj, '_fields'):
169 return 1
170 if all is not None:
171 # only document that which the programmer exported in __all__
172 return name in all
173 else:
174 return not name.startswith('_')
175
176 def classify_class_attrs(object):
177 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
178 def fixup(data):
179 name, kind, cls, value = data
180 if inspect.isdatadescriptor(value):
181 kind = 'data descriptor'
182 return name, kind, cls, value
183 return map(fixup, inspect.classify_class_attrs(object))
184
185 # ----------------------------------------------------- module manipulation
186
187 def ispackage(path):
188 """Guess whether a path refers to a package directory."""
189 if os.path.isdir(path):
190 for ext in ('.py', '.pyc', '.pyo'):
191 if os.path.isfile(os.path.join(path, '__init__' + ext)):
192 return True
193 return False
194
195 def source_synopsis(file):
196 line = file.readline()
197 while line[:1] == '#' or not strip(line):
198 line = file.readline()
199 if not line: break
200 line = strip(line)
201 if line[:4] == 'r"""': line = line[1:]
202 if line[:3] == '"""':
203 line = line[3:]
204 if line[-1:] == '\\': line = line[:-1]
205 while not strip(line):
206 line = file.readline()
207 if not line: break
208 result = strip(split(line, '"""')[0])
209 else: result = None
210 return result
211
212 def synopsis(filename, cache={}):
213 """Get the one-line summary out of a module file."""
214 mtime = os.stat(filename).st_mtime
215 lastupdate, result = cache.get(filename, (0, None))
216 if lastupdate < mtime:
217 info = inspect.getmoduleinfo(filename)
218 try:
219 file = open(filename)
220 except IOError:
221 # module can't be opened, so skip it
222 return None
223 if info and 'b' in info[2]: # binary modules have to be imported
224 try: module = imp.load_module('__temp__', file, filename, info[1:])
225 except: return None
226 result = (module.__doc__ or '').splitlines()[0]
227 del sys.modules['__temp__']
228 else: # text modules can be directly examined
229 result = source_synopsis(file)
230 file.close()
231 cache[filename] = (mtime, result)
232 return result
233
234 class ErrorDuringImport(Exception):
235 """Errors that occurred while trying to import something to document it."""
236 def __init__(self, filename, exc_info):
237 exc, value, tb = exc_info
238 self.filename = filename
239 self.exc = exc
240 self.value = value
241 self.tb = tb
242
243 def __str__(self):
244 exc = self.exc
245 if type(exc) is types.ClassType:
246 exc = exc.__name__
247 return 'problem in %s - %s: %s' % (self.filename, exc, self.value)
248
249 def importfile(path):
250 """Import a Python source file or compiled file given its path."""
251 magic = imp.get_magic()
252 file = open(path, 'r')
253 if file.read(len(magic)) == magic:
254 kind = imp.PY_COMPILED
255 else:
256 kind = imp.PY_SOURCE
257 file.close()
258 filename = os.path.basename(path)
259 name, ext = os.path.splitext(filename)
260 file = open(path, 'r')
261 try:
262 module = imp.load_module(name, file, path, (ext, 'r', kind))
263 except:
264 raise ErrorDuringImport(path, sys.exc_info())
265 file.close()
266 return module
267
268 def safeimport(path, forceload=0, cache={}):
269 """Import a module; handle errors; return None if the module isn't found.
270
271 If the module *is* found but an exception occurs, it's wrapped in an
272 ErrorDuringImport exception and reraised. Unlike __import__, if a
273 package path is specified, the module at the end of the path is returned,
274 not the package at the beginning. If the optional 'forceload' argument
275 is 1, we reload the module from disk (unless it's a dynamic extension)."""
276 try:
277 # If forceload is 1 and the module has been previously loaded from
278 # disk, we always have to reload the module. Checking the file's
279 # mtime isn't good enough (e.g. the module could contain a class
280 # that inherits from another module that has changed).
281 if forceload and path in sys.modules:
282 if path not in sys.builtin_module_names:
283 # Avoid simply calling reload() because it leaves names in
284 # the currently loaded module lying around if they're not
285 # defined in the new source file. Instead, remove the
286 # module from sys.modules and re-import. Also remove any
287 # submodules because they won't appear in the newly loaded
288 # module's namespace if they're already in sys.modules.
289 subs = [m for m in sys.modules if m.startswith(path + '.')]
290 for key in [path] + subs:
291 # Prevent garbage collection.
292 cache[key] = sys.modules[key]
293 del sys.modules[key]
294 module = __import__(path)
295 except:
296 # Did the error occur before or after the module was found?
297 (exc, value, tb) = info = sys.exc_info()
298 if path in sys.modules:
299 # An error occurred while executing the imported module.
300 raise ErrorDuringImport(sys.modules[path].__file__, info)
301 elif exc is SyntaxError:
302 # A SyntaxError occurred before we could execute the module.
303 raise ErrorDuringImport(value.filename, info)
304 elif exc is ImportError and extract_tb(tb)[-1][2]=='safeimport':
305 # The import error occurred directly in this function,
306 # which means there is no such module in the path.
307 return None
308 else:
309 # Some other error occurred during the importing process.
310 raise ErrorDuringImport(path, sys.exc_info())
311 for part in split(path, '.')[1:]:
312 try: module = getattr(module, part)
313 except AttributeError: return None
314 return module
315
316 # ---------------------------------------------------- formatter base class
317
318 class Doc:
319 def document(self, object, name=None, *args):
320 """Generate documentation for an object."""
321 args = (object, name) + args
322 # 'try' clause is to attempt to handle the possibility that inspect
323 # identifies something in a way that pydoc itself has issues handling;
324 # think 'super' and how it is a descriptor (which raises the exception
325 # by lacking a __name__ attribute) and an instance.
326 if inspect.isgetsetdescriptor(object): return self.docdata(*args)
327 if inspect.ismemberdescriptor(object): return self.docdata(*args)
328 try:
329 if inspect.ismodule(object): return self.docmodule(*args)
330 if inspect.isclass(object): return self.docclass(*args)
331 if inspect.isroutine(object): return self.docroutine(*args)
332 except AttributeError:
333 pass
334 if isinstance(object, property): return self.docproperty(*args)
335 return self.docother(*args)
336
337 def fail(self, object, name=None, *args):
338 """Raise an exception for unimplemented types."""
339 message = "don't know how to document object%s of type %s" % (
340 name and ' ' + repr(name), type(object).__name__)
341 raise TypeError, message
342
343 docmodule = docclass = docroutine = docother = docproperty = docdata = fail
344
345 def getdocloc(self, object):
346 """Return the location of module docs or None"""
347
348 try:
349 file = inspect.getabsfile(object)
350 except TypeError:
351 file = '(built-in)'
352
353 docloc = os.environ.get("PYTHONDOCS",
354 "http://docs.python.org/library")
355 basedir = os.path.join(sys.exec_prefix, "lib",
356 "python"+sys.version[0:3])
357 if (isinstance(object, type(os)) and
358 (object.__name__ in ('errno', 'exceptions', 'gc', 'imp',
359 'marshal', 'posix', 'signal', 'sys',
360 'thread', 'zipimport') or
361 (file.startswith(basedir) and
362 not file.startswith(os.path.join(basedir, 'site-packages')))) and
363 object.__name__ not in ('xml.etree', 'test.pydoc_mod')):
364 if docloc.startswith("http://"):
365 docloc = "%s/%s" % (docloc.rstrip("/"), object.__name__)
366 else:
367 docloc = os.path.join(docloc, object.__name__ + ".html")
368 else:
369 docloc = None
370 return docloc
371
372 # -------------------------------------------- HTML documentation generator
373
374 class HTMLRepr(Repr):
375 """Class for safely making an HTML representation of a Python object."""
376 def __init__(self):
377 Repr.__init__(self)
378 self.maxlist = self.maxtuple = 20
379 self.maxdict = 10
380 self.maxstring = self.maxother = 100
381
382 def escape(self, text):
383 return replace(text, '&', '&amp;', '<', '&lt;', '>', '&gt;')
384
385 def repr(self, object):
386 return Repr.repr(self, object)
387
388 def repr1(self, x, level):
389 if hasattr(type(x), '__name__'):
390 methodname = 'repr_' + join(split(type(x).__name__), '_')
391 if hasattr(self, methodname):
392 return getattr(self, methodname)(x, level)
393 return self.escape(cram(stripid(repr(x)), self.maxother))
394
395 def repr_string(self, x, level):
396 test = cram(x, self.maxstring)
397 testrepr = repr(test)
398 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
399 # Backslashes are only literal in the string and are never
400 # needed to make any special characters, so show a raw string.
401 return 'r' + testrepr[0] + self.escape(test) + testrepr[0]
402 return re.sub(r'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
403 r'<font color="#c040c0">\1</font>',
404 self.escape(testrepr))
405
406 repr_str = repr_string
407
408 def repr_instance(self, x, level):
409 try:
410 return self.escape(cram(stripid(repr(x)), self.maxstring))
411 except:
412 return self.escape('<%s instance>' % x.__class__.__name__)
413
414 repr_unicode = repr_string
415
416 class HTMLDoc(Doc):
417 """Formatter class for HTML documentation."""
418
419 # ------------------------------------------- HTML formatting utilities
420
421 _repr_instance = HTMLRepr()
422 repr = _repr_instance.repr
423 escape = _repr_instance.escape
424
425 def page(self, title, contents):
426 """Format an HTML page."""
427 return '''
428 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
429 <html><head><title>Python: %s</title>
430 </head><body bgcolor="#f0f0f8">
431 %s
432 </body></html>''' % (title, contents)
433
434 def heading(self, title, fgcol, bgcol, extras=''):
435 """Format a page heading."""
436 return '''
437 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
438 <tr bgcolor="%s">
439 <td valign=bottom>&nbsp;<br>
440 <font color="%s" face="helvetica, arial">&nbsp;<br>%s</font></td
441 ><td align=right valign=bottom
442 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
443 ''' % (bgcol, fgcol, title, fgcol, extras or '&nbsp;')
444
445 def section(self, title, fgcol, bgcol, contents, width=6,
446 prelude='', marginalia=None, gap='&nbsp;'):
447 """Format a section with a heading."""
448 if marginalia is None:
449 marginalia = '<tt>' + '&nbsp;' * width + '</tt>'
450 result = '''<p>
451 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
452 <tr bgcolor="%s">
453 <td colspan=3 valign=bottom>&nbsp;<br>
454 <font color="%s" face="helvetica, arial">%s</font></td></tr>
455 ''' % (bgcol, fgcol, title)
456 if prelude:
457 result = result + '''
458 <tr bgcolor="%s"><td rowspan=2>%s</td>
459 <td colspan=2>%s</td></tr>
460 <tr><td>%s</td>''' % (bgcol, marginalia, prelude, gap)
461 else:
462 result = result + '''
463 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol, marginalia, gap)
464
465 return result + '\n<td width="100%%">%s</td></tr></table>' % contents
466
467 def bigsection(self, title, *args):
468 """Format a section with a big heading."""
469 title = '<big><strong>%s</strong></big>' % title
470 return self.section(title, *args)
471
472 def preformat(self, text):
473 """Format literal preformatted text."""
474 text = self.escape(expandtabs(text))
475 return replace(text, '\n\n', '\n \n', '\n\n', '\n \n',
476 ' ', '&nbsp;', '\n', '<br>\n')
477
478 def multicolumn(self, list, format, cols=4):
479 """Format a list of items into a multi-column list."""
480 result = ''
481 rows = (len(list)+cols-1)//cols
482 for col in range(cols):
483 result = result + '<td width="%d%%" valign=top>' % (100//cols)
484 for i in range(rows*col, rows*col+rows):
485 if i < len(list):
486 result = result + format(list[i]) + '<br>\n'
487 result = result + '</td>'
488 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
489
490 def grey(self, text): return '<font color="#909090">%s</font>' % text
491
492 def namelink(self, name, *dicts):
493 """Make a link for an identifier, given name-to-URL mappings."""
494 for dict in dicts:
495 if name in dict:
496 return '<a href="%s">%s</a>' % (dict[name], name)
497 return name
498
499 def classlink(self, object, modname):
500 """Make a link for a class."""
501 name, module = object.__name__, sys.modules.get(object.__module__)
502 if hasattr(module, name) and getattr(module, name) is object:
503 return '<a href="%s.html#%s">%s</a>' % (
504 module.__name__, name, classname(object, modname))
505 return classname(object, modname)
506
507 def modulelink(self, object):
508 """Make a link for a module."""
509 return '<a href="%s.html">%s</a>' % (object.__name__, object.__name__)
510
511 def modpkglink(self, data):
512 """Make a link for a module or package to display in an index."""
513 name, path, ispackage, shadowed = data
514 if shadowed:
515 return self.grey(name)
516 if path:
517 url = '%s.%s.html' % (path, name)
518 else:
519 url = '%s.html' % name
520 if ispackage:
521 text = '<strong>%s</strong>&nbsp;(package)' % name
522 else:
523 text = name
524 return '<a href="%s">%s</a>' % (url, text)
525
526 def markup(self, text, escape=None, funcs={}, classes={}, methods={}):
527 """Mark up some plain text, given a context of symbols to look for.
528 Each context dictionary maps object names to anchor names."""
529 escape = escape or self.escape
530 results = []
531 here = 0
532 pattern = re.compile(r'\b((http|ftp)://\S+[\w/]|'
533 r'RFC[- ]?(\d+)|'
534 r'PEP[- ]?(\d+)|'
535 r'(self\.)?(\w+))')
536 while True:
537 match = pattern.search(text, here)
538 if not match: break
539 start, end = match.span()
540 results.append(escape(text[here:start]))
541
542 all, scheme, rfc, pep, selfdot, name = match.groups()
543 if scheme:
544 url = escape(all).replace('"', '&quot;')
545 results.append('<a href="%s">%s</a>' % (url, url))
546 elif rfc:
547 url = 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc)
548 results.append('<a href="%s">%s</a>' % (url, escape(all)))
549 elif pep:
550 url = 'http://www.python.org/dev/peps/pep-%04d/' % int(pep)
551 results.append('<a href="%s">%s</a>' % (url, escape(all)))
552 elif text[end:end+1] == '(':
553 results.append(self.namelink(name, methods, funcs, classes))
554 elif selfdot:
555 results.append('self.<strong>%s</strong>' % name)
556 else:
557 results.append(self.namelink(name, classes))
558 here = end
559 results.append(escape(text[here:]))
560 return join(results, '')
561
562 # ---------------------------------------------- type-specific routines
563
564 def formattree(self, tree, modname, parent=None):
565 """Produce HTML for a class tree as given by inspect.getclasstree()."""
566 result = ''
567 for entry in tree:
568 if type(entry) is type(()):
569 c, bases = entry
570 result = result + '<dt><font face="helvetica, arial">'
571 result = result + self.classlink(c, modname)
572 if bases and bases != (parent,):
573 parents = []
574 for base in bases:
575 parents.append(self.classlink(base, modname))
576 result = result + '(' + join(parents, ', ') + ')'
577 result = result + '\n</font></dt>'
578 elif type(entry) is type([]):
579 result = result + '<dd>\n%s</dd>\n' % self.formattree(
580 entry, modname, c)
581 return '<dl>\n%s</dl>\n' % result
582
583 def docmodule(self, object, name=None, mod=None, *ignored):
584 """Produce HTML documentation for a module object."""
585 name = object.__name__ # ignore the passed-in name
586 try:
587 all = object.__all__
588 except AttributeError:
589 all = None
590 parts = split(name, '.')
591 links = []
592 for i in range(len(parts)-1):
593 links.append(
594 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
595 (join(parts[:i+1], '.'), parts[i]))
596 linkedname = join(links + parts[-1:], '.')
597 head = '<big><big><strong>%s</strong></big></big>' % linkedname
598 try:
599 path = inspect.getabsfile(object)
600 url = path
601 if sys.platform == 'win32':
602 import nturl2path
603 url = nturl2path.pathname2url(path)
604 filelink = '<a href="file:%s">%s</a>' % (url, path)
605 except TypeError:
606 filelink = '(built-in)'
607 info = []
608 if hasattr(object, '__version__'):
609 version = str(object.__version__)
610 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
611 version = strip(version[11:-1])
612 info.append('version %s' % self.escape(version))
613 if hasattr(object, '__date__'):
614 info.append(self.escape(str(object.__date__)))
615 if info:
616 head = head + ' (%s)' % join(info, ', ')
617 docloc = self.getdocloc(object)
618 if docloc is not None:
619 docloc = '<br><a href="%(docloc)s">Module Docs</a>' % locals()
620 else:
621 docloc = ''
622 result = self.heading(
623 head, '#ffffff', '#7799ee',
624 '<a href=".">index</a><br>' + filelink + docloc)
625
626 modules = inspect.getmembers(object, inspect.ismodule)
627
628 classes, cdict = [], {}
629 for key, value in inspect.getmembers(object, inspect.isclass):
630 # if __all__ exists, believe it. Otherwise use old heuristic.
631 if (all is not None or
632 (inspect.getmodule(value) or object) is object):
633 if visiblename(key, all, object):
634 classes.append((key, value))
635 cdict[key] = cdict[value] = '#' + key
636 for key, value in classes:
637 for base in value.__bases__:
638 key, modname = base.__name__, base.__module__
639 module = sys.modules.get(modname)
640 if modname != name and module and hasattr(module, key):
641 if getattr(module, key) is base:
642 if not key in cdict:
643 cdict[key] = cdict[base] = modname + '.html#' + key
644 funcs, fdict = [], {}
645 for key, value in inspect.getmembers(object, inspect.isroutine):
646 # if __all__ exists, believe it. Otherwise use old heuristic.
647 if (all is not None or
648 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
649 if visiblename(key, all, object):
650 funcs.append((key, value))
651 fdict[key] = '#-' + key
652 if inspect.isfunction(value): fdict[value] = fdict[key]
653 data = []
654 for key, value in inspect.getmembers(object, isdata):
655 if visiblename(key, all, object):
656 data.append((key, value))
657
658 doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
659 doc = doc and '<tt>%s</tt>' % doc
660 result = result + '<p>%s</p>\n' % doc
661
662 if hasattr(object, '__path__'):
663 modpkgs = []
664 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
665 modpkgs.append((modname, name, ispkg, 0))
666 modpkgs.sort()
667 contents = self.multicolumn(modpkgs, self.modpkglink)
668 result = result + self.bigsection(
669 'Package Contents', '#ffffff', '#aa55cc', contents)
670 elif modules:
671 contents = self.multicolumn(
672 modules, lambda key_value, s=self: s.modulelink(key_value[1]))
673 result = result + self.bigsection(
674 'Modules', '#ffffff', '#aa55cc', contents)
675
676 if classes:
677 classlist = map(lambda key_value: key_value[1], classes)
678 contents = [
679 self.formattree(inspect.getclasstree(classlist, 1), name)]
680 for key, value in classes:
681 contents.append(self.document(value, key, name, fdict, cdict))
682 result = result + self.bigsection(
683 'Classes', '#ffffff', '#ee77aa', join(contents))
684 if funcs:
685 contents = []
686 for key, value in funcs:
687 contents.append(self.document(value, key, name, fdict, cdict))
688 result = result + self.bigsection(
689 'Functions', '#ffffff', '#eeaa77', join(contents))
690 if data:
691 contents = []
692 for key, value in data:
693 contents.append(self.document(value, key))
694 result = result + self.bigsection(
695 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
696 if hasattr(object, '__author__'):
697 contents = self.markup(str(object.__author__), self.preformat)
698 result = result + self.bigsection(
699 'Author', '#ffffff', '#7799ee', contents)
700 if hasattr(object, '__credits__'):
701 contents = self.markup(str(object.__credits__), self.preformat)
702 result = result + self.bigsection(
703 'Credits', '#ffffff', '#7799ee', contents)
704
705 return result
706
707 def docclass(self, object, name=None, mod=None, funcs={}, classes={},
708 *ignored):
709 """Produce HTML documentation for a class object."""
710 realname = object.__name__
711 name = name or realname
712 bases = object.__bases__
713
714 contents = []
715 push = contents.append
716
717 # Cute little class to pump out a horizontal rule between sections.
718 class HorizontalRule:
719 def __init__(self):
720 self.needone = 0
721 def maybe(self):
722 if self.needone:
723 push('<hr>\n')
724 self.needone = 1
725 hr = HorizontalRule()
726
727 # List the mro, if non-trivial.
728 mro = deque(inspect.getmro(object))
729 if len(mro) > 2:
730 hr.maybe()
731 push('<dl><dt>Method resolution order:</dt>\n')
732 for base in mro:
733 push('<dd>%s</dd>\n' % self.classlink(base,
734 object.__module__))
735 push('</dl>\n')
736
737 def spill(msg, attrs, predicate):
738 ok, attrs = _split_list(attrs, predicate)
739 if ok:
740 hr.maybe()
741 push(msg)
742 for name, kind, homecls, value in ok:
743 push(self.document(getattr(object, name), name, mod,
744 funcs, classes, mdict, object))
745 push('\n')
746 return attrs
747
748 def spilldescriptors(msg, attrs, predicate):
749 ok, attrs = _split_list(attrs, predicate)
750 if ok:
751 hr.maybe()
752 push(msg)
753 for name, kind, homecls, value in ok:
754 push(self._docdescriptor(name, value, mod))
755 return attrs
756
757 def spilldata(msg, attrs, predicate):
758 ok, attrs = _split_list(attrs, predicate)
759 if ok:
760 hr.maybe()
761 push(msg)
762 for name, kind, homecls, value in ok:
763 base = self.docother(getattr(object, name), name, mod)
764 if (hasattr(value, '__call__') or
765 inspect.isdatadescriptor(value)):
766 doc = getattr(value, "__doc__", None)
767 else:
768 doc = None
769 if doc is None:
770 push('<dl><dt>%s</dl>\n' % base)
771 else:
772 doc = self.markup(getdoc(value), self.preformat,
773 funcs, classes, mdict)
774 doc = '<dd><tt>%s</tt>' % doc
775 push('<dl><dt>%s%s</dl>\n' % (base, doc))
776 push('\n')
777 return attrs
778
779 attrs = filter(lambda data: visiblename(data[0], obj=object),
780 classify_class_attrs(object))
781 mdict = {}
782 for key, kind, homecls, value in attrs:
783 mdict[key] = anchor = '#' + name + '-' + key
784 value = getattr(object, key)
785 try:
786 # The value may not be hashable (e.g., a data attr with
787 # a dict or list value).
788 mdict[value] = anchor
789 except TypeError:
790 pass
791
792 while attrs:
793 if mro:
794 thisclass = mro.popleft()
795 else:
796 thisclass = attrs[0][2]
797 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
798
799 if thisclass is __builtin__.object:
800 attrs = inherited
801 continue
802 elif thisclass is object:
803 tag = 'defined here'
804 else:
805 tag = 'inherited from %s' % self.classlink(thisclass,
806 object.__module__)
807 tag += ':<br>\n'
808
809 # Sort attrs by name.
810 try:
811 attrs.sort(key=lambda t: t[0])
812 except TypeError:
813 attrs.sort(lambda t1, t2: cmp(t1[0], t2[0])) # 2.3 compat
814
815 # Pump out the attrs, segregated by kind.
816 attrs = spill('Methods %s' % tag, attrs,
817 lambda t: t[1] == 'method')
818 attrs = spill('Class methods %s' % tag, attrs,
819 lambda t: t[1] == 'class method')
820 attrs = spill('Static methods %s' % tag, attrs,
821 lambda t: t[1] == 'static method')
822 attrs = spilldescriptors('Data descriptors %s' % tag, attrs,
823 lambda t: t[1] == 'data descriptor')
824 attrs = spilldata('Data and other attributes %s' % tag, attrs,
825 lambda t: t[1] == 'data')
826 assert attrs == []
827 attrs = inherited
828
829 contents = ''.join(contents)
830
831 if name == realname:
832 title = '<a name="%s">class <strong>%s</strong></a>' % (
833 name, realname)
834 else:
835 title = '<strong>%s</strong> = <a name="%s">class %s</a>' % (
836 name, name, realname)
837 if bases:
838 parents = []
839 for base in bases:
840 parents.append(self.classlink(base, object.__module__))
841 title = title + '(%s)' % join(parents, ', ')
842 doc = self.markup(getdoc(object), self.preformat, funcs, classes, mdict)
843 doc = doc and '<tt>%s<br>&nbsp;</tt>' % doc
844
845 return self.section(title, '#000000', '#ffc8d8', contents, 3, doc)
846
847 def formatvalue(self, object):
848 """Format an argument default value as text."""
849 return self.grey('=' + self.repr(object))
850
851 def docroutine(self, object, name=None, mod=None,
852 funcs={}, classes={}, methods={}, cl=None):
853 """Produce HTML documentation for a function or method object."""
854 realname = object.__name__
855 name = name or realname
856 anchor = (cl and cl.__name__ or '') + '-' + name
857 note = ''
858 skipdocs = 0
859 if inspect.ismethod(object):
860 imclass = object.im_class
861 if cl:
862 if imclass is not cl:
863 note = ' from ' + self.classlink(imclass, mod)
864 else:
865 if object.im_self is not None:
866 note = ' method of %s instance' % self.classlink(
867 object.im_self.__class__, mod)
868 else:
869 note = ' unbound %s method' % self.classlink(imclass,mod)
870 object = object.im_func
871
872 if name == realname:
873 title = '<a name="%s"><strong>%s</strong></a>' % (anchor, realname)
874 else:
875 if (cl and realname in cl.__dict__ and
876 cl.__dict__[realname] is object):
877 reallink = '<a href="#%s">%s</a>' % (
878 cl.__name__ + '-' + realname, realname)
879 skipdocs = 1
880 else:
881 reallink = realname
882 title = '<a name="%s"><strong>%s</strong></a> = %s' % (
883 anchor, name, reallink)
884 if inspect.isfunction(object):
885 args, varargs, varkw, defaults = inspect.getargspec(object)
886 argspec = inspect.formatargspec(
887 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
888 if realname == '<lambda>':
889 title = '<strong>%s</strong> <em>lambda</em> ' % name
890 argspec = argspec[1:-1] # remove parentheses
891 else:
892 argspec = '(...)'
893
894 decl = title + argspec + (note and self.grey(
895 '<font face="helvetica, arial">%s</font>' % note))
896
897 if skipdocs:
898 return '<dl><dt>%s</dt></dl>\n' % decl
899 else:
900 doc = self.markup(
901 getdoc(object), self.preformat, funcs, classes, methods)
902 doc = doc and '<dd><tt>%s</tt></dd>' % doc
903 return '<dl><dt>%s</dt>%s</dl>\n' % (decl, doc)
904
905 def _docdescriptor(self, name, value, mod):
906 results = []
907 push = results.append
908
909 if name:
910 push('<dl><dt><strong>%s</strong></dt>\n' % name)
911 if value.__doc__ is not None:
912 doc = self.markup(getdoc(value), self.preformat)
913 push('<dd><tt>%s</tt></dd>\n' % doc)
914 push('</dl>\n')
915
916 return ''.join(results)
917
918 def docproperty(self, object, name=None, mod=None, cl=None):
919 """Produce html documentation for a property."""
920 return self._docdescriptor(name, object, mod)
921
922 def docother(self, object, name=None, mod=None, *ignored):
923 """Produce HTML documentation for a data object."""
924 lhs = name and '<strong>%s</strong> = ' % name or ''
925 return lhs + self.repr(object)
926
927 def docdata(self, object, name=None, mod=None, cl=None):
928 """Produce html documentation for a data descriptor."""
929 return self._docdescriptor(name, object, mod)
930
931 def index(self, dir, shadowed=None):
932 """Generate an HTML index for a directory of modules."""
933 modpkgs = []
934 if shadowed is None: shadowed = {}
935 for importer, name, ispkg in pkgutil.iter_modules([dir]):
936 modpkgs.append((name, '', ispkg, name in shadowed))
937 shadowed[name] = 1
938
939 modpkgs.sort()
940 contents = self.multicolumn(modpkgs, self.modpkglink)
941 return self.bigsection(dir, '#ffffff', '#ee77aa', contents)
942
943 # -------------------------------------------- text documentation generator
944
945 class TextRepr(Repr):
946 """Class for safely making a text representation of a Python object."""
947 def __init__(self):
948 Repr.__init__(self)
949 self.maxlist = self.maxtuple = 20
950 self.maxdict = 10
951 self.maxstring = self.maxother = 100
952
953 def repr1(self, x, level):
954 if hasattr(type(x), '__name__'):
955 methodname = 'repr_' + join(split(type(x).__name__), '_')
956 if hasattr(self, methodname):
957 return getattr(self, methodname)(x, level)
958 return cram(stripid(repr(x)), self.maxother)
959
960 def repr_string(self, x, level):
961 test = cram(x, self.maxstring)
962 testrepr = repr(test)
963 if '\\' in test and '\\' not in replace(testrepr, r'\\', ''):
964 # Backslashes are only literal in the string and are never
965 # needed to make any special characters, so show a raw string.
966 return 'r' + testrepr[0] + test + testrepr[0]
967 return testrepr
968
969 repr_str = repr_string
970
971 def repr_instance(self, x, level):
972 try:
973 return cram(stripid(repr(x)), self.maxstring)
974 except:
975 return '<%s instance>' % x.__class__.__name__
976
977 class TextDoc(Doc):
978 """Formatter class for text documentation."""
979
980 # ------------------------------------------- text formatting utilities
981
982 _repr_instance = TextRepr()
983 repr = _repr_instance.repr
984
985 def bold(self, text):
986 """Format a string in bold by overstriking."""
987 return join(map(lambda ch: ch + '\b' + ch, text), '')
988
989 def indent(self, text, prefix=' '):
990 """Indent text by prepending a given prefix to each line."""
991 if not text: return ''
992 lines = split(text, '\n')
993 lines = map(lambda line, prefix=prefix: prefix + line, lines)
994 if lines: lines[-1] = rstrip(lines[-1])
995 return join(lines, '\n')
996
997 def section(self, title, contents):
998 """Format a section with a given heading."""
999 return self.bold(title) + '\n' + rstrip(self.indent(contents)) + '\n\n'
1000
1001 # ---------------------------------------------- type-specific routines
1002
1003 def formattree(self, tree, modname, parent=None, prefix=''):
1004 """Render in text a class tree as returned by inspect.getclasstree()."""
1005 result = ''
1006 for entry in tree:
1007 if type(entry) is type(()):
1008 c, bases = entry
1009 result = result + prefix + classname(c, modname)
1010 if bases and bases != (parent,):
1011 parents = map(lambda c, m=modname: classname(c, m), bases)
1012 result = result + '(%s)' % join(parents, ', ')
1013 result = result + '\n'
1014 elif type(entry) is type([]):
1015 result = result + self.formattree(
1016 entry, modname, c, prefix + ' ')
1017 return result
1018
1019 def docmodule(self, object, name=None, mod=None):
1020 """Produce text documentation for a given module object."""
1021 name = object.__name__ # ignore the passed-in name
1022 synop, desc = splitdoc(getdoc(object))
1023 result = self.section('NAME', name + (synop and ' - ' + synop))
1024
1025 try:
1026 all = object.__all__
1027 except AttributeError:
1028 all = None
1029
1030 try:
1031 file = inspect.getabsfile(object)
1032 except TypeError:
1033 file = '(built-in)'
1034 result = result + self.section('FILE', file)
1035
1036 docloc = self.getdocloc(object)
1037 if docloc is not None:
1038 result = result + self.section('MODULE DOCS', docloc)
1039
1040 if desc:
1041 result = result + self.section('DESCRIPTION', desc)
1042
1043 classes = []
1044 for key, value in inspect.getmembers(object, inspect.isclass):
1045 # if __all__ exists, believe it. Otherwise use old heuristic.
1046 if (all is not None
1047 or (inspect.getmodule(value) or object) is object):
1048 if visiblename(key, all, object):
1049 classes.append((key, value))
1050 funcs = []
1051 for key, value in inspect.getmembers(object, inspect.isroutine):
1052 # if __all__ exists, believe it. Otherwise use old heuristic.
1053 if (all is not None or
1054 inspect.isbuiltin(value) or inspect.getmodule(value) is object):
1055 if visiblename(key, all, object):
1056 funcs.append((key, value))
1057 data = []
1058 for key, value in inspect.getmembers(object, isdata):
1059 if visiblename(key, all, object):
1060 data.append((key, value))
1061
1062 modpkgs = []
1063 modpkgs_names = set()
1064 if hasattr(object, '__path__'):
1065 for importer, modname, ispkg in pkgutil.iter_modules(object.__path__):
1066 modpkgs_names.add(modname)
1067 if ispkg:
1068 modpkgs.append(modname + ' (package)')
1069 else:
1070 modpkgs.append(modname)
1071
1072 modpkgs.sort()
1073 result = result + self.section(
1074 'PACKAGE CONTENTS', join(modpkgs, '\n'))
1075
1076 # Detect submodules as sometimes created by C extensions
1077 submodules = []
1078 for key, value in inspect.getmembers(object, inspect.ismodule):
1079 if value.__name__.startswith(name + '.') and key not in modpkgs_names:
1080 submodules.append(key)
1081 if submodules:
1082 submodules.sort()
1083 result = result + self.section(
1084 'SUBMODULES', join(submodules, '\n'))
1085
1086 if classes:
1087 classlist = map(lambda key_value: key_value[1], classes)
1088 contents = [self.formattree(
1089 inspect.getclasstree(classlist, 1), name)]
1090 for key, value in classes:
1091 contents.append(self.document(value, key, name))
1092 result = result + self.section('CLASSES', join(contents, '\n'))
1093
1094 if funcs:
1095 contents = []
1096 for key, value in funcs:
1097 contents.append(self.document(value, key, name))
1098 result = result + self.section('FUNCTIONS', join(contents, '\n'))
1099
1100 if data:
1101 contents = []
1102 for key, value in data:
1103 contents.append(self.docother(value, key, name, maxlen=70))
1104 result = result + self.section('DATA', join(contents, '\n'))
1105
1106 if hasattr(object, '__version__'):
1107 version = str(object.__version__)
1108 if version[:11] == '$' + 'Revision: ' and version[-1:] == '$':
1109 version = strip(version[11:-1])
1110 result = result + self.section('VERSION', version)
1111 if hasattr(object, '__date__'):
1112 result = result + self.section('DATE', str(object.__date__))
1113 if hasattr(object, '__author__'):
1114 result = result + self.section('AUTHOR', str(object.__author__))
1115 if hasattr(object, '__credits__'):
1116 result = result + self.section('CREDITS', str(object.__credits__))
1117 return result
1118
1119 def docclass(self, object, name=None, mod=None, *ignored):
1120 """Produce text documentation for a given class object."""
1121 realname = object.__name__
1122 name = name or realname
1123 bases = object.__bases__
1124
1125 def makename(c, m=object.__module__):
1126 return classname(c, m)
1127
1128 if name == realname:
1129 title = 'class ' + self.bold(realname)
1130 else:
1131 title = self.bold(name) + ' = class ' + realname
1132 if bases:
1133 parents = map(makename, bases)
1134 title = title + '(%s)' % join(parents, ', ')
1135
1136 doc = getdoc(object)
1137 contents = doc and [doc + '\n'] or []
1138 push = contents.append
1139
1140 # List the mro, if non-trivial.
1141 mro = deque(inspect.getmro(object))
1142 if len(mro) > 2:
1143 push("Method resolution order:")
1144 for base in mro:
1145 push(' ' + makename(base))
1146 push('')
1147
1148 # Cute little class to pump out a horizontal rule between sections.
1149 class HorizontalRule:
1150 def __init__(self):
1151 self.needone = 0
1152 def maybe(self):
1153 if self.needone:
1154 push('-' * 70)
1155 self.needone = 1
1156 hr = HorizontalRule()
1157
1158 def spill(msg, attrs, predicate):
1159 ok, attrs = _split_list(attrs, predicate)
1160 if ok:
1161 hr.maybe()
1162 push(msg)
1163 for name, kind, homecls, value in ok:
1164 push(self.document(getattr(object, name),
1165 name, mod, object))
1166 return attrs
1167
1168 def spilldescriptors(msg, attrs, predicate):
1169 ok, attrs = _split_list(attrs, predicate)
1170 if ok:
1171 hr.maybe()
1172 push(msg)
1173 for name, kind, homecls, value in ok:
1174 push(self._docdescriptor(name, value, mod))
1175 return attrs
1176
1177 def spilldata(msg, attrs, predicate):
1178 ok, attrs = _split_list(attrs, predicate)
1179 if ok:
1180 hr.maybe()
1181 push(msg)
1182 for name, kind, homecls, value in ok:
1183 if (hasattr(value, '__call__') or
1184 inspect.isdatadescriptor(value)):
1185 doc = getdoc(value)
1186 else:
1187 doc = None
1188 push(self.docother(getattr(object, name),
1189 name, mod, maxlen=70, doc=doc) + '\n')
1190 return attrs
1191
1192 attrs = filter(lambda data: visiblename(data[0], obj=object),
1193 classify_class_attrs(object))
1194 while attrs:
1195 if mro:
1196 thisclass = mro.popleft()
1197 else:
1198 thisclass = attrs[0][2]
1199 attrs, inherited = _split_list(attrs, lambda t: t[2] is thisclass)
1200
1201 if thisclass is __builtin__.object:
1202 attrs = inherited
1203 continue
1204 elif thisclass is object:
1205 tag = "defined here"
1206 else:
1207 tag = "inherited from %s" % classname(thisclass,
1208 object.__module__)
1209
1210 # Sort attrs by name.
1211 attrs.sort()
1212
1213 # Pump out the attrs, segregated by kind.
1214 attrs = spill("Methods %s:\n" % tag, attrs,
1215 lambda t: t[1] == 'method')
1216 attrs = spill("Class methods %s:\n" % tag, attrs,
1217 lambda t: t[1] == 'class method')
1218 attrs = spill("Static methods %s:\n" % tag, attrs,
1219 lambda t: t[1] == 'static method')
1220 attrs = spilldescriptors("Data descriptors %s:\n" % tag, attrs,
1221 lambda t: t[1] == 'data descriptor')
1222 attrs = spilldata("Data and other attributes %s:\n" % tag, attrs,
1223 lambda t: t[1] == 'data')
1224 assert attrs == []
1225 attrs = inherited
1226
1227 contents = '\n'.join(contents)
1228 if not contents:
1229 return title + '\n'
1230 return title + '\n' + self.indent(rstrip(contents), ' | ') + '\n'
1231
1232 def formatvalue(self, object):
1233 """Format an argument default value as text."""
1234 return '=' + self.repr(object)
1235
1236 def docroutine(self, object, name=None, mod=None, cl=None):
1237 """Produce text documentation for a function or method object."""
1238 realname = object.__name__
1239 name = name or realname
1240 note = ''
1241 skipdocs = 0
1242 if inspect.ismethod(object):
1243 imclass = object.im_class
1244 if cl:
1245 if imclass is not cl:
1246 note = ' from ' + classname(imclass, mod)
1247 else:
1248 if object.im_self is not None:
1249 note = ' method of %s instance' % classname(
1250 object.im_self.__class__, mod)
1251 else:
1252 note = ' unbound %s method' % classname(imclass,mod)
1253 object = object.im_func
1254
1255 if name == realname:
1256 title = self.bold(realname)
1257 else:
1258 if (cl and realname in cl.__dict__ and
1259 cl.__dict__[realname] is object):
1260 skipdocs = 1
1261 title = self.bold(name) + ' = ' + realname
1262 if inspect.isfunction(object):
1263 args, varargs, varkw, defaults = inspect.getargspec(object)
1264 argspec = inspect.formatargspec(
1265 args, varargs, varkw, defaults, formatvalue=self.formatvalue)
1266 if realname == '<lambda>':
1267 title = self.bold(name) + ' lambda '
1268 argspec = argspec[1:-1] # remove parentheses
1269 else:
1270 argspec = '(...)'
1271 decl = title + argspec + note
1272
1273 if skipdocs:
1274 return decl + '\n'
1275 else:
1276 doc = getdoc(object) or ''
1277 return decl + '\n' + (doc and rstrip(self.indent(doc)) + '\n')
1278
1279 def _docdescriptor(self, name, value, mod):
1280 results = []
1281 push = results.append
1282
1283 if name:
1284 push(self.bold(name))
1285 push('\n')
1286 doc = getdoc(value) or ''
1287 if doc:
1288 push(self.indent(doc))
1289 push('\n')
1290 return ''.join(results)
1291
1292 def docproperty(self, object, name=None, mod=None, cl=None):
1293 """Produce text documentation for a property."""
1294 return self._docdescriptor(name, object, mod)
1295
1296 def docdata(self, object, name=None, mod=None, cl=None):
1297 """Produce text documentation for a data descriptor."""
1298 return self._docdescriptor(name, object, mod)
1299
1300 def docother(self, object, name=None, mod=None, parent=None, maxlen=None, doc=None):
1301 """Produce text documentation for a data object."""
1302 repr = self.repr(object)
1303 if maxlen:
1304 line = (name and name + ' = ' or '') + repr
1305 chop = maxlen - len(line)
1306 if chop < 0: repr = repr[:chop] + '...'
1307 line = (name and self.bold(name) + ' = ' or '') + repr
1308 if doc is not None:
1309 line += '\n' + self.indent(str(doc))
1310 return line
1311
1312 # --------------------------------------------------------- user interfaces
1313
1314 def pager(text):
1315 """The first time this is called, determine what kind of pager to use."""
1316 global pager
1317 pager = getpager()
1318 pager(text)
1319
1320 def getpager():
1321 """Decide what method to use for paging through text."""
1322 if type(sys.stdout) is not types.FileType:
1323 return plainpager
1324 if not sys.stdin.isatty() or not sys.stdout.isatty():
1325 return plainpager
1326 if 'PAGER' in os.environ:
1327 if sys.platform == 'win32': # pipes completely broken in Windows
1328 return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
1329 elif os.environ.get('TERM') in ('dumb', 'emacs'):
1330 return lambda text: pipepager(plain(text), os.environ['PAGER'])
1331 else:
1332 return lambda text: pipepager(text, os.environ['PAGER'])
1333 if os.environ.get('TERM') in ('dumb', 'emacs'):
1334 return plainpager
1335 if sys.platform == 'win32' or sys.platform.startswith('os2'):
1336 return lambda text: tempfilepager(plain(text), 'more <')
1337 if hasattr(os, 'system') and os.system('(less) 2>/dev/null') == 0:
1338 return lambda text: pipepager(text, 'less')
1339
1340 import tempfile
1341 (fd, filename) = tempfile.mkstemp()
1342 os.close(fd)
1343 try:
1344 if hasattr(os, 'system') and os.system('more "%s"' % filename) == 0:
1345 return lambda text: pipepager(text, 'more')
1346 else:
1347 return ttypager
1348 finally:
1349 os.unlink(filename)
1350
1351 def plain(text):
1352 """Remove boldface formatting from text."""
1353 return re.sub('.\b', '', text)
1354
1355 def pipepager(text, cmd):
1356 """Page through text by feeding it to another program."""
1357 pipe = os.popen(cmd, 'w')
1358 try:
1359 pipe.write(text)
1360 pipe.close()
1361 except IOError:
1362 pass # Ignore broken pipes caused by quitting the pager program.
1363
1364 def tempfilepager(text, cmd):
1365 """Page through text by invoking a program on a temporary file."""
1366 import tempfile
1367 filename = tempfile.mktemp()
1368 file = open(filename, 'w')
1369 file.write(text)
1370 file.close()
1371 try:
1372 os.system(cmd + ' "' + filename + '"')
1373 finally:
1374 os.unlink(filename)
1375
1376 def ttypager(text):
1377 """Page through text on a text terminal."""
1378 lines = split(plain(text), '\n')
1379 try:
1380 import tty
1381 fd = sys.stdin.fileno()
1382 old = tty.tcgetattr(fd)
1383 tty.setcbreak(fd)
1384 getchar = lambda: sys.stdin.read(1)
1385 except (ImportError, AttributeError):
1386 tty = None
1387 getchar = lambda: sys.stdin.readline()[:-1][:1]
1388
1389 try:
1390 r = inc = os.environ.get('LINES', 25) - 1
1391 sys.stdout.write(join(lines[:inc], '\n') + '\n')
1392 while lines[r:]:
1393 sys.stdout.write('-- more --')
1394 sys.stdout.flush()
1395 c = getchar()
1396
1397 if c in ('q', 'Q'):
1398 sys.stdout.write('\r \r')
1399 break
1400 elif c in ('\r', '\n'):
1401 sys.stdout.write('\r \r' + lines[r] + '\n')
1402 r = r + 1
1403 continue
1404 if c in ('b', 'B', '\x1b'):
1405 r = r - inc - inc
1406 if r < 0: r = 0
1407 sys.stdout.write('\n' + join(lines[r:r+inc], '\n') + '\n')
1408 r = r + inc
1409
1410 finally:
1411 if tty:
1412 tty.tcsetattr(fd, tty.TCSAFLUSH, old)
1413
1414 def plainpager(text):
1415 """Simply print unformatted text. This is the ultimate fallback."""
1416 sys.stdout.write(plain(text))
1417
1418 def describe(thing):
1419 """Produce a short description of the given thing."""
1420 if inspect.ismodule(thing):
1421 if thing.__name__ in sys.builtin_module_names:
1422 return 'built-in module ' + thing.__name__
1423 if hasattr(thing, '__path__'):
1424 return 'package ' + thing.__name__
1425 else:
1426 return 'module ' + thing.__name__
1427 if inspect.isbuiltin(thing):
1428 return 'built-in function ' + thing.__name__
1429 if inspect.isgetsetdescriptor(thing):
1430 return 'getset descriptor %s.%s.%s' % (
1431 thing.__objclass__.__module__, thing.__objclass__.__name__,
1432 thing.__name__)
1433 if inspect.ismemberdescriptor(thing):
1434 return 'member descriptor %s.%s.%s' % (
1435 thing.__objclass__.__module__, thing.__objclass__.__name__,
1436 thing.__name__)
1437 if inspect.isclass(thing):
1438 return 'class ' + thing.__name__
1439 if inspect.isfunction(thing):
1440 return 'function ' + thing.__name__
1441 if inspect.ismethod(thing):
1442 return 'method ' + thing.__name__
1443 if type(thing) is types.InstanceType:
1444 return 'instance of ' + thing.__class__.__name__
1445 return type(thing).__name__
1446
1447 def locate(path, forceload=0):
1448 """Locate an object by name or dotted path, importing as necessary."""
1449 parts = [part for part in split(path, '.') if part]
1450 module, n = None, 0
1451 while n < len(parts):
1452 nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
1453 if nextmodule: module, n = nextmodule, n + 1
1454 else: break
1455 if module:
1456 object = module
1457 for part in parts[n:]:
1458 try: object = getattr(object, part)
1459 except AttributeError: return None
1460 return object
1461 else:
1462 if hasattr(__builtin__, path):
1463 return getattr(__builtin__, path)
1464
1465 # --------------------------------------- interactive interpreter interface
1466
1467 text = TextDoc()
1468 html = HTMLDoc()
1469
1470 class _OldStyleClass: pass
1471 _OLD_INSTANCE_TYPE = type(_OldStyleClass())
1472
1473 def resolve(thing, forceload=0):
1474 """Given an object or a path to an object, get the object and its name."""
1475 if isinstance(thing, str):
1476 object = locate(thing, forceload)
1477 if not object:
1478 raise ImportError, 'no Python documentation found for %r' % thing
1479 return object, thing
1480 else:
1481 return thing, getattr(thing, '__name__', None)
1482
1483 def render_doc(thing, title='Python Library Documentation: %s', forceload=0):
1484 """Render text documentation, given an object or a path to an object."""
1485 object, name = resolve(thing, forceload)
1486 desc = describe(object)
1487 module = inspect.getmodule(object)
1488 if name and '.' in name:
1489 desc += ' in ' + name[:name.rfind('.')]
1490 elif module and module is not object:
1491 desc += ' in module ' + module.__name__
1492 if type(object) is _OLD_INSTANCE_TYPE:
1493 # If the passed object is an instance of an old-style class,
1494 # document its available methods instead of its value.
1495 object = object.__class__
1496 elif not (inspect.ismodule(object) or
1497 inspect.isclass(object) or
1498 inspect.isroutine(object) or
1499 inspect.isgetsetdescriptor(object) or
1500 inspect.ismemberdescriptor(object) or
1501 isinstance(object, property)):
1502 # If the passed object is a piece of data or an instance,
1503 # document its available methods instead of its value.
1504 object = type(object)
1505 desc += ' object'
1506 return title % desc + '\n\n' + text.document(object, name)
1507
1508 def doc(thing, title='Python Library Documentation: %s', forceload=0):
1509 """Display text documentation, given an object or a path to an object."""
1510 try:
1511 pager(render_doc(thing, title, forceload))
1512 except (ImportError, ErrorDuringImport), value:
1513 print value
1514
1515 def writedoc(thing, forceload=0):
1516 """Write HTML documentation to a file in the current directory."""
1517 try:
1518 object, name = resolve(thing, forceload)
1519 page = html.page(describe(object), html.document(object, name))
1520 file = open(name + '.html', 'w')
1521 file.write(page)
1522 file.close()
1523 print 'wrote', name + '.html'
1524 except (ImportError, ErrorDuringImport), value:
1525 print value
1526
1527 def writedocs(dir, pkgpath='', done=None):
1528 """Write out HTML documentation for all modules in a directory tree."""
1529 if done is None: done = {}
1530 for importer, modname, ispkg in pkgutil.walk_packages([dir], pkgpath):
1531 writedoc(modname)
1532 return
1533
1534 class Helper:
1535
1536 # These dictionaries map a topic name to either an alias, or a tuple
1537 # (label, seealso-items). The "label" is the label of the corresponding
1538 # section in the .rst file under Doc/ and an index into the dictionary
1539 # in pydoc_data/topics.py.
1540 #
1541 # CAUTION: if you change one of these dictionaries, be sure to adapt the
1542 # list of needed labels in Doc/tools/sphinxext/pyspecific.py and
1543 # regenerate the pydoc_data/topics.py file by running
1544 # make pydoc-topics
1545 # in Doc/ and copying the output file into the Lib/ directory.
1546
1547 keywords = {
1548 'and': 'BOOLEAN',
1549 'as': 'with',
1550 'assert': ('assert', ''),
1551 'break': ('break', 'while for'),
1552 'class': ('class', 'CLASSES SPECIALMETHODS'),
1553 'continue': ('continue', 'while for'),
1554 'def': ('function', ''),
1555 'del': ('del', 'BASICMETHODS'),
1556 'elif': 'if',
1557 'else': ('else', 'while for'),
1558 'except': 'try',
1559 'exec': ('exec', ''),
1560 'finally': 'try',
1561 'for': ('for', 'break continue while'),
1562 'from': 'import',
1563 'global': ('global', 'NAMESPACES'),
1564 'if': ('if', 'TRUTHVALUE'),
1565 'import': ('import', 'MODULES'),
1566 'in': ('in', 'SEQUENCEMETHODS2'),
1567 'is': 'COMPARISON',
1568 'lambda': ('lambda', 'FUNCTIONS'),
1569 'not': 'BOOLEAN',
1570 'or': 'BOOLEAN',
1571 'pass': ('pass', ''),
1572 'print': ('print', ''),
1573 'raise': ('raise', 'EXCEPTIONS'),
1574 'return': ('return', 'FUNCTIONS'),
1575 'try': ('try', 'EXCEPTIONS'),
1576 'while': ('while', 'break continue if TRUTHVALUE'),
1577 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1578 'yield': ('yield', ''),
1579 }
1580 # Either add symbols to this dictionary or to the symbols dictionary
1581 # directly: Whichever is easier. They are merged later.
1582 _symbols_inverse = {
1583 'STRINGS' : ("'", "'''", "r'", "u'", '"""', '"', 'r"', 'u"'),
1584 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1585 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1586 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1587 'UNARY' : ('-', '~'),
1588 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1589 '^=', '<<=', '>>=', '**=', '//='),
1590 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1591 'COMPLEX' : ('j', 'J')
1592 }
1593 symbols = {
1594 '%': 'OPERATORS FORMATTING',
1595 '**': 'POWER',
1596 ',': 'TUPLES LISTS FUNCTIONS',
1597 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1598 '...': 'ELLIPSIS',
1599 ':': 'SLICINGS DICTIONARYLITERALS',
1600 '@': 'def class',
1601 '\\': 'STRINGS',
1602 '_': 'PRIVATENAMES',
1603 '__': 'PRIVATENAMES SPECIALMETHODS',
1604 '`': 'BACKQUOTES',
1605 '(': 'TUPLES FUNCTIONS CALLS',
1606 ')': 'TUPLES FUNCTIONS CALLS',
1607 '[': 'LISTS SUBSCRIPTS SLICINGS',
1608 ']': 'LISTS SUBSCRIPTS SLICINGS'
1609 }
1610 for topic, symbols_ in _symbols_inverse.iteritems():
1611 for symbol in symbols_:
1612 topics = symbols.get(symbol, topic)
1613 if topic not in topics:
1614 topics = topics + ' ' + topic
1615 symbols[symbol] = topics
1616
1617 topics = {
1618 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1619 'FUNCTIONS CLASSES MODULES FILES inspect'),
1620 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING '
1621 'TYPES'),
1622 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1623 'FORMATTING': ('formatstrings', 'OPERATORS'),
1624 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1625 'FORMATTING TYPES'),
1626 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1627 'INTEGER': ('integers', 'int range'),
1628 'FLOAT': ('floating', 'float math'),
1629 'COMPLEX': ('imaginary', 'complex cmath'),
1630 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1631 'MAPPINGS': 'DICTIONARIES',
1632 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1633 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1634 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1635 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
1636 'FRAMEOBJECTS': 'TYPES',
1637 'TRACEBACKS': 'TYPES',
1638 'NONE': ('bltin-null-object', ''),
1639 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
1640 'FILES': ('bltin-file-objects', ''),
1641 'SPECIALATTRIBUTES': ('specialattrs', ''),
1642 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1643 'MODULES': ('typesmodules', 'import'),
1644 'PACKAGES': 'import',
1645 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1646 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1647 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1648 'LISTS DICTIONARIES BACKQUOTES'),
1649 'OPERATORS': 'EXPRESSIONS',
1650 'PRECEDENCE': 'EXPRESSIONS',
1651 'OBJECTS': ('objects', 'TYPES'),
1652 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
1653 'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS '
1654 'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1655 'BASICMETHODS': ('customization', 'cmp hash repr str SPECIALMETHODS'),
1656 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1657 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
1658 'SEQUENCEMETHODS1': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 '
1659 'SPECIALMETHODS'),
1660 'SEQUENCEMETHODS2': ('sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 '
1661 'SPECIALMETHODS'),
1662 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1663 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1664 'SPECIALMETHODS'),
1665 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1666 'NAMESPACES': ('naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1667 'DYNAMICFEATURES': ('dynamic-features', ''),
1668 'SCOPING': 'NAMESPACES',
1669 'FRAMES': 'NAMESPACES',
1670 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1671 'COERCIONS': ('coercion-rules','CONVERSIONS'),
1672 'CONVERSIONS': ('conversions', 'COERCIONS'),
1673 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1674 'SPECIALIDENTIFIERS': ('id-classes', ''),
1675 'PRIVATENAMES': ('atom-identifiers', ''),
1676 'LITERALS': ('atom-literals', 'STRINGS BACKQUOTES NUMBERS '
1677 'TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1678 'TUPLES': 'SEQUENCES',
1679 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1680 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1681 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1682 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1683 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1684 'BACKQUOTES': ('string-conversions', 'repr str STRINGS LITERALS'),
1685 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr '
1686 'ATTRIBUTEMETHODS'),
1687 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS1'),
1688 'SLICINGS': ('slicings', 'SEQUENCEMETHODS2'),
1689 'CALLS': ('calls', 'EXPRESSIONS'),
1690 'POWER': ('power', 'EXPRESSIONS'),
1691 'UNARY': ('unary', 'EXPRESSIONS'),
1692 'BINARY': ('binary', 'EXPRESSIONS'),
1693 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1694 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1695 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1696 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
1697 'ASSERTION': 'assert',
1698 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1699 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
1700 'DELETION': 'del',
1701 'PRINTING': 'print',
1702 'RETURNING': 'return',
1703 'IMPORTING': 'import',
1704 'CONDITIONAL': 'if',
1705 'LOOPING': ('compound', 'for while break continue'),
1706 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1707 'DEBUGGING': ('debugger', 'pdb'),
1708 'CONTEXTMANAGERS': ('context-managers', 'with'),
1709 }
1710
1711 def __init__(self, input=None, output=None):
1712 self._input = input
1713 self._output = output
1714
1715 input = property(lambda self: self._input or sys.stdin)
1716 output = property(lambda self: self._output or sys.stdout)
1717
1718 def __repr__(self):
1719 if inspect.stack()[1][3] == '?':
1720 self()
1721 return ''
1722 return '<pydoc.Helper instance>'
1723
1724 _GoInteractive = object()
1725 def __call__(self, request=_GoInteractive):
1726 if request is not self._GoInteractive:
1727 self.help(request)
1728 else:
1729 self.intro()
1730 self.interact()
1731 self.output.write('''
1732 You are now leaving help and returning to the Python interpreter.
1733 If you want to ask for help on a particular object directly from the
1734 interpreter, you can type "help(object)". Executing "help('string')"
1735 has the same effect as typing a particular string at the help> prompt.
1736 ''')
1737
1738 def interact(self):
1739 self.output.write('\n')
1740 while True:
1741 try:
1742 request = self.getline('help> ')
1743 if not request: break
1744 except (KeyboardInterrupt, EOFError):
1745 break
1746 request = strip(replace(request, '"', '', "'", ''))
1747 if lower(request) in ('q', 'quit'): break
1748 self.help(request)
1749
1750 def getline(self, prompt):
1751 """Read one line, using raw_input when available."""
1752 if self.input is sys.stdin:
1753 return raw_input(prompt)
1754 else:
1755 self.output.write(prompt)
1756 self.output.flush()
1757 return self.input.readline()
1758
1759 def help(self, request):
1760 if type(request) is type(''):
1761 request = request.strip()
1762 if request == 'help': self.intro()
1763 elif request == 'keywords': self.listkeywords()
1764 elif request == 'symbols': self.listsymbols()
1765 elif request == 'topics': self.listtopics()
1766 elif request == 'modules': self.listmodules()
1767 elif request[:8] == 'modules ':
1768 self.listmodules(split(request)[1])
1769 elif request in self.symbols: self.showsymbol(request)
1770 elif request in self.keywords: self.showtopic(request)
1771 elif request in self.topics: self.showtopic(request)
1772 elif request: doc(request, 'Help on %s:')
1773 elif isinstance(request, Helper): self()
1774 else: doc(request, 'Help on %s:')
1775 self.output.write('\n')
1776
1777 def intro(self):
1778 self.output.write('''
1779 Welcome to Python %s! This is the online help utility.
1780
1781 If this is your first time using Python, you should definitely check out
1782 the tutorial on the Internet at http://docs.python.org/tutorial/.
1783
1784 Enter the name of any module, keyword, or topic to get help on writing
1785 Python programs and using Python modules. To quit this help utility and
1786 return to the interpreter, just type "quit".
1787
1788 To get a list of available modules, keywords, or topics, type "modules",
1789 "keywords", or "topics". Each module also comes with a one-line summary
1790 of what it does; to list the modules whose summaries contain a given word
1791 such as "spam", type "modules spam".
1792 ''' % sys.version[:3])
1793
1794 def list(self, items, columns=4, width=80):
1795 items = items[:]
1796 items.sort()
1797 colw = width / columns
1798 rows = (len(items) + columns - 1) / columns
1799 for row in range(rows):
1800 for col in range(columns):
1801 i = col * rows + row
1802 if i < len(items):
1803 self.output.write(items[i])
1804 if col < columns - 1:
1805 self.output.write(' ' + ' ' * (colw-1 - len(items[i])))
1806 self.output.write('\n')
1807
1808 def listkeywords(self):
1809 self.output.write('''
1810 Here is a list of the Python keywords. Enter any keyword to get more help.
1811
1812 ''')
1813 self.list(self.keywords.keys())
1814
1815 def listsymbols(self):
1816 self.output.write('''
1817 Here is a list of the punctuation symbols which Python assigns special meaning
1818 to. Enter any symbol to get more help.
1819
1820 ''')
1821 self.list(self.symbols.keys())
1822
1823 def listtopics(self):
1824 self.output.write('''
1825 Here is a list of available topics. Enter any topic name to get more help.
1826
1827 ''')
1828 self.list(self.topics.keys())
1829
1830 def showtopic(self, topic, more_xrefs=''):
1831 try:
1832 import pydoc_data.topics
1833 except ImportError:
1834 self.output.write('''
1835 Sorry, topic and keyword documentation is not available because the
1836 module "pydoc_data.topics" could not be found.
1837 ''')
1838 return
1839 target = self.topics.get(topic, self.keywords.get(topic))
1840 if not target:
1841 self.output.write('no documentation found for %s\n' % repr(topic))
1842 return
1843 if type(target) is type(''):
1844 return self.showtopic(target, more_xrefs)
1845
1846 label, xrefs = target
1847 try:
1848 doc = pydoc_data.topics.topics[label]
1849 except KeyError:
1850 self.output.write('no documentation found for %s\n' % repr(topic))
1851 return
1852 pager(strip(doc) + '\n')
1853 if more_xrefs:
1854 xrefs = (xrefs or '') + ' ' + more_xrefs
1855 if xrefs:
1856 import StringIO, formatter
1857 buffer = StringIO.StringIO()
1858 formatter.DumbWriter(buffer).send_flowing_data(
1859 'Related help topics: ' + join(split(xrefs), ', ') + '\n')
1860 self.output.write('\n%s\n' % buffer.getvalue())
1861
1862 def showsymbol(self, symbol):
1863 target = self.symbols[symbol]
1864 topic, _, xrefs = target.partition(' ')
1865 self.showtopic(topic, xrefs)
1866
1867 def listmodules(self, key=''):
1868 if key:
1869 self.output.write('''
1870 Here is a list of matching modules. Enter any module name to get more help.
1871
1872 ''')
1873 apropos(key)
1874 else:
1875 self.output.write('''
1876 Please wait a moment while I gather a list of all available modules...
1877
1878 ''')
1879 modules = {}
1880 def callback(path, modname, desc, modules=modules):
1881 if modname and modname[-9:] == '.__init__':
1882 modname = modname[:-9] + ' (package)'
1883 if find(modname, '.') < 0:
1884 modules[modname] = 1
1885 def onerror(modname):
1886 callback(None, modname, None)
1887 ModuleScanner().run(callback, onerror=onerror)
1888 self.list(modules.keys())
1889 self.output.write('''
1890 Enter any module name to get more help. Or, type "modules spam" to search
1891 for modules whose descriptions contain the word "spam".
1892 ''')
1893
1894 help = Helper()
1895
1896 class Scanner:
1897 """A generic tree iterator."""
1898 def __init__(self, roots, children, descendp):
1899 self.roots = roots[:]
1900 self.state = []
1901 self.children = children
1902 self.descendp = descendp
1903
1904 def next(self):
1905 if not self.state:
1906 if not self.roots:
1907 return None
1908 root = self.roots.pop(0)
1909 self.state = [(root, self.children(root))]
1910 node, children = self.state[-1]
1911 if not children:
1912 self.state.pop()
1913 return self.next()
1914 child = children.pop(0)
1915 if self.descendp(child):
1916 self.state.append((child, self.children(child)))
1917 return child
1918
1919
1920 class ModuleScanner:
1921 """An interruptible scanner that searches module synopses."""
1922
1923 def run(self, callback, key=None, completer=None, onerror=None):
1924 if key: key = lower(key)
1925 self.quit = False
1926 seen = {}
1927
1928 for modname in sys.builtin_module_names:
1929 if modname != '__main__':
1930 seen[modname] = 1
1931 if key is None:
1932 callback(None, modname, '')
1933 else:
1934 desc = split(__import__(modname).__doc__ or '', '\n')[0]
1935 if find(lower(modname + ' - ' + desc), key) >= 0:
1936 callback(None, modname, desc)
1937
1938 for importer, modname, ispkg in pkgutil.walk_packages(onerror=onerror):
1939 if self.quit:
1940 break
1941 if key is None:
1942 callback(None, modname, '')
1943 else:
1944 loader = importer.find_module(modname)
1945 if hasattr(loader,'get_source'):
1946 import StringIO
1947 desc = source_synopsis(
1948 StringIO.StringIO(loader.get_source(modname))
1949 ) or ''
1950 if hasattr(loader,'get_filename'):
1951 path = loader.get_filename(modname)
1952 else:
1953 path = None
1954 else:
1955 module = loader.load_module(modname)
1956 desc = (module.__doc__ or '').splitlines()[0]
1957 path = getattr(module,'__file__',None)
1958 if find(lower(modname + ' - ' + desc), key) >= 0:
1959 callback(path, modname, desc)
1960
1961 if completer:
1962 completer()
1963
1964 def apropos(key):
1965 """Print all the one-line module summaries that contain a substring."""
1966 def callback(path, modname, desc):
1967 if modname[-9:] == '.__init__':
1968 modname = modname[:-9] + ' (package)'
1969 print modname, desc and '- ' + desc
1970 try: import warnings
1971 except ImportError: pass
1972 else: warnings.filterwarnings('ignore') # ignore problems during import
1973 ModuleScanner().run(callback, key)
1974
1975 # --------------------------------------------------- web browser interface
1976
1977 def serve(port, callback=None, completer=None):
1978 import BaseHTTPServer, mimetools, select
1979
1980 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1981 class Message(mimetools.Message):
1982 def __init__(self, fp, seekable=1):
1983 Message = self.__class__
1984 Message.__bases__[0].__bases__[0].__init__(self, fp, seekable)
1985 self.encodingheader = self.getheader('content-transfer-encoding')
1986 self.typeheader = self.getheader('content-type')
1987 self.parsetype()
1988 self.parseplist()
1989
1990 class DocHandler(BaseHTTPServer.BaseHTTPRequestHandler):
1991 def send_document(self, title, contents):
1992 try:
1993 self.send_response(200)
1994 self.send_header('Content-Type', 'text/html')
1995 self.end_headers()
1996 self.wfile.write(html.page(title, contents))
1997 except IOError: pass
1998
1999 def do_GET(self):
2000 path = self.path
2001 if path[-5:] == '.html': path = path[:-5]
2002 if path[:1] == '/': path = path[1:]
2003 if path and path != '.':
2004 try:
2005 obj = locate(path, forceload=1)
2006 except ErrorDuringImport, value:
2007 self.send_document(path, html.escape(str(value)))
2008 return
2009 if obj:
2010 self.send_document(describe(obj), html.document(obj, path))
2011 else:
2012 self.send_document(path,
2013 'no Python documentation found for %s' % repr(path))
2014 else:
2015 heading = html.heading(
2016 '<big><big><strong>Python: Index of Modules</strong></big></big>',
2017 '#ffffff', '#7799ee')
2018 def bltinlink(name):
2019 return '<a href="%s.html">%s</a>' % (name, name)
2020 names = filter(lambda x: x != '__main__',
2021 sys.builtin_module_names)
2022 contents = html.multicolumn(names, bltinlink)
2023 indices = ['<p>' + html.bigsection(
2024 'Built-in Modules', '#ffffff', '#ee77aa', contents)]
2025
2026 seen = {}
2027 for dir in sys.path:
2028 indices.append(html.index(dir, seen))
2029 contents = heading + join(indices) + '''<p align=right>
2030 <font color="#909090" face="helvetica, arial"><strong>
2031 pydoc</strong> by Ka-Ping Yee &lt;ping@lfw.org&gt;</font>'''
2032 self.send_document('Index of Modules', contents)
2033
2034 def log_message(self, *args): pass
2035
2036 class DocServer(BaseHTTPServer.HTTPServer):
2037 def __init__(self, port, callback):
2038 host = 'localhost'
2039 self.address = (host, port)
2040 self.url = 'http://%s:%d/' % (host, port)
2041 self.callback = callback
2042 self.base.__init__(self, self.address, self.handler)
2043
2044 def serve_until_quit(self):
2045 import select
2046 self.quit = False
2047 while not self.quit:
2048 rd, wr, ex = select.select([self.socket.fileno()], [], [], 1)
2049 if rd: self.handle_request()
2050
2051 def server_activate(self):
2052 self.base.server_activate(self)
2053 if self.callback: self.callback(self)
2054
2055 DocServer.base = BaseHTTPServer.HTTPServer
2056 DocServer.handler = DocHandler
2057 DocHandler.MessageClass = Message
2058 try:
2059 try:
2060 DocServer(port, callback).serve_until_quit()
2061 except (KeyboardInterrupt, select.error):
2062 pass
2063 finally:
2064 if completer: completer()
2065
2066 # ----------------------------------------------------- graphical interface
2067
2068 def gui():
2069 """Graphical interface (starts web server and pops up a control window)."""
2070 class GUI:
2071 def __init__(self, window, port=7464):
2072 self.window = window
2073 self.server = None
2074 self.scanner = None
2075
2076 import Tkinter
2077 self.server_frm = Tkinter.Frame(window)
2078 self.title_lbl = Tkinter.Label(self.server_frm,
2079 text='Starting server...\n ')
2080 self.open_btn = Tkinter.Button(self.server_frm,
2081 text='open browser', command=self.open, state='disabled')
2082 self.quit_btn = Tkinter.Button(self.server_frm,
2083 text='quit serving', command=self.quit, state='disabled')
2084
2085 self.search_frm = Tkinter.Frame(window)
2086 self.search_lbl = Tkinter.Label(self.search_frm, text='Search for')
2087 self.search_ent = Tkinter.Entry(self.search_frm)
2088 self.search_ent.bind('<Return>', self.search)
2089 self.stop_btn = Tkinter.Button(self.search_frm,
2090 text='stop', pady=0, command=self.stop, state='disabled')
2091 if sys.platform == 'win32':
2092 # Trying to hide and show this button crashes under Windows.
2093 self.stop_btn.pack(side='right')
2094
2095 self.window.title('pydoc')
2096 self.window.protocol('WM_DELETE_WINDOW', self.quit)
2097 self.title_lbl.pack(side='top', fill='x')
2098 self.open_btn.pack(side='left', fill='x', expand=1)
2099 self.quit_btn.pack(side='right', fill='x', expand=1)
2100 self.server_frm.pack(side='top', fill='x')
2101
2102 self.search_lbl.pack(side='left')
2103 self.search_ent.pack(side='right', fill='x', expand=1)
2104 self.search_frm.pack(side='top', fill='x')
2105 self.search_ent.focus_set()
2106
2107 font = ('helvetica', sys.platform == 'win32' and 8 or 10)
2108 self.result_lst = Tkinter.Listbox(window, font=font, height=6)
2109 self.result_lst.bind('<Button-1>', self.select)
2110 self.result_lst.bind('<Double-Button-1>', self.goto)
2111 self.result_scr = Tkinter.Scrollbar(window,
2112 orient='vertical', command=self.result_lst.yview)
2113 self.result_lst.config(yscrollcommand=self.result_scr.set)
2114
2115 self.result_frm = Tkinter.Frame(window)
2116 self.goto_btn = Tkinter.Button(self.result_frm,
2117 text='go to selected', command=self.goto)
2118 self.hide_btn = Tkinter.Button(self.result_frm,
2119 text='hide results', command=self.hide)
2120 self.goto_btn.pack(side='left', fill='x', expand=1)
2121 self.hide_btn.pack(side='right', fill='x', expand=1)
2122
2123 self.window.update()
2124 self.minwidth = self.window.winfo_width()
2125 self.minheight = self.window.winfo_height()
2126 self.bigminheight = (self.server_frm.winfo_reqheight() +
2127 self.search_frm.winfo_reqheight() +
2128 self.result_lst.winfo_reqheight() +
2129 self.result_frm.winfo_reqheight())
2130 self.bigwidth, self.bigheight = self.minwidth, self.bigminheight
2131 self.expanded = 0
2132 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2133 self.window.wm_minsize(self.minwidth, self.minheight)
2134 self.window.tk.willdispatch()
2135
2136 import threading
2137 threading.Thread(
2138 target=serve, args=(port, self.ready, self.quit)).start()
2139
2140 def ready(self, server):
2141 self.server = server
2142 self.title_lbl.config(
2143 text='Python documentation server at\n' + server.url)
2144 self.open_btn.config(state='normal')
2145 self.quit_btn.config(state='normal')
2146
2147 def open(self, event=None, url=None):
2148 url = url or self.server.url
2149 try:
2150 import webbrowser
2151 webbrowser.open(url)
2152 except ImportError: # pre-webbrowser.py compatibility
2153 if sys.platform == 'win32':
2154 os.system('start "%s"' % url)
2155 else:
2156 rc = os.system('netscape -remote "openURL(%s)" &' % url)
2157 if rc: os.system('netscape "%s" &' % url)
2158
2159 def quit(self, event=None):
2160 if self.server:
2161 self.server.quit = 1
2162 self.window.quit()
2163
2164 def search(self, event=None):
2165 key = self.search_ent.get()
2166 self.stop_btn.pack(side='right')
2167 self.stop_btn.config(state='normal')
2168 self.search_lbl.config(text='Searching for "%s"...' % key)
2169 self.search_ent.forget()
2170 self.search_lbl.pack(side='left')
2171 self.result_lst.delete(0, 'end')
2172 self.goto_btn.config(state='disabled')
2173 self.expand()
2174
2175 import threading
2176 if self.scanner:
2177 self.scanner.quit = 1
2178 self.scanner = ModuleScanner()
2179 threading.Thread(target=self.scanner.run,
2180 args=(self.update, key, self.done)).start()
2181
2182 def update(self, path, modname, desc):
2183 if modname[-9:] == '.__init__':
2184 modname = modname[:-9] + ' (package)'
2185 self.result_lst.insert('end',
2186 modname + ' - ' + (desc or '(no description)'))
2187
2188 def stop(self, event=None):
2189 if self.scanner:
2190 self.scanner.quit = 1
2191 self.scanner = None
2192
2193 def done(self):
2194 self.scanner = None
2195 self.search_lbl.config(text='Search for')
2196 self.search_lbl.pack(side='left')
2197 self.search_ent.pack(side='right', fill='x', expand=1)
2198 if sys.platform != 'win32': self.stop_btn.forget()
2199 self.stop_btn.config(state='disabled')
2200
2201 def select(self, event=None):
2202 self.goto_btn.config(state='normal')
2203
2204 def goto(self, event=None):
2205 selection = self.result_lst.curselection()
2206 if selection:
2207 modname = split(self.result_lst.get(selection[0]))[0]
2208 self.open(url=self.server.url + modname + '.html')
2209
2210 def collapse(self):
2211 if not self.expanded: return
2212 self.result_frm.forget()
2213 self.result_scr.forget()
2214 self.result_lst.forget()
2215 self.bigwidth = self.window.winfo_width()
2216 self.bigheight = self.window.winfo_height()
2217 self.window.wm_geometry('%dx%d' % (self.minwidth, self.minheight))
2218 self.window.wm_minsize(self.minwidth, self.minheight)
2219 self.expanded = 0
2220
2221 def expand(self):
2222 if self.expanded: return
2223 self.result_frm.pack(side='bottom', fill='x')
2224 self.result_scr.pack(side='right', fill='y')
2225 self.result_lst.pack(side='top', fill='both', expand=1)
2226 self.window.wm_geometry('%dx%d' % (self.bigwidth, self.bigheight))
2227 self.window.wm_minsize(self.minwidth, self.bigminheight)
2228 self.expanded = 1
2229
2230 def hide(self, event=None):
2231 self.stop()
2232 self.collapse()
2233
2234 import Tkinter
2235 try:
2236 root = Tkinter.Tk()
2237 # Tk will crash if pythonw.exe has an XP .manifest
2238 # file and the root has is not destroyed explicitly.
2239 # If the problem is ever fixed in Tk, the explicit
2240 # destroy can go.
2241 try:
2242 gui = GUI(root)
2243 root.mainloop()
2244 finally:
2245 root.destroy()
2246 except KeyboardInterrupt:
2247 pass
2248
2249 # -------------------------------------------------- command-line interface
2250
2251 def ispath(x):
2252 return isinstance(x, str) and find(x, os.sep) >= 0
2253
2254 def cli():
2255 """Command-line interface (looks at sys.argv to decide what to do)."""
2256 import getopt
2257 class BadUsage: pass
2258
2259 # Scripts don't get the current directory in their path by default
2260 # unless they are run with the '-m' switch
2261 if '' not in sys.path:
2262 scriptdir = os.path.dirname(sys.argv[0])
2263 if scriptdir in sys.path:
2264 sys.path.remove(scriptdir)
2265 sys.path.insert(0, '.')
2266
2267 try:
2268 opts, args = getopt.getopt(sys.argv[1:], 'gk:p:w')
2269 writing = 0
2270
2271 for opt, val in opts:
2272 if opt == '-g':
2273 gui()
2274 return
2275 if opt == '-k':
2276 apropos(val)
2277 return
2278 if opt == '-p':
2279 try:
2280 port = int(val)
2281 except ValueError:
2282 raise BadUsage
2283 def ready(server):
2284 print 'pydoc server ready at %s' % server.url
2285 def stopped():
2286 print 'pydoc server stopped'
2287 serve(port, ready, stopped)
2288 return
2289 if opt == '-w':
2290 writing = 1
2291
2292 if not args: raise BadUsage
2293 for arg in args:
2294 if ispath(arg) and not os.path.exists(arg):
2295 print 'file %r does not exist' % arg
2296 break
2297 try:
2298 if ispath(arg) and os.path.isfile(arg):
2299 arg = importfile(arg)
2300 if writing:
2301 if ispath(arg) and os.path.isdir(arg):
2302 writedocs(arg)
2303 else:
2304 writedoc(arg)
2305 else:
2306 help.help(arg)
2307 except ErrorDuringImport, value:
2308 print value
2309
2310 except (getopt.error, BadUsage):
2311 cmd = os.path.basename(sys.argv[0])
2312 print """pydoc - the Python documentation tool
2313
2314 %s <name> ...
2315 Show text documentation on something. <name> may be the name of a
2316 Python keyword, topic, function, module, or package, or a dotted
2317 reference to a class or function within a module or module in a
2318 package. If <name> contains a '%s', it is used as the path to a
2319 Python source file to document. If name is 'keywords', 'topics',
2320 or 'modules', a listing of these things is displayed.
2321
2322 %s -k <keyword>
2323 Search for a keyword in the synopsis lines of all available modules.
2324
2325 %s -p <port>
2326 Start an HTTP server on the given port on the local machine.
2327
2328 %s -g
2329 Pop up a graphical interface for finding and serving documentation.
2330
2331 %s -w <name> ...
2332 Write out the HTML documentation for a module to a file in the current
2333 directory. If <name> contains a '%s', it is treated as a filename; if
2334 it names a directory, documentation is written for all the contents.
2335 """ % (cmd, os.sep, cmd, cmd, cmd, cmd, os.sep)
2336
2337 if __name__ == '__main__': cli()