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