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 if _re_stripid
.search(repr(Exception)):
128 return _re_stripid
.sub(r
'\1', text
)
131 def _is_some_method(obj
):
132 return inspect
.ismethod(obj
) or inspect
.ismethoddescriptor(obj
)
136 for key
, value
in inspect
.getmembers(cl
, _is_some_method
):
138 for base
in cl
.__bases
__:
139 methods
.update(allmethods(base
)) # all your base are belong to us
140 for key
in methods
.keys():
141 methods
[key
] = getattr(cl
, key
)
144 def _split_list(s
, predicate
):
145 """Split sequence s via predicate, and return pair ([true], [false]).
147 The return value is a 2-tuple of lists,
148 ([x for x in s if predicate(x)],
149 [x for x in s if not predicate(x)])
161 def visiblename(name
, all
=None):
162 """Decide whether to show documentation on a variable."""
163 # Certain special names are redundant.
164 _hidden_names
= ('__builtins__', '__doc__', '__file__', '__path__',
165 '__module__', '__name__', '__slots__', '__package__')
166 if name
in _hidden_names
: return 0
167 # Private names are hidden, but special names are displayed.
168 if name
.startswith('__') and name
.endswith('__'): return 1
170 # only document that which the programmer exported in __all__
173 return not name
.startswith('_')
175 def classify_class_attrs(object):
176 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
178 name
, kind
, cls
, value
= data
179 if inspect
.isdatadescriptor(value
):
180 kind
= 'data descriptor'
181 return name
, kind
, cls
, value
182 return map(fixup
, inspect
.classify_class_attrs(object))
184 # ----------------------------------------------------- module manipulation
187 """Guess whether a path refers to a package directory."""
188 if os
.path
.isdir(path
):
189 for ext
in ('.py', '.pyc', '.pyo'):
190 if os
.path
.isfile(os
.path
.join(path
, '__init__' + ext
)):
194 def source_synopsis(file):
195 line
= file.readline()
196 while line
[:1] == '#' or not strip(line
):
197 line
= file.readline()
200 if line
[:4] == 'r"""': line
= line
[1:]
201 if line
[:3] == '"""':
203 if line
[-1:] == '\\': line
= line
[:-1]
204 while not strip(line
):
205 line
= file.readline()
207 result
= strip(split(line
, '"""')[0])
211 def synopsis(filename
, cache
={}):
212 """Get the one-line summary out of a module file."""
213 mtime
= os
.stat(filename
).st_mtime
214 lastupdate
, result
= cache
.get(filename
, (0, None))
215 if lastupdate
< mtime
:
216 info
= inspect
.getmoduleinfo(filename
)
218 file = open(filename
)
220 # module can't be opened, so skip it
222 if info
and 'b' in info
[2]: # binary modules have to be imported
223 try: module
= imp
.load_module('__temp__', file, filename
, info
[1:])
225 result
= (module
.__doc
__ or '').splitlines()[0]
226 del sys
.modules
['__temp__']
227 else: # text modules can be directly examined
228 result
= source_synopsis(file)
230 cache
[filename
] = (mtime
, result
)
233 class ErrorDuringImport(Exception):
234 """Errors that occurred while trying to import something to document it."""
235 def __init__(self
, filename
, exc_info
):
236 exc
, value
, tb
= exc_info
237 self
.filename
= filename
244 if type(exc
) is types
.ClassType
:
246 return 'problem in %s - %s: %s' % (self
.filename
, exc
, self
.value
)
248 def importfile(path
):
249 """Import a Python source file or compiled file given its path."""
250 magic
= imp
.get_magic()
251 file = open(path
, 'r')
252 if file.read(len(magic
)) == magic
:
253 kind
= imp
.PY_COMPILED
257 filename
= os
.path
.basename(path
)
258 name
, ext
= os
.path
.splitext(filename
)
259 file = open(path
, 'r')
261 module
= imp
.load_module(name
, file, path
, (ext
, 'r', kind
))
263 raise ErrorDuringImport(path
, sys
.exc_info())
267 def safeimport(path
, forceload
=0, cache
={}):
268 """Import a module; handle errors; return None if the module isn't found.
270 If the module *is* found but an exception occurs, it's wrapped in an
271 ErrorDuringImport exception and reraised. Unlike __import__, if a
272 package path is specified, the module at the end of the path is returned,
273 not the package at the beginning. If the optional 'forceload' argument
274 is 1, we reload the module from disk (unless it's a dynamic extension)."""
276 # If forceload is 1 and the module has been previously loaded from
277 # disk, we always have to reload the module. Checking the file's
278 # mtime isn't good enough (e.g. the module could contain a class
279 # that inherits from another module that has changed).
280 if forceload
and path
in sys
.modules
:
281 if path
not in sys
.builtin_module_names
:
282 # Avoid simply calling reload() because it leaves names in
283 # the currently loaded module lying around if they're not
284 # defined in the new source file. Instead, remove the
285 # module from sys.modules and re-import. Also remove any
286 # submodules because they won't appear in the newly loaded
287 # module's namespace if they're already in sys.modules.
288 subs
= [m
for m
in sys
.modules
if m
.startswith(path
+ '.')]
289 for key
in [path
] + subs
:
290 # Prevent garbage collection.
291 cache
[key
] = sys
.modules
[key
]
293 module
= __import__(path
)
295 # Did the error occur before or after the module was found?
296 (exc
, value
, tb
) = info
= sys
.exc_info()
297 if path
in sys
.modules
:
298 # An error occurred while executing the imported module.
299 raise ErrorDuringImport(sys
.modules
[path
].__file
__, info
)
300 elif exc
is SyntaxError:
301 # A SyntaxError occurred before we could execute the module.
302 raise ErrorDuringImport(value
.filename
, info
)
303 elif exc
is ImportError and extract_tb(tb
)[-1][2]=='safeimport':
304 # The import error occurred directly in this function,
305 # which means there is no such module in the path.
308 # Some other error occurred during the importing process.
309 raise ErrorDuringImport(path
, sys
.exc_info())
310 for part
in split(path
, '.')[1:]:
311 try: module
= getattr(module
, part
)
312 except AttributeError: return None
315 # ---------------------------------------------------- formatter base class
318 def document(self
, object, name
=None, *args
):
319 """Generate documentation for an object."""
320 args
= (object, name
) + args
321 # 'try' clause is to attempt to handle the possibility that inspect
322 # identifies something in a way that pydoc itself has issues handling;
323 # think 'super' and how it is a descriptor (which raises the exception
324 # by lacking a __name__ attribute) and an instance.
325 if inspect
.isgetsetdescriptor(object): return self
.docdata(*args
)
326 if inspect
.ismemberdescriptor(object): return self
.docdata(*args
)
328 if inspect
.ismodule(object): return self
.docmodule(*args
)
329 if inspect
.isclass(object): return self
.docclass(*args
)
330 if inspect
.isroutine(object): return self
.docroutine(*args
)
331 except AttributeError:
333 if isinstance(object, property): return self
.docproperty(*args
)
334 return self
.docother(*args
)
336 def fail(self
, object, name
=None, *args
):
337 """Raise an exception for unimplemented types."""
338 message
= "don't know how to document object%s of type %s" % (
339 name
and ' ' + repr(name
), type(object).__name
__)
340 raise TypeError, message
342 docmodule
= docclass
= docroutine
= docother
= docproperty
= docdata
= fail
344 def getdocloc(self
, object):
345 """Return the location of module docs or None"""
348 file = inspect
.getabsfile(object)
352 docloc
= os
.environ
.get("PYTHONDOCS",
353 "http://docs.python.org/library")
354 basedir
= os
.path
.join(sys
.exec_prefix
, "lib",
355 "python"+sys
.version
[0:3])
356 if (isinstance(object, type(os
)) and
357 (object.__name
__ in ('errno', 'exceptions', 'gc', 'imp',
358 'marshal', 'posix', 'signal', 'sys',
359 'thread', 'zipimport') or
360 (file.startswith(basedir
) and
361 not file.startswith(os
.path
.join(basedir
, 'site-packages'))))):
362 if docloc
.startswith("http://"):
363 docloc
= "%s/%s" % (docloc
.rstrip("/"), object.__name
__)
365 docloc
= os
.path
.join(docloc
, object.__name
__ + ".html")
370 # -------------------------------------------- HTML documentation generator
372 class HTMLRepr(Repr
):
373 """Class for safely making an HTML representation of a Python object."""
376 self
.maxlist
= self
.maxtuple
= 20
378 self
.maxstring
= self
.maxother
= 100
380 def escape(self
, text
):
381 return replace(text
, '&', '&', '<', '<', '>', '>')
383 def repr(self
, object):
384 return Repr
.repr(self
, object)
386 def repr1(self
, x
, level
):
387 if hasattr(type(x
), '__name__'):
388 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
389 if hasattr(self
, methodname
):
390 return getattr(self
, methodname
)(x
, level
)
391 return self
.escape(cram(stripid(repr(x
)), self
.maxother
))
393 def repr_string(self
, x
, level
):
394 test
= cram(x
, self
.maxstring
)
395 testrepr
= repr(test
)
396 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
397 # Backslashes are only literal in the string and are never
398 # needed to make any special characters, so show a raw string.
399 return 'r' + testrepr
[0] + self
.escape(test
) + testrepr
[0]
400 return re
.sub(r
'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
401 r'<font color="#c040c0">\1</font>',
402 self
.escape(testrepr
))
404 repr_str
= repr_string
406 def repr_instance(self
, x
, level
):
408 return self
.escape(cram(stripid(repr(x
)), self
.maxstring
))
410 return self
.escape('<%s instance>' % x
.__class
__.__name
__)
412 repr_unicode
= repr_string
415 """Formatter class for HTML documentation."""
417 # ------------------------------------------- HTML formatting utilities
419 _repr_instance
= HTMLRepr()
420 repr = _repr_instance
.repr
421 escape
= _repr_instance
.escape
423 def page(self
, title
, contents
):
424 """Format an HTML page."""
426 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
427 <html><head><title>Python: %s</title>
428 </head><body bgcolor="#f0f0f8">
430 </body></html>''' % (title
, contents
)
432 def heading(self
, title
, fgcol
, bgcol
, extras
=''):
433 """Format a page heading."""
435 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
437 <td valign=bottom> <br>
438 <font color="%s" face="helvetica, arial"> <br>%s</font></td
439 ><td align=right valign=bottom
440 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
441 ''' % (bgcol
, fgcol
, title
, fgcol
, extras
or ' ')
443 def section(self
, title
, fgcol
, bgcol
, contents
, width
=6,
444 prelude
='', marginalia
=None, gap
=' '):
445 """Format a section with a heading."""
446 if marginalia
is None:
447 marginalia
= '<tt>' + ' ' * width
+ '</tt>'
449 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
451 <td colspan=3 valign=bottom> <br>
452 <font color="%s" face="helvetica, arial">%s</font></td></tr>
453 ''' % (bgcol
, fgcol
, title
)
455 result
= result
+ '''
456 <tr bgcolor="%s"><td rowspan=2>%s</td>
457 <td colspan=2>%s</td></tr>
458 <tr><td>%s</td>''' % (bgcol
, marginalia
, prelude
, gap
)
460 result
= result
+ '''
461 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol
, marginalia
, gap
)
463 return result
+ '\n<td width="100%%">%s</td></tr></table>' % contents
465 def bigsection(self
, title
, *args
):
466 """Format a section with a big heading."""
467 title
= '<big><strong>%s</strong></big>' % title
468 return self
.section(title
, *args
)
470 def preformat(self
, text
):
471 """Format literal preformatted text."""
472 text
= self
.escape(expandtabs(text
))
473 return replace(text
, '\n\n', '\n \n', '\n\n', '\n \n',
474 ' ', ' ', '\n', '<br>\n')
476 def multicolumn(self
, list, format
, cols
=4):
477 """Format a list of items into a multi-column list."""
479 rows
= (len(list)+cols
-1)/cols
480 for col
in range(cols
):
481 result
= result
+ '<td width="%d%%" valign=top>' % (100/cols
)
482 for i
in range(rows
*col
, rows
*col
+rows
):
484 result
= result
+ format(list[i
]) + '<br>\n'
485 result
= result
+ '</td>'
486 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
488 def grey(self
, text
): return '<font color="#909090">%s</font>' % text
490 def namelink(self
, name
, *dicts
):
491 """Make a link for an identifier, given name-to-URL mappings."""
494 return '<a href="%s">%s</a>' % (dict[name
], name
)
497 def classlink(self
, object, modname
):
498 """Make a link for a class."""
499 name
, module
= object.__name
__, sys
.modules
.get(object.__module
__)
500 if hasattr(module
, name
) and getattr(module
, name
) is object:
501 return '<a href="%s.html#%s">%s</a>' % (
502 module
.__name
__, name
, classname(object, modname
))
503 return classname(object, modname
)
505 def modulelink(self
, object):
506 """Make a link for a module."""
507 return '<a href="%s.html">%s</a>' % (object.__name
__, object.__name
__)
509 def modpkglink(self
, data
):
510 """Make a link for a module or package to display in an index."""
511 name
, path
, ispackage
, shadowed
= data
513 return self
.grey(name
)
515 url
= '%s.%s.html' % (path
, name
)
517 url
= '%s.html' % name
519 text
= '<strong>%s</strong> (package)' % name
522 return '<a href="%s">%s</a>' % (url
, text
)
524 def markup(self
, text
, escape
=None, funcs
={}, classes
={}, methods
={}):
525 """Mark up some plain text, given a context of symbols to look for.
526 Each context dictionary maps object names to anchor names."""
527 escape
= escape
or self
.escape
530 pattern
= re
.compile(r
'\b((http|ftp)://\S+[\w/]|'
535 match
= pattern
.search(text
, here
)
537 start
, end
= match
.span()
538 results
.append(escape(text
[here
:start
]))
540 all
, scheme
, rfc
, pep
, selfdot
, name
= match
.groups()
542 url
= escape(all
).replace('"', '"')
543 results
.append('<a href="%s">%s</a>' % (url
, url
))
545 url
= 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc
)
546 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
548 url
= 'http://www.python.org/dev/peps/pep-%04d/' % int(pep
)
549 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
550 elif text
[end
:end
+1] == '(':
551 results
.append(self
.namelink(name
, methods
, funcs
, classes
))
553 results
.append('self.<strong>%s</strong>' % name
)
555 results
.append(self
.namelink(name
, classes
))
557 results
.append(escape(text
[here
:]))
558 return join(results
, '')
560 # ---------------------------------------------- type-specific routines
562 def formattree(self
, tree
, modname
, parent
=None):
563 """Produce HTML for a class tree as given by inspect.getclasstree()."""
566 if type(entry
) is type(()):
568 result
= result
+ '<dt><font face="helvetica, arial">'
569 result
= result
+ self
.classlink(c
, modname
)
570 if bases
and bases
!= (parent
,):
573 parents
.append(self
.classlink(base
, modname
))
574 result
= result
+ '(' + join(parents
, ', ') + ')'
575 result
= result
+ '\n</font></dt>'
576 elif type(entry
) is type([]):
577 result
= result
+ '<dd>\n%s</dd>\n' % self
.formattree(
579 return '<dl>\n%s</dl>\n' % result
581 def docmodule(self
, object, name
=None, mod
=None, *ignored
):
582 """Produce HTML documentation for a module object."""
583 name
= object.__name
__ # ignore the passed-in name
586 except AttributeError:
588 parts
= split(name
, '.')
590 for i
in range(len(parts
)-1):
592 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
593 (join(parts
[:i
+1], '.'), parts
[i
]))
594 linkedname
= join(links
+ parts
[-1:], '.')
595 head
= '<big><big><strong>%s</strong></big></big>' % linkedname
597 path
= inspect
.getabsfile(object)
599 if sys
.platform
== 'win32':
601 url
= nturl2path
.pathname2url(path
)
602 filelink
= '<a href="file:%s">%s</a>' % (url
, path
)
604 filelink
= '(built-in)'
606 if hasattr(object, '__version__'):
607 version
= str(object.__version
__)
608 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
609 version
= strip(version
[11:-1])
610 info
.append('version %s' % self
.escape(version
))
611 if hasattr(object, '__date__'):
612 info
.append(self
.escape(str(object.__date
__)))
614 head
= head
+ ' (%s)' % join(info
, ', ')
615 docloc
= self
.getdocloc(object)
616 if docloc
is not None:
617 docloc
= '<br><a href="%(docloc)s">Module Docs</a>' % locals()
620 result
= self
.heading(
621 head
, '#ffffff', '#7799ee',
622 '<a href=".">index</a><br>' + filelink
+ docloc
)
624 modules
= inspect
.getmembers(object, inspect
.ismodule
)
626 classes
, cdict
= [], {}
627 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
628 # if __all__ exists, believe it. Otherwise use old heuristic.
629 if (all
is not None or
630 (inspect
.getmodule(value
) or object) is object):
631 if visiblename(key
, all
):
632 classes
.append((key
, value
))
633 cdict
[key
] = cdict
[value
] = '#' + key
634 for key
, value
in classes
:
635 for base
in value
.__bases
__:
636 key
, modname
= base
.__name
__, base
.__module
__
637 module
= sys
.modules
.get(modname
)
638 if modname
!= name
and module
and hasattr(module
, key
):
639 if getattr(module
, key
) is base
:
641 cdict
[key
] = cdict
[base
] = modname
+ '.html#' + key
642 funcs
, fdict
= [], {}
643 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
644 # if __all__ exists, believe it. Otherwise use old heuristic.
645 if (all
is not None or
646 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
647 if visiblename(key
, all
):
648 funcs
.append((key
, value
))
649 fdict
[key
] = '#-' + key
650 if inspect
.isfunction(value
): fdict
[value
] = fdict
[key
]
652 for key
, value
in inspect
.getmembers(object, isdata
):
653 if visiblename(key
, all
):
654 data
.append((key
, value
))
656 doc
= self
.markup(getdoc(object), self
.preformat
, fdict
, cdict
)
657 doc
= doc
and '<tt>%s</tt>' % doc
658 result
= result
+ '<p>%s</p>\n' % doc
660 if hasattr(object, '__path__'):
662 for importer
, modname
, ispkg
in pkgutil
.iter_modules(object.__path
__):
663 modpkgs
.append((modname
, name
, ispkg
, 0))
665 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
666 result
= result
+ self
.bigsection(
667 'Package Contents', '#ffffff', '#aa55cc', contents
)
669 contents
= self
.multicolumn(
670 modules
, lambda key_value
, s
=self
: s
.modulelink(key_value
[1]))
671 result
= result
+ self
.bigsection(
672 'Modules', '#ffffff', '#aa55cc', contents
)
675 classlist
= map(lambda key_value
: key_value
[1], classes
)
677 self
.formattree(inspect
.getclasstree(classlist
, 1), name
)]
678 for key
, value
in classes
:
679 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
680 result
= result
+ self
.bigsection(
681 'Classes', '#ffffff', '#ee77aa', join(contents
))
684 for key
, value
in funcs
:
685 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
686 result
= result
+ self
.bigsection(
687 'Functions', '#ffffff', '#eeaa77', join(contents
))
690 for key
, value
in data
:
691 contents
.append(self
.document(value
, key
))
692 result
= result
+ self
.bigsection(
693 'Data', '#ffffff', '#55aa55', join(contents
, '<br>\n'))
694 if hasattr(object, '__author__'):
695 contents
= self
.markup(str(object.__author
__), self
.preformat
)
696 result
= result
+ self
.bigsection(
697 'Author', '#ffffff', '#7799ee', contents
)
698 if hasattr(object, '__credits__'):
699 contents
= self
.markup(str(object.__credits
__), self
.preformat
)
700 result
= result
+ self
.bigsection(
701 'Credits', '#ffffff', '#7799ee', contents
)
705 def docclass(self
, object, name
=None, mod
=None, funcs
={}, classes
={},
707 """Produce HTML documentation for a class object."""
708 realname
= object.__name
__
709 name
= name
or realname
710 bases
= object.__bases
__
713 push
= contents
.append
715 # Cute little class to pump out a horizontal rule between sections.
716 class HorizontalRule
:
723 hr
= HorizontalRule()
725 # List the mro, if non-trivial.
726 mro
= deque(inspect
.getmro(object))
729 push('<dl><dt>Method resolution order:</dt>\n')
731 push('<dd>%s</dd>\n' % self
.classlink(base
,
735 def spill(msg
, attrs
, predicate
):
736 ok
, attrs
= _split_list(attrs
, predicate
)
740 for name
, kind
, homecls
, value
in ok
:
741 push(self
.document(getattr(object, name
), name
, mod
,
742 funcs
, classes
, mdict
, object))
746 def spilldescriptors(msg
, attrs
, predicate
):
747 ok
, attrs
= _split_list(attrs
, predicate
)
751 for name
, kind
, homecls
, value
in ok
:
752 push(self
._docdescriptor
(name
, value
, mod
))
755 def spilldata(msg
, attrs
, predicate
):
756 ok
, attrs
= _split_list(attrs
, predicate
)
760 for name
, kind
, homecls
, value
in ok
:
761 base
= self
.docother(getattr(object, name
), name
, mod
)
762 if (hasattr(value
, '__call__') or
763 inspect
.isdatadescriptor(value
)):
764 doc
= getattr(value
, "__doc__", None)
768 push('<dl><dt>%s</dl>\n' % base
)
770 doc
= self
.markup(getdoc(value
), self
.preformat
,
771 funcs
, classes
, mdict
)
772 doc
= '<dd><tt>%s</tt>' % doc
773 push('<dl><dt>%s%s</dl>\n' % (base
, doc
))
777 attrs
= filter(lambda data
: visiblename(data
[0]),
778 classify_class_attrs(object))
780 for key
, kind
, homecls
, value
in attrs
:
781 mdict
[key
] = anchor
= '#' + name
+ '-' + key
782 value
= getattr(object, key
)
784 # The value may not be hashable (e.g., a data attr with
785 # a dict or list value).
786 mdict
[value
] = anchor
792 thisclass
= mro
.popleft()
794 thisclass
= attrs
[0][2]
795 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
797 if thisclass
is __builtin__
.object:
800 elif thisclass
is object:
803 tag
= 'inherited from %s' % self
.classlink(thisclass
,
807 # Sort attrs by name.
809 attrs
.sort(key
=lambda t
: t
[0])
811 attrs
.sort(lambda t1
, t2
: cmp(t1
[0], t2
[0])) # 2.3 compat
813 # Pump out the attrs, segregated by kind.
814 attrs
= spill('Methods %s' % tag
, attrs
,
815 lambda t
: t
[1] == 'method')
816 attrs
= spill('Class methods %s' % tag
, attrs
,
817 lambda t
: t
[1] == 'class method')
818 attrs
= spill('Static methods %s' % tag
, attrs
,
819 lambda t
: t
[1] == 'static method')
820 attrs
= spilldescriptors('Data descriptors %s' % tag
, attrs
,
821 lambda t
: t
[1] == 'data descriptor')
822 attrs
= spilldata('Data and other attributes %s' % tag
, attrs
,
823 lambda t
: t
[1] == 'data')
827 contents
= ''.join(contents
)
830 title
= '<a name="%s">class <strong>%s</strong></a>' % (
833 title
= '<strong>%s</strong> = <a name="%s">class %s</a>' % (
834 name
, name
, realname
)
838 parents
.append(self
.classlink(base
, object.__module
__))
839 title
= title
+ '(%s)' % join(parents
, ', ')
840 doc
= self
.markup(getdoc(object), self
.preformat
, funcs
, classes
, mdict
)
841 doc
= doc
and '<tt>%s<br> </tt>' % doc
843 return self
.section(title
, '#000000', '#ffc8d8', contents
, 3, doc
)
845 def formatvalue(self
, object):
846 """Format an argument default value as text."""
847 return self
.grey('=' + self
.repr(object))
849 def docroutine(self
, object, name
=None, mod
=None,
850 funcs
={}, classes
={}, methods
={}, cl
=None):
851 """Produce HTML documentation for a function or method object."""
852 realname
= object.__name
__
853 name
= name
or realname
854 anchor
= (cl
and cl
.__name
__ or '') + '-' + name
857 if inspect
.ismethod(object):
858 imclass
= object.im_class
860 if imclass
is not cl
:
861 note
= ' from ' + self
.classlink(imclass
, mod
)
863 if object.im_self
is not None:
864 note
= ' method of %s instance' % self
.classlink(
865 object.im_self
.__class
__, mod
)
867 note
= ' unbound %s method' % self
.classlink(imclass
,mod
)
868 object = object.im_func
871 title
= '<a name="%s"><strong>%s</strong></a>' % (anchor
, realname
)
873 if (cl
and realname
in cl
.__dict
__ and
874 cl
.__dict
__[realname
] is object):
875 reallink
= '<a href="#%s">%s</a>' % (
876 cl
.__name
__ + '-' + realname
, realname
)
880 title
= '<a name="%s"><strong>%s</strong></a> = %s' % (
881 anchor
, name
, reallink
)
882 if inspect
.isfunction(object):
883 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
884 argspec
= inspect
.formatargspec(
885 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
886 if realname
== '<lambda>':
887 title
= '<strong>%s</strong> <em>lambda</em> ' % name
888 argspec
= argspec
[1:-1] # remove parentheses
892 decl
= title
+ argspec
+ (note
and self
.grey(
893 '<font face="helvetica, arial">%s</font>' % note
))
896 return '<dl><dt>%s</dt></dl>\n' % decl
899 getdoc(object), self
.preformat
, funcs
, classes
, methods
)
900 doc
= doc
and '<dd><tt>%s</tt></dd>' % doc
901 return '<dl><dt>%s</dt>%s</dl>\n' % (decl
, doc
)
903 def _docdescriptor(self
, name
, value
, mod
):
905 push
= results
.append
908 push('<dl><dt><strong>%s</strong></dt>\n' % name
)
909 if value
.__doc
__ is not None:
910 doc
= self
.markup(getdoc(value
), self
.preformat
)
911 push('<dd><tt>%s</tt></dd>\n' % doc
)
914 return ''.join(results
)
916 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
917 """Produce html documentation for a property."""
918 return self
._docdescriptor
(name
, object, mod
)
920 def docother(self
, object, name
=None, mod
=None, *ignored
):
921 """Produce HTML documentation for a data object."""
922 lhs
= name
and '<strong>%s</strong> = ' % name
or ''
923 return lhs
+ self
.repr(object)
925 def docdata(self
, object, name
=None, mod
=None, cl
=None):
926 """Produce html documentation for a data descriptor."""
927 return self
._docdescriptor
(name
, object, mod
)
929 def index(self
, dir, shadowed
=None):
930 """Generate an HTML index for a directory of modules."""
932 if shadowed
is None: shadowed
= {}
933 for importer
, name
, ispkg
in pkgutil
.iter_modules([dir]):
934 modpkgs
.append((name
, '', ispkg
, name
in shadowed
))
938 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
939 return self
.bigsection(dir, '#ffffff', '#ee77aa', contents
)
941 # -------------------------------------------- text documentation generator
943 class TextRepr(Repr
):
944 """Class for safely making a text representation of a Python object."""
947 self
.maxlist
= self
.maxtuple
= 20
949 self
.maxstring
= self
.maxother
= 100
951 def repr1(self
, x
, level
):
952 if hasattr(type(x
), '__name__'):
953 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
954 if hasattr(self
, methodname
):
955 return getattr(self
, methodname
)(x
, level
)
956 return cram(stripid(repr(x
)), self
.maxother
)
958 def repr_string(self
, x
, level
):
959 test
= cram(x
, self
.maxstring
)
960 testrepr
= repr(test
)
961 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
962 # Backslashes are only literal in the string and are never
963 # needed to make any special characters, so show a raw string.
964 return 'r' + testrepr
[0] + test
+ testrepr
[0]
967 repr_str
= repr_string
969 def repr_instance(self
, x
, level
):
971 return cram(stripid(repr(x
)), self
.maxstring
)
973 return '<%s instance>' % x
.__class
__.__name
__
976 """Formatter class for text documentation."""
978 # ------------------------------------------- text formatting utilities
980 _repr_instance
= TextRepr()
981 repr = _repr_instance
.repr
983 def bold(self
, text
):
984 """Format a string in bold by overstriking."""
985 return join(map(lambda ch
: ch
+ '\b' + ch
, text
), '')
987 def indent(self
, text
, prefix
=' '):
988 """Indent text by prepending a given prefix to each line."""
989 if not text
: return ''
990 lines
= split(text
, '\n')
991 lines
= map(lambda line
, prefix
=prefix
: prefix
+ line
, lines
)
992 if lines
: lines
[-1] = rstrip(lines
[-1])
993 return join(lines
, '\n')
995 def section(self
, title
, contents
):
996 """Format a section with a given heading."""
997 return self
.bold(title
) + '\n' + rstrip(self
.indent(contents
)) + '\n\n'
999 # ---------------------------------------------- type-specific routines
1001 def formattree(self
, tree
, modname
, parent
=None, prefix
=''):
1002 """Render in text a class tree as returned by inspect.getclasstree()."""
1005 if type(entry
) is type(()):
1007 result
= result
+ prefix
+ classname(c
, modname
)
1008 if bases
and bases
!= (parent
,):
1009 parents
= map(lambda c
, m
=modname
: classname(c
, m
), bases
)
1010 result
= result
+ '(%s)' % join(parents
, ', ')
1011 result
= result
+ '\n'
1012 elif type(entry
) is type([]):
1013 result
= result
+ self
.formattree(
1014 entry
, modname
, c
, prefix
+ ' ')
1017 def docmodule(self
, object, name
=None, mod
=None):
1018 """Produce text documentation for a given module object."""
1019 name
= object.__name
__ # ignore the passed-in name
1020 synop
, desc
= splitdoc(getdoc(object))
1021 result
= self
.section('NAME', name
+ (synop
and ' - ' + synop
))
1024 all
= object.__all
__
1025 except AttributeError:
1029 file = inspect
.getabsfile(object)
1032 result
= result
+ self
.section('FILE', file)
1034 docloc
= self
.getdocloc(object)
1035 if docloc
is not None:
1036 result
= result
+ self
.section('MODULE DOCS', docloc
)
1039 result
= result
+ self
.section('DESCRIPTION', desc
)
1042 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
1043 # if __all__ exists, believe it. Otherwise use old heuristic.
1045 or (inspect
.getmodule(value
) or object) is object):
1046 if visiblename(key
, all
):
1047 classes
.append((key
, value
))
1049 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
1050 # if __all__ exists, believe it. Otherwise use old heuristic.
1051 if (all
is not None or
1052 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
1053 if visiblename(key
, all
):
1054 funcs
.append((key
, value
))
1056 for key
, value
in inspect
.getmembers(object, isdata
):
1057 if visiblename(key
, all
):
1058 data
.append((key
, value
))
1061 modpkgs_names
= set()
1062 if hasattr(object, '__path__'):
1063 for importer
, modname
, ispkg
in pkgutil
.iter_modules(object.__path
__):
1064 modpkgs_names
.add(modname
)
1066 modpkgs
.append(modname
+ ' (package)')
1068 modpkgs
.append(modname
)
1071 result
= result
+ self
.section(
1072 'PACKAGE CONTENTS', join(modpkgs
, '\n'))
1074 # Detect submodules as sometimes created by C extensions
1076 for key
, value
in inspect
.getmembers(object, inspect
.ismodule
):
1077 if value
.__name
__.startswith(name
+ '.') and key
not in modpkgs_names
:
1078 submodules
.append(key
)
1081 result
= result
+ self
.section(
1082 'SUBMODULES', join(submodules
, '\n'))
1085 classlist
= map(lambda key_value
: key_value
[1], classes
)
1086 contents
= [self
.formattree(
1087 inspect
.getclasstree(classlist
, 1), name
)]
1088 for key
, value
in classes
:
1089 contents
.append(self
.document(value
, key
, name
))
1090 result
= result
+ self
.section('CLASSES', join(contents
, '\n'))
1094 for key
, value
in funcs
:
1095 contents
.append(self
.document(value
, key
, name
))
1096 result
= result
+ self
.section('FUNCTIONS', join(contents
, '\n'))
1100 for key
, value
in data
:
1101 contents
.append(self
.docother(value
, key
, name
, maxlen
=70))
1102 result
= result
+ self
.section('DATA', join(contents
, '\n'))
1104 if hasattr(object, '__version__'):
1105 version
= str(object.__version
__)
1106 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
1107 version
= strip(version
[11:-1])
1108 result
= result
+ self
.section('VERSION', version
)
1109 if hasattr(object, '__date__'):
1110 result
= result
+ self
.section('DATE', str(object.__date
__))
1111 if hasattr(object, '__author__'):
1112 result
= result
+ self
.section('AUTHOR', str(object.__author
__))
1113 if hasattr(object, '__credits__'):
1114 result
= result
+ self
.section('CREDITS', str(object.__credits
__))
1117 def docclass(self
, object, name
=None, mod
=None):
1118 """Produce text documentation for a given class object."""
1119 realname
= object.__name
__
1120 name
= name
or realname
1121 bases
= object.__bases
__
1123 def makename(c
, m
=object.__module
__):
1124 return classname(c
, m
)
1126 if name
== realname
:
1127 title
= 'class ' + self
.bold(realname
)
1129 title
= self
.bold(name
) + ' = class ' + realname
1131 parents
= map(makename
, bases
)
1132 title
= title
+ '(%s)' % join(parents
, ', ')
1134 doc
= getdoc(object)
1135 contents
= doc
and [doc
+ '\n'] or []
1136 push
= contents
.append
1138 # List the mro, if non-trivial.
1139 mro
= deque(inspect
.getmro(object))
1141 push("Method resolution order:")
1143 push(' ' + makename(base
))
1146 # Cute little class to pump out a horizontal rule between sections.
1147 class HorizontalRule
:
1154 hr
= HorizontalRule()
1156 def spill(msg
, attrs
, predicate
):
1157 ok
, attrs
= _split_list(attrs
, predicate
)
1161 for name
, kind
, homecls
, value
in ok
:
1162 push(self
.document(getattr(object, name
),
1166 def spilldescriptors(msg
, attrs
, predicate
):
1167 ok
, attrs
= _split_list(attrs
, predicate
)
1171 for name
, kind
, homecls
, value
in ok
:
1172 push(self
._docdescriptor
(name
, value
, mod
))
1175 def spilldata(msg
, attrs
, predicate
):
1176 ok
, attrs
= _split_list(attrs
, predicate
)
1180 for name
, kind
, homecls
, value
in ok
:
1181 if (hasattr(value
, '__call__') or
1182 inspect
.isdatadescriptor(value
)):
1186 push(self
.docother(getattr(object, name
),
1187 name
, mod
, maxlen
=70, doc
=doc
) + '\n')
1190 attrs
= filter(lambda data
: visiblename(data
[0]),
1191 classify_class_attrs(object))
1194 thisclass
= mro
.popleft()
1196 thisclass
= attrs
[0][2]
1197 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
1199 if thisclass
is __builtin__
.object:
1202 elif thisclass
is object:
1203 tag
= "defined here"
1205 tag
= "inherited from %s" % classname(thisclass
,
1208 # Sort attrs by name.
1211 # Pump out the attrs, segregated by kind.
1212 attrs
= spill("Methods %s:\n" % tag
, attrs
,
1213 lambda t
: t
[1] == 'method')
1214 attrs
= spill("Class methods %s:\n" % tag
, attrs
,
1215 lambda t
: t
[1] == 'class method')
1216 attrs
= spill("Static methods %s:\n" % tag
, attrs
,
1217 lambda t
: t
[1] == 'static method')
1218 attrs
= spilldescriptors("Data descriptors %s:\n" % tag
, attrs
,
1219 lambda t
: t
[1] == 'data descriptor')
1220 attrs
= spilldata("Data and other attributes %s:\n" % tag
, attrs
,
1221 lambda t
: t
[1] == 'data')
1225 contents
= '\n'.join(contents
)
1228 return title
+ '\n' + self
.indent(rstrip(contents
), ' | ') + '\n'
1230 def formatvalue(self
, object):
1231 """Format an argument default value as text."""
1232 return '=' + self
.repr(object)
1234 def docroutine(self
, object, name
=None, mod
=None, cl
=None):
1235 """Produce text documentation for a function or method object."""
1236 realname
= object.__name
__
1237 name
= name
or realname
1240 if inspect
.ismethod(object):
1241 imclass
= object.im_class
1243 if imclass
is not cl
:
1244 note
= ' from ' + classname(imclass
, mod
)
1246 if object.im_self
is not None:
1247 note
= ' method of %s instance' % classname(
1248 object.im_self
.__class
__, mod
)
1250 note
= ' unbound %s method' % classname(imclass
,mod
)
1251 object = object.im_func
1253 if name
== realname
:
1254 title
= self
.bold(realname
)
1256 if (cl
and realname
in cl
.__dict
__ and
1257 cl
.__dict
__[realname
] is object):
1259 title
= self
.bold(name
) + ' = ' + realname
1260 if inspect
.isfunction(object):
1261 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
1262 argspec
= inspect
.formatargspec(
1263 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
1264 if realname
== '<lambda>':
1265 title
= self
.bold(name
) + ' lambda '
1266 argspec
= argspec
[1:-1] # remove parentheses
1269 decl
= title
+ argspec
+ note
1274 doc
= getdoc(object) or ''
1275 return decl
+ '\n' + (doc
and rstrip(self
.indent(doc
)) + '\n')
1277 def _docdescriptor(self
, name
, value
, mod
):
1279 push
= results
.append
1282 push(self
.bold(name
))
1284 doc
= getdoc(value
) or ''
1286 push(self
.indent(doc
))
1288 return ''.join(results
)
1290 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
1291 """Produce text documentation for a property."""
1292 return self
._docdescriptor
(name
, object, mod
)
1294 def docdata(self
, object, name
=None, mod
=None, cl
=None):
1295 """Produce text documentation for a data descriptor."""
1296 return self
._docdescriptor
(name
, object, mod
)
1298 def docother(self
, object, name
=None, mod
=None, parent
=None, maxlen
=None, doc
=None):
1299 """Produce text documentation for a data object."""
1300 repr = self
.repr(object)
1302 line
= (name
and name
+ ' = ' or '') + repr
1303 chop
= maxlen
- len(line
)
1304 if chop
< 0: repr = repr[:chop
] + '...'
1305 line
= (name
and self
.bold(name
) + ' = ' or '') + repr
1307 line
+= '\n' + self
.indent(str(doc
))
1310 # --------------------------------------------------------- user interfaces
1313 """The first time this is called, determine what kind of pager to use."""
1319 """Decide what method to use for paging through text."""
1320 if type(sys
.stdout
) is not types
.FileType
:
1322 if not sys
.stdin
.isatty() or not sys
.stdout
.isatty():
1324 if 'PAGER' in os
.environ
:
1325 if sys
.platform
== 'win32': # pipes completely broken in Windows
1326 return lambda text
: tempfilepager(plain(text
), os
.environ
['PAGER'])
1327 elif os
.environ
.get('TERM') in ('dumb', 'emacs'):
1328 return lambda text
: pipepager(plain(text
), os
.environ
['PAGER'])
1330 return lambda text
: pipepager(text
, os
.environ
['PAGER'])
1331 if os
.environ
.get('TERM') in ('dumb', 'emacs'):
1333 if sys
.platform
== 'win32' or sys
.platform
.startswith('os2'):
1334 return lambda text
: tempfilepager(plain(text
), 'more <')
1335 if hasattr(os
, 'system') and os
.system('(less) 2>/dev/null') == 0:
1336 return lambda text
: pipepager(text
, 'less')
1339 (fd
, filename
) = tempfile
.mkstemp()
1342 if hasattr(os
, 'system') and os
.system('more "%s"' % filename
) == 0:
1343 return lambda text
: pipepager(text
, 'more')
1350 """Remove boldface formatting from text."""
1351 return re
.sub('.\b', '', text
)
1353 def pipepager(text
, cmd
):
1354 """Page through text by feeding it to another program."""
1355 pipe
= os
.popen(cmd
, 'w')
1360 pass # Ignore broken pipes caused by quitting the pager program.
1362 def tempfilepager(text
, cmd
):
1363 """Page through text by invoking a program on a temporary file."""
1365 filename
= tempfile
.mktemp()
1366 file = open(filename
, 'w')
1370 os
.system(cmd
+ ' "' + filename
+ '"')
1375 """Page through text on a text terminal."""
1376 lines
= split(plain(text
), '\n')
1379 fd
= sys
.stdin
.fileno()
1380 old
= tty
.tcgetattr(fd
)
1382 getchar
= lambda: sys
.stdin
.read(1)
1383 except (ImportError, AttributeError):
1385 getchar
= lambda: sys
.stdin
.readline()[:-1][:1]
1388 r
= inc
= os
.environ
.get('LINES', 25) - 1
1389 sys
.stdout
.write(join(lines
[:inc
], '\n') + '\n')
1391 sys
.stdout
.write('-- more --')
1396 sys
.stdout
.write('\r \r')
1398 elif c
in ('\r', '\n'):
1399 sys
.stdout
.write('\r \r' + lines
[r
] + '\n')
1402 if c
in ('b', 'B', '\x1b'):
1405 sys
.stdout
.write('\n' + join(lines
[r
:r
+inc
], '\n') + '\n')
1410 tty
.tcsetattr(fd
, tty
.TCSAFLUSH
, old
)
1412 def plainpager(text
):
1413 """Simply print unformatted text. This is the ultimate fallback."""
1414 sys
.stdout
.write(plain(text
))
1416 def describe(thing
):
1417 """Produce a short description of the given thing."""
1418 if inspect
.ismodule(thing
):
1419 if thing
.__name
__ in sys
.builtin_module_names
:
1420 return 'built-in module ' + thing
.__name
__
1421 if hasattr(thing
, '__path__'):
1422 return 'package ' + thing
.__name
__
1424 return 'module ' + thing
.__name
__
1425 if inspect
.isbuiltin(thing
):
1426 return 'built-in function ' + thing
.__name
__
1427 if inspect
.isgetsetdescriptor(thing
):
1428 return 'getset descriptor %s.%s.%s' % (
1429 thing
.__objclass
__.__module
__, thing
.__objclass
__.__name
__,
1431 if inspect
.ismemberdescriptor(thing
):
1432 return 'member descriptor %s.%s.%s' % (
1433 thing
.__objclass
__.__module
__, thing
.__objclass
__.__name
__,
1435 if inspect
.isclass(thing
):
1436 return 'class ' + thing
.__name
__
1437 if inspect
.isfunction(thing
):
1438 return 'function ' + thing
.__name
__
1439 if inspect
.ismethod(thing
):
1440 return 'method ' + thing
.__name
__
1441 if type(thing
) is types
.InstanceType
:
1442 return 'instance of ' + thing
.__class
__.__name
__
1443 return type(thing
).__name
__
1445 def locate(path
, forceload
=0):
1446 """Locate an object by name or dotted path, importing as necessary."""
1447 parts
= [part
for part
in split(path
, '.') if part
]
1449 while n
< len(parts
):
1450 nextmodule
= safeimport(join(parts
[:n
+1], '.'), forceload
)
1451 if nextmodule
: module
, n
= nextmodule
, n
+ 1
1455 for part
in parts
[n
:]:
1456 try: object = getattr(object, part
)
1457 except AttributeError: return None
1460 if hasattr(__builtin__
, path
):
1461 return getattr(__builtin__
, path
)
1463 # --------------------------------------- interactive interpreter interface
1468 class _OldStyleClass
: pass
1469 _OLD_INSTANCE_TYPE
= type(_OldStyleClass())
1471 def resolve(thing
, forceload
=0):
1472 """Given an object or a path to an object, get the object and its name."""
1473 if isinstance(thing
, str):
1474 object = locate(thing
, forceload
)
1476 raise ImportError, 'no Python documentation found for %r' % thing
1477 return object, thing
1479 return thing
, getattr(thing
, '__name__', None)
1481 def render_doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1482 """Render text documentation, given an object or a path to an object."""
1483 object, name
= resolve(thing
, forceload
)
1484 desc
= describe(object)
1485 module
= inspect
.getmodule(object)
1486 if name
and '.' in name
:
1487 desc
+= ' in ' + name
[:name
.rfind('.')]
1488 elif module
and module
is not object:
1489 desc
+= ' in module ' + module
.__name
__
1490 if type(object) is _OLD_INSTANCE_TYPE
:
1491 # If the passed object is an instance of an old-style class,
1492 # document its available methods instead of its value.
1493 object = object.__class
__
1494 elif not (inspect
.ismodule(object) or
1495 inspect
.isclass(object) or
1496 inspect
.isroutine(object) or
1497 inspect
.isgetsetdescriptor(object) or
1498 inspect
.ismemberdescriptor(object) or
1499 isinstance(object, property)):
1500 # If the passed object is a piece of data or an instance,
1501 # document its available methods instead of its value.
1502 object = type(object)
1504 return title
% desc
+ '\n\n' + text
.document(object, name
)
1506 def doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1507 """Display text documentation, given an object or a path to an object."""
1509 pager(render_doc(thing
, title
, forceload
))
1510 except (ImportError, ErrorDuringImport
), value
:
1513 def writedoc(thing
, forceload
=0):
1514 """Write HTML documentation to a file in the current directory."""
1516 object, name
= resolve(thing
, forceload
)
1517 page
= html
.page(describe(object), html
.document(object, name
))
1518 file = open(name
+ '.html', 'w')
1521 print 'wrote', name
+ '.html'
1522 except (ImportError, ErrorDuringImport
), value
:
1525 def writedocs(dir, pkgpath
='', done
=None):
1526 """Write out HTML documentation for all modules in a directory tree."""
1527 if done
is None: done
= {}
1528 for importer
, modname
, ispkg
in pkgutil
.walk_packages([dir], pkgpath
):
1534 # These dictionaries map a topic name to either an alias, or a tuple
1535 # (label, seealso-items). The "label" is the label of the corresponding
1536 # section in the .rst file under Doc/ and an index into the dictionary
1537 # in pydoc_data/topics.py.
1539 # CAUTION: if you change one of these dictionaries, be sure to adapt the
1540 # list of needed labels in Doc/tools/sphinxext/pyspecific.py and
1541 # regenerate the pydoc_data/topics.py file by running
1543 # in Doc/ and copying the output file into the Lib/ directory.
1548 'assert': ('assert', ''),
1549 'break': ('break', 'while for'),
1550 'class': ('class', 'CLASSES SPECIALMETHODS'),
1551 'continue': ('continue', 'while for'),
1552 'def': ('function', ''),
1553 'del': ('del', 'BASICMETHODS'),
1555 'else': ('else', 'while for'),
1557 'exec': ('exec', ''),
1559 'for': ('for', 'break continue while'),
1561 'global': ('global', 'NAMESPACES'),
1562 'if': ('if', 'TRUTHVALUE'),
1563 'import': ('import', 'MODULES'),
1564 'in': ('in', 'SEQUENCEMETHODS2'),
1566 'lambda': ('lambda', 'FUNCTIONS'),
1569 'pass': ('pass', ''),
1570 'print': ('print', ''),
1571 'raise': ('raise', 'EXCEPTIONS'),
1572 'return': ('return', 'FUNCTIONS'),
1573 'try': ('try', 'EXCEPTIONS'),
1574 'while': ('while', 'break continue if TRUTHVALUE'),
1575 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1576 'yield': ('yield', ''),
1578 # Either add symbols to this dictionary or to the symbols dictionary
1579 # directly: Whichever is easier. They are merged later.
1580 _symbols_inverse
= {
1581 'STRINGS' : ("'", "'''", "r'", "u'", '"""', '"', 'r"', 'u"'),
1582 'OPERATORS' : ('+', '-', '*', '**', '/', '//', '%', '<<', '>>', '&',
1583 '|', '^', '~', '<', '>', '<=', '>=', '==', '!=', '<>'),
1584 'COMPARISON' : ('<', '>', '<=', '>=', '==', '!=', '<>'),
1585 'UNARY' : ('-', '~'),
1586 'AUGMENTEDASSIGNMENT' : ('+=', '-=', '*=', '/=', '%=', '&=', '|=',
1587 '^=', '<<=', '>>=', '**=', '//='),
1588 'BITWISE' : ('<<', '>>', '&', '|', '^', '~'),
1589 'COMPLEX' : ('j', 'J')
1592 '%': 'OPERATORS FORMATTING',
1594 ',': 'TUPLES LISTS FUNCTIONS',
1595 '.': 'ATTRIBUTES FLOAT MODULES OBJECTS',
1597 ':': 'SLICINGS DICTIONARYLITERALS',
1600 '_': 'PRIVATENAMES',
1601 '__': 'PRIVATENAMES SPECIALMETHODS',
1603 '(': 'TUPLES FUNCTIONS CALLS',
1604 ')': 'TUPLES FUNCTIONS CALLS',
1605 '[': 'LISTS SUBSCRIPTS SLICINGS',
1606 ']': 'LISTS SUBSCRIPTS SLICINGS'
1608 for topic
, symbols_
in _symbols_inverse
.iteritems():
1609 for symbol
in symbols_
:
1610 topics
= symbols
.get(symbol
, topic
)
1611 if topic
not in topics
:
1612 topics
= topics
+ ' ' + topic
1613 symbols
[symbol
] = topics
1616 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1617 'FUNCTIONS CLASSES MODULES FILES inspect'),
1618 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING '
1620 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1621 'FORMATTING': ('formatstrings', 'OPERATORS'),
1622 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1623 'FORMATTING TYPES'),
1624 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1625 'INTEGER': ('integers', 'int range'),
1626 'FLOAT': ('floating', 'float math'),
1627 'COMPLEX': ('imaginary', 'complex cmath'),
1628 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1629 'MAPPINGS': 'DICTIONARIES',
1630 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1631 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1632 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1633 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
1634 'FRAMEOBJECTS': 'TYPES',
1635 'TRACEBACKS': 'TYPES',
1636 'NONE': ('bltin-null-object', ''),
1637 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
1638 'FILES': ('bltin-file-objects', ''),
1639 'SPECIALATTRIBUTES': ('specialattrs', ''),
1640 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1641 'MODULES': ('typesmodules', 'import'),
1642 'PACKAGES': 'import',
1643 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1644 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1645 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1646 'LISTS DICTIONARIES BACKQUOTES'),
1647 'OPERATORS': 'EXPRESSIONS',
1648 'PRECEDENCE': 'EXPRESSIONS',
1649 'OBJECTS': ('objects', 'TYPES'),
1650 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
1651 'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS '
1652 'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1653 'BASICMETHODS': ('customization', 'cmp hash repr str SPECIALMETHODS'),
1654 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1655 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
1656 'SEQUENCEMETHODS1': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 '
1658 'SEQUENCEMETHODS2': ('sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 '
1660 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1661 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1663 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1664 'NAMESPACES': ('naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1665 'DYNAMICFEATURES': ('dynamic-features', ''),
1666 'SCOPING': 'NAMESPACES',
1667 'FRAMES': 'NAMESPACES',
1668 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1669 'COERCIONS': ('coercion-rules','CONVERSIONS'),
1670 'CONVERSIONS': ('conversions', 'COERCIONS'),
1671 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1672 'SPECIALIDENTIFIERS': ('id-classes', ''),
1673 'PRIVATENAMES': ('atom-identifiers', ''),
1674 'LITERALS': ('atom-literals', 'STRINGS BACKQUOTES NUMBERS '
1675 'TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1676 'TUPLES': 'SEQUENCES',
1677 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1678 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1679 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1680 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1681 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1682 'BACKQUOTES': ('string-conversions', 'repr str STRINGS LITERALS'),
1683 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr '
1684 'ATTRIBUTEMETHODS'),
1685 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS1'),
1686 'SLICINGS': ('slicings', 'SEQUENCEMETHODS2'),
1687 'CALLS': ('calls', 'EXPRESSIONS'),
1688 'POWER': ('power', 'EXPRESSIONS'),
1689 'UNARY': ('unary', 'EXPRESSIONS'),
1690 'BINARY': ('binary', 'EXPRESSIONS'),
1691 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1692 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1693 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1694 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
1695 'ASSERTION': 'assert',
1696 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1697 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
1699 'PRINTING': 'print',
1700 'RETURNING': 'return',
1701 'IMPORTING': 'import',
1702 'CONDITIONAL': 'if',
1703 'LOOPING': ('compound', 'for while break continue'),
1704 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1705 'DEBUGGING': ('debugger', 'pdb'),
1706 'CONTEXTMANAGERS': ('context-managers', 'with'),
1709 def __init__(self
, input, output
):
1711 self
.output
= output
1714 if inspect
.stack()[1][3] == '?':
1717 return '<pydoc.Helper instance>'
1719 def __call__(self
, request
=None):
1720 if request
is not None:
1725 self
.output
.write('''
1726 You are now leaving help and returning to the Python interpreter.
1727 If you want to ask for help on a particular object directly from the
1728 interpreter, you can type "help(object)". Executing "help('string')"
1729 has the same effect as typing a particular string at the help> prompt.
1733 self
.output
.write('\n')
1736 request
= self
.getline('help> ')
1737 if not request
: break
1738 except (KeyboardInterrupt, EOFError):
1740 request
= strip(replace(request
, '"', '', "'", ''))
1741 if lower(request
) in ('q', 'quit'): break
1744 def getline(self
, prompt
):
1745 """Read one line, using raw_input when available."""
1746 if self
.input is sys
.stdin
:
1747 return raw_input(prompt
)
1749 self
.output
.write(prompt
)
1751 return self
.input.readline()
1753 def help(self
, request
):
1754 if type(request
) is type(''):
1755 request
= request
.strip()
1756 if request
== 'help': self
.intro()
1757 elif request
== 'keywords': self
.listkeywords()
1758 elif request
== 'symbols': self
.listsymbols()
1759 elif request
== 'topics': self
.listtopics()
1760 elif request
== 'modules': self
.listmodules()
1761 elif request
[:8] == 'modules ':
1762 self
.listmodules(split(request
)[1])
1763 elif request
in self
.symbols
: self
.showsymbol(request
)
1764 elif request
in self
.keywords
: self
.showtopic(request
)
1765 elif request
in self
.topics
: self
.showtopic(request
)
1766 elif request
: doc(request
, 'Help on %s:')
1767 elif isinstance(request
, Helper
): self()
1768 else: doc(request
, 'Help on %s:')
1769 self
.output
.write('\n')
1772 self
.output
.write('''
1773 Welcome to Python %s! This is the online help utility.
1775 If this is your first time using Python, you should definitely check out
1776 the tutorial on the Internet at http://docs.python.org/tutorial/.
1778 Enter the name of any module, keyword, or topic to get help on writing
1779 Python programs and using Python modules. To quit this help utility and
1780 return to the interpreter, just type "quit".
1782 To get a list of available modules, keywords, or topics, type "modules",
1783 "keywords", or "topics". Each module also comes with a one-line summary
1784 of what it does; to list the modules whose summaries contain a given word
1785 such as "spam", type "modules spam".
1786 ''' % sys
.version
[:3])
1788 def list(self
, items
, columns
=4, width
=80):
1791 colw
= width
/ columns
1792 rows
= (len(items
) + columns
- 1) / columns
1793 for row
in range(rows
):
1794 for col
in range(columns
):
1795 i
= col
* rows
+ row
1797 self
.output
.write(items
[i
])
1798 if col
< columns
- 1:
1799 self
.output
.write(' ' + ' ' * (colw
-1 - len(items
[i
])))
1800 self
.output
.write('\n')
1802 def listkeywords(self
):
1803 self
.output
.write('''
1804 Here is a list of the Python keywords. Enter any keyword to get more help.
1807 self
.list(self
.keywords
.keys())
1809 def listsymbols(self
):
1810 self
.output
.write('''
1811 Here is a list of the punctuation symbols which Python assigns special meaning
1812 to. Enter any symbol to get more help.
1815 self
.list(self
.symbols
.keys())
1817 def listtopics(self
):
1818 self
.output
.write('''
1819 Here is a list of available topics. Enter any topic name to get more help.
1822 self
.list(self
.topics
.keys())
1824 def showtopic(self
, topic
, more_xrefs
=''):
1826 import pydoc_data
.topics
1828 self
.output
.write('''
1829 Sorry, topic and keyword documentation is not available because the
1830 module "pydoc_data.topics" could not be found.
1833 target
= self
.topics
.get(topic
, self
.keywords
.get(topic
))
1835 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1837 if type(target
) is type(''):
1838 return self
.showtopic(target
, more_xrefs
)
1840 label
, xrefs
= target
1842 doc
= pydoc_data
.topics
.topics
[label
]
1844 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1846 pager(strip(doc
) + '\n')
1848 xrefs
= (xrefs
or '') + ' ' + more_xrefs
1850 import StringIO
, formatter
1851 buffer = StringIO
.StringIO()
1852 formatter
.DumbWriter(buffer).send_flowing_data(
1853 'Related help topics: ' + join(split(xrefs
), ', ') + '\n')
1854 self
.output
.write('\n%s\n' % buffer.getvalue())
1856 def showsymbol(self
, symbol
):
1857 target
= self
.symbols
[symbol
]
1858 topic
, _
, xrefs
= target
.partition(' ')
1859 self
.showtopic(topic
, xrefs
)
1861 def listmodules(self
, key
=''):
1863 self
.output
.write('''
1864 Here is a list of matching modules. Enter any module name to get more help.
1869 self
.output
.write('''
1870 Please wait a moment while I gather a list of all available modules...
1874 def callback(path
, modname
, desc
, modules
=modules
):
1875 if modname
and modname
[-9:] == '.__init__':
1876 modname
= modname
[:-9] + ' (package)'
1877 if find(modname
, '.') < 0:
1878 modules
[modname
] = 1
1879 def onerror(modname
):
1880 callback(None, modname
, None)
1881 ModuleScanner().run(callback
, onerror
=onerror
)
1882 self
.list(modules
.keys())
1883 self
.output
.write('''
1884 Enter any module name to get more help. Or, type "modules spam" to search
1885 for modules whose descriptions contain the word "spam".
1888 help = Helper(sys
.stdin
, sys
.stdout
)
1891 """A generic tree iterator."""
1892 def __init__(self
, roots
, children
, descendp
):
1893 self
.roots
= roots
[:]
1895 self
.children
= children
1896 self
.descendp
= descendp
1902 root
= self
.roots
.pop(0)
1903 self
.state
= [(root
, self
.children(root
))]
1904 node
, children
= self
.state
[-1]
1908 child
= children
.pop(0)
1909 if self
.descendp(child
):
1910 self
.state
.append((child
, self
.children(child
)))
1914 class ModuleScanner
:
1915 """An interruptible scanner that searches module synopses."""
1917 def run(self
, callback
, key
=None, completer
=None, onerror
=None):
1918 if key
: key
= lower(key
)
1922 for modname
in sys
.builtin_module_names
:
1923 if modname
!= '__main__':
1926 callback(None, modname
, '')
1928 desc
= split(__import__(modname
).__doc
__ or '', '\n')[0]
1929 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1930 callback(None, modname
, desc
)
1932 for importer
, modname
, ispkg
in pkgutil
.walk_packages(onerror
=onerror
):
1936 callback(None, modname
, '')
1938 loader
= importer
.find_module(modname
)
1939 if hasattr(loader
,'get_source'):
1941 desc
= source_synopsis(
1942 StringIO
.StringIO(loader
.get_source(modname
))
1944 if hasattr(loader
,'get_filename'):
1945 path
= loader
.get_filename(modname
)
1949 module
= loader
.load_module(modname
)
1950 desc
= (module
.__doc
__ or '').splitlines()[0]
1951 path
= getattr(module
,'__file__',None)
1952 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1953 callback(path
, modname
, desc
)
1959 """Print all the one-line module summaries that contain a substring."""
1960 def callback(path
, modname
, desc
):
1961 if modname
[-9:] == '.__init__':
1962 modname
= modname
[:-9] + ' (package)'
1963 print modname
, desc
and '- ' + desc
1964 try: import warnings
1965 except ImportError: pass
1966 else: warnings
.filterwarnings('ignore') # ignore problems during import
1967 ModuleScanner().run(callback
, key
)
1969 # --------------------------------------------------- web browser interface
1971 def serve(port
, callback
=None, completer
=None):
1972 import BaseHTTPServer
, mimetools
, select
1974 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1975 class Message(mimetools
.Message
):
1976 def __init__(self
, fp
, seekable
=1):
1977 Message
= self
.__class
__
1978 Message
.__bases
__[0].__bases
__[0].__init
__(self
, fp
, seekable
)
1979 self
.encodingheader
= self
.getheader('content-transfer-encoding')
1980 self
.typeheader
= self
.getheader('content-type')
1984 class DocHandler(BaseHTTPServer
.BaseHTTPRequestHandler
):
1985 def send_document(self
, title
, contents
):
1987 self
.send_response(200)
1988 self
.send_header('Content-Type', 'text/html')
1990 self
.wfile
.write(html
.page(title
, contents
))
1991 except IOError: pass
1995 if path
[-5:] == '.html': path
= path
[:-5]
1996 if path
[:1] == '/': path
= path
[1:]
1997 if path
and path
!= '.':
1999 obj
= locate(path
, forceload
=1)
2000 except ErrorDuringImport
, value
:
2001 self
.send_document(path
, html
.escape(str(value
)))
2004 self
.send_document(describe(obj
), html
.document(obj
, path
))
2006 self
.send_document(path
,
2007 'no Python documentation found for %s' % repr(path
))
2009 heading
= html
.heading(
2010 '<big><big><strong>Python: Index of Modules</strong></big></big>',
2011 '#ffffff', '#7799ee')
2012 def bltinlink(name
):
2013 return '<a href="%s.html">%s</a>' % (name
, name
)
2014 names
= filter(lambda x
: x
!= '__main__',
2015 sys
.builtin_module_names
)
2016 contents
= html
.multicolumn(names
, bltinlink
)
2017 indices
= ['<p>' + html
.bigsection(
2018 'Built-in Modules', '#ffffff', '#ee77aa', contents
)]
2021 for dir in sys
.path
:
2022 indices
.append(html
.index(dir, seen
))
2023 contents
= heading
+ join(indices
) + '''<p align=right>
2024 <font color="#909090" face="helvetica, arial"><strong>
2025 pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>'''
2026 self
.send_document('Index of Modules', contents
)
2028 def log_message(self
, *args
): pass
2030 class DocServer(BaseHTTPServer
.HTTPServer
):
2031 def __init__(self
, port
, callback
):
2032 host
= (sys
.platform
== 'mac') and '127.0.0.1' or 'localhost'
2033 self
.address
= ('', port
)
2034 self
.url
= 'http://%s:%d/' % (host
, port
)
2035 self
.callback
= callback
2036 self
.base
.__init
__(self
, self
.address
, self
.handler
)
2038 def serve_until_quit(self
):
2041 while not self
.quit
:
2042 rd
, wr
, ex
= select
.select([self
.socket
.fileno()], [], [], 1)
2043 if rd
: self
.handle_request()
2045 def server_activate(self
):
2046 self
.base
.server_activate(self
)
2047 if self
.callback
: self
.callback(self
)
2049 DocServer
.base
= BaseHTTPServer
.HTTPServer
2050 DocServer
.handler
= DocHandler
2051 DocHandler
.MessageClass
= Message
2054 DocServer(port
, callback
).serve_until_quit()
2055 except (KeyboardInterrupt, select
.error
):
2058 if completer
: completer()
2060 # ----------------------------------------------------- graphical interface
2063 """Graphical interface (starts web server and pops up a control window)."""
2065 def __init__(self
, window
, port
=7464):
2066 self
.window
= window
2071 self
.server_frm
= Tkinter
.Frame(window
)
2072 self
.title_lbl
= Tkinter
.Label(self
.server_frm
,
2073 text
='Starting server...\n ')
2074 self
.open_btn
= Tkinter
.Button(self
.server_frm
,
2075 text
='open browser', command
=self
.open, state
='disabled')
2076 self
.quit_btn
= Tkinter
.Button(self
.server_frm
,
2077 text
='quit serving', command
=self
.quit
, state
='disabled')
2079 self
.search_frm
= Tkinter
.Frame(window
)
2080 self
.search_lbl
= Tkinter
.Label(self
.search_frm
, text
='Search for')
2081 self
.search_ent
= Tkinter
.Entry(self
.search_frm
)
2082 self
.search_ent
.bind('<Return>', self
.search
)
2083 self
.stop_btn
= Tkinter
.Button(self
.search_frm
,
2084 text
='stop', pady
=0, command
=self
.stop
, state
='disabled')
2085 if sys
.platform
== 'win32':
2086 # Trying to hide and show this button crashes under Windows.
2087 self
.stop_btn
.pack(side
='right')
2089 self
.window
.title('pydoc')
2090 self
.window
.protocol('WM_DELETE_WINDOW', self
.quit
)
2091 self
.title_lbl
.pack(side
='top', fill
='x')
2092 self
.open_btn
.pack(side
='left', fill
='x', expand
=1)
2093 self
.quit_btn
.pack(side
='right', fill
='x', expand
=1)
2094 self
.server_frm
.pack(side
='top', fill
='x')
2096 self
.search_lbl
.pack(side
='left')
2097 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2098 self
.search_frm
.pack(side
='top', fill
='x')
2099 self
.search_ent
.focus_set()
2101 font
= ('helvetica', sys
.platform
== 'win32' and 8 or 10)
2102 self
.result_lst
= Tkinter
.Listbox(window
, font
=font
, height
=6)
2103 self
.result_lst
.bind('<Button-1>', self
.select
)
2104 self
.result_lst
.bind('<Double-Button-1>', self
.goto
)
2105 self
.result_scr
= Tkinter
.Scrollbar(window
,
2106 orient
='vertical', command
=self
.result_lst
.yview
)
2107 self
.result_lst
.config(yscrollcommand
=self
.result_scr
.set)
2109 self
.result_frm
= Tkinter
.Frame(window
)
2110 self
.goto_btn
= Tkinter
.Button(self
.result_frm
,
2111 text
='go to selected', command
=self
.goto
)
2112 self
.hide_btn
= Tkinter
.Button(self
.result_frm
,
2113 text
='hide results', command
=self
.hide
)
2114 self
.goto_btn
.pack(side
='left', fill
='x', expand
=1)
2115 self
.hide_btn
.pack(side
='right', fill
='x', expand
=1)
2117 self
.window
.update()
2118 self
.minwidth
= self
.window
.winfo_width()
2119 self
.minheight
= self
.window
.winfo_height()
2120 self
.bigminheight
= (self
.server_frm
.winfo_reqheight() +
2121 self
.search_frm
.winfo_reqheight() +
2122 self
.result_lst
.winfo_reqheight() +
2123 self
.result_frm
.winfo_reqheight())
2124 self
.bigwidth
, self
.bigheight
= self
.minwidth
, self
.bigminheight
2126 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2127 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2128 self
.window
.tk
.willdispatch()
2132 target
=serve
, args
=(port
, self
.ready
, self
.quit
)).start()
2134 def ready(self
, server
):
2135 self
.server
= server
2136 self
.title_lbl
.config(
2137 text
='Python documentation server at\n' + server
.url
)
2138 self
.open_btn
.config(state
='normal')
2139 self
.quit_btn
.config(state
='normal')
2141 def open(self
, event
=None, url
=None):
2142 url
= url
or self
.server
.url
2145 webbrowser
.open(url
)
2146 except ImportError: # pre-webbrowser.py compatibility
2147 if sys
.platform
== 'win32':
2148 os
.system('start "%s"' % url
)
2149 elif sys
.platform
== 'mac':
2151 except ImportError: pass
2152 else: ic
.launchurl(url
)
2154 rc
= os
.system('netscape -remote "openURL(%s)" &' % url
)
2155 if rc
: os
.system('netscape "%s" &' % url
)
2157 def quit(self
, event
=None):
2159 self
.server
.quit
= 1
2162 def search(self
, event
=None):
2163 key
= self
.search_ent
.get()
2164 self
.stop_btn
.pack(side
='right')
2165 self
.stop_btn
.config(state
='normal')
2166 self
.search_lbl
.config(text
='Searching for "%s"...' % key
)
2167 self
.search_ent
.forget()
2168 self
.search_lbl
.pack(side
='left')
2169 self
.result_lst
.delete(0, 'end')
2170 self
.goto_btn
.config(state
='disabled')
2175 self
.scanner
.quit
= 1
2176 self
.scanner
= ModuleScanner()
2177 threading
.Thread(target
=self
.scanner
.run
,
2178 args
=(self
.update
, key
, self
.done
)).start()
2180 def update(self
, path
, modname
, desc
):
2181 if modname
[-9:] == '.__init__':
2182 modname
= modname
[:-9] + ' (package)'
2183 self
.result_lst
.insert('end',
2184 modname
+ ' - ' + (desc
or '(no description)'))
2186 def stop(self
, event
=None):
2188 self
.scanner
.quit
= 1
2193 self
.search_lbl
.config(text
='Search for')
2194 self
.search_lbl
.pack(side
='left')
2195 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2196 if sys
.platform
!= 'win32': self
.stop_btn
.forget()
2197 self
.stop_btn
.config(state
='disabled')
2199 def select(self
, event
=None):
2200 self
.goto_btn
.config(state
='normal')
2202 def goto(self
, event
=None):
2203 selection
= self
.result_lst
.curselection()
2205 modname
= split(self
.result_lst
.get(selection
[0]))[0]
2206 self
.open(url
=self
.server
.url
+ modname
+ '.html')
2209 if not self
.expanded
: return
2210 self
.result_frm
.forget()
2211 self
.result_scr
.forget()
2212 self
.result_lst
.forget()
2213 self
.bigwidth
= self
.window
.winfo_width()
2214 self
.bigheight
= self
.window
.winfo_height()
2215 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2216 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2220 if self
.expanded
: return
2221 self
.result_frm
.pack(side
='bottom', fill
='x')
2222 self
.result_scr
.pack(side
='right', fill
='y')
2223 self
.result_lst
.pack(side
='top', fill
='both', expand
=1)
2224 self
.window
.wm_geometry('%dx%d' % (self
.bigwidth
, self
.bigheight
))
2225 self
.window
.wm_minsize(self
.minwidth
, self
.bigminheight
)
2228 def hide(self
, event
=None):
2235 # Tk will crash if pythonw.exe has an XP .manifest
2236 # file and the root has is not destroyed explicitly.
2237 # If the problem is ever fixed in Tk, the explicit
2244 except KeyboardInterrupt:
2247 # -------------------------------------------------- command-line interface
2250 return isinstance(x
, str) and find(x
, os
.sep
) >= 0
2253 """Command-line interface (looks at sys.argv to decide what to do)."""
2255 class BadUsage
: pass
2257 # Scripts don't get the current directory in their path by default.
2258 scriptdir
= os
.path
.dirname(sys
.argv
[0])
2259 if scriptdir
in sys
.path
:
2260 sys
.path
.remove(scriptdir
)
2261 sys
.path
.insert(0, '.')
2264 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'gk:p:w')
2267 for opt
, val
in opts
:
2280 print 'pydoc server ready at %s' % server
.url
2282 print 'pydoc server stopped'
2283 serve(port
, ready
, stopped
)
2288 if not args
: raise BadUsage
2290 if ispath(arg
) and not os
.path
.exists(arg
):
2291 print 'file %r does not exist' % arg
2294 if ispath(arg
) and os
.path
.isfile(arg
):
2295 arg
= importfile(arg
)
2297 if ispath(arg
) and os
.path
.isdir(arg
):
2303 except ErrorDuringImport
, value
:
2306 except (getopt
.error
, BadUsage
):
2307 cmd
= os
.path
.basename(sys
.argv
[0])
2308 print """pydoc - the Python documentation tool
2311 Show text documentation on something. <name> may be the name of a
2312 Python keyword, topic, function, module, or package, or a dotted
2313 reference to a class or function within a module or module in a
2314 package. If <name> contains a '%s', it is used as the path to a
2315 Python source file to document. If name is 'keywords', 'topics',
2316 or 'modules', a listing of these things is displayed.
2319 Search for a keyword in the synopsis lines of all available modules.
2322 Start an HTTP server on the given port on the local machine.
2325 Pop up a graphical interface for finding and serving documentation.
2328 Write out the HTML documentation for a module to a file in the current
2329 directory. If <name> contains a '%s', it is treated as a filename; if
2330 it names a directory, documentation is written for all the contents.
2331 """ % (cmd
, os
.sep
, cmd
, cmd
, cmd
, cmd
, os
.sep
)
2333 if __name__
== '__main__': cli()