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