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