]>
git.proxmox.com Git - mirror_edk2.git/blob - AppPkg/Applications/Python/Python-2.7.2/Lib/pydoc.py
4b5b387a60f41e916675b26bfd6ecf33f416ff55
2 # -*- coding: latin-1 -*-
3 """Generate Python documentation in HTML or text for interactive use.
5 In the Python interpreter, do "from pydoc import help" to provide online
6 help. Calling help(thing) on a Python object documents the object.
8 Or, at the shell command line outside of Python:
10 Run "pydoc <name>" to show documentation on something. <name> may be
11 the name of a function, module, package, or a dotted reference to a
12 class or function within a module or module in a package. If the
13 argument contains a path segment delimiter (e.g. slash on Unix,
14 backslash on Windows) it is treated as the path to a Python source file.
16 Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17 of all available modules.
19 Run "pydoc -p <port>" to start an HTTP server on a given port on the
20 local machine to generate documentation web pages.
22 For platforms without a command line, "pydoc -g" starts the HTTP server
23 and also pops up a little window for controlling it.
25 Run "pydoc -w <name>" to write out the HTML documentation for a module
26 to a file named "<name>.html".
28 Module docs for core modules are assumed to be in
30 http://docs.python.org/library/
32 This can be overridden by setting the PYTHONDOCS environment variable
33 to a different URL or to a local directory containing the Library
34 Reference Manual pages.
37 __author__
= "Ka-Ping Yee <ping@lfw.org>"
38 __date__
= "26 February 2001"
40 __version__
= "$Revision$"
41 __credits__
= """Guido van Rossum, for an excellent programming language.
42 Tommy Burnette, the original creator of manpy.
43 Paul Prescod, for all his work on onlinehelp.
44 Richard Chamberlain, for the first implementation of textdoc.
47 # Known bugs that can't be fixed here:
48 # - imp.load_module() cannot be prevented from clobbering existing
49 # loaded modules, so calling synopsis() on a binary module file
50 # changes the contents of any existing module with the same name.
51 # - If the __file__ attribute on a module is a relative path and
52 # the current directory is changed with os.chdir(), an incorrect
53 # path will be displayed.
55 import sys
, imp
, os
, re
, types
, inspect
, __builtin__
, pkgutil
57 from string
import expandtabs
, find
, join
, lower
, split
, strip
, rfind
, rstrip
58 from traceback
import extract_tb
60 from collections
import deque
62 # Python 2.3 compatibility
67 # --------------------------------------------------------- common routines
70 """Convert sys.path into a list of absolute, existing, unique paths."""
74 dir = os
.path
.abspath(dir or '.')
75 normdir
= os
.path
.normcase(dir)
76 if normdir
not in normdirs
and os
.path
.isdir(dir):
78 normdirs
.append(normdir
)
82 """Get the doc string or comments for an object."""
83 result
= inspect
.getdoc(object) or inspect
.getcomments(object)
84 return result
and re
.sub('^ *\n', '', rstrip(result
)) or ''
87 """Split a doc string into a synopsis line (if any) and the rest."""
88 lines
= split(strip(doc
), '\n')
91 elif len(lines
) >= 2 and not rstrip(lines
[1]):
92 return lines
[0], join(lines
[2:], '\n')
93 return '', join(lines
, '\n')
95 def classname(object, modname
):
96 """Get a class name and qualify it with a module name if necessary."""
97 name
= object.__name
__
98 if object.__module
__ != modname
:
99 name
= object.__module
__ + '.' + name
103 """Check if an object is of a type that probably means it's data."""
104 return not (inspect
.ismodule(object) or inspect
.isclass(object) or
105 inspect
.isroutine(object) or inspect
.isframe(object) or
106 inspect
.istraceback(object) or inspect
.iscode(object))
108 def replace(text
, *pairs
):
109 """Do a series of global replacements on a string."""
111 text
= join(split(text
, pairs
[0]), pairs
[1])
115 def cram(text
, maxlen
):
116 """Omit part of a string if needed to make it fit in a maximum length."""
117 if len(text
) > maxlen
:
118 pre
= max(0, (maxlen
-3)//2)
119 post
= max(0, maxlen
-3-pre
)
120 return text
[:pre
] + '...' + text
[len(text
)-post
:]
123 _re_stripid
= re
.compile(r
' at 0x[0-9a-f]{6,16}(>+)$', re
.IGNORECASE
)
125 """Remove the hexadecimal id from a Python object representation."""
126 # The behaviour of %p is implementation-dependent in terms of case.
127 return _re_stripid
.sub(r
'\1', text
)
129 def _is_some_method(obj
):
130 return inspect
.ismethod(obj
) or inspect
.ismethoddescriptor(obj
)
134 for key
, value
in inspect
.getmembers(cl
, _is_some_method
):
136 for base
in cl
.__bases
__:
137 methods
.update(allmethods(base
)) # all your base are belong to us
138 for key
in methods
.keys():
139 methods
[key
] = getattr(cl
, key
)
142 def _split_list(s
, predicate
):
143 """Split sequence s via predicate, and return pair ([true], [false]).
145 The return value is a 2-tuple of lists,
146 ([x for x in s if predicate(x)],
147 [x for x in s if not predicate(x)])
159 def visiblename(name
, all
=None, obj
=None):
160 """Decide whether to show documentation on a variable."""
161 # Certain special names are redundant.
162 _hidden_names
= ('__builtins__', '__doc__', '__file__', '__path__',
163 '__module__', '__name__', '__slots__', '__package__')
164 if name
in _hidden_names
: return 0
165 # Private names are hidden, but special names are displayed.
166 if name
.startswith('__') and name
.endswith('__'): return 1
167 # Namedtuples have public fields and methods with a single leading underscore
168 if name
.startswith('_') and hasattr(obj
, '_fields'):
171 # only document that which the programmer exported in __all__
174 return not name
.startswith('_')
176 def classify_class_attrs(object):
177 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
179 name
, kind
, cls
, value
= data
180 if inspect
.isdatadescriptor(value
):
181 kind
= 'data descriptor'
182 return name
, kind
, cls
, value
183 return map(fixup
, inspect
.classify_class_attrs(object))
185 # ----------------------------------------------------- module manipulation
188 """Guess whether a path refers to a package directory."""
189 if os
.path
.isdir(path
):
190 for ext
in ('.py', '.pyc', '.pyo'):
191 if os
.path
.isfile(os
.path
.join(path
, '__init__' + ext
)):
195 def source_synopsis(file):
196 line
= file.readline()
197 while line
[:1] == '#' or not strip(line
):
198 line
= file.readline()
201 if line
[:4] == 'r"""': line
= line
[1:]
202 if line
[:3] == '"""':
204 if line
[-1:] == '\\': line
= line
[:-1]
205 while not strip(line
):
206 line
= file.readline()
208 result
= strip(split(line
, '"""')[0])
212 def synopsis(filename
, cache
={}):
213 """Get the one-line summary out of a module file."""
214 mtime
= os
.stat(filename
).st_mtime
215 lastupdate
, result
= cache
.get(filename
, (0, None))
216 if lastupdate
< mtime
:
217 info
= inspect
.getmoduleinfo(filename
)
219 file = open(filename
)
221 # module can't be opened, so skip it
223 if info
and 'b' in info
[2]: # binary modules have to be imported
224 try: module
= imp
.load_module('__temp__', file, filename
, info
[1:])
226 result
= (module
.__doc
__ or '').splitlines()[0]
227 del sys
.modules
['__temp__']
228 else: # text modules can be directly examined
229 result
= source_synopsis(file)
231 cache
[filename
] = (mtime
, result
)
234 class ErrorDuringImport(Exception):
235 """Errors that occurred while trying to import something to document it."""
236 def __init__(self
, filename
, exc_info
):
237 exc
, value
, tb
= exc_info
238 self
.filename
= filename
245 if type(exc
) is types
.ClassType
:
247 return 'problem in %s - %s: %s' % (self
.filename
, exc
, self
.value
)
249 def importfile(path
):
250 """Import a Python source file or compiled file given its path."""
251 magic
= imp
.get_magic()
252 file = open(path
, 'r')
253 if file.read(len(magic
)) == magic
:
254 kind
= imp
.PY_COMPILED
258 filename
= os
.path
.basename(path
)
259 name
, ext
= os
.path
.splitext(filename
)
260 file = open(path
, 'r')
262 module
= imp
.load_module(name
, file, path
, (ext
, 'r', kind
))
264 raise ErrorDuringImport(path
, sys
.exc_info())
268 def safeimport(path
, forceload
=0, cache
={}):
269 """Import a module; handle errors; return None if the module isn't found.
271 If the module *is* found but an exception occurs, it's wrapped in an
272 ErrorDuringImport exception and reraised. Unlike __import__, if a
273 package path is specified, the module at the end of the path is returned,
274 not the package at the beginning. If the optional 'forceload' argument
275 is 1, we reload the module from disk (unless it's a dynamic extension)."""
277 # If forceload is 1 and the module has been previously loaded from
278 # disk, we always have to reload the module. Checking the file's
279 # mtime isn't good enough (e.g. the module could contain a class
280 # that inherits from another module that has changed).
281 if forceload
and path
in sys
.modules
:
282 if path
not in sys
.builtin_module_names
:
283 # Avoid simply calling reload() because it leaves names in
284 # the currently loaded module lying around if they're not
285 # defined in the new source file. Instead, remove the
286 # module from sys.modules and re-import. Also remove any
287 # submodules because they won't appear in the newly loaded
288 # module's namespace if they're already in sys.modules.
289 subs
= [m
for m
in sys
.modules
if m
.startswith(path
+ '.')]
290 for key
in [path
] + subs
:
291 # Prevent garbage collection.
292 cache
[key
] = sys
.modules
[key
]
294 module
= __import__(path
)
296 # Did the error occur before or after the module was found?
297 (exc
, value
, tb
) = info
= sys
.exc_info()
298 if path
in sys
.modules
:
299 # An error occurred while executing the imported module.
300 raise ErrorDuringImport(sys
.modules
[path
].__file
__, info
)
301 elif exc
is SyntaxError:
302 # A SyntaxError occurred before we could execute the module.
303 raise ErrorDuringImport(value
.filename
, info
)
304 elif exc
is ImportError and extract_tb(tb
)[-1][2]=='safeimport':
305 # The import error occurred directly in this function,
306 # which means there is no such module in the path.
309 # Some other error occurred during the importing process.
310 raise ErrorDuringImport(path
, sys
.exc_info())
311 for part
in split(path
, '.')[1:]:
312 try: module
= getattr(module
, part
)
313 except AttributeError: return None
316 # ---------------------------------------------------- formatter base class
319 def document(self
, object, name
=None, *args
):
320 """Generate documentation for an object."""
321 args
= (object, name
) + args
322 # 'try' clause is to attempt to handle the possibility that inspect
323 # identifies something in a way that pydoc itself has issues handling;
324 # think 'super' and how it is a descriptor (which raises the exception
325 # by lacking a __name__ attribute) and an instance.
326 if inspect
.isgetsetdescriptor(object): return self
.docdata(*args
)
327 if inspect
.ismemberdescriptor(object): return self
.docdata(*args
)
329 if inspect
.ismodule(object): return self
.docmodule(*args
)
330 if inspect
.isclass(object): return self
.docclass(*args
)
331 if inspect
.isroutine(object): return self
.docroutine(*args
)
332 except AttributeError:
334 if isinstance(object, property): return self
.docproperty(*args
)
335 return self
.docother(*args
)
337 def fail(self
, object, name
=None, *args
):
338 """Raise an exception for unimplemented types."""
339 message
= "don't know how to document object%s of type %s" % (
340 name
and ' ' + repr(name
), type(object).__name
__)
341 raise TypeError, message
343 docmodule
= docclass
= docroutine
= docother
= docproperty
= docdata
= fail
345 def getdocloc(self
, object):
346 """Return the location of module docs or None"""
349 file = inspect
.getabsfile(object)
353 docloc
= os
.environ
.get("PYTHONDOCS",
354 "http://docs.python.org/library")
355 basedir
= os
.path
.join(sys
.exec_prefix
, "lib",
356 "python"+sys
.version
[0:3])
357 if (isinstance(object, type(os
)) and
358 (object.__name
__ in ('errno', 'exceptions', 'gc', 'imp',
359 'marshal', 'posix', 'signal', 'sys',
360 'thread', 'zipimport') or
361 (file.startswith(basedir
) and
362 not file.startswith(os
.path
.join(basedir
, 'site-packages')))) and
363 object.__name
__ not in ('xml.etree', 'test.pydoc_mod')):
364 if docloc
.startswith("http://"):
365 docloc
= "%s/%s" % (docloc
.rstrip("/"), object.__name
__)
367 docloc
= os
.path
.join(docloc
, object.__name
__ + ".html")
372 # -------------------------------------------- HTML documentation generator
374 class HTMLRepr(Repr
):
375 """Class for safely making an HTML representation of a Python object."""
378 self
.maxlist
= self
.maxtuple
= 20
380 self
.maxstring
= self
.maxother
= 100
382 def escape(self
, text
):
383 return replace(text
, '&', '&', '<', '<', '>', '>')
385 def repr(self
, object):
386 return Repr
.repr(self
, object)
388 def repr1(self
, x
, level
):
389 if hasattr(type(x
), '__name__'):
390 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
391 if hasattr(self
, methodname
):
392 return getattr(self
, methodname
)(x
, level
)
393 return self
.escape(cram(stripid(repr(x
)), self
.maxother
))
395 def repr_string(self
, x
, level
):
396 test
= cram(x
, self
.maxstring
)
397 testrepr
= repr(test
)
398 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
399 # Backslashes are only literal in the string and are never
400 # needed to make any special characters, so show a raw string.
401 return 'r' + testrepr
[0] + self
.escape(test
) + testrepr
[0]
402 return re
.sub(r
'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
403 r'<font color="#c040c0">\1</font>',
404 self
.escape(testrepr
))
406 repr_str
= repr_string
408 def repr_instance(self
, x
, level
):
410 return self
.escape(cram(stripid(repr(x
)), self
.maxstring
))
412 return self
.escape('<%s instance>' % x
.__class
__.__name
__)
414 repr_unicode
= repr_string
417 """Formatter class for HTML documentation."""
419 # ------------------------------------------- HTML formatting utilities
421 _repr_instance
= HTMLRepr()
422 repr = _repr_instance
.repr
423 escape
= _repr_instance
.escape
425 def page(self
, title
, contents
):
426 """Format an HTML page."""
428 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
429 <html><head><title>Python: %s</title>
430 </head><body bgcolor="#f0f0f8">
432 </body></html>''' % (title
, contents
)
434 def heading(self
, title
, fgcol
, bgcol
, extras
=''):
435 """Format a page heading."""
437 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
439 <td valign=bottom> <br>
440 <font color="%s" face="helvetica, arial"> <br>%s</font></td
441 ><td align=right valign=bottom
442 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
443 ''' % (bgcol
, fgcol
, title
, fgcol
, extras
or ' ')
445 def section(self
, title
, fgcol
, bgcol
, contents
, width
=6,
446 prelude
='', marginalia
=None, gap
=' '):
447 """Format a section with a heading."""
448 if marginalia
is None:
449 marginalia
= '<tt>' + ' ' * width
+ '</tt>'
451 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
453 <td colspan=3 valign=bottom> <br>
454 <font color="%s" face="helvetica, arial">%s</font></td></tr>
455 ''' % (bgcol
, fgcol
, title
)
457 result
= result
+ '''
458 <tr bgcolor="%s"><td rowspan=2>%s</td>
459 <td colspan=2>%s</td></tr>
460 <tr><td>%s</td>''' % (bgcol
, marginalia
, prelude
, gap
)
462 result
= result
+ '''
463 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol
, marginalia
, gap
)
465 return result
+ '\n<td width="100%%">%s</td></tr></table>' % contents
467 def bigsection(self
, title
, *args
):
468 """Format a section with a big heading."""
469 title
= '<big><strong>%s</strong></big>' % title
470 return self
.section(title
, *args
)
472 def preformat(self
, text
):
473 """Format literal preformatted text."""
474 text
= self
.escape(expandtabs(text
))
475 return replace(text
, '\n\n', '\n \n', '\n\n', '\n \n',
476 ' ', ' ', '\n', '<br>\n')
478 def multicolumn(self
, list, format
, cols
=4):
479 """Format a list of items into a multi-column list."""
481 rows
= (len(list)+cols
-1)//cols
482 for col
in range(cols
):
483 result
= result
+ '<td width="%d%%" valign=top>' % (100//cols
)
484 for i
in range(rows
*col
, rows
*col
+rows
):
486 result
= result
+ format(list[i
]) + '<br>\n'
487 result
= result
+ '</td>'
488 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
490 def grey(self
, text
): return '<font color="#909090">%s</font>' % text
492 def namelink(self
, name
, *dicts
):
493 """Make a link for an identifier, given name-to-URL mappings."""
496 return '<a href="%s">%s</a>' % (dict[name
], name
)
499 def classlink(self
, object, modname
):
500 """Make a link for a class."""
501 name
, module
= object.__name
__, sys
.modules
.get(object.__module
__)
502 if hasattr(module
, name
) and getattr(module
, name
) is object:
503 return '<a href="%s.html#%s">%s</a>' % (
504 module
.__name
__, name
, classname(object, modname
))
505 return classname(object, modname
)
507 def modulelink(self
, object):
508 """Make a link for a module."""
509 return '<a href="%s.html">%s</a>' % (object.__name
__, object.__name
__)
511 def modpkglink(self
, data
):
512 """Make a link for a module or package to display in an index."""
513 name
, path
, ispackage
, shadowed
= data
515 return self
.grey(name
)
517 url
= '%s.%s.html' % (path
, name
)
519 url
= '%s.html' % name
521 text
= '<strong>%s</strong> (package)' % name
524 return '<a href="%s">%s</a>' % (url
, text
)
526 def markup(self
, text
, escape
=None, funcs
={}, classes
={}, methods
={}):
527 """Mark up some plain text, given a context of symbols to look for.
528 Each context dictionary maps object names to anchor names."""
529 escape
= escape
or self
.escape
532 pattern
= re
.compile(r
'\b((http|ftp)://\S+[\w/]|'
537 match
= pattern
.search(text
, here
)
539 start
, end
= match
.span()
540 results
.append(escape(text
[here
:start
]))
542 all
, scheme
, rfc
, pep
, selfdot
, name
= match
.groups()
544 url
= escape(all
).replace('"', '"')
545 results
.append('<a href="%s">%s</a>' % (url
, url
))
547 url
= 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc
)
548 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
550 url
= 'http://www.python.org/dev/peps/pep-%04d/' % int(pep
)
551 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
552 elif text
[end
:end
+1] == '(':
553 results
.append(self
.namelink(name
, methods
, funcs
, classes
))
555 results
.append('self.<strong>%s</strong>' % name
)
557 results
.append(self
.namelink(name
, classes
))
559 results
.append(escape(text
[here
:]))
560 return join(results
, '')
562 # ---------------------------------------------- type-specific routines
564 def formattree(self
, tree
, modname
, parent
=None):
565 """Produce HTML for a class tree as given by inspect.getclasstree()."""
568 if type(entry
) is type(()):
570 result
= result
+ '<dt><font face="helvetica, arial">'
571 result
= result
+ self
.classlink(c
, modname
)
572 if bases
and bases
!= (parent
,):
575 parents
.append(self
.classlink(base
, modname
))
576 result
= result
+ '(' + join(parents
, ', ') + ')'
577 result
= result
+ '\n</font></dt>'
578 elif type(entry
) is type([]):
579 result
= result
+ '<dd>\n%s</dd>\n' % self
.formattree(
581 return '<dl>\n%s</dl>\n' % result
583 def docmodule(self
, object, name
=None, mod
=None, *ignored
):
584 """Produce HTML documentation for a module object."""
585 name
= object.__name
__ # ignore the passed-in name
588 except AttributeError:
590 parts
= split(name
, '.')
592 for i
in range(len(parts
)-1):
594 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
595 (join(parts
[:i
+1], '.'), parts
[i
]))
596 linkedname
= join(links
+ parts
[-1:], '.')
597 head
= '<big><big><strong>%s</strong></big></big>' % linkedname
599 path
= inspect
.getabsfile(object)
601 if sys
.platform
== 'win32':
603 url
= nturl2path
.pathname2url(path
)
604 filelink
= '<a href="file:%s">%s</a>' % (url
, path
)
606 filelink
= '(built-in)'
608 if hasattr(object, '__version__'):
609 version
= str(object.__version
__)
610 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
611 version
= strip(version
[11:-1])
612 info
.append('version %s' % self
.escape(version
))
613 if hasattr(object, '__date__'):
614 info
.append(self
.escape(str(object.__date
__)))
616 head
= head
+ ' (%s)' % join(info
, ', ')
617 docloc
= self
.getdocloc(object)
618 if docloc
is not None:
619 docloc
= '<br><a href="%(docloc)s">Module Docs</a>' % locals()
622 result
= self
.heading(
623 head
, '#ffffff', '#7799ee',
624 '<a href=".">index</a><br>' + filelink
+ docloc
)
626 modules
= inspect
.getmembers(object, inspect
.ismodule
)
628 classes
, cdict
= [], {}
629 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
630 # if __all__ exists, believe it. Otherwise use old heuristic.
631 if (all
is not None or
632 (inspect
.getmodule(value
) or object) is object):
633 if visiblename(key
, all
, object):
634 classes
.append((key
, value
))
635 cdict
[key
] = cdict
[value
] = '#' + key
636 for key
, value
in classes
:
637 for base
in value
.__bases
__:
638 key
, modname
= base
.__name
__, base
.__module
__
639 module
= sys
.modules
.get(modname
)
640 if modname
!= name
and module
and hasattr(module
, key
):
641 if getattr(module
, key
) is base
:
643 cdict
[key
] = cdict
[base
] = modname
+ '.html#' + key
644 funcs
, fdict
= [], {}
645 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
646 # if __all__ exists, believe it. Otherwise use old heuristic.
647 if (all
is not None or
648 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
649 if visiblename(key
, all
, object):
650 funcs
.append((key
, value
))
651 fdict
[key
] = '#-' + key
652 if inspect
.isfunction(value
): fdict
[value
] = fdict
[key
]
654 for key
, value
in inspect
.getmembers(object, isdata
):
655 if visiblename(key
, all
, object):
656 data
.append((key
, value
))
658 doc
= self
.markup(getdoc(object), self
.preformat
, fdict
, cdict
)
659 doc
= doc
and '<tt>%s</tt>' % doc
660 result
= result
+ '<p>%s</p>\n' % doc
662 if hasattr(object, '__path__'):
664 for importer
, modname
, ispkg
in pkgutil
.iter_modules(object.__path
__):
665 modpkgs
.append((modname
, name
, ispkg
, 0))
667 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
668 result
= result
+ self
.bigsection(
669 'Package Contents', '#ffffff', '#aa55cc', contents
)
671 contents
= self
.multicolumn(
672 modules
, lambda key_value
, s
=self
: s
.modulelink(key_value
[1]))
673 result
= result
+ self
.bigsection(
674 'Modules', '#ffffff', '#aa55cc', contents
)
677 classlist
= map(lambda key_value
: key_value
[1], classes
)
679 self
.formattree(inspect
.getclasstree(classlist
, 1), name
)]
680 for key
, value
in classes
:
681 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
682 result
= result
+ self
.bigsection(
683 'Classes', '#ffffff', '#ee77aa', join(contents
))
686 for key
, value
in funcs
:
687 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
688 result
= result
+ self
.bigsection(
689 'Functions', '#ffffff', '#eeaa77', join(contents
))
692 for key
, value
in data
:
693 contents
.append(self
.document(value
, key
))
694 result
= result
+ self
.bigsection(
695 'Data', '#ffffff', '#55aa55', join(contents
, '<br>\n'))
696 if hasattr(object, '__author__'):
697 contents
= self
.markup(str(object.__author
__), self
.preformat
)
698 result
= result
+ self
.bigsection(
699 'Author', '#ffffff', '#7799ee', contents
)
700 if hasattr(object, '__credits__'):
701 contents
= self
.markup(str(object.__credits
__), self
.preformat
)
702 result
= result
+ self
.bigsection(
703 'Credits', '#ffffff', '#7799ee', contents
)
707 def docclass(self
, object, name
=None, mod
=None, funcs
={}, classes
={},
709 """Produce HTML documentation for a class object."""
710 realname
= object.__name
__
711 name
= name
or realname
712 bases
= object.__bases
__
715 push
= contents
.append
717 # Cute little class to pump out a horizontal rule between sections.
718 class HorizontalRule
:
725 hr
= HorizontalRule()
727 # List the mro, if non-trivial.
728 mro
= deque(inspect
.getmro(object))
731 push('<dl><dt>Method resolution order:</dt>\n')
733 push('<dd>%s</dd>\n' % self
.classlink(base
,
737 def spill(msg
, attrs
, predicate
):
738 ok
, attrs
= _split_list(attrs
, predicate
)
742 for name
, kind
, homecls
, value
in ok
:
743 push(self
.document(getattr(object, name
), name
, mod
,
744 funcs
, classes
, mdict
, object))
748 def spilldescriptors(msg
, attrs
, predicate
):
749 ok
, attrs
= _split_list(attrs
, predicate
)
753 for name
, kind
, homecls
, value
in ok
:
754 push(self
._docdescriptor
(name
, value
, mod
))
757 def spilldata(msg
, attrs
, predicate
):
758 ok
, attrs
= _split_list(attrs
, predicate
)
762 for name
, kind
, homecls
, value
in ok
:
763 base
= self
.docother(getattr(object, name
), name
, mod
)
764 if (hasattr(value
, '__call__') or
765 inspect
.isdatadescriptor(value
)):
766 doc
= getattr(value
, "__doc__", None)
770 push('<dl><dt>%s</dl>\n' % base
)
772 doc
= self
.markup(getdoc(value
), self
.preformat
,
773 funcs
, classes
, mdict
)
774 doc
= '<dd><tt>%s</tt>' % doc
775 push('<dl><dt>%s%s</dl>\n' % (base
, doc
))
779 attrs
= filter(lambda data
: visiblename(data
[0], obj
=object),
780 classify_class_attrs(object))
782 for key
, kind
, homecls
, value
in attrs
:
783 mdict
[key
] = anchor
= '#' + name
+ '-' + key
784 value
= getattr(object, key
)
786 # The value may not be hashable (e.g., a data attr with
787 # a dict or list value).
788 mdict
[value
] = anchor
794 thisclass
= mro
.popleft()
796 thisclass
= attrs
[0][2]
797 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
799 if thisclass
is __builtin__
.object:
802 elif thisclass
is object:
805 tag
= 'inherited from %s' % self
.classlink(thisclass
,
809 # Sort attrs by name.
811 attrs
.sort(key
=lambda t
: t
[0])
813 attrs
.sort(lambda t1
, t2
: cmp(t1
[0], t2
[0])) # 2.3 compat
815 # Pump out the attrs, segregated by kind.
816 attrs
= spill('Methods %s' % tag
, attrs
,
817 lambda t
: t
[1] == 'method')
818 attrs
= spill('Class methods %s' % tag
, attrs
,
819 lambda t
: t
[1] == 'class method')
820 attrs
= spill('Static methods %s' % tag
, attrs
,
821 lambda t
: t
[1] == 'static method')
822 attrs
= spilldescriptors('Data descriptors %s' % tag
, attrs
,
823 lambda t
: t
[1] == 'data descriptor')
824 attrs
= spilldata('Data and other attributes %s' % tag
, attrs
,
825 lambda t
: t
[1] == 'data')
829 contents
= ''.join(contents
)
832 title
= '<a name="%s">class <strong>%s</strong></a>' % (
835 title
= '<strong>%s</strong> = <a name="%s">class %s</a>' % (
836 name
, name
, realname
)
840 parents
.append(self
.classlink(base
, object.__module
__))
841 title
= title
+ '(%s)' % join(parents
, ', ')
842 doc
= self
.markup(getdoc(object), self
.preformat
, funcs
, classes
, mdict
)
843 doc
= doc
and '<tt>%s<br> </tt>' % doc
845 return self
.section(title
, '#000000', '#ffc8d8', contents
, 3, doc
)
847 def formatvalue(self
, object):
848 """Format an argument default value as text."""
849 return self
.grey('=' + self
.repr(object))
851 def docroutine(self
, object, name
=None, mod
=None,
852 funcs
={}, classes
={}, methods
={}, cl
=None):
853 """Produce HTML documentation for a function or method object."""
854 realname
= object.__name
__
855 name
= name
or realname
856 anchor
= (cl
and cl
.__name
__ or '') + '-' + name
859 if inspect
.ismethod(object):
860 imclass
= object.im_class
862 if imclass
is not cl
:
863 note
= ' from ' + self
.classlink(imclass
, mod
)
865 if object.im_self
is not None:
866 note
= ' method of %s instance' % self
.classlink(
867 object.im_self
.__class
__, mod
)
869 note
= ' unbound %s method' % self
.classlink(imclass
,mod
)
870 object = object.im_func
873 title
= '<a name="%s"><strong>%s</strong></a>' % (anchor
, realname
)
875 if (cl
and realname
in cl
.__dict
__ and
876 cl
.__dict
__[realname
] is object):
877 reallink
= '<a href="#%s">%s</a>' % (
878 cl
.__name
__ + '-' + realname
, realname
)
882 title
= '<a name="%s"><strong>%s</strong></a> = %s' % (
883 anchor
, name
, reallink
)
884 if inspect
.isfunction(object):
885 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
886 argspec
= inspect
.formatargspec(
887 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
888 if realname
== '<lambda>':
889 title
= '<strong>%s</strong> <em>lambda</em> ' % name
890 argspec
= argspec
[1:-1] # remove parentheses
894 decl
= title
+ argspec
+ (note
and self
.grey(
895 '<font face="helvetica, arial">%s</font>' % note
))
898 return '<dl><dt>%s</dt></dl>\n' % decl
901 getdoc(object), self
.preformat
, funcs
, classes
, methods
)
902 doc
= doc
and '<dd><tt>%s</tt></dd>' % doc
903 return '<dl><dt>%s</dt>%s</dl>\n' % (decl
, doc
)
905 def _docdescriptor(self
, name
, value
, mod
):
907 push
= results
.append
910 push('<dl><dt><strong>%s</strong></dt>\n' % name
)
911 if value
.__doc
__ is not None:
912 doc
= self
.markup(getdoc(value
), self
.preformat
)
913 push('<dd><tt>%s</tt></dd>\n' % doc
)
916 return ''.join(results
)
918 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
919 """Produce html documentation for a property."""
920 return self
._docdescriptor
(name
, object, mod
)
922 def docother(self
, object, name
=None, mod
=None, *ignored
):
923 """Produce HTML documentation for a data object."""
924 lhs
= name
and '<strong>%s</strong> = ' % name
or ''
925 return lhs
+ self
.repr(object)
927 def docdata(self
, object, name
=None, mod
=None, cl
=None):
928 """Produce html documentation for a data descriptor."""
929 return self
._docdescriptor
(name
, object, mod
)
931 def index(self
, dir, shadowed
=None):
932 """Generate an HTML index for a directory of modules."""
934 if shadowed
is None: shadowed
= {}
935 for importer
, name
, ispkg
in pkgutil
.iter_modules([dir]):
936 modpkgs
.append((name
, '', ispkg
, name
in shadowed
))
940 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
941 return self
.bigsection(dir, '#ffffff', '#ee77aa', contents
)
943 # -------------------------------------------- text documentation generator
945 class TextRepr(Repr
):
946 """Class for safely making a text representation of a Python object."""
949 self
.maxlist
= self
.maxtuple
= 20
951 self
.maxstring
= self
.maxother
= 100
953 def repr1(self
, x
, level
):
954 if hasattr(type(x
), '__name__'):
955 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
956 if hasattr(self
, methodname
):
957 return getattr(self
, methodname
)(x
, level
)
958 return cram(stripid(repr(x
)), self
.maxother
)
960 def repr_string(self
, x
, level
):
961 test
= cram(x
, self
.maxstring
)
962 testrepr
= repr(test
)
963 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
964 # Backslashes are only literal in the string and are never
965 # needed to make any special characters, so show a raw string.
966 return 'r' + testrepr
[0] + test
+ testrepr
[0]
969 repr_str
= repr_string
971 def repr_instance(self
, x
, level
):
973 return cram(stripid(repr(x
)), self
.maxstring
)
975 return '<%s instance>' % x
.__class
__.__name
__
978 """Formatter class for text documentation."""
980 # ------------------------------------------- text formatting utilities
982 _repr_instance
= TextRepr()
983 repr = _repr_instance
.repr
985 def bold(self
, text
):
986 """Format a string in bold by overstriking."""
987 return join(map(lambda ch
: ch
+ '\b' + ch
, text
), '')
989 def indent(self
, text
, prefix
=' '):
990 """Indent text by prepending a given prefix to each line."""
991 if not text
: return ''
992 lines
= split(text
, '\n')
993 lines
= map(lambda line
, prefix
=prefix
: prefix
+ line
, lines
)
994 if lines
: lines
[-1] = rstrip(lines
[-1])
995 return join(lines
, '\n')
997 def section(self
, title
, contents
):
998 """Format a section with a given heading."""
999 return self
.bold(title
) + '\n' + rstrip(self
.indent(contents
)) + '\n\n'
1001 # ---------------------------------------------- type-specific routines
1003 def formattree(self
, tree
, modname
, parent
=None, prefix
=''):
1004 """Render in text a class tree as returned by inspect.getclasstree()."""
1007 if type(entry
) is type(()):
1009 result
= result
+ prefix
+ classname(c
, modname
)
1010 if bases
and bases
!= (parent
,):
1011 parents
= map(lambda c
, m
=modname
: classname(c
, m
), bases
)
1012 result
= result
+ '(%s)' % join(parents
, ', ')
1013 result
= result
+ '\n'
1014 elif type(entry
) is type([]):
1015 result
= result
+ self
.formattree(
1016 entry
, modname
, c
, prefix
+ ' ')
1019 def docmodule(self
, object, name
=None, mod
=None):
1020 """Produce text documentation for a given module object."""
1021 name
= object.__name
__ # ignore the passed-in name
1022 synop
, desc
= splitdoc(getdoc(object))
1023 result
= self
.section('NAME', name
+ (synop
and ' - ' + synop
))
1026 all
= object.__all
__
1027 except AttributeError:
1031 file = inspect
.getabsfile(object)
1034 result
= result
+ self
.section('FILE', file)
1036 docloc
= self
.getdocloc(object)
1037 if docloc
is not None:
1038 result
= result
+ self
.section('MODULE DOCS', docloc
)
1041 result
= result
+ self
.section('DESCRIPTION', desc
)
1044 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
1045 # if __all__ exists, believe it. Otherwise use old heuristic.
1047 or (inspect
.getmodule(value
) or object) is object):
1048 if visiblename(key
, all
, object):
1049 classes
.append((key
, value
))
1051 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
1052 # if __all__ exists, believe it. Otherwise use old heuristic.
1053 if (all
is not None or
1054 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
1055 if visiblename(key
, all
, object):
1056 funcs
.append((key
, value
))
1058 for key
, value
in inspect
.getmembers(object, isdata
):
1059 if visiblename(key
, all
, object):
1060 data
.append((key
, value
))
1063 modpkgs_names
= set()
1064 if hasattr(object, '__path__'):
1065 for importer
, modname
, ispkg
in pkgutil
.iter_modules(object.__path
__):
1066 modpkgs_names
.add(modname
)
1068 modpkgs
.append(modname
+ ' (package)')
1070 modpkgs
.append(modname
)
1073 result
= result
+ self
.section(
1074 'PACKAGE CONTENTS', join(modpkgs
, '\n'))
1076 # Detect submodules as sometimes created by C extensions
1078 for key
, value
in inspect
.getmembers(object, inspect
.ismodule
):
1079 if value
.__name
__.startswith(name
+ '.') and key
not in modpkgs_names
:
1080 submodules
.append(key
)
1083 result
= result
+ self
.section(
1084 'SUBMODULES', join(submodules
, '\n'))
1087 classlist
= map(lambda key_value
: key_value
[1], classes
)
1088 contents
= [self
.formattree(
1089 inspect
.getclasstree(classlist
, 1), name
)]
1090 for key
, value
in classes
:
1091 contents
.append(self
.document(value
, key
, name
))
1092 result
= result
+ self
.section('CLASSES', join(contents
, '\n'))
1096 for key
, value
in funcs
:
1097 contents
.append(self
.document(value
, key
, name
))
1098 result
= result
+ self
.section('FUNCTIONS', join(contents
, '\n'))
1102 for key
, value
in data
:
1103 contents
.append(self
.docother(value
, key
, name
, maxlen
=70))
1104 result
= result
+ self
.section('DATA', join(contents
, '\n'))
1106 if hasattr(object, '__version__'):
1107 version
= str(object.__version
__)
1108 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
1109 version
= strip(version
[11:-1])
1110 result
= result
+ self
.section('VERSION', version
)
1111 if hasattr(object, '__date__'):
1112 result
= result
+ self
.section('DATE', str(object.__date
__))
1113 if hasattr(object, '__author__'):
1114 result
= result
+ self
.section('AUTHOR', str(object.__author
__))
1115 if hasattr(object, '__credits__'):
1116 result
= result
+ self
.section('CREDITS', str(object.__credits
__))
1119 def docclass(self
, object, name
=None, mod
=None, *ignored
):
1120 """Produce text documentation for a given class object."""
1121 realname
= object.__name
__
1122 name
= name
or realname
1123 bases
= object.__bases
__
1125 def makename(c
, m
=object.__module
__):
1126 return classname(c
, m
)
1128 if name
== realname
:
1129 title
= 'class ' + self
.bold(realname
)
1131 title
= self
.bold(name
) + ' = class ' + realname
1133 parents
= map(makename
, bases
)
1134 title
= title
+ '(%s)' % join(parents
, ', ')
1136 doc
= getdoc(object)
1137 contents
= doc
and [doc
+ '\n'] or []
1138 push
= contents
.append
1140 # List the mro, if non-trivial.
1141 mro
= deque(inspect
.getmro(object))
1143 push("Method resolution order:")
1145 push(' ' + makename(base
))
1148 # Cute little class to pump out a horizontal rule between sections.
1149 class HorizontalRule
:
1156 hr
= HorizontalRule()
1158 def spill(msg
, attrs
, predicate
):
1159 ok
, attrs
= _split_list(attrs
, predicate
)
1163 for name
, kind
, homecls
, value
in ok
:
1164 push(self
.document(getattr(object, name
),
1168 def spilldescriptors(msg
, attrs
, predicate
):
1169 ok
, attrs
= _split_list(attrs
, predicate
)
1173 for name
, kind
, homecls
, value
in ok
:
1174 push(self
._docdescriptor
(name
, value
, mod
))
1177 def spilldata(msg
, attrs
, predicate
):
1178 ok
, attrs
= _split_list(attrs
, predicate
)
1182 for name
, kind
, homecls
, value
in ok
:
1183 if (hasattr(value
, '__call__') or
1184 inspect
.isdatadescriptor(value
)):
1188 push(self
.docother(getattr(object, name
),
1189 name
, mod
, maxlen
=70, doc
=doc
) + '\n')
1192 attrs
= filter(lambda data
: visiblename(data
[0], obj
=object),
1193 classify_class_attrs(object))
1196 thisclass
= mro
.popleft()
1198 thisclass
= attrs
[0][2]
1199 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
1201 if thisclass
is __builtin__
.object:
1204 elif thisclass
is object:
1205 tag
= "defined here"
1207 tag
= "inherited from %s" % classname(thisclass
,
1210 # Sort attrs by name.
1213 # Pump out the attrs, segregated by kind.
1214 attrs
= spill("Methods %s:\n" % tag
, attrs
,
1215 lambda t
: t
[1] == 'method')
1216 attrs
= spill("Class methods %s:\n" % tag
, attrs
,
1217 lambda t
: t
[1] == 'class method')
1218 attrs
= spill("Static methods %s:\n" % tag
, attrs
,
1219 lambda t
: t
[1] == 'static method')
1220 attrs
= spilldescriptors("Data descriptors %s:\n" % tag
, attrs
,
1221 lambda t
: t
[1] == 'data descriptor')
1222 attrs
= spilldata("Data and other attributes %s:\n" % tag
, attrs
,
1223 lambda t
: t
[1] == 'data')
1227 contents
= '\n'.join(contents
)
1230 return title
+ '\n' + self
.indent(rstrip(contents
), ' | ') + '\n'
1232 def formatvalue(self
, object):
1233 """Format an argument default value as text."""
1234 return '=' + self
.repr(object)
1236 def docroutine(self
, object, name
=None, mod
=None, cl
=None):
1237 """Produce text documentation for a function or method object."""
1238 realname
= object.__name
__
1239 name
= name
or realname
1242 if inspect
.ismethod(object):
1243 imclass
= object.im_class
1245 if imclass
is not cl
:
1246 note
= ' from ' + classname(imclass
, mod
)
1248 if object.im_self
is not None:
1249 note
= ' method of %s instance' % classname(
1250 object.im_self
.__class
__, mod
)
1252 note
= ' unbound %s method' % classname(imclass
,mod
)
1253 object = object.im_func
1255 if name
== realname
:
1256 title
= self
.bold(realname
)
1258 if (cl
and realname
in cl
.__dict
__ and
1259 cl
.__dict
__[realname
] is object):
1261 title
= self
.bold(name
) + ' = ' + realname
1262 if inspect
.isfunction(object):
1263 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
1264 argspec
= inspect
.formatargspec(
1265 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
1266 if realname
== '<lambda>':
1267 title
= self
.bold(name
) + ' lambda '
1268 argspec
= argspec
[1:-1] # remove parentheses
1271 decl
= title
+ argspec
+ note
1276 doc
= getdoc(object) or ''
1277 return decl
+ '\n' + (doc
and rstrip(self
.indent(doc
)) + '\n')
1279 def _docdescriptor(self
, name
, value
, mod
):
1281 push
= results
.append
1284 push(self
.bold(name
))
1286 doc
= getdoc(value
) or ''
1288 push(self
.indent(doc
))
1290 return ''.join(results
)
1292 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
1293 """Produce text documentation for a property."""
1294 return self
._docdescriptor
(name
, object, mod
)
1296 def docdata(self
, object, name
=None, mod
=None, cl
=None):
1297 """Produce text documentation for a data descriptor."""
1298 return self
._docdescriptor
(name
, object, mod
)
1300 def docother(self
, object, name
=None, mod
=None, parent
=None, maxlen
=None, doc
=None):
1301 """Produce text documentation for a data object."""
1302 repr = self
.repr(object)
1304 line
= (name
and name
+ ' = ' or '') + repr
1305 chop
= maxlen
- len(line
)
1306 if chop
< 0: repr = repr[:chop
] + '...'
1307 line
= (name
and self
.bold(name
) + ' = ' or '') + repr
1309 line
+= '\n' + self
.indent(str(doc
))
1312 # --------------------------------------------------------- user interfaces
1315 """The first time this is called, determine what kind of pager to use."""
1321 """Decide what method to use for paging through text."""
1322 if type(sys
.stdout
) is not types
.FileType
:
1324 if not sys
.stdin
.isatty() or not sys
.stdout
.isatty():
1326 if 'PAGER' in os
.environ
:
1327 if sys
.platform
== 'win32': # pipes completely broken in Windows
1328 return lambda text
: tempfilepager(plain(text
), os
.environ
['PAGER'])
1329 elif os
.environ
.get('TERM') in ('dumb', 'emacs'):
1330 return lambda text
: pipepager(plain(text
), os
.environ
['PAGER'])
1332 return lambda text
: pipepager(text
, os
.environ
['PAGER'])
1333 if os
.environ
.get('TERM') in ('dumb', 'emacs'):
1335 if sys
.platform
== 'win32' or sys
.platform
.startswith('os2'):
1336 return lambda text
: tempfilepager(plain(text
), 'more <')
1337 if hasattr(os
, 'system') and os
.system('(less) 2>/dev/null') == 0:
1338 return lambda text
: pipepager(text
, 'less')
1341 (fd
, filename
) = tempfile
.mkstemp()
1344 if hasattr(os
, 'system') and os
.system('more "%s"' % filename
) == 0:
1345 return lambda text
: pipepager(text
, 'more')
1352 """Remove boldface formatting from text."""
1353 return re
.sub('.\b', '', text
)
1355 def pipepager(text
, cmd
):
1356 """Page through text by feeding it to another program."""
1357 pipe
= os
.popen(cmd
, 'w')
1362 pass # Ignore broken pipes caused by quitting the pager program.
1364 def tempfilepager(text
, cmd
):
1365 """Page through text by invoking a program on a temporary file."""
1367 filename
= tempfile
.mktemp()
1368 file = open(filename
, 'w')
1372 os
.system(cmd
+ ' "' + filename
+ '"')
1377 """Page through text on a text terminal."""
1378 lines
= split(plain(text
), '\n')
1381 fd
= sys
.stdin
.fileno()
1382 old
= tty
.tcgetattr(fd
)
1384 getchar
= lambda: sys
.stdin
.read(1)
1385 except (ImportError, AttributeError):
1387 getchar
= lambda: sys
.stdin
.readline()[:-1][:1]
1390 r
= inc
= os
.environ
.get('LINES', 25) - 1
1391 sys
.stdout
.write(join(lines
[:inc
], '\n') + '\n')
1393 sys
.stdout
.write('-- more --')
1398 sys
.stdout
.write('\r \r')
1400 elif c
in ('\r', '\n'):
1401 sys
.stdout
.write('\r \r' + lines
[r
] + '\n')
1404 if c
in ('b', 'B', '\x1b'):
1407 sys
.stdout
.write('\n' + join(lines
[r
:r
+inc
], '\n') + '\n')
1412 tty
.tcsetattr(fd
, tty
.TCSAFLUSH
, old
)
1414 def plainpager(text
):
1415 """Simply print unformatted text. This is the ultimate fallback."""
1416 sys
.stdout
.write(plain(text
))
1418 def describe(thing
):
1419 """Produce a short description of the given thing."""
1420 if inspect
.ismodule(thing
):
1421 if thing
.__name
__ in sys
.builtin_module_names
:
1422 return 'built-in module ' + thing
.__name
__
1423 if hasattr(thing
, '__path__'):
1424 return 'package ' + thing
.__name
__
1426 return 'module ' + thing
.__name
__
1427 if inspect
.isbuiltin(thing
):
1428 return 'built-in function ' + thing
.__name
__
1429 if inspect
.isgetsetdescriptor(thing
):
1430 return 'getset descriptor %s.%s.%s' % (
1431 thing
.__objclass
__.__module
__, thing
.__objclass
__.__name
__,
1433 if inspect
.ismemberdescriptor(thing
):
1434 return 'member descriptor %s.%s.%s' % (
1435 thing
.__objclass
__.__module
__, thing
.__objclass
__.__name
__,
1437 if inspect
.isclass(thing
):
1438 return 'class ' + thing
.__name
__
1439 if inspect
.isfunction(thing
):
1440 return 'function ' + thing
.__name
__
1441 if inspect
.ismethod(thing
):
1442 return 'method ' + thing
.__name
__
1443 if type(thing
) is types
.InstanceType
:
1444 return 'instance of ' + thing
.__class
__.__name
__
1445 return type(thing
).__name
__
1447 def locate(path
, forceload
=0):
1448 """Locate an object by name or dotted path, importing as necessary."""
1449 parts
= [part
for part
in split(path
, '.') if part
]
1451 while n
< len(parts
):
1452 nextmodule
= safeimport(join(parts
[:n
+1], '.'), forceload
)
1453 if nextmodule
: module
, n
= nextmodule
, n
+ 1
1457 for part
in parts
[n
:]:
1458 try: object = getattr(object, part
)
1459 except AttributeError: return None
1462 if hasattr(__builtin__
, path
):
1463 return getattr(__builtin__
, path
)
1465 # --------------------------------------- interactive interpreter interface
1470 class _OldStyleClass
: pass
1471 _OLD_INSTANCE_TYPE
= type(_OldStyleClass())
1473 def resolve(thing
, forceload
=0):
1474 """Given an object or a path to an object, get the object and its name."""
1475 if isinstance(thing
, str):
1476 object = locate(thing
, forceload
)
1478 raise ImportError, 'no Python documentation found for %r' % thing
1479 return object, thing
1481 return thing
, getattr(thing
, '__name__', None)
1483 def render_doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1484 """Render text documentation, given an object or a path to an object."""
1485 object, name
= resolve(thing
, forceload
)
1486 desc
= describe(object)
1487 module
= inspect
.getmodule(object)
1488 if name
and '.' in name
:
1489 desc
+= ' in ' + name
[:name
.rfind('.')]
1490 elif module
and module
is not object:
1491 desc
+= ' in module ' + module
.__name
__
1492 if type(object) is _OLD_INSTANCE_TYPE
:
1493 # If the passed object is an instance of an old-style class,
1494 # document its available methods instead of its value.
1495 object = object.__class
__
1496 elif not (inspect
.ismodule(object) or
1497 inspect
.isclass(object) or
1498 inspect
.isroutine(object) or
1499 inspect
.isgetsetdescriptor(object) or
1500 inspect
.ismemberdescriptor(object) or
1501 isinstance(object, property)):
1502 # If the passed object is a piece of data or an instance,
1503 # document its available methods instead of its value.
1504 object = type(object)
1506 return title
% desc
+ '\n\n' + text
.document(object, name
)
1508 def doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1509 """Display text documentation, given an object or a path to an object."""
1511 pager(render_doc(thing
, title
, forceload
))
1512 except (ImportError, ErrorDuringImport
), value
:
1515 def writedoc(thing
, forceload
=0):
1516 """Write HTML documentation to a file in the current directory."""
1518 object, name
= resolve(thing
, forceload
)
1519 page
= html
.page(describe(object), html
.document(object, name
))
1520 file = open(name
+ '.html', 'w')
1523 print 'wrote', name
+ '.html'
1524 except (ImportError, ErrorDuringImport
), value
:
1527 def writedocs(dir, pkgpath
='', done
=None):
1528 """Write out HTML documentation for all modules in a directory tree."""
1529 if done
is None: done
= {}
1530 for importer
, modname
, ispkg
in pkgutil
.walk_packages([dir], pkgpath
):
1536 # These dictionaries map a topic name to either an alias, or a tuple
1537 # (label, seealso-items). The "label" is the label of the corresponding
1538 # section in the .rst file under Doc/ and an index into the dictionary
1539 # in pydoc_data/topics.py.
1541 # CAUTION: if you change one of these dictionaries, be sure to adapt the
1542 # list of needed labels in Doc/tools/sphinxext/pyspecific.py and
1543 # regenerate the pydoc_data/topics.py file by running
1545 # in Doc/ and copying the output file into the Lib/ directory.
1550 'assert': ('assert', ''),
1551 'break': ('break', 'while for'),
1552 'class': ('class', 'CLASSES SPECIALMETHODS'),
1553 'continue': ('continue', 'while for'),
1554 'def': ('function', ''),
1555 'del': ('del', 'BASICMETHODS'),
1557 'else': ('else', 'while for'),
1559 'exec': ('exec', ''),
1561 'for': ('for', 'break continue while'),
1563 'global': ('global', 'NAMESPACES'),
1564 'if': ('if', 'TRUTHVALUE'),
1565 'import': ('import', 'MODULES'),
1566 'in': ('in', 'SEQUENCEMETHODS2'),
1568 'lambda': ('lambda', 'FUNCTIONS'),
1571 'pass': ('pass', ''),
1572 'print': ('print', ''),
1573 'raise': ('raise', 'EXCEPTIONS'),
1574 'return': ('return', 'FUNCTIONS'),
1575 'try': ('try', 'EXCEPTIONS'),
1576 'while': ('while', 'break continue if TRUTHVALUE'),
1577 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1578 'yield': ('yield', ''),
1580 # Either add symbols to this dictionary or to the symbols dictionary
1581 # directly: Whichever is easier. They are merged later.
1582 _symbols_inverse
= {
1583 'STRINGS' : ("'", "'''", "r'", "u'", '"""', '"', 'r"', 'u"'),
1584 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1585 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1586 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1587 'UNARY' : ('-', '~'),
1588 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1589 '^=', '<<=', '>>=', '**=', '//='),
1590 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1591 'COMPLEX' : ('j', 'J')
1594 '%': 'OPERATORS FORMATTING',
1596 ',': 'TUPLES LISTS FUNCTIONS',
1597 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1599 ':': 'SLICINGS DICTIONARYLITERALS',
1602 '_': 'PRIVATENAMES',
1603 '__': 'PRIVATENAMES SPECIALMETHODS',
1605 '(': 'TUPLES FUNCTIONS CALLS',
1606 ')': 'TUPLES FUNCTIONS CALLS',
1607 '[': 'LISTS SUBSCRIPTS SLICINGS',
1608 ']': 'LISTS SUBSCRIPTS SLICINGS'
1610 for topic
, symbols_
in _symbols_inverse
.iteritems():
1611 for symbol
in symbols_
:
1612 topics
= symbols
.get(symbol
, topic
)
1613 if topic
not in topics
:
1614 topics
= topics
+ ' ' + topic
1615 symbols
[symbol
] = topics
1618 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1619 'FUNCTIONS CLASSES MODULES FILES inspect'),
1620 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING '
1622 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1623 'FORMATTING': ('formatstrings', 'OPERATORS'),
1624 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1625 'FORMATTING TYPES'),
1626 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1627 'INTEGER': ('integers', 'int range'),
1628 'FLOAT': ('floating', 'float math'),
1629 'COMPLEX': ('imaginary', 'complex cmath'),
1630 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1631 'MAPPINGS': 'DICTIONARIES',
1632 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1633 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1634 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1635 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
1636 'FRAMEOBJECTS': 'TYPES',
1637 'TRACEBACKS': 'TYPES',
1638 'NONE': ('bltin-null-object', ''),
1639 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
1640 'FILES': ('bltin-file-objects', ''),
1641 'SPECIALATTRIBUTES': ('specialattrs', ''),
1642 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1643 'MODULES': ('typesmodules', 'import'),
1644 'PACKAGES': 'import',
1645 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1646 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1647 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1648 'LISTS DICTIONARIES BACKQUOTES'),
1649 'OPERATORS': 'EXPRESSIONS',
1650 'PRECEDENCE': 'EXPRESSIONS',
1651 'OBJECTS': ('objects', 'TYPES'),
1652 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
1653 'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS '
1654 'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1655 'BASICMETHODS': ('customization', 'cmp hash repr str SPECIALMETHODS'),
1656 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1657 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
1658 'SEQUENCEMETHODS1': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 '
1660 'SEQUENCEMETHODS2': ('sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 '
1662 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1663 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1665 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1666 'NAMESPACES': ('naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1667 'DYNAMICFEATURES': ('dynamic-features', ''),
1668 'SCOPING': 'NAMESPACES',
1669 'FRAMES': 'NAMESPACES',
1670 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1671 'COERCIONS': ('coercion-rules','CONVERSIONS'),
1672 'CONVERSIONS': ('conversions', 'COERCIONS'),
1673 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1674 'SPECIALIDENTIFIERS': ('id-classes', ''),
1675 'PRIVATENAMES': ('atom-identifiers', ''),
1676 'LITERALS': ('atom-literals', 'STRINGS BACKQUOTES NUMBERS '
1677 'TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1678 'TUPLES': 'SEQUENCES',
1679 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1680 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1681 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1682 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1683 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1684 'BACKQUOTES': ('string-conversions', 'repr str STRINGS LITERALS'),
1685 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr '
1686 'ATTRIBUTEMETHODS'),
1687 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS1'),
1688 'SLICINGS': ('slicings', 'SEQUENCEMETHODS2'),
1689 'CALLS': ('calls', 'EXPRESSIONS'),
1690 'POWER': ('power', 'EXPRESSIONS'),
1691 'UNARY': ('unary', 'EXPRESSIONS'),
1692 'BINARY': ('binary', 'EXPRESSIONS'),
1693 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1694 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1695 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1696 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
1697 'ASSERTION': 'assert',
1698 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1699 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
1701 'PRINTING': 'print',
1702 'RETURNING': 'return',
1703 'IMPORTING': 'import',
1704 'CONDITIONAL': 'if',
1705 'LOOPING': ('compound', 'for while break continue'),
1706 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1707 'DEBUGGING': ('debugger', 'pdb'),
1708 'CONTEXTMANAGERS': ('context-managers', 'with'),
1711 def __init__(self
, input=None, output
=None):
1713 self
._output
= output
1715 input = property(lambda self
: self
._input
or sys
.stdin
)
1716 output
= property(lambda self
: self
._output
or sys
.stdout
)
1719 if inspect
.stack()[1][3] == '?':
1722 return '<pydoc.Helper instance>'
1724 _GoInteractive
= object()
1725 def __call__(self
, request
=_GoInteractive
):
1726 if request
is not self
._GoInteractive
:
1731 self
.output
.write('''
1732 You are now leaving help and returning to the Python interpreter.
1733 If you want to ask for help on a particular object directly from the
1734 interpreter, you can type "help(object)". Executing "help('string')"
1735 has the same effect as typing a particular string at the help> prompt.
1739 self
.output
.write('\n')
1742 request
= self
.getline('help> ')
1743 if not request
: break
1744 except (KeyboardInterrupt, EOFError):
1746 request
= strip(replace(request
, '"', '', "'", ''))
1747 if lower(request
) in ('q', 'quit'): break
1750 def getline(self
, prompt
):
1751 """Read one line, using raw_input when available."""
1752 if self
.input is sys
.stdin
:
1753 return raw_input(prompt
)
1755 self
.output
.write(prompt
)
1757 return self
.input.readline()
1759 def help(self
, request
):
1760 if type(request
) is type(''):
1761 request
= request
.strip()
1762 if request
== 'help': self
.intro()
1763 elif request
== 'keywords': self
.listkeywords()
1764 elif request
== 'symbols': self
.listsymbols()
1765 elif request
== 'topics': self
.listtopics()
1766 elif request
== 'modules': self
.listmodules()
1767 elif request
[:8] == 'modules ':
1768 self
.listmodules(split(request
)[1])
1769 elif request
in self
.symbols
: self
.showsymbol(request
)
1770 elif request
in self
.keywords
: self
.showtopic(request
)
1771 elif request
in self
.topics
: self
.showtopic(request
)
1772 elif request
: doc(request
, 'Help on %s:')
1773 elif isinstance(request
, Helper
): self()
1774 else: doc(request
, 'Help on %s:')
1775 self
.output
.write('\n')
1778 self
.output
.write('''
1779 Welcome to Python %s! This is the online help utility.
1781 If this is your first time using Python, you should definitely check out
1782 the tutorial on the Internet at http://docs.python.org/tutorial/.
1784 Enter the name of any module, keyword, or topic to get help on writing
1785 Python programs and using Python modules. To quit this help utility and
1786 return to the interpreter, just type "quit".
1788 To get a list of available modules, keywords, or topics, type "modules",
1789 "keywords", or "topics". Each module also comes with a one-line summary
1790 of what it does; to list the modules whose summaries contain a given word
1791 such as "spam", type "modules spam".
1792 ''' % sys
.version
[:3])
1794 def list(self
, items
, columns
=4, width
=80):
1797 colw
= width
/ columns
1798 rows
= (len(items
) + columns
- 1) / columns
1799 for row
in range(rows
):
1800 for col
in range(columns
):
1801 i
= col
* rows
+ row
1803 self
.output
.write(items
[i
])
1804 if col
< columns
- 1:
1805 self
.output
.write(' ' + ' ' * (colw
-1 - len(items
[i
])))
1806 self
.output
.write('\n')
1808 def listkeywords(self
):
1809 self
.output
.write('''
1810 Here is a list of the Python keywords. Enter any keyword to get more help.
1813 self
.list(self
.keywords
.keys())
1815 def listsymbols(self
):
1816 self
.output
.write('''
1817 Here is a list of the punctuation symbols which Python assigns special meaning
1818 to. Enter any symbol to get more help.
1821 self
.list(self
.symbols
.keys())
1823 def listtopics(self
):
1824 self
.output
.write('''
1825 Here is a list of available topics. Enter any topic name to get more help.
1828 self
.list(self
.topics
.keys())
1830 def showtopic(self
, topic
, more_xrefs
=''):
1832 import pydoc_data
.topics
1834 self
.output
.write('''
1835 Sorry, topic and keyword documentation is not available because the
1836 module "pydoc_data.topics" could not be found.
1839 target
= self
.topics
.get(topic
, self
.keywords
.get(topic
))
1841 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1843 if type(target
) is type(''):
1844 return self
.showtopic(target
, more_xrefs
)
1846 label
, xrefs
= target
1848 doc
= pydoc_data
.topics
.topics
[label
]
1850 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1852 pager(strip(doc
) + '\n')
1854 xrefs
= (xrefs
or '') + ' ' + more_xrefs
1856 import StringIO
, formatter
1857 buffer = StringIO
.StringIO()
1858 formatter
.DumbWriter(buffer).send_flowing_data(
1859 'Related help topics: ' + join(split(xrefs
), ', ') + '\n')
1860 self
.output
.write('\n%s\n' % buffer.getvalue())
1862 def showsymbol(self
, symbol
):
1863 target
= self
.symbols
[symbol
]
1864 topic
, _
, xrefs
= target
.partition(' ')
1865 self
.showtopic(topic
, xrefs
)
1867 def listmodules(self
, key
=''):
1869 self
.output
.write('''
1870 Here is a list of matching modules. Enter any module name to get more help.
1875 self
.output
.write('''
1876 Please wait a moment while I gather a list of all available modules...
1880 def callback(path
, modname
, desc
, modules
=modules
):
1881 if modname
and modname
[-9:] == '.__init__':
1882 modname
= modname
[:-9] + ' (package)'
1883 if find(modname
, '.') < 0:
1884 modules
[modname
] = 1
1885 def onerror(modname
):
1886 callback(None, modname
, None)
1887 ModuleScanner().run(callback
, onerror
=onerror
)
1888 self
.list(modules
.keys())
1889 self
.output
.write('''
1890 Enter any module name to get more help. Or, type "modules spam" to search
1891 for modules whose descriptions contain the word "spam".
1897 """A generic tree iterator."""
1898 def __init__(self
, roots
, children
, descendp
):
1899 self
.roots
= roots
[:]
1901 self
.children
= children
1902 self
.descendp
= descendp
1908 root
= self
.roots
.pop(0)
1909 self
.state
= [(root
, self
.children(root
))]
1910 node
, children
= self
.state
[-1]
1914 child
= children
.pop(0)
1915 if self
.descendp(child
):
1916 self
.state
.append((child
, self
.children(child
)))
1920 class ModuleScanner
:
1921 """An interruptible scanner that searches module synopses."""
1923 def run(self
, callback
, key
=None, completer
=None, onerror
=None):
1924 if key
: key
= lower(key
)
1928 for modname
in sys
.builtin_module_names
:
1929 if modname
!= '__main__':
1932 callback(None, modname
, '')
1934 desc
= split(__import__(modname
).__doc
__ or '', '\n')[0]
1935 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1936 callback(None, modname
, desc
)
1938 for importer
, modname
, ispkg
in pkgutil
.walk_packages(onerror
=onerror
):
1942 callback(None, modname
, '')
1944 loader
= importer
.find_module(modname
)
1945 if hasattr(loader
,'get_source'):
1947 desc
= source_synopsis(
1948 StringIO
.StringIO(loader
.get_source(modname
))
1950 if hasattr(loader
,'get_filename'):
1951 path
= loader
.get_filename(modname
)
1955 module
= loader
.load_module(modname
)
1956 desc
= (module
.__doc
__ or '').splitlines()[0]
1957 path
= getattr(module
,'__file__',None)
1958 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1959 callback(path
, modname
, desc
)
1965 """Print all the one-line module summaries that contain a substring."""
1966 def callback(path
, modname
, desc
):
1967 if modname
[-9:] == '.__init__':
1968 modname
= modname
[:-9] + ' (package)'
1969 print modname
, desc
and '- ' + desc
1970 try: import warnings
1971 except ImportError: pass
1972 else: warnings
.filterwarnings('ignore') # ignore problems during import
1973 ModuleScanner().run(callback
, key
)
1975 # --------------------------------------------------- web browser interface
1977 def serve(port
, callback
=None, completer
=None):
1978 import BaseHTTPServer
, mimetools
, select
1980 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1981 class Message(mimetools
.Message
):
1982 def __init__(self
, fp
, seekable
=1):
1983 Message
= self
.__class
__
1984 Message
.__bases
__[0].__bases
__[0].__init
__(self
, fp
, seekable
)
1985 self
.encodingheader
= self
.getheader('content-transfer-encoding')
1986 self
.typeheader
= self
.getheader('content-type')
1990 class DocHandler(BaseHTTPServer
.BaseHTTPRequestHandler
):
1991 def send_document(self
, title
, contents
):
1993 self
.send_response(200)
1994 self
.send_header('Content-Type', 'text/html')
1996 self
.wfile
.write(html
.page(title
, contents
))
1997 except IOError: pass
2001 if path
[-5:] == '.html': path
= path
[:-5]
2002 if path
[:1] == '/': path
= path
[1:]
2003 if path
and path
!= '.':
2005 obj
= locate(path
, forceload
=1)
2006 except ErrorDuringImport
, value
:
2007 self
.send_document(path
, html
.escape(str(value
)))
2010 self
.send_document(describe(obj
), html
.document(obj
, path
))
2012 self
.send_document(path
,
2013 'no Python documentation found for %s' % repr(path
))
2015 heading
= html
.heading(
2016 '<big><big><strong>Python: Index of Modules</strong></big></big>',
2017 '#ffffff', '#7799ee')
2018 def bltinlink(name
):
2019 return '<a href="%s.html">%s</a>' % (name
, name
)
2020 names
= filter(lambda x
: x
!= '__main__',
2021 sys
.builtin_module_names
)
2022 contents
= html
.multicolumn(names
, bltinlink
)
2023 indices
= ['<p>' + html
.bigsection(
2024 'Built-in Modules', '#ffffff', '#ee77aa', contents
)]
2027 for dir in sys
.path
:
2028 indices
.append(html
.index(dir, seen
))
2029 contents
= heading
+ join(indices
) + '''<p align=right>
2030 <font color="#909090" face="helvetica, arial"><strong>
2031 pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>'''
2032 self
.send_document('Index of Modules', contents
)
2034 def log_message(self
, *args
): pass
2036 class DocServer(BaseHTTPServer
.HTTPServer
):
2037 def __init__(self
, port
, callback
):
2039 self
.address
= (host
, port
)
2040 self
.url
= 'http://%s:%d/' % (host
, port
)
2041 self
.callback
= callback
2042 self
.base
.__init
__(self
, self
.address
, self
.handler
)
2044 def serve_until_quit(self
):
2047 while not self
.quit
:
2048 rd
, wr
, ex
= select
.select([self
.socket
.fileno()], [], [], 1)
2049 if rd
: self
.handle_request()
2051 def server_activate(self
):
2052 self
.base
.server_activate(self
)
2053 if self
.callback
: self
.callback(self
)
2055 DocServer
.base
= BaseHTTPServer
.HTTPServer
2056 DocServer
.handler
= DocHandler
2057 DocHandler
.MessageClass
= Message
2060 DocServer(port
, callback
).serve_until_quit()
2061 except (KeyboardInterrupt, select
.error
):
2064 if completer
: completer()
2066 # ----------------------------------------------------- graphical interface
2069 """Graphical interface (starts web server and pops up a control window)."""
2071 def __init__(self
, window
, port
=7464):
2072 self
.window
= window
2077 self
.server_frm
= Tkinter
.Frame(window
)
2078 self
.title_lbl
= Tkinter
.Label(self
.server_frm
,
2079 text
='Starting server...\n ')
2080 self
.open_btn
= Tkinter
.Button(self
.server_frm
,
2081 text
='open browser', command
=self
.open, state
='disabled')
2082 self
.quit_btn
= Tkinter
.Button(self
.server_frm
,
2083 text
='quit serving', command
=self
.quit
, state
='disabled')
2085 self
.search_frm
= Tkinter
.Frame(window
)
2086 self
.search_lbl
= Tkinter
.Label(self
.search_frm
, text
='Search for')
2087 self
.search_ent
= Tkinter
.Entry(self
.search_frm
)
2088 self
.search_ent
.bind('<Return>', self
.search
)
2089 self
.stop_btn
= Tkinter
.Button(self
.search_frm
,
2090 text
='stop', pady
=0, command
=self
.stop
, state
='disabled')
2091 if sys
.platform
== 'win32':
2092 # Trying to hide and show this button crashes under Windows.
2093 self
.stop_btn
.pack(side
='right')
2095 self
.window
.title('pydoc')
2096 self
.window
.protocol('WM_DELETE_WINDOW', self
.quit
)
2097 self
.title_lbl
.pack(side
='top', fill
='x')
2098 self
.open_btn
.pack(side
='left', fill
='x', expand
=1)
2099 self
.quit_btn
.pack(side
='right', fill
='x', expand
=1)
2100 self
.server_frm
.pack(side
='top', fill
='x')
2102 self
.search_lbl
.pack(side
='left')
2103 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2104 self
.search_frm
.pack(side
='top', fill
='x')
2105 self
.search_ent
.focus_set()
2107 font
= ('helvetica', sys
.platform
== 'win32' and 8 or 10)
2108 self
.result_lst
= Tkinter
.Listbox(window
, font
=font
, height
=6)
2109 self
.result_lst
.bind('<Button-1>', self
.select
)
2110 self
.result_lst
.bind('<Double-Button-1>', self
.goto
)
2111 self
.result_scr
= Tkinter
.Scrollbar(window
,
2112 orient
='vertical', command
=self
.result_lst
.yview
)
2113 self
.result_lst
.config(yscrollcommand
=self
.result_scr
.set)
2115 self
.result_frm
= Tkinter
.Frame(window
)
2116 self
.goto_btn
= Tkinter
.Button(self
.result_frm
,
2117 text
='go to selected', command
=self
.goto
)
2118 self
.hide_btn
= Tkinter
.Button(self
.result_frm
,
2119 text
='hide results', command
=self
.hide
)
2120 self
.goto_btn
.pack(side
='left', fill
='x', expand
=1)
2121 self
.hide_btn
.pack(side
='right', fill
='x', expand
=1)
2123 self
.window
.update()
2124 self
.minwidth
= self
.window
.winfo_width()
2125 self
.minheight
= self
.window
.winfo_height()
2126 self
.bigminheight
= (self
.server_frm
.winfo_reqheight() +
2127 self
.search_frm
.winfo_reqheight() +
2128 self
.result_lst
.winfo_reqheight() +
2129 self
.result_frm
.winfo_reqheight())
2130 self
.bigwidth
, self
.bigheight
= self
.minwidth
, self
.bigminheight
2132 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2133 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2134 self
.window
.tk
.willdispatch()
2138 target
=serve
, args
=(port
, self
.ready
, self
.quit
)).start()
2140 def ready(self
, server
):
2141 self
.server
= server
2142 self
.title_lbl
.config(
2143 text
='Python documentation server at\n' + server
.url
)
2144 self
.open_btn
.config(state
='normal')
2145 self
.quit_btn
.config(state
='normal')
2147 def open(self
, event
=None, url
=None):
2148 url
= url
or self
.server
.url
2151 webbrowser
.open(url
)
2152 except ImportError: # pre-webbrowser.py compatibility
2153 if sys
.platform
== 'win32':
2154 os
.system('start "%s"' % url
)
2156 rc
= os
.system('netscape -remote "openURL(%s)" &' % url
)
2157 if rc
: os
.system('netscape "%s" &' % url
)
2159 def quit(self
, event
=None):
2161 self
.server
.quit
= 1
2164 def search(self
, event
=None):
2165 key
= self
.search_ent
.get()
2166 self
.stop_btn
.pack(side
='right')
2167 self
.stop_btn
.config(state
='normal')
2168 self
.search_lbl
.config(text
='Searching for "%s"...' % key
)
2169 self
.search_ent
.forget()
2170 self
.search_lbl
.pack(side
='left')
2171 self
.result_lst
.delete(0, 'end')
2172 self
.goto_btn
.config(state
='disabled')
2177 self
.scanner
.quit
= 1
2178 self
.scanner
= ModuleScanner()
2179 threading
.Thread(target
=self
.scanner
.run
,
2180 args
=(self
.update
, key
, self
.done
)).start()
2182 def update(self
, path
, modname
, desc
):
2183 if modname
[-9:] == '.__init__':
2184 modname
= modname
[:-9] + ' (package)'
2185 self
.result_lst
.insert('end',
2186 modname
+ ' - ' + (desc
or '(no description)'))
2188 def stop(self
, event
=None):
2190 self
.scanner
.quit
= 1
2195 self
.search_lbl
.config(text
='Search for')
2196 self
.search_lbl
.pack(side
='left')
2197 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2198 if sys
.platform
!= 'win32': self
.stop_btn
.forget()
2199 self
.stop_btn
.config(state
='disabled')
2201 def select(self
, event
=None):
2202 self
.goto_btn
.config(state
='normal')
2204 def goto(self
, event
=None):
2205 selection
= self
.result_lst
.curselection()
2207 modname
= split(self
.result_lst
.get(selection
[0]))[0]
2208 self
.open(url
=self
.server
.url
+ modname
+ '.html')
2211 if not self
.expanded
: return
2212 self
.result_frm
.forget()
2213 self
.result_scr
.forget()
2214 self
.result_lst
.forget()
2215 self
.bigwidth
= self
.window
.winfo_width()
2216 self
.bigheight
= self
.window
.winfo_height()
2217 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2218 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2222 if self
.expanded
: return
2223 self
.result_frm
.pack(side
='bottom', fill
='x')
2224 self
.result_scr
.pack(side
='right', fill
='y')
2225 self
.result_lst
.pack(side
='top', fill
='both', expand
=1)
2226 self
.window
.wm_geometry('%dx%d' % (self
.bigwidth
, self
.bigheight
))
2227 self
.window
.wm_minsize(self
.minwidth
, self
.bigminheight
)
2230 def hide(self
, event
=None):
2237 # Tk will crash if pythonw.exe has an XP .manifest
2238 # file and the root has is not destroyed explicitly.
2239 # If the problem is ever fixed in Tk, the explicit
2246 except KeyboardInterrupt:
2249 # -------------------------------------------------- command-line interface
2252 return isinstance(x
, str) and find(x
, os
.sep
) >= 0
2255 """Command-line interface (looks at sys.argv to decide what to do)."""
2257 class BadUsage
: pass
2259 # Scripts don't get the current directory in their path by default
2260 # unless they are run with the '-m' switch
2261 if '' not in sys
.path
:
2262 scriptdir
= os
.path
.dirname(sys
.argv
[0])
2263 if scriptdir
in sys
.path
:
2264 sys
.path
.remove(scriptdir
)
2265 sys
.path
.insert(0, '.')
2268 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'gk:p:w')
2271 for opt
, val
in opts
:
2284 print 'pydoc server ready at %s' % server
.url
2286 print 'pydoc server stopped'
2287 serve(port
, ready
, stopped
)
2292 if not args
: raise BadUsage
2294 if ispath(arg
) and not os
.path
.exists(arg
):
2295 print 'file %r does not exist' % arg
2298 if ispath(arg
) and os
.path
.isfile(arg
):
2299 arg
= importfile(arg
)
2301 if ispath(arg
) and os
.path
.isdir(arg
):
2307 except ErrorDuringImport
, value
:
2310 except (getopt
.error
, BadUsage
):
2311 cmd
= os
.path
.basename(sys
.argv
[0])
2312 print """pydoc - the Python documentation tool
2315 Show text documentation on something. <name> may be the name of a
2316 Python keyword, topic, function, module, or package, or a dotted
2317 reference to a class or function within a module or module in a
2318 package. If <name> contains a '%s', it is used as the path to a
2319 Python source file to document. If name is 'keywords', 'topics',
2320 or 'modules', a listing of these things is displayed.
2323 Search for a keyword in the synopsis lines of all available modules.
2326 Start an HTTP server on the given port on the local machine.
2329 Pop up a graphical interface for finding and serving documentation.
2332 Write out the HTML documentation for a module to a file in the current
2333 directory. If <name> contains a '%s', it is treated as a filename; if
2334 it names a directory, documentation is written for all the contents.
2335 """ % (cmd
, os
.sep
, cmd
, cmd
, cmd
, cmd
, os
.sep
)
2337 if __name__
== '__main__': cli()