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://www.python.org/doc/current/lib/
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
59 from collections
import deque
61 # Python 2.3 compatibility
66 # --------------------------------------------------------- common routines
69 """Convert sys.path into a list of absolute, existing, unique paths."""
73 dir = os
.path
.abspath(dir or '.')
74 normdir
= os
.path
.normcase(dir)
75 if normdir
not in normdirs
and os
.path
.isdir(dir):
77 normdirs
.append(normdir
)
81 """Get the doc string or comments for an object."""
82 result
= inspect
.getdoc(object) or inspect
.getcomments(object)
83 return result
and re
.sub('^ *\n', '', rstrip(result
)) or ''
86 """Split a doc string into a synopsis line (if any) and the rest."""
87 lines
= split(strip(doc
), '\n')
90 elif len(lines
) >= 2 and not rstrip(lines
[1]):
91 return lines
[0], join(lines
[2:], '\n')
92 return '', join(lines
, '\n')
94 def classname(object, modname
):
95 """Get a class name and qualify it with a module name if necessary."""
96 name
= object.__name
__
97 if object.__module
__ != modname
:
98 name
= object.__module
__ + '.' + name
102 """Check if an object is of a type that probably means it's data."""
103 return not (inspect
.ismodule(object) or inspect
.isclass(object) or
104 inspect
.isroutine(object) or inspect
.isframe(object) or
105 inspect
.istraceback(object) or inspect
.iscode(object))
107 def replace(text
, *pairs
):
108 """Do a series of global replacements on a string."""
110 text
= join(split(text
, pairs
[0]), pairs
[1])
114 def cram(text
, maxlen
):
115 """Omit part of a string if needed to make it fit in a maximum length."""
116 if len(text
) > maxlen
:
117 pre
= max(0, (maxlen
-3)//2)
118 post
= max(0, maxlen
-3-pre
)
119 return text
[:pre
] + '...' + text
[len(text
)-post
:]
122 _re_stripid
= re
.compile(r
' at 0x[0-9a-f]{6,16}(>+)$', re
.IGNORECASE
)
124 """Remove the hexadecimal id from a Python object representation."""
125 # The behaviour of %p is implementation-dependent in terms of case.
126 if _re_stripid
.search(repr(Exception)):
127 return _re_stripid
.sub(r
'\1', text
)
130 def _is_some_method(obj
):
131 return inspect
.ismethod(obj
) or inspect
.ismethoddescriptor(obj
)
135 for key
, value
in inspect
.getmembers(cl
, _is_some_method
):
137 for base
in cl
.__bases
__:
138 methods
.update(allmethods(base
)) # all your base are belong to us
139 for key
in methods
.keys():
140 methods
[key
] = getattr(cl
, key
)
143 def _split_list(s
, predicate
):
144 """Split sequence s via predicate, and return pair ([true], [false]).
146 The return value is a 2-tuple of lists,
147 ([x for x in s if predicate(x)],
148 [x for x in s if not predicate(x)])
160 def visiblename(name
, all
=None):
161 """Decide whether to show documentation on a variable."""
162 # Certain special names are redundant.
163 if name
in ('__builtins__', '__doc__', '__file__', '__path__',
164 '__module__', '__name__', '__slots__'): return 0
165 # Private names are hidden, but special names are displayed.
166 if name
.startswith('__') and name
.endswith('__'): return 1
168 # only document that which the programmer exported in __all__
171 return not name
.startswith('_')
173 def classify_class_attrs(object):
174 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
175 def fixup((name
, kind
, cls
, value
)):
176 if inspect
.isdatadescriptor(value
):
177 kind
= 'data descriptor'
178 return name
, kind
, cls
, value
179 return map(fixup
, inspect
.classify_class_attrs(object))
181 # ----------------------------------------------------- module manipulation
184 """Guess whether a path refers to a package directory."""
185 if os
.path
.isdir(path
):
186 for ext
in ('.py', '.pyc', '.pyo'):
187 if os
.path
.isfile(os
.path
.join(path
, '__init__' + ext
)):
191 def source_synopsis(file):
192 line
= file.readline()
193 while line
[:1] == '#' or not strip(line
):
194 line
= file.readline()
197 if line
[:4] == 'r"""': line
= line
[1:]
198 if line
[:3] == '"""':
200 if line
[-1:] == '\\': line
= line
[:-1]
201 while not strip(line
):
202 line
= file.readline()
204 result
= strip(split(line
, '"""')[0])
208 def synopsis(filename
, cache
={}):
209 """Get the one-line summary out of a module file."""
210 mtime
= os
.stat(filename
).st_mtime
211 lastupdate
, result
= cache
.get(filename
, (0, None))
212 if lastupdate
< mtime
:
213 info
= inspect
.getmoduleinfo(filename
)
215 file = open(filename
)
217 # module can't be opened, so skip it
219 if info
and 'b' in info
[2]: # binary modules have to be imported
220 try: module
= imp
.load_module('__temp__', file, filename
, info
[1:])
222 result
= (module
.__doc
__ or '').splitlines()[0]
223 del sys
.modules
['__temp__']
224 else: # text modules can be directly examined
225 result
= source_synopsis(file)
227 cache
[filename
] = (mtime
, result
)
230 class ErrorDuringImport(Exception):
231 """Errors that occurred while trying to import something to document it."""
232 def __init__(self
, filename
, (exc
, value
, tb
)):
233 self
.filename
= filename
240 if type(exc
) is types
.ClassType
:
242 return 'problem in %s - %s: %s' % (self
.filename
, exc
, self
.value
)
244 def importfile(path
):
245 """Import a Python source file or compiled file given its path."""
246 magic
= imp
.get_magic()
247 file = open(path
, 'r')
248 if file.read(len(magic
)) == magic
:
249 kind
= imp
.PY_COMPILED
253 filename
= os
.path
.basename(path
)
254 name
, ext
= os
.path
.splitext(filename
)
255 file = open(path
, 'r')
257 module
= imp
.load_module(name
, file, path
, (ext
, 'r', kind
))
259 raise ErrorDuringImport(path
, sys
.exc_info())
263 def safeimport(path
, forceload
=0, cache
={}):
264 """Import a module; handle errors; return None if the module isn't found.
266 If the module *is* found but an exception occurs, it's wrapped in an
267 ErrorDuringImport exception and reraised. Unlike __import__, if a
268 package path is specified, the module at the end of the path is returned,
269 not the package at the beginning. If the optional 'forceload' argument
270 is 1, we reload the module from disk (unless it's a dynamic extension)."""
272 # If forceload is 1 and the module has been previously loaded from
273 # disk, we always have to reload the module. Checking the file's
274 # mtime isn't good enough (e.g. the module could contain a class
275 # that inherits from another module that has changed).
276 if forceload
and path
in sys
.modules
:
277 if path
not in sys
.builtin_module_names
:
278 # Avoid simply calling reload() because it leaves names in
279 # the currently loaded module lying around if they're not
280 # defined in the new source file. Instead, remove the
281 # module from sys.modules and re-import. Also remove any
282 # submodules because they won't appear in the newly loaded
283 # module's namespace if they're already in sys.modules.
284 subs
= [m
for m
in sys
.modules
if m
.startswith(path
+ '.')]
285 for key
in [path
] + subs
:
286 # Prevent garbage collection.
287 cache
[key
] = sys
.modules
[key
]
289 module
= __import__(path
)
291 # Did the error occur before or after the module was found?
292 (exc
, value
, tb
) = info
= sys
.exc_info()
293 if path
in sys
.modules
:
294 # An error occurred while executing the imported module.
295 raise ErrorDuringImport(sys
.modules
[path
].__file
__, info
)
296 elif exc
is SyntaxError:
297 # A SyntaxError occurred before we could execute the module.
298 raise ErrorDuringImport(value
.filename
, info
)
299 elif exc
is ImportError and \
300 split(lower(str(value
)))[:2] == ['no', 'module']:
301 # The module was not found.
304 # Some other error occurred during the importing process.
305 raise ErrorDuringImport(path
, sys
.exc_info())
306 for part
in split(path
, '.')[1:]:
307 try: module
= getattr(module
, part
)
308 except AttributeError: return None
311 # ---------------------------------------------------- formatter base class
314 def document(self
, object, name
=None, *args
):
315 """Generate documentation for an object."""
316 args
= (object, name
) + args
317 # 'try' clause is to attempt to handle the possibility that inspect
318 # identifies something in a way that pydoc itself has issues handling;
319 # think 'super' and how it is a descriptor (which raises the exception
320 # by lacking a __name__ attribute) and an instance.
322 if inspect
.ismodule(object): return self
.docmodule(*args
)
323 if inspect
.isclass(object): return self
.docclass(*args
)
324 if inspect
.isroutine(object): return self
.docroutine(*args
)
325 except AttributeError:
327 if isinstance(object, property): return self
.docproperty(*args
)
328 return self
.docother(*args
)
330 def fail(self
, object, name
=None, *args
):
331 """Raise an exception for unimplemented types."""
332 message
= "don't know how to document object%s of type %s" % (
333 name
and ' ' + repr(name
), type(object).__name
__)
334 raise TypeError, message
336 docmodule
= docclass
= docroutine
= docother
= fail
338 def getdocloc(self
, object):
339 """Return the location of module docs or None"""
342 file = inspect
.getabsfile(object)
346 docloc
= os
.environ
.get("PYTHONDOCS",
347 "http://www.python.org/doc/current/lib")
348 basedir
= os
.path
.join(sys
.exec_prefix
, "lib",
349 "python"+sys
.version
[0:3])
350 if (isinstance(object, type(os
)) and
351 (object.__name
__ in ('errno', 'exceptions', 'gc', 'imp',
352 'marshal', 'posix', 'signal', 'sys',
353 'thread', 'zipimport') or
354 (file.startswith(basedir
) and
355 not file.startswith(os
.path
.join(basedir
, 'site-packages'))))):
356 htmlfile
= "module-%s.html" % object.__name
__
357 if docloc
.startswith("http://"):
358 docloc
= "%s/%s" % (docloc
.rstrip("/"), htmlfile
)
360 docloc
= os
.path
.join(docloc
, htmlfile
)
365 # -------------------------------------------- HTML documentation generator
367 class HTMLRepr(Repr
):
368 """Class for safely making an HTML representation of a Python object."""
371 self
.maxlist
= self
.maxtuple
= 20
373 self
.maxstring
= self
.maxother
= 100
375 def escape(self
, text
):
376 return replace(text
, '&', '&', '<', '<', '>', '>')
378 def repr(self
, object):
379 return Repr
.repr(self
, object)
381 def repr1(self
, x
, level
):
382 if hasattr(type(x
), '__name__'):
383 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
384 if hasattr(self
, methodname
):
385 return getattr(self
, methodname
)(x
, level
)
386 return self
.escape(cram(stripid(repr(x
)), self
.maxother
))
388 def repr_string(self
, x
, level
):
389 test
= cram(x
, self
.maxstring
)
390 testrepr
= repr(test
)
391 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
392 # Backslashes are only literal in the string and are never
393 # needed to make any special characters, so show a raw string.
394 return 'r' + testrepr
[0] + self
.escape(test
) + testrepr
[0]
395 return re
.sub(r
'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
396 r'<font color="#c040c0">\1</font>',
397 self
.escape(testrepr
))
399 repr_str
= repr_string
401 def repr_instance(self
, x
, level
):
403 return self
.escape(cram(stripid(repr(x
)), self
.maxstring
))
405 return self
.escape('<%s instance>' % x
.__class
__.__name
__)
407 repr_unicode
= repr_string
410 """Formatter class for HTML documentation."""
412 # ------------------------------------------- HTML formatting utilities
414 _repr_instance
= HTMLRepr()
415 repr = _repr_instance
.repr
416 escape
= _repr_instance
.escape
418 def page(self
, title
, contents
):
419 """Format an HTML page."""
421 <!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
422 <html><head><title>Python: %s</title>
423 </head><body bgcolor="#f0f0f8">
425 </body></html>''' % (title
, contents
)
427 def heading(self
, title
, fgcol
, bgcol
, extras
=''):
428 """Format a page heading."""
430 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
432 <td valign=bottom> <br>
433 <font color="%s" face="helvetica, arial"> <br>%s</font></td
434 ><td align=right valign=bottom
435 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
436 ''' % (bgcol
, fgcol
, title
, fgcol
, extras
or ' ')
438 def section(self
, title
, fgcol
, bgcol
, contents
, width
=6,
439 prelude
='', marginalia
=None, gap
=' '):
440 """Format a section with a heading."""
441 if marginalia
is None:
442 marginalia
= '<tt>' + ' ' * width
+ '</tt>'
444 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
446 <td colspan=3 valign=bottom> <br>
447 <font color="%s" face="helvetica, arial">%s</font></td></tr>
448 ''' % (bgcol
, fgcol
, title
)
450 result
= result
+ '''
451 <tr bgcolor="%s"><td rowspan=2>%s</td>
452 <td colspan=2>%s</td></tr>
453 <tr><td>%s</td>''' % (bgcol
, marginalia
, prelude
, gap
)
455 result
= result
+ '''
456 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol
, marginalia
, gap
)
458 return result
+ '\n<td width="100%%">%s</td></tr></table>' % contents
460 def bigsection(self
, title
, *args
):
461 """Format a section with a big heading."""
462 title
= '<big><strong>%s</strong></big>' % title
463 return self
.section(title
, *args
)
465 def preformat(self
, text
):
466 """Format literal preformatted text."""
467 text
= self
.escape(expandtabs(text
))
468 return replace(text
, '\n\n', '\n \n', '\n\n', '\n \n',
469 ' ', ' ', '\n', '<br>\n')
471 def multicolumn(self
, list, format
, cols
=4):
472 """Format a list of items into a multi-column list."""
474 rows
= (len(list)+cols
-1)/cols
475 for col
in range(cols
):
476 result
= result
+ '<td width="%d%%" valign=top>' % (100/cols
)
477 for i
in range(rows
*col
, rows
*col
+rows
):
479 result
= result
+ format(list[i
]) + '<br>\n'
480 result
= result
+ '</td>'
481 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
483 def grey(self
, text
): return '<font color="#909090">%s</font>' % text
485 def namelink(self
, name
, *dicts
):
486 """Make a link for an identifier, given name-to-URL mappings."""
489 return '<a href="%s">%s</a>' % (dict[name
], name
)
492 def classlink(self
, object, modname
):
493 """Make a link for a class."""
494 name
, module
= object.__name
__, sys
.modules
.get(object.__module
__)
495 if hasattr(module
, name
) and getattr(module
, name
) is object:
496 return '<a href="%s.html#%s">%s</a>' % (
497 module
.__name
__, name
, classname(object, modname
))
498 return classname(object, modname
)
500 def modulelink(self
, object):
501 """Make a link for a module."""
502 return '<a href="%s.html">%s</a>' % (object.__name
__, object.__name
__)
504 def modpkglink(self
, (name
, path
, ispackage
, shadowed
)):
505 """Make a link for a module or package to display in an index."""
507 return self
.grey(name
)
509 url
= '%s.%s.html' % (path
, name
)
511 url
= '%s.html' % name
513 text
= '<strong>%s</strong> (package)' % name
516 return '<a href="%s">%s</a>' % (url
, text
)
518 def markup(self
, text
, escape
=None, funcs
={}, classes
={}, methods
={}):
519 """Mark up some plain text, given a context of symbols to look for.
520 Each context dictionary maps object names to anchor names."""
521 escape
= escape
or self
.escape
524 pattern
= re
.compile(r
'\b((http|ftp)://\S+[\w/]|'
529 match
= pattern
.search(text
, here
)
531 start
, end
= match
.span()
532 results
.append(escape(text
[here
:start
]))
534 all
, scheme
, rfc
, pep
, selfdot
, name
= match
.groups()
536 url
= escape(all
).replace('"', '"')
537 results
.append('<a href="%s">%s</a>' % (url
, url
))
539 url
= 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc
)
540 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
542 url
= 'http://www.python.org/peps/pep-%04d.html' % int(pep
)
543 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
544 elif text
[end
:end
+1] == '(':
545 results
.append(self
.namelink(name
, methods
, funcs
, classes
))
547 results
.append('self.<strong>%s</strong>' % name
)
549 results
.append(self
.namelink(name
, classes
))
551 results
.append(escape(text
[here
:]))
552 return join(results
, '')
554 # ---------------------------------------------- type-specific routines
556 def formattree(self
, tree
, modname
, parent
=None):
557 """Produce HTML for a class tree as given by inspect.getclasstree()."""
560 if type(entry
) is type(()):
562 result
= result
+ '<dt><font face="helvetica, arial">'
563 result
= result
+ self
.classlink(c
, modname
)
564 if bases
and bases
!= (parent
,):
567 parents
.append(self
.classlink(base
, modname
))
568 result
= result
+ '(' + join(parents
, ', ') + ')'
569 result
= result
+ '\n</font></dt>'
570 elif type(entry
) is type([]):
571 result
= result
+ '<dd>\n%s</dd>\n' % self
.formattree(
573 return '<dl>\n%s</dl>\n' % result
575 def docmodule(self
, object, name
=None, mod
=None, *ignored
):
576 """Produce HTML documentation for a module object."""
577 name
= object.__name
__ # ignore the passed-in name
580 except AttributeError:
582 parts
= split(name
, '.')
584 for i
in range(len(parts
)-1):
586 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
587 (join(parts
[:i
+1], '.'), parts
[i
]))
588 linkedname
= join(links
+ parts
[-1:], '.')
589 head
= '<big><big><strong>%s</strong></big></big>' % linkedname
591 path
= inspect
.getabsfile(object)
593 if sys
.platform
== 'win32':
595 url
= nturl2path
.pathname2url(path
)
596 filelink
= '<a href="file:%s">%s</a>' % (url
, path
)
598 filelink
= '(built-in)'
600 if hasattr(object, '__version__'):
601 version
= str(object.__version
__)
602 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
603 version
= strip(version
[11:-1])
604 info
.append('version %s' % self
.escape(version
))
605 if hasattr(object, '__date__'):
606 info
.append(self
.escape(str(object.__date
__)))
608 head
= head
+ ' (%s)' % join(info
, ', ')
609 docloc
= self
.getdocloc(object)
610 if docloc
is not None:
611 docloc
= '<br><a href="%(docloc)s">Module Docs</a>' % locals()
614 result
= self
.heading(
615 head
, '#ffffff', '#7799ee',
616 '<a href=".">index</a><br>' + filelink
+ docloc
)
618 modules
= inspect
.getmembers(object, inspect
.ismodule
)
620 classes
, cdict
= [], {}
621 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
622 # if __all__ exists, believe it. Otherwise use old heuristic.
623 if (all
is not None or
624 (inspect
.getmodule(value
) or object) is object):
625 if visiblename(key
, all
):
626 classes
.append((key
, value
))
627 cdict
[key
] = cdict
[value
] = '#' + key
628 for key
, value
in classes
:
629 for base
in value
.__bases
__:
630 key
, modname
= base
.__name
__, base
.__module
__
631 module
= sys
.modules
.get(modname
)
632 if modname
!= name
and module
and hasattr(module
, key
):
633 if getattr(module
, key
) is base
:
635 cdict
[key
] = cdict
[base
] = modname
+ '.html#' + key
636 funcs
, fdict
= [], {}
637 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
638 # if __all__ exists, believe it. Otherwise use old heuristic.
639 if (all
is not None or
640 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
641 if visiblename(key
, all
):
642 funcs
.append((key
, value
))
643 fdict
[key
] = '#-' + key
644 if inspect
.isfunction(value
): fdict
[value
] = fdict
[key
]
646 for key
, value
in inspect
.getmembers(object, isdata
):
647 if visiblename(key
, all
):
648 data
.append((key
, value
))
650 doc
= self
.markup(getdoc(object), self
.preformat
, fdict
, cdict
)
651 doc
= doc
and '<tt>%s</tt>' % doc
652 result
= result
+ '<p>%s</p>\n' % doc
654 if hasattr(object, '__path__'):
656 for importer
, modname
, ispkg
in pkgutil
.iter_modules(object.__path
__):
657 modpkgs
.append((modname
, name
, ispkg
, 0))
659 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
660 result
= result
+ self
.bigsection(
661 'Package Contents', '#ffffff', '#aa55cc', contents
)
663 contents
= self
.multicolumn(
664 modules
, lambda (key
, value
), s
=self
: s
.modulelink(value
))
665 result
= result
+ self
.bigsection(
666 'Modules', '#fffff', '#aa55cc', contents
)
669 classlist
= map(lambda (key
, value
): value
, classes
)
671 self
.formattree(inspect
.getclasstree(classlist
, 1), name
)]
672 for key
, value
in classes
:
673 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
674 result
= result
+ self
.bigsection(
675 'Classes', '#ffffff', '#ee77aa', join(contents
))
678 for key
, value
in funcs
:
679 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
680 result
= result
+ self
.bigsection(
681 'Functions', '#ffffff', '#eeaa77', join(contents
))
684 for key
, value
in data
:
685 contents
.append(self
.document(value
, key
))
686 result
= result
+ self
.bigsection(
687 'Data', '#ffffff', '#55aa55', join(contents
, '<br>\n'))
688 if hasattr(object, '__author__'):
689 contents
= self
.markup(str(object.__author
__), self
.preformat
)
690 result
= result
+ self
.bigsection(
691 'Author', '#ffffff', '#7799ee', contents
)
692 if hasattr(object, '__credits__'):
693 contents
= self
.markup(str(object.__credits
__), self
.preformat
)
694 result
= result
+ self
.bigsection(
695 'Credits', '#ffffff', '#7799ee', contents
)
699 def docclass(self
, object, name
=None, mod
=None, funcs
={}, classes
={},
701 """Produce HTML documentation for a class object."""
702 realname
= object.__name
__
703 name
= name
or realname
704 bases
= object.__bases
__
707 push
= contents
.append
709 # Cute little class to pump out a horizontal rule between sections.
710 class HorizontalRule
:
717 hr
= HorizontalRule()
719 # List the mro, if non-trivial.
720 mro
= deque(inspect
.getmro(object))
723 push('<dl><dt>Method resolution order:</dt>\n')
725 push('<dd>%s</dd>\n' % self
.classlink(base
,
729 def spill(msg
, attrs
, predicate
):
730 ok
, attrs
= _split_list(attrs
, predicate
)
734 for name
, kind
, homecls
, value
in ok
:
735 push(self
.document(getattr(object, name
), name
, mod
,
736 funcs
, classes
, mdict
, object))
740 def spilldescriptors(msg
, attrs
, predicate
):
741 ok
, attrs
= _split_list(attrs
, predicate
)
745 for name
, kind
, homecls
, value
in ok
:
746 push(self
._docdescriptor
(name
, value
, mod
))
749 def spilldata(msg
, attrs
, predicate
):
750 ok
, attrs
= _split_list(attrs
, predicate
)
754 for name
, kind
, homecls
, value
in ok
:
755 base
= self
.docother(getattr(object, name
), name
, mod
)
756 if callable(value
) or inspect
.isdatadescriptor(value
):
757 doc
= getattr(value
, "__doc__", None)
761 push('<dl><dt>%s</dl>\n' % base
)
763 doc
= self
.markup(getdoc(value
), self
.preformat
,
764 funcs
, classes
, mdict
)
765 doc
= '<dd><tt>%s</tt>' % doc
766 push('<dl><dt>%s%s</dl>\n' % (base
, doc
))
770 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
771 classify_class_attrs(object))
773 for key
, kind
, homecls
, value
in attrs
:
774 mdict
[key
] = anchor
= '#' + name
+ '-' + key
775 value
= getattr(object, key
)
777 # The value may not be hashable (e.g., a data attr with
778 # a dict or list value).
779 mdict
[value
] = anchor
785 thisclass
= mro
.popleft()
787 thisclass
= attrs
[0][2]
788 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
790 if thisclass
is __builtin__
.object:
793 elif thisclass
is object:
796 tag
= 'inherited from %s' % self
.classlink(thisclass
,
800 # Sort attrs by name.
802 attrs
.sort(key
=lambda t
: t
[0])
804 attrs
.sort(lambda t1
, t2
: cmp(t1
[0], t2
[0])) # 2.3 compat
806 # Pump out the attrs, segregated by kind.
807 attrs
= spill('Methods %s' % tag
, attrs
,
808 lambda t
: t
[1] == 'method')
809 attrs
= spill('Class methods %s' % tag
, attrs
,
810 lambda t
: t
[1] == 'class method')
811 attrs
= spill('Static methods %s' % tag
, attrs
,
812 lambda t
: t
[1] == 'static method')
813 attrs
= spilldescriptors('Data descriptors %s' % tag
, attrs
,
814 lambda t
: t
[1] == 'data descriptor')
815 attrs
= spilldata('Data and other attributes %s' % tag
, attrs
,
816 lambda t
: t
[1] == 'data')
820 contents
= ''.join(contents
)
823 title
= '<a name="%s">class <strong>%s</strong></a>' % (
826 title
= '<strong>%s</strong> = <a name="%s">class %s</a>' % (
827 name
, name
, realname
)
831 parents
.append(self
.classlink(base
, object.__module
__))
832 title
= title
+ '(%s)' % join(parents
, ', ')
833 doc
= self
.markup(getdoc(object), self
.preformat
, funcs
, classes
, mdict
)
834 doc
= doc
and '<tt>%s<br> </tt>' % doc
836 return self
.section(title
, '#000000', '#ffc8d8', contents
, 3, doc
)
838 def formatvalue(self
, object):
839 """Format an argument default value as text."""
840 return self
.grey('=' + self
.repr(object))
842 def docroutine(self
, object, name
=None, mod
=None,
843 funcs
={}, classes
={}, methods
={}, cl
=None):
844 """Produce HTML documentation for a function or method object."""
845 realname
= object.__name
__
846 name
= name
or realname
847 anchor
= (cl
and cl
.__name
__ or '') + '-' + name
850 if inspect
.ismethod(object):
851 imclass
= object.im_class
853 if imclass
is not cl
:
854 note
= ' from ' + self
.classlink(imclass
, mod
)
857 note
= ' method of %s instance' % self
.classlink(
858 object.im_self
.__class
__, mod
)
860 note
= ' unbound %s method' % self
.classlink(imclass
,mod
)
861 object = object.im_func
864 title
= '<a name="%s"><strong>%s</strong></a>' % (anchor
, realname
)
866 if (cl
and realname
in cl
.__dict
__ and
867 cl
.__dict
__[realname
] is object):
868 reallink
= '<a href="#%s">%s</a>' % (
869 cl
.__name
__ + '-' + realname
, realname
)
873 title
= '<a name="%s"><strong>%s</strong></a> = %s' % (
874 anchor
, name
, reallink
)
875 if inspect
.isfunction(object):
876 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
877 argspec
= inspect
.formatargspec(
878 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
879 if realname
== '<lambda>':
880 title
= '<strong>%s</strong> <em>lambda</em> ' % name
881 argspec
= argspec
[1:-1] # remove parentheses
885 decl
= title
+ argspec
+ (note
and self
.grey(
886 '<font face="helvetica, arial">%s</font>' % note
))
889 return '<dl><dt>%s</dt></dl>\n' % decl
892 getdoc(object), self
.preformat
, funcs
, classes
, methods
)
893 doc
= doc
and '<dd><tt>%s</tt></dd>' % doc
894 return '<dl><dt>%s</dt>%s</dl>\n' % (decl
, doc
)
896 def _docdescriptor(self
, name
, value
, mod
):
898 push
= results
.append
901 push('<dl><dt><strong>%s</strong></dt>\n' % name
)
902 if value
.__doc
__ is not None:
903 doc
= self
.markup(getdoc(value
), self
.preformat
)
904 push('<dd><tt>%s</tt></dd>\n' % doc
)
907 return ''.join(results
)
909 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
910 """Produce html documentation for a property."""
911 return self
._docdescriptor
(name
, object, mod
)
913 def docother(self
, object, name
=None, mod
=None, *ignored
):
914 """Produce HTML documentation for a data object."""
915 lhs
= name
and '<strong>%s</strong> = ' % name
or ''
916 return lhs
+ self
.repr(object)
918 def index(self
, dir, shadowed
=None):
919 """Generate an HTML index for a directory of modules."""
921 if shadowed
is None: shadowed
= {}
922 for importer
, name
, ispkg
in pkgutil
.iter_modules([dir]):
923 modpkgs
.append((name
, '', ispkg
, name
in shadowed
))
927 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
928 return self
.bigsection(dir, '#ffffff', '#ee77aa', contents
)
930 # -------------------------------------------- text documentation generator
932 class TextRepr(Repr
):
933 """Class for safely making a text representation of a Python object."""
936 self
.maxlist
= self
.maxtuple
= 20
938 self
.maxstring
= self
.maxother
= 100
940 def repr1(self
, x
, level
):
941 if hasattr(type(x
), '__name__'):
942 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
943 if hasattr(self
, methodname
):
944 return getattr(self
, methodname
)(x
, level
)
945 return cram(stripid(repr(x
)), self
.maxother
)
947 def repr_string(self
, x
, level
):
948 test
= cram(x
, self
.maxstring
)
949 testrepr
= repr(test
)
950 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
951 # Backslashes are only literal in the string and are never
952 # needed to make any special characters, so show a raw string.
953 return 'r' + testrepr
[0] + test
+ testrepr
[0]
956 repr_str
= repr_string
958 def repr_instance(self
, x
, level
):
960 return cram(stripid(repr(x
)), self
.maxstring
)
962 return '<%s instance>' % x
.__class
__.__name
__
965 """Formatter class for text documentation."""
967 # ------------------------------------------- text formatting utilities
969 _repr_instance
= TextRepr()
970 repr = _repr_instance
.repr
972 def bold(self
, text
):
973 """Format a string in bold by overstriking."""
974 return join(map(lambda ch
: ch
+ '\b' + ch
, text
), '')
976 def indent(self
, text
, prefix
=' '):
977 """Indent text by prepending a given prefix to each line."""
978 if not text
: return ''
979 lines
= split(text
, '\n')
980 lines
= map(lambda line
, prefix
=prefix
: prefix
+ line
, lines
)
981 if lines
: lines
[-1] = rstrip(lines
[-1])
982 return join(lines
, '\n')
984 def section(self
, title
, contents
):
985 """Format a section with a given heading."""
986 return self
.bold(title
) + '\n' + rstrip(self
.indent(contents
)) + '\n\n'
988 # ---------------------------------------------- type-specific routines
990 def formattree(self
, tree
, modname
, parent
=None, prefix
=''):
991 """Render in text a class tree as returned by inspect.getclasstree()."""
994 if type(entry
) is type(()):
996 result
= result
+ prefix
+ classname(c
, modname
)
997 if bases
and bases
!= (parent
,):
998 parents
= map(lambda c
, m
=modname
: classname(c
, m
), bases
)
999 result
= result
+ '(%s)' % join(parents
, ', ')
1000 result
= result
+ '\n'
1001 elif type(entry
) is type([]):
1002 result
= result
+ self
.formattree(
1003 entry
, modname
, c
, prefix
+ ' ')
1006 def docmodule(self
, object, name
=None, mod
=None):
1007 """Produce text documentation for a given module object."""
1008 name
= object.__name
__ # ignore the passed-in name
1009 synop
, desc
= splitdoc(getdoc(object))
1010 result
= self
.section('NAME', name
+ (synop
and ' - ' + synop
))
1013 all
= object.__all
__
1014 except AttributeError:
1018 file = inspect
.getabsfile(object)
1021 result
= result
+ self
.section('FILE', file)
1023 docloc
= self
.getdocloc(object)
1024 if docloc
is not None:
1025 result
= result
+ self
.section('MODULE DOCS', docloc
)
1028 result
= result
+ self
.section('DESCRIPTION', desc
)
1031 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
1032 # if __all__ exists, believe it. Otherwise use old heuristic.
1034 or (inspect
.getmodule(value
) or object) is object):
1035 if visiblename(key
, all
):
1036 classes
.append((key
, value
))
1038 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
1039 # if __all__ exists, believe it. Otherwise use old heuristic.
1040 if (all
is not None or
1041 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
1042 if visiblename(key
, all
):
1043 funcs
.append((key
, value
))
1045 for key
, value
in inspect
.getmembers(object, isdata
):
1046 if visiblename(key
, all
):
1047 data
.append((key
, value
))
1049 if hasattr(object, '__path__'):
1051 for importer
, modname
, ispkg
in pkgutil
.iter_modules(object.__path
__):
1053 modpkgs
.append(modname
+ ' (package)')
1055 modpkgs
.append(modname
)
1058 result
= result
+ self
.section(
1059 'PACKAGE CONTENTS', join(modpkgs
, '\n'))
1062 classlist
= map(lambda (key
, value
): value
, classes
)
1063 contents
= [self
.formattree(
1064 inspect
.getclasstree(classlist
, 1), name
)]
1065 for key
, value
in classes
:
1066 contents
.append(self
.document(value
, key
, name
))
1067 result
= result
+ self
.section('CLASSES', join(contents
, '\n'))
1071 for key
, value
in funcs
:
1072 contents
.append(self
.document(value
, key
, name
))
1073 result
= result
+ self
.section('FUNCTIONS', join(contents
, '\n'))
1077 for key
, value
in data
:
1078 contents
.append(self
.docother(value
, key
, name
, maxlen
=70))
1079 result
= result
+ self
.section('DATA', join(contents
, '\n'))
1081 if hasattr(object, '__version__'):
1082 version
= str(object.__version
__)
1083 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
1084 version
= strip(version
[11:-1])
1085 result
= result
+ self
.section('VERSION', version
)
1086 if hasattr(object, '__date__'):
1087 result
= result
+ self
.section('DATE', str(object.__date
__))
1088 if hasattr(object, '__author__'):
1089 result
= result
+ self
.section('AUTHOR', str(object.__author
__))
1090 if hasattr(object, '__credits__'):
1091 result
= result
+ self
.section('CREDITS', str(object.__credits
__))
1094 def docclass(self
, object, name
=None, mod
=None):
1095 """Produce text documentation for a given class object."""
1096 realname
= object.__name
__
1097 name
= name
or realname
1098 bases
= object.__bases
__
1100 def makename(c
, m
=object.__module
__):
1101 return classname(c
, m
)
1103 if name
== realname
:
1104 title
= 'class ' + self
.bold(realname
)
1106 title
= self
.bold(name
) + ' = class ' + realname
1108 parents
= map(makename
, bases
)
1109 title
= title
+ '(%s)' % join(parents
, ', ')
1111 doc
= getdoc(object)
1112 contents
= doc
and [doc
+ '\n'] or []
1113 push
= contents
.append
1115 # List the mro, if non-trivial.
1116 mro
= deque(inspect
.getmro(object))
1118 push("Method resolution order:")
1120 push(' ' + makename(base
))
1123 # Cute little class to pump out a horizontal rule between sections.
1124 class HorizontalRule
:
1131 hr
= HorizontalRule()
1133 def spill(msg
, attrs
, predicate
):
1134 ok
, attrs
= _split_list(attrs
, predicate
)
1138 for name
, kind
, homecls
, value
in ok
:
1139 push(self
.document(getattr(object, name
),
1143 def spilldescriptors(msg
, attrs
, predicate
):
1144 ok
, attrs
= _split_list(attrs
, predicate
)
1148 for name
, kind
, homecls
, value
in ok
:
1149 push(self
._docdescriptor
(name
, value
, mod
))
1152 def spilldata(msg
, attrs
, predicate
):
1153 ok
, attrs
= _split_list(attrs
, predicate
)
1157 for name
, kind
, homecls
, value
in ok
:
1158 if callable(value
) or inspect
.isdatadescriptor(value
):
1162 push(self
.docother(getattr(object, name
),
1163 name
, mod
, maxlen
=70, doc
=doc
) + '\n')
1166 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
1167 classify_class_attrs(object))
1170 thisclass
= mro
.popleft()
1172 thisclass
= attrs
[0][2]
1173 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
1175 if thisclass
is __builtin__
.object:
1178 elif thisclass
is object:
1179 tag
= "defined here"
1181 tag
= "inherited from %s" % classname(thisclass
,
1183 filter(lambda t
: not t
[0].startswith('_'), attrs
)
1185 # Sort attrs by name.
1188 # Pump out the attrs, segregated by kind.
1189 attrs
= spill("Methods %s:\n" % tag
, attrs
,
1190 lambda t
: t
[1] == 'method')
1191 attrs
= spill("Class methods %s:\n" % tag
, attrs
,
1192 lambda t
: t
[1] == 'class method')
1193 attrs
= spill("Static methods %s:\n" % tag
, attrs
,
1194 lambda t
: t
[1] == 'static method')
1195 attrs
= spilldescriptors("Data descriptors %s:\n" % tag
, attrs
,
1196 lambda t
: t
[1] == 'data descriptor')
1197 attrs
= spilldata("Data and other attributes %s:\n" % tag
, attrs
,
1198 lambda t
: t
[1] == 'data')
1202 contents
= '\n'.join(contents
)
1205 return title
+ '\n' + self
.indent(rstrip(contents
), ' | ') + '\n'
1207 def formatvalue(self
, object):
1208 """Format an argument default value as text."""
1209 return '=' + self
.repr(object)
1211 def docroutine(self
, object, name
=None, mod
=None, cl
=None):
1212 """Produce text documentation for a function or method object."""
1213 realname
= object.__name
__
1214 name
= name
or realname
1217 if inspect
.ismethod(object):
1218 imclass
= object.im_class
1220 if imclass
is not cl
:
1221 note
= ' from ' + classname(imclass
, mod
)
1224 note
= ' method of %s instance' % classname(
1225 object.im_self
.__class
__, mod
)
1227 note
= ' unbound %s method' % classname(imclass
,mod
)
1228 object = object.im_func
1230 if name
== realname
:
1231 title
= self
.bold(realname
)
1233 if (cl
and realname
in cl
.__dict
__ and
1234 cl
.__dict
__[realname
] is object):
1236 title
= self
.bold(name
) + ' = ' + realname
1237 if inspect
.isfunction(object):
1238 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
1239 argspec
= inspect
.formatargspec(
1240 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
1241 if realname
== '<lambda>':
1242 title
= self
.bold(name
) + ' lambda '
1243 argspec
= argspec
[1:-1] # remove parentheses
1246 decl
= title
+ argspec
+ note
1251 doc
= getdoc(object) or ''
1252 return decl
+ '\n' + (doc
and rstrip(self
.indent(doc
)) + '\n')
1254 def _docdescriptor(self
, name
, value
, mod
):
1256 push
= results
.append
1259 push(self
.bold(name
))
1261 doc
= getdoc(value
) or ''
1263 push(self
.indent(doc
))
1265 return ''.join(results
)
1267 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
1268 """Produce text documentation for a property."""
1269 return self
._docdescriptor
(name
, object, mod
)
1271 def docother(self
, object, name
=None, mod
=None, parent
=None, maxlen
=None, doc
=None):
1272 """Produce text documentation for a data object."""
1273 repr = self
.repr(object)
1275 line
= (name
and name
+ ' = ' or '') + repr
1276 chop
= maxlen
- len(line
)
1277 if chop
< 0: repr = repr[:chop
] + '...'
1278 line
= (name
and self
.bold(name
) + ' = ' or '') + repr
1280 line
+= '\n' + self
.indent(str(doc
))
1283 # --------------------------------------------------------- user interfaces
1286 """The first time this is called, determine what kind of pager to use."""
1292 """Decide what method to use for paging through text."""
1293 if type(sys
.stdout
) is not types
.FileType
:
1295 if not sys
.stdin
.isatty() or not sys
.stdout
.isatty():
1297 if 'PAGER' in os
.environ
:
1298 if sys
.platform
== 'win32': # pipes completely broken in Windows
1299 return lambda text
: tempfilepager(plain(text
), os
.environ
['PAGER'])
1300 elif os
.environ
.get('TERM') in ('dumb', 'emacs'):
1301 return lambda text
: pipepager(plain(text
), os
.environ
['PAGER'])
1303 return lambda text
: pipepager(text
, os
.environ
['PAGER'])
1304 if os
.environ
.get('TERM') in ('dumb', 'emacs'):
1306 if sys
.platform
== 'win32' or sys
.platform
.startswith('os2'):
1307 return lambda text
: tempfilepager(plain(text
), 'more <')
1308 if hasattr(os
, 'system') and os
.system('(less) 2>/dev/null') == 0:
1309 return lambda text
: pipepager(text
, 'less')
1312 (fd
, filename
) = tempfile
.mkstemp()
1315 if hasattr(os
, 'system') and os
.system('more %s' % filename
) == 0:
1316 return lambda text
: pipepager(text
, 'more')
1323 """Remove boldface formatting from text."""
1324 return re
.sub('.\b', '', text
)
1326 def pipepager(text
, cmd
):
1327 """Page through text by feeding it to another program."""
1328 pipe
= os
.popen(cmd
, 'w')
1333 pass # Ignore broken pipes caused by quitting the pager program.
1335 def tempfilepager(text
, cmd
):
1336 """Page through text by invoking a program on a temporary file."""
1338 filename
= tempfile
.mktemp()
1339 file = open(filename
, 'w')
1343 os
.system(cmd
+ ' ' + filename
)
1348 """Page through text on a text terminal."""
1349 lines
= split(plain(text
), '\n')
1352 fd
= sys
.stdin
.fileno()
1353 old
= tty
.tcgetattr(fd
)
1355 getchar
= lambda: sys
.stdin
.read(1)
1356 except (ImportError, AttributeError):
1358 getchar
= lambda: sys
.stdin
.readline()[:-1][:1]
1361 r
= inc
= os
.environ
.get('LINES', 25) - 1
1362 sys
.stdout
.write(join(lines
[:inc
], '\n') + '\n')
1364 sys
.stdout
.write('-- more --')
1369 sys
.stdout
.write('\r \r')
1371 elif c
in ('\r', '\n'):
1372 sys
.stdout
.write('\r \r' + lines
[r
] + '\n')
1375 if c
in ('b', 'B', '\x1b'):
1378 sys
.stdout
.write('\n' + join(lines
[r
:r
+inc
], '\n') + '\n')
1383 tty
.tcsetattr(fd
, tty
.TCSAFLUSH
, old
)
1385 def plainpager(text
):
1386 """Simply print unformatted text. This is the ultimate fallback."""
1387 sys
.stdout
.write(plain(text
))
1389 def describe(thing
):
1390 """Produce a short description of the given thing."""
1391 if inspect
.ismodule(thing
):
1392 if thing
.__name
__ in sys
.builtin_module_names
:
1393 return 'built-in module ' + thing
.__name
__
1394 if hasattr(thing
, '__path__'):
1395 return 'package ' + thing
.__name
__
1397 return 'module ' + thing
.__name
__
1398 if inspect
.isbuiltin(thing
):
1399 return 'built-in function ' + thing
.__name
__
1400 if inspect
.isclass(thing
):
1401 return 'class ' + thing
.__name
__
1402 if inspect
.isfunction(thing
):
1403 return 'function ' + thing
.__name
__
1404 if inspect
.ismethod(thing
):
1405 return 'method ' + thing
.__name
__
1406 if type(thing
) is types
.InstanceType
:
1407 return 'instance of ' + thing
.__class
__.__name
__
1408 return type(thing
).__name
__
1410 def locate(path
, forceload
=0):
1411 """Locate an object by name or dotted path, importing as necessary."""
1412 parts
= [part
for part
in split(path
, '.') if part
]
1414 while n
< len(parts
):
1415 nextmodule
= safeimport(join(parts
[:n
+1], '.'), forceload
)
1416 if nextmodule
: module
, n
= nextmodule
, n
+ 1
1420 for part
in parts
[n
:]:
1421 try: object = getattr(object, part
)
1422 except AttributeError: return None
1425 if hasattr(__builtin__
, path
):
1426 return getattr(__builtin__
, path
)
1428 # --------------------------------------- interactive interpreter interface
1433 def resolve(thing
, forceload
=0):
1434 """Given an object or a path to an object, get the object and its name."""
1435 if isinstance(thing
, str):
1436 object = locate(thing
, forceload
)
1438 raise ImportError, 'no Python documentation found for %r' % thing
1439 return object, thing
1441 return thing
, getattr(thing
, '__name__', None)
1443 def doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1444 """Display text documentation, given an object or a path to an object."""
1446 object, name
= resolve(thing
, forceload
)
1447 desc
= describe(object)
1448 module
= inspect
.getmodule(object)
1449 if name
and '.' in name
:
1450 desc
+= ' in ' + name
[:name
.rfind('.')]
1451 elif module
and module
is not object:
1452 desc
+= ' in module ' + module
.__name
__
1453 if not (inspect
.ismodule(object) or
1454 inspect
.isclass(object) or
1455 inspect
.isroutine(object) or
1456 isinstance(object, property)):
1457 # If the passed object is a piece of data or an instance,
1458 # document its available methods instead of its value.
1459 object = type(object)
1461 pager(title
% desc
+ '\n\n' + text
.document(object, name
))
1462 except (ImportError, ErrorDuringImport
), value
:
1465 def writedoc(thing
, forceload
=0):
1466 """Write HTML documentation to a file in the current directory."""
1468 object, name
= resolve(thing
, forceload
)
1469 page
= html
.page(describe(object), html
.document(object, name
))
1470 file = open(name
+ '.html', 'w')
1473 print 'wrote', name
+ '.html'
1474 except (ImportError, ErrorDuringImport
), value
:
1477 def writedocs(dir, pkgpath
='', done
=None):
1478 """Write out HTML documentation for all modules in a directory tree."""
1479 if done
is None: done
= {}
1480 for importer
, modname
, ispkg
in pkgutil
.walk_packages([dir], pkgpath
):
1487 'assert': ('ref/assert', ''),
1488 'break': ('ref/break', 'while for'),
1489 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1490 'continue': ('ref/continue', 'while for'),
1491 'def': ('ref/function', ''),
1492 'del': ('ref/del', 'BASICMETHODS'),
1494 'else': ('ref/if', 'while for'),
1496 'exec': ('ref/exec', ''),
1498 'for': ('ref/for', 'break continue while'),
1500 'global': ('ref/global', 'NAMESPACES'),
1501 'if': ('ref/if', 'TRUTHVALUE'),
1502 'import': ('ref/import', 'MODULES'),
1503 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1505 'lambda': ('ref/lambdas', 'FUNCTIONS'),
1508 'pass': ('ref/pass', ''),
1509 'print': ('ref/print', ''),
1510 'raise': ('ref/raise', 'EXCEPTIONS'),
1511 'return': ('ref/return', 'FUNCTIONS'),
1512 'try': ('ref/try', 'EXCEPTIONS'),
1513 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1514 'yield': ('ref/yield', ''),
1518 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
1519 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
1520 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1521 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
1522 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
1523 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1524 'INTEGER': ('ref/integers', 'int range'),
1525 'FLOAT': ('ref/floating', 'float math'),
1526 'COMPLEX': ('ref/imaginary', 'complex cmath'),
1527 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1528 'MAPPINGS': 'DICTIONARIES',
1529 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1530 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1531 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
1532 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
1533 'FRAMEOBJECTS': 'TYPES',
1534 'TRACEBACKS': 'TYPES',
1535 'NONE': ('lib/bltin-null-object', ''),
1536 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1537 'FILES': ('lib/bltin-file-objects', ''),
1538 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1539 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1540 'MODULES': ('lib/typesmodules', 'import'),
1541 'PACKAGES': 'import',
1542 'EXPRESSIONS': ('ref/summary', 'lambda or and not in is BOOLEAN COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES LISTS DICTIONARIES BACKQUOTES'),
1543 'OPERATORS': 'EXPRESSIONS',
1544 'PRECEDENCE': 'EXPRESSIONS',
1545 'OBJECTS': ('ref/objects', 'TYPES'),
1546 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1547 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1548 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1549 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1550 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1551 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1552 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1553 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
1554 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1555 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1556 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
1557 'SCOPING': 'NAMESPACES',
1558 'FRAMES': 'NAMESPACES',
1559 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1560 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1561 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
1562 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1563 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
1564 'PRIVATENAMES': ('ref/atom-identifiers', ''),
1565 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1566 'TUPLES': 'SEQUENCES',
1567 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
1568 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
1569 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
1570 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
1571 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1572 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
1573 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1574 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1575 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1576 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1577 'POWER': ('ref/power', 'EXPRESSIONS'),
1578 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1579 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1580 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1581 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1582 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
1583 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
1584 'ASSERTION': 'assert',
1585 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
1586 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
1588 'PRINTING': 'print',
1589 'RETURNING': 'return',
1590 'IMPORTING': 'import',
1591 'CONDITIONAL': 'if',
1592 'LOOPING': ('ref/compound', 'for while break continue'),
1593 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
1594 'DEBUGGING': ('lib/module-pdb', 'pdb'),
1597 def __init__(self
, input, output
):
1599 self
.output
= output
1601 execdir
= os
.path
.dirname(sys
.executable
)
1602 homedir
= os
.environ
.get('PYTHONHOME')
1603 for dir in [os
.environ
.get('PYTHONDOCS'),
1604 homedir
and os
.path
.join(homedir
, 'doc'),
1605 os
.path
.join(execdir
, 'doc'),
1606 '/usr/doc/python-docs-' + split(sys
.version
)[0],
1607 '/usr/doc/python-' + split(sys
.version
)[0],
1608 '/usr/doc/python-docs-' + sys
.version
[:3],
1609 '/usr/doc/python-' + sys
.version
[:3],
1610 os
.path
.join(sys
.prefix
, 'Resources/English.lproj/Documentation')]:
1611 if dir and os
.path
.isdir(os
.path
.join(dir, 'lib')):
1615 if inspect
.stack()[1][3] == '?':
1618 return '<pydoc.Helper instance>'
1620 def __call__(self
, request
=None):
1621 if request
is not None:
1626 self
.output
.write('''
1627 You are now leaving help and returning to the Python interpreter.
1628 If you want to ask for help on a particular object directly from the
1629 interpreter, you can type "help(object)". Executing "help('string')"
1630 has the same effect as typing a particular string at the help> prompt.
1634 self
.output
.write('\n')
1637 request
= self
.getline('help> ')
1638 if not request
: break
1639 except (KeyboardInterrupt, EOFError):
1641 request
= strip(replace(request
, '"', '', "'", ''))
1642 if lower(request
) in ('q', 'quit'): break
1645 def getline(self
, prompt
):
1646 """Read one line, using raw_input when available."""
1647 if self
.input is sys
.stdin
:
1648 return raw_input(prompt
)
1650 self
.output
.write(prompt
)
1652 return self
.input.readline()
1654 def help(self
, request
):
1655 if type(request
) is type(''):
1656 if request
== 'help': self
.intro()
1657 elif request
== 'keywords': self
.listkeywords()
1658 elif request
== 'topics': self
.listtopics()
1659 elif request
== 'modules': self
.listmodules()
1660 elif request
[:8] == 'modules ':
1661 self
.listmodules(split(request
)[1])
1662 elif request
in self
.keywords
: self
.showtopic(request
)
1663 elif request
in self
.topics
: self
.showtopic(request
)
1664 elif request
: doc(request
, 'Help on %s:')
1665 elif isinstance(request
, Helper
): self()
1666 else: doc(request
, 'Help on %s:')
1667 self
.output
.write('\n')
1670 self
.output
.write('''
1671 Welcome to Python %s! This is the online help utility.
1673 If this is your first time using Python, you should definitely check out
1674 the tutorial on the Internet at http://www.python.org/doc/tut/.
1676 Enter the name of any module, keyword, or topic to get help on writing
1677 Python programs and using Python modules. To quit this help utility and
1678 return to the interpreter, just type "quit".
1680 To get a list of available modules, keywords, or topics, type "modules",
1681 "keywords", or "topics". Each module also comes with a one-line summary
1682 of what it does; to list the modules whose summaries contain a given word
1683 such as "spam", type "modules spam".
1684 ''' % sys
.version
[:3])
1686 def list(self
, items
, columns
=4, width
=80):
1689 colw
= width
/ columns
1690 rows
= (len(items
) + columns
- 1) / columns
1691 for row
in range(rows
):
1692 for col
in range(columns
):
1693 i
= col
* rows
+ row
1695 self
.output
.write(items
[i
])
1696 if col
< columns
- 1:
1697 self
.output
.write(' ' + ' ' * (colw
-1 - len(items
[i
])))
1698 self
.output
.write('\n')
1700 def listkeywords(self
):
1701 self
.output
.write('''
1702 Here is a list of the Python keywords. Enter any keyword to get more help.
1705 self
.list(self
.keywords
.keys())
1707 def listtopics(self
):
1708 self
.output
.write('''
1709 Here is a list of available topics. Enter any topic name to get more help.
1712 self
.list(self
.topics
.keys())
1714 def showtopic(self
, topic
):
1716 self
.output
.write('''
1717 Sorry, topic and keyword documentation is not available because the Python
1718 HTML documentation files could not be found. If you have installed them,
1719 please set the environment variable PYTHONDOCS to indicate their location.
1722 target
= self
.topics
.get(topic
, self
.keywords
.get(topic
))
1724 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1726 if type(target
) is type(''):
1727 return self
.showtopic(target
)
1729 filename
, xrefs
= target
1730 filename
= self
.docdir
+ '/' + filename
+ '.html'
1732 file = open(filename
)
1734 self
.output
.write('could not read docs from %s\n' % filename
)
1737 divpat
= re
.compile('<div[^>]*navigat.*?</div.*?>', re
.I | re
.S
)
1738 addrpat
= re
.compile('<address.*?>.*?</address.*?>', re
.I | re
.S
)
1739 document
= re
.sub(addrpat
, '', re
.sub(divpat
, '', file.read()))
1742 import htmllib
, formatter
, StringIO
1743 buffer = StringIO
.StringIO()
1744 parser
= htmllib
.HTMLParser(
1745 formatter
.AbstractFormatter(formatter
.DumbWriter(buffer)))
1746 parser
.start_table
= parser
.do_p
1747 parser
.end_table
= lambda parser
=parser
: parser
.do_p({})
1748 parser
.start_tr
= parser
.do_br
1749 parser
.start_td
= parser
.start_th
= lambda a
, b
=buffer: b
.write('\t')
1750 parser
.feed(document
)
1751 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1752 pager(' ' + strip(buffer) + '\n')
1754 buffer = StringIO
.StringIO()
1755 formatter
.DumbWriter(buffer).send_flowing_data(
1756 'Related help topics: ' + join(split(xrefs
), ', ') + '\n')
1757 self
.output
.write('\n%s\n' % buffer.getvalue())
1759 def listmodules(self
, key
=''):
1761 self
.output
.write('''
1762 Here is a list of matching modules. Enter any module name to get more help.
1767 self
.output
.write('''
1768 Please wait a moment while I gather a list of all available modules...
1772 def callback(path
, modname
, desc
, modules
=modules
):
1773 if modname
and modname
[-9:] == '.__init__':
1774 modname
= modname
[:-9] + ' (package)'
1775 if find(modname
, '.') < 0:
1776 modules
[modname
] = 1
1777 ModuleScanner().run(callback
)
1778 self
.list(modules
.keys())
1779 self
.output
.write('''
1780 Enter any module name to get more help. Or, type "modules spam" to search
1781 for modules whose descriptions contain the word "spam".
1784 help = Helper(sys
.stdin
, sys
.stdout
)
1787 """A generic tree iterator."""
1788 def __init__(self
, roots
, children
, descendp
):
1789 self
.roots
= roots
[:]
1791 self
.children
= children
1792 self
.descendp
= descendp
1798 root
= self
.roots
.pop(0)
1799 self
.state
= [(root
, self
.children(root
))]
1800 node
, children
= self
.state
[-1]
1804 child
= children
.pop(0)
1805 if self
.descendp(child
):
1806 self
.state
.append((child
, self
.children(child
)))
1810 class ModuleScanner
:
1811 """An interruptible scanner that searches module synopses."""
1813 def run(self
, callback
, key
=None, completer
=None):
1814 if key
: key
= lower(key
)
1818 for modname
in sys
.builtin_module_names
:
1819 if modname
!= '__main__':
1822 callback(None, modname
, '')
1824 desc
= split(__import__(modname
).__doc
__ or '', '\n')[0]
1825 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1826 callback(None, modname
, desc
)
1828 for importer
, modname
, ispkg
in pkgutil
.walk_packages():
1832 callback(None, modname
, '')
1834 loader
= importer
.find_module(modname
)
1835 if hasattr(loader
,'get_source'):
1837 desc
= source_synopsis(
1838 StringIO
.StringIO(loader
.get_source(modname
))
1840 if hasattr(loader
,'get_filename'):
1841 path
= loader
.get_filename(modname
)
1845 module
= loader
.load_module(modname
)
1846 desc
= (module
.__doc
__ or '').splitlines()[0]
1847 path
= getattr(module
,'__file__',None)
1848 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1849 callback(path
, modname
, desc
)
1855 """Print all the one-line module summaries that contain a substring."""
1856 def callback(path
, modname
, desc
):
1857 if modname
[-9:] == '.__init__':
1858 modname
= modname
[:-9] + ' (package)'
1859 print modname
, desc
and '- ' + desc
1860 try: import warnings
1861 except ImportError: pass
1862 else: warnings
.filterwarnings('ignore') # ignore problems during import
1863 ModuleScanner().run(callback
, key
)
1865 # --------------------------------------------------- web browser interface
1867 def serve(port
, callback
=None, completer
=None):
1868 import BaseHTTPServer
, mimetools
, select
1870 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1871 class Message(mimetools
.Message
):
1872 def __init__(self
, fp
, seekable
=1):
1873 Message
= self
.__class
__
1874 Message
.__bases
__[0].__bases
__[0].__init
__(self
, fp
, seekable
)
1875 self
.encodingheader
= self
.getheader('content-transfer-encoding')
1876 self
.typeheader
= self
.getheader('content-type')
1880 class DocHandler(BaseHTTPServer
.BaseHTTPRequestHandler
):
1881 def send_document(self
, title
, contents
):
1883 self
.send_response(200)
1884 self
.send_header('Content-Type', 'text/html')
1886 self
.wfile
.write(html
.page(title
, contents
))
1887 except IOError: pass
1891 if path
[-5:] == '.html': path
= path
[:-5]
1892 if path
[:1] == '/': path
= path
[1:]
1893 if path
and path
!= '.':
1895 obj
= locate(path
, forceload
=1)
1896 except ErrorDuringImport
, value
:
1897 self
.send_document(path
, html
.escape(str(value
)))
1900 self
.send_document(describe(obj
), html
.document(obj
, path
))
1902 self
.send_document(path
,
1903 'no Python documentation found for %s' % repr(path
))
1905 heading
= html
.heading(
1906 '<big><big><strong>Python: Index of Modules</strong></big></big>',
1907 '#ffffff', '#7799ee')
1908 def bltinlink(name
):
1909 return '<a href="%s.html">%s</a>' % (name
, name
)
1910 names
= filter(lambda x
: x
!= '__main__',
1911 sys
.builtin_module_names
)
1912 contents
= html
.multicolumn(names
, bltinlink
)
1913 indices
= ['<p>' + html
.bigsection(
1914 'Built-in Modules', '#ffffff', '#ee77aa', contents
)]
1917 for dir in sys
.path
:
1918 indices
.append(html
.index(dir, seen
))
1919 contents
= heading
+ join(indices
) + '''<p align=right>
1920 <font color="#909090" face="helvetica, arial"><strong>
1921 pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>'''
1922 self
.send_document('Index of Modules', contents
)
1924 def log_message(self
, *args
): pass
1926 class DocServer(BaseHTTPServer
.HTTPServer
):
1927 def __init__(self
, port
, callback
):
1928 host
= (sys
.platform
== 'mac') and '127.0.0.1' or 'localhost'
1929 self
.address
= ('', port
)
1930 self
.url
= 'http://%s:%d/' % (host
, port
)
1931 self
.callback
= callback
1932 self
.base
.__init
__(self
, self
.address
, self
.handler
)
1934 def serve_until_quit(self
):
1937 while not self
.quit
:
1938 rd
, wr
, ex
= select
.select([self
.socket
.fileno()], [], [], 1)
1939 if rd
: self
.handle_request()
1941 def server_activate(self
):
1942 self
.base
.server_activate(self
)
1943 if self
.callback
: self
.callback(self
)
1945 DocServer
.base
= BaseHTTPServer
.HTTPServer
1946 DocServer
.handler
= DocHandler
1947 DocHandler
.MessageClass
= Message
1950 DocServer(port
, callback
).serve_until_quit()
1951 except (KeyboardInterrupt, select
.error
):
1954 if completer
: completer()
1956 # ----------------------------------------------------- graphical interface
1959 """Graphical interface (starts web server and pops up a control window)."""
1961 def __init__(self
, window
, port
=7464):
1962 self
.window
= window
1967 self
.server_frm
= Tkinter
.Frame(window
)
1968 self
.title_lbl
= Tkinter
.Label(self
.server_frm
,
1969 text
='Starting server...\n ')
1970 self
.open_btn
= Tkinter
.Button(self
.server_frm
,
1971 text
='open browser', command
=self
.open, state
='disabled')
1972 self
.quit_btn
= Tkinter
.Button(self
.server_frm
,
1973 text
='quit serving', command
=self
.quit
, state
='disabled')
1975 self
.search_frm
= Tkinter
.Frame(window
)
1976 self
.search_lbl
= Tkinter
.Label(self
.search_frm
, text
='Search for')
1977 self
.search_ent
= Tkinter
.Entry(self
.search_frm
)
1978 self
.search_ent
.bind('<Return>', self
.search
)
1979 self
.stop_btn
= Tkinter
.Button(self
.search_frm
,
1980 text
='stop', pady
=0, command
=self
.stop
, state
='disabled')
1981 if sys
.platform
== 'win32':
1982 # Trying to hide and show this button crashes under Windows.
1983 self
.stop_btn
.pack(side
='right')
1985 self
.window
.title('pydoc')
1986 self
.window
.protocol('WM_DELETE_WINDOW', self
.quit
)
1987 self
.title_lbl
.pack(side
='top', fill
='x')
1988 self
.open_btn
.pack(side
='left', fill
='x', expand
=1)
1989 self
.quit_btn
.pack(side
='right', fill
='x', expand
=1)
1990 self
.server_frm
.pack(side
='top', fill
='x')
1992 self
.search_lbl
.pack(side
='left')
1993 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
1994 self
.search_frm
.pack(side
='top', fill
='x')
1995 self
.search_ent
.focus_set()
1997 font
= ('helvetica', sys
.platform
== 'win32' and 8 or 10)
1998 self
.result_lst
= Tkinter
.Listbox(window
, font
=font
, height
=6)
1999 self
.result_lst
.bind('<Button-1>', self
.select
)
2000 self
.result_lst
.bind('<Double-Button-1>', self
.goto
)
2001 self
.result_scr
= Tkinter
.Scrollbar(window
,
2002 orient
='vertical', command
=self
.result_lst
.yview
)
2003 self
.result_lst
.config(yscrollcommand
=self
.result_scr
.set)
2005 self
.result_frm
= Tkinter
.Frame(window
)
2006 self
.goto_btn
= Tkinter
.Button(self
.result_frm
,
2007 text
='go to selected', command
=self
.goto
)
2008 self
.hide_btn
= Tkinter
.Button(self
.result_frm
,
2009 text
='hide results', command
=self
.hide
)
2010 self
.goto_btn
.pack(side
='left', fill
='x', expand
=1)
2011 self
.hide_btn
.pack(side
='right', fill
='x', expand
=1)
2013 self
.window
.update()
2014 self
.minwidth
= self
.window
.winfo_width()
2015 self
.minheight
= self
.window
.winfo_height()
2016 self
.bigminheight
= (self
.server_frm
.winfo_reqheight() +
2017 self
.search_frm
.winfo_reqheight() +
2018 self
.result_lst
.winfo_reqheight() +
2019 self
.result_frm
.winfo_reqheight())
2020 self
.bigwidth
, self
.bigheight
= self
.minwidth
, self
.bigminheight
2022 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2023 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2024 self
.window
.tk
.willdispatch()
2028 target
=serve
, args
=(port
, self
.ready
, self
.quit
)).start()
2030 def ready(self
, server
):
2031 self
.server
= server
2032 self
.title_lbl
.config(
2033 text
='Python documentation server at\n' + server
.url
)
2034 self
.open_btn
.config(state
='normal')
2035 self
.quit_btn
.config(state
='normal')
2037 def open(self
, event
=None, url
=None):
2038 url
= url
or self
.server
.url
2041 webbrowser
.open(url
)
2042 except ImportError: # pre-webbrowser.py compatibility
2043 if sys
.platform
== 'win32':
2044 os
.system('start "%s"' % url
)
2045 elif sys
.platform
== 'mac':
2047 except ImportError: pass
2048 else: ic
.launchurl(url
)
2050 rc
= os
.system('netscape -remote "openURL(%s)" &' % url
)
2051 if rc
: os
.system('netscape "%s" &' % url
)
2053 def quit(self
, event
=None):
2055 self
.server
.quit
= 1
2058 def search(self
, event
=None):
2059 key
= self
.search_ent
.get()
2060 self
.stop_btn
.pack(side
='right')
2061 self
.stop_btn
.config(state
='normal')
2062 self
.search_lbl
.config(text
='Searching for "%s"...' % key
)
2063 self
.search_ent
.forget()
2064 self
.search_lbl
.pack(side
='left')
2065 self
.result_lst
.delete(0, 'end')
2066 self
.goto_btn
.config(state
='disabled')
2071 self
.scanner
.quit
= 1
2072 self
.scanner
= ModuleScanner()
2073 threading
.Thread(target
=self
.scanner
.run
,
2074 args
=(self
.update
, key
, self
.done
)).start()
2076 def update(self
, path
, modname
, desc
):
2077 if modname
[-9:] == '.__init__':
2078 modname
= modname
[:-9] + ' (package)'
2079 self
.result_lst
.insert('end',
2080 modname
+ ' - ' + (desc
or '(no description)'))
2082 def stop(self
, event
=None):
2084 self
.scanner
.quit
= 1
2089 self
.search_lbl
.config(text
='Search for')
2090 self
.search_lbl
.pack(side
='left')
2091 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2092 if sys
.platform
!= 'win32': self
.stop_btn
.forget()
2093 self
.stop_btn
.config(state
='disabled')
2095 def select(self
, event
=None):
2096 self
.goto_btn
.config(state
='normal')
2098 def goto(self
, event
=None):
2099 selection
= self
.result_lst
.curselection()
2101 modname
= split(self
.result_lst
.get(selection
[0]))[0]
2102 self
.open(url
=self
.server
.url
+ modname
+ '.html')
2105 if not self
.expanded
: return
2106 self
.result_frm
.forget()
2107 self
.result_scr
.forget()
2108 self
.result_lst
.forget()
2109 self
.bigwidth
= self
.window
.winfo_width()
2110 self
.bigheight
= self
.window
.winfo_height()
2111 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2112 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2116 if self
.expanded
: return
2117 self
.result_frm
.pack(side
='bottom', fill
='x')
2118 self
.result_scr
.pack(side
='right', fill
='y')
2119 self
.result_lst
.pack(side
='top', fill
='both', expand
=1)
2120 self
.window
.wm_geometry('%dx%d' % (self
.bigwidth
, self
.bigheight
))
2121 self
.window
.wm_minsize(self
.minwidth
, self
.bigminheight
)
2124 def hide(self
, event
=None):
2131 # Tk will crash if pythonw.exe has an XP .manifest
2132 # file and the root has is not destroyed explicitly.
2133 # If the problem is ever fixed in Tk, the explicit
2140 except KeyboardInterrupt:
2143 # -------------------------------------------------- command-line interface
2146 return isinstance(x
, str) and find(x
, os
.sep
) >= 0
2149 """Command-line interface (looks at sys.argv to decide what to do)."""
2151 class BadUsage
: pass
2153 # Scripts don't get the current directory in their path by default.
2154 scriptdir
= os
.path
.dirname(sys
.argv
[0])
2155 if scriptdir
in sys
.path
:
2156 sys
.path
.remove(scriptdir
)
2157 sys
.path
.insert(0, '.')
2160 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'gk:p:w')
2163 for opt
, val
in opts
:
2176 print 'pydoc server ready at %s' % server
.url
2178 print 'pydoc server stopped'
2179 serve(port
, ready
, stopped
)
2184 if not args
: raise BadUsage
2186 if ispath(arg
) and not os
.path
.exists(arg
):
2187 print 'file %r does not exist' % arg
2190 if ispath(arg
) and os
.path
.isfile(arg
):
2191 arg
= importfile(arg
)
2193 if ispath(arg
) and os
.path
.isdir(arg
):
2199 except ErrorDuringImport
, value
:
2202 except (getopt
.error
, BadUsage
):
2203 cmd
= os
.path
.basename(sys
.argv
[0])
2204 print """pydoc - the Python documentation tool
2207 Show text documentation on something. <name> may be the name of a
2208 Python keyword, topic, function, module, or package, or a dotted
2209 reference to a class or function within a module or module in a
2210 package. If <name> contains a '%s', it is used as the path to a
2211 Python source file to document. If name is 'keywords', 'topics',
2212 or 'modules', a listing of these things is displayed.
2215 Search for a keyword in the synopsis lines of all available modules.
2218 Start an HTTP server on the given port on the local machine.
2221 Pop up a graphical interface for finding and serving documentation.
2224 Write out the HTML documentation for a module to a file in the current
2225 directory. If <name> contains a '%s', it is treated as a filename; if
2226 it names a directory, documentation is written for all the contents.
2227 """ % (cmd
, os
.sep
, cmd
, cmd
, cmd
, cmd
, os
.sep
)
2229 if __name__
== '__main__': cli()