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
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 _hidden_names
= ('__builtins__', '__doc__', '__file__', '__path__',
164 '__module__', '__name__', '__slots__', '__package__')
165 if name
in _hidden_names
: return 0
166 # Private names are hidden, but special names are displayed.
167 if name
.startswith('__') and name
.endswith('__'): return 1
169 # only document that which the programmer exported in __all__
172 return not name
.startswith('_')
174 def classify_class_attrs(object):
175 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
176 def fixup((name
, kind
, cls
, value
)):
177 if inspect
.isdatadescriptor(value
):
178 kind
= 'data descriptor'
179 return name
, kind
, cls
, value
180 return map(fixup
, inspect
.classify_class_attrs(object))
182 # ----------------------------------------------------- module manipulation
185 """Guess whether a path refers to a package directory."""
186 if os
.path
.isdir(path
):
187 for ext
in ('.py', '.pyc', '.pyo'):
188 if os
.path
.isfile(os
.path
.join(path
, '__init__' + ext
)):
192 def source_synopsis(file):
193 line
= file.readline()
194 while line
[:1] == '#' or not strip(line
):
195 line
= file.readline()
198 if line
[:4] == 'r"""': line
= line
[1:]
199 if line
[:3] == '"""':
201 if line
[-1:] == '\\': line
= line
[:-1]
202 while not strip(line
):
203 line
= file.readline()
205 result
= strip(split(line
, '"""')[0])
209 def synopsis(filename
, cache
={}):
210 """Get the one-line summary out of a module file."""
211 mtime
= os
.stat(filename
).st_mtime
212 lastupdate
, result
= cache
.get(filename
, (0, None))
213 if lastupdate
< mtime
:
214 info
= inspect
.getmoduleinfo(filename
)
216 file = open(filename
)
218 # module can't be opened, so skip it
220 if info
and 'b' in info
[2]: # binary modules have to be imported
221 try: module
= imp
.load_module('__temp__', file, filename
, info
[1:])
223 result
= (module
.__doc
__ or '').splitlines()[0]
224 del sys
.modules
['__temp__']
225 else: # text modules can be directly examined
226 result
= source_synopsis(file)
228 cache
[filename
] = (mtime
, result
)
231 class ErrorDuringImport(Exception):
232 """Errors that occurred while trying to import something to document it."""
233 def __init__(self
, filename
, (exc
, value
, tb
)):
234 self
.filename
= filename
241 if type(exc
) is types
.ClassType
:
243 return 'problem in %s - %s: %s' % (self
.filename
, exc
, self
.value
)
245 def importfile(path
):
246 """Import a Python source file or compiled file given its path."""
247 magic
= imp
.get_magic()
248 file = open(path
, 'r')
249 if file.read(len(magic
)) == magic
:
250 kind
= imp
.PY_COMPILED
254 filename
= os
.path
.basename(path
)
255 name
, ext
= os
.path
.splitext(filename
)
256 file = open(path
, 'r')
258 module
= imp
.load_module(name
, file, path
, (ext
, 'r', kind
))
260 raise ErrorDuringImport(path
, sys
.exc_info())
264 def safeimport(path
, forceload
=0, cache
={}):
265 """Import a module; handle errors; return None if the module isn't found.
267 If the module *is* found but an exception occurs, it's wrapped in an
268 ErrorDuringImport exception and reraised. Unlike __import__, if a
269 package path is specified, the module at the end of the path is returned,
270 not the package at the beginning. If the optional 'forceload' argument
271 is 1, we reload the module from disk (unless it's a dynamic extension)."""
273 # If forceload is 1 and the module has been previously loaded from
274 # disk, we always have to reload the module. Checking the file's
275 # mtime isn't good enough (e.g. the module could contain a class
276 # that inherits from another module that has changed).
277 if forceload
and path
in sys
.modules
:
278 if path
not in sys
.builtin_module_names
:
279 # Avoid simply calling reload() because it leaves names in
280 # the currently loaded module lying around if they're not
281 # defined in the new source file. Instead, remove the
282 # module from sys.modules and re-import. Also remove any
283 # submodules because they won't appear in the newly loaded
284 # module's namespace if they're already in sys.modules.
285 subs
= [m
for m
in sys
.modules
if m
.startswith(path
+ '.')]
286 for key
in [path
] + subs
:
287 # Prevent garbage collection.
288 cache
[key
] = sys
.modules
[key
]
290 module
= __import__(path
)
292 # Did the error occur before or after the module was found?
293 (exc
, value
, tb
) = info
= sys
.exc_info()
294 if path
in sys
.modules
:
295 # An error occurred while executing the imported module.
296 raise ErrorDuringImport(sys
.modules
[path
].__file
__, info
)
297 elif exc
is SyntaxError:
298 # A SyntaxError occurred before we could execute the module.
299 raise ErrorDuringImport(value
.filename
, info
)
300 elif exc
is ImportError and \
301 split(lower(str(value
)))[:2] == ['no', 'module']:
302 # The module was not found.
305 # Some other error occurred during the importing process.
306 raise ErrorDuringImport(path
, sys
.exc_info())
307 for part
in split(path
, '.')[1:]:
308 try: module
= getattr(module
, part
)
309 except AttributeError: return None
312 # ---------------------------------------------------- formatter base class
315 def document(self
, object, name
=None, *args
):
316 """Generate documentation for an object."""
317 args
= (object, name
) + args
318 # 'try' clause is to attempt to handle the possibility that inspect
319 # identifies something in a way that pydoc itself has issues handling;
320 # think 'super' and how it is a descriptor (which raises the exception
321 # by lacking a __name__ attribute) and an instance.
322 if inspect
.isgetsetdescriptor(object): return self
.docdata(*args
)
323 if inspect
.ismemberdescriptor(object): return self
.docdata(*args
)
325 if inspect
.ismodule(object): return self
.docmodule(*args
)
326 if inspect
.isclass(object): return self
.docclass(*args
)
327 if inspect
.isroutine(object): return self
.docroutine(*args
)
328 except AttributeError:
330 if isinstance(object, property): return self
.docproperty(*args
)
331 return self
.docother(*args
)
333 def fail(self
, object, name
=None, *args
):
334 """Raise an exception for unimplemented types."""
335 message
= "don't know how to document object%s of type %s" % (
336 name
and ' ' + repr(name
), type(object).__name
__)
337 raise TypeError, message
339 docmodule
= docclass
= docroutine
= docother
= docproperty
= docdata
= fail
341 def getdocloc(self
, object):
342 """Return the location of module docs or None"""
345 file = inspect
.getabsfile(object)
349 docloc
= os
.environ
.get("PYTHONDOCS",
350 "http://docs.python.org/library")
351 basedir
= os
.path
.join(sys
.exec_prefix
, "lib",
352 "python"+sys
.version
[0:3])
353 if (isinstance(object, type(os
)) and
354 (object.__name
__ in ('errno', 'exceptions', 'gc', 'imp',
355 'marshal', 'posix', 'signal', 'sys',
356 'thread', 'zipimport') or
357 (file.startswith(basedir
) and
358 not file.startswith(os
.path
.join(basedir
, 'site-packages'))))):
359 if docloc
.startswith("http://"):
360 docloc
= "%s/%s" % (docloc
.rstrip("/"), object.__name
__)
362 docloc
= os
.path
.join(docloc
, object.__name
__ + ".html")
367 # -------------------------------------------- HTML documentation generator
369 class HTMLRepr(Repr
):
370 """Class for safely making an HTML representation of a Python object."""
373 self
.maxlist
= self
.maxtuple
= 20
375 self
.maxstring
= self
.maxother
= 100
377 def escape(self
, text
):
378 return replace(text
, '&', '&', '<', '<', '>', '>')
380 def repr(self
, object):
381 return Repr
.repr(self
, object)
383 def repr1(self
, x
, level
):
384 if hasattr(type(x
), '__name__'):
385 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
386 if hasattr(self
, methodname
):
387 return getattr(self
, methodname
)(x
, level
)
388 return self
.escape(cram(stripid(repr(x
)), self
.maxother
))
390 def repr_string(self
, x
, level
):
391 test
= cram(x
, self
.maxstring
)
392 testrepr
= repr(test
)
393 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
394 # Backslashes are only literal in the string and are never
395 # needed to make any special characters, so show a raw string.
396 return 'r' + testrepr
[0] + self
.escape(test
) + testrepr
[0]
397 return re
.sub(r
'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
398 r'<font color="#c040c0">\1</font>',
399 self
.escape(testrepr
))
401 repr_str
= repr_string
403 def repr_instance(self
, x
, level
):
405 return self
.escape(cram(stripid(repr(x
)), self
.maxstring
))
407 return self
.escape('<%s instance>' % x
.__class
__.__name
__)
409 repr_unicode
= repr_string
412 """Formatter class for HTML documentation."""
414 # ------------------------------------------- HTML formatting utilities
416 _repr_instance
= HTMLRepr()
417 repr = _repr_instance
.repr
418 escape
= _repr_instance
.escape
420 def page(self
, title
, contents
):
421 """Format an HTML page."""
423 <!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
424 <html><head><title>Python: %s</title>
425 </head><body bgcolor="#f0f0f8">
427 </body></html>''' % (title
, contents
)
429 def heading(self
, title
, fgcol
, bgcol
, extras
=''):
430 """Format a page heading."""
432 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
434 <td valign=bottom> <br>
435 <font color="%s" face="helvetica, arial"> <br>%s</font></td
436 ><td align=right valign=bottom
437 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
438 ''' % (bgcol
, fgcol
, title
, fgcol
, extras
or ' ')
440 def section(self
, title
, fgcol
, bgcol
, contents
, width
=6,
441 prelude
='', marginalia
=None, gap
=' '):
442 """Format a section with a heading."""
443 if marginalia
is None:
444 marginalia
= '<tt>' + ' ' * width
+ '</tt>'
446 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
448 <td colspan=3 valign=bottom> <br>
449 <font color="%s" face="helvetica, arial">%s</font></td></tr>
450 ''' % (bgcol
, fgcol
, title
)
452 result
= result
+ '''
453 <tr bgcolor="%s"><td rowspan=2>%s</td>
454 <td colspan=2>%s</td></tr>
455 <tr><td>%s</td>''' % (bgcol
, marginalia
, prelude
, gap
)
457 result
= result
+ '''
458 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol
, marginalia
, gap
)
460 return result
+ '\n<td width="100%%">%s</td></tr></table>' % contents
462 def bigsection(self
, title
, *args
):
463 """Format a section with a big heading."""
464 title
= '<big><strong>%s</strong></big>' % title
465 return self
.section(title
, *args
)
467 def preformat(self
, text
):
468 """Format literal preformatted text."""
469 text
= self
.escape(expandtabs(text
))
470 return replace(text
, '\n\n', '\n \n', '\n\n', '\n \n',
471 ' ', ' ', '\n', '<br>\n')
473 def multicolumn(self
, list, format
, cols
=4):
474 """Format a list of items into a multi-column list."""
476 rows
= (len(list)+cols
-1)/cols
477 for col
in range(cols
):
478 result
= result
+ '<td width="%d%%" valign=top>' % (100/cols
)
479 for i
in range(rows
*col
, rows
*col
+rows
):
481 result
= result
+ format(list[i
]) + '<br>\n'
482 result
= result
+ '</td>'
483 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
485 def grey(self
, text
): return '<font color="#909090">%s</font>' % text
487 def namelink(self
, name
, *dicts
):
488 """Make a link for an identifier, given name-to-URL mappings."""
491 return '<a href="%s">%s</a>' % (dict[name
], name
)
494 def classlink(self
, object, modname
):
495 """Make a link for a class."""
496 name
, module
= object.__name
__, sys
.modules
.get(object.__module
__)
497 if hasattr(module
, name
) and getattr(module
, name
) is object:
498 return '<a href="%s.html#%s">%s</a>' % (
499 module
.__name
__, name
, classname(object, modname
))
500 return classname(object, modname
)
502 def modulelink(self
, object):
503 """Make a link for a module."""
504 return '<a href="%s.html">%s</a>' % (object.__name
__, object.__name
__)
506 def modpkglink(self
, (name
, path
, ispackage
, shadowed
)):
507 """Make a link for a module or package to display in an index."""
509 return self
.grey(name
)
511 url
= '%s.%s.html' % (path
, name
)
513 url
= '%s.html' % name
515 text
= '<strong>%s</strong> (package)' % name
518 return '<a href="%s">%s</a>' % (url
, text
)
520 def markup(self
, text
, escape
=None, funcs
={}, classes
={}, methods
={}):
521 """Mark up some plain text, given a context of symbols to look for.
522 Each context dictionary maps object names to anchor names."""
523 escape
= escape
or self
.escape
526 pattern
= re
.compile(r
'\b((http|ftp)://\S+[\w/]|'
531 match
= pattern
.search(text
, here
)
533 start
, end
= match
.span()
534 results
.append(escape(text
[here
:start
]))
536 all
, scheme
, rfc
, pep
, selfdot
, name
= match
.groups()
538 url
= escape(all
).replace('"', '"')
539 results
.append('<a href="%s">%s</a>' % (url
, url
))
541 url
= 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc
)
542 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
544 url
= 'http://www.python.org/dev/peps/pep-%04d/' % int(pep
)
545 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
546 elif text
[end
:end
+1] == '(':
547 results
.append(self
.namelink(name
, methods
, funcs
, classes
))
549 results
.append('self.<strong>%s</strong>' % name
)
551 results
.append(self
.namelink(name
, classes
))
553 results
.append(escape(text
[here
:]))
554 return join(results
, '')
556 # ---------------------------------------------- type-specific routines
558 def formattree(self
, tree
, modname
, parent
=None):
559 """Produce HTML for a class tree as given by inspect.getclasstree()."""
562 if type(entry
) is type(()):
564 result
= result
+ '<dt><font face="helvetica, arial">'
565 result
= result
+ self
.classlink(c
, modname
)
566 if bases
and bases
!= (parent
,):
569 parents
.append(self
.classlink(base
, modname
))
570 result
= result
+ '(' + join(parents
, ', ') + ')'
571 result
= result
+ '\n</font></dt>'
572 elif type(entry
) is type([]):
573 result
= result
+ '<dd>\n%s</dd>\n' % self
.formattree(
575 return '<dl>\n%s</dl>\n' % result
577 def docmodule(self
, object, name
=None, mod
=None, *ignored
):
578 """Produce HTML documentation for a module object."""
579 name
= object.__name
__ # ignore the passed-in name
582 except AttributeError:
584 parts
= split(name
, '.')
586 for i
in range(len(parts
)-1):
588 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
589 (join(parts
[:i
+1], '.'), parts
[i
]))
590 linkedname
= join(links
+ parts
[-1:], '.')
591 head
= '<big><big><strong>%s</strong></big></big>' % linkedname
593 path
= inspect
.getabsfile(object)
595 if sys
.platform
== 'win32':
597 url
= nturl2path
.pathname2url(path
)
598 filelink
= '<a href="file:%s">%s</a>' % (url
, path
)
600 filelink
= '(built-in)'
602 if hasattr(object, '__version__'):
603 version
= str(object.__version
__)
604 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
605 version
= strip(version
[11:-1])
606 info
.append('version %s' % self
.escape(version
))
607 if hasattr(object, '__date__'):
608 info
.append(self
.escape(str(object.__date
__)))
610 head
= head
+ ' (%s)' % join(info
, ', ')
611 docloc
= self
.getdocloc(object)
612 if docloc
is not None:
613 docloc
= '<br><a href="%(docloc)s">Module Docs</a>' % locals()
616 result
= self
.heading(
617 head
, '#ffffff', '#7799ee',
618 '<a href=".">index</a><br>' + filelink
+ docloc
)
620 modules
= inspect
.getmembers(object, inspect
.ismodule
)
622 classes
, cdict
= [], {}
623 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
624 # if __all__ exists, believe it. Otherwise use old heuristic.
625 if (all
is not None or
626 (inspect
.getmodule(value
) or object) is object):
627 if visiblename(key
, all
):
628 classes
.append((key
, value
))
629 cdict
[key
] = cdict
[value
] = '#' + key
630 for key
, value
in classes
:
631 for base
in value
.__bases
__:
632 key
, modname
= base
.__name
__, base
.__module
__
633 module
= sys
.modules
.get(modname
)
634 if modname
!= name
and module
and hasattr(module
, key
):
635 if getattr(module
, key
) is base
:
637 cdict
[key
] = cdict
[base
] = modname
+ '.html#' + key
638 funcs
, fdict
= [], {}
639 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
640 # if __all__ exists, believe it. Otherwise use old heuristic.
641 if (all
is not None or
642 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
643 if visiblename(key
, all
):
644 funcs
.append((key
, value
))
645 fdict
[key
] = '#-' + key
646 if inspect
.isfunction(value
): fdict
[value
] = fdict
[key
]
648 for key
, value
in inspect
.getmembers(object, isdata
):
649 if visiblename(key
, all
):
650 data
.append((key
, value
))
652 doc
= self
.markup(getdoc(object), self
.preformat
, fdict
, cdict
)
653 doc
= doc
and '<tt>%s</tt>' % doc
654 result
= result
+ '<p>%s</p>\n' % doc
656 if hasattr(object, '__path__'):
658 for importer
, modname
, ispkg
in pkgutil
.iter_modules(object.__path
__):
659 modpkgs
.append((modname
, name
, ispkg
, 0))
661 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
662 result
= result
+ self
.bigsection(
663 'Package Contents', '#ffffff', '#aa55cc', contents
)
665 contents
= self
.multicolumn(
666 modules
, lambda (key
, value
), s
=self
: s
.modulelink(value
))
667 result
= result
+ self
.bigsection(
668 'Modules', '#ffffff', '#aa55cc', contents
)
671 classlist
= map(lambda (key
, value
): value
, classes
)
673 self
.formattree(inspect
.getclasstree(classlist
, 1), name
)]
674 for key
, value
in classes
:
675 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
676 result
= result
+ self
.bigsection(
677 'Classes', '#ffffff', '#ee77aa', join(contents
))
680 for key
, value
in funcs
:
681 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
682 result
= result
+ self
.bigsection(
683 'Functions', '#ffffff', '#eeaa77', join(contents
))
686 for key
, value
in data
:
687 contents
.append(self
.document(value
, key
))
688 result
= result
+ self
.bigsection(
689 'Data', '#ffffff', '#55aa55', join(contents
, '<br>\n'))
690 if hasattr(object, '__author__'):
691 contents
= self
.markup(str(object.__author
__), self
.preformat
)
692 result
= result
+ self
.bigsection(
693 'Author', '#ffffff', '#7799ee', contents
)
694 if hasattr(object, '__credits__'):
695 contents
= self
.markup(str(object.__credits
__), self
.preformat
)
696 result
= result
+ self
.bigsection(
697 'Credits', '#ffffff', '#7799ee', contents
)
701 def docclass(self
, object, name
=None, mod
=None, funcs
={}, classes
={},
703 """Produce HTML documentation for a class object."""
704 realname
= object.__name
__
705 name
= name
or realname
706 bases
= object.__bases
__
709 push
= contents
.append
711 # Cute little class to pump out a horizontal rule between sections.
712 class HorizontalRule
:
719 hr
= HorizontalRule()
721 # List the mro, if non-trivial.
722 mro
= deque(inspect
.getmro(object))
725 push('<dl><dt>Method resolution order:</dt>\n')
727 push('<dd>%s</dd>\n' % self
.classlink(base
,
731 def spill(msg
, attrs
, predicate
):
732 ok
, attrs
= _split_list(attrs
, predicate
)
736 for name
, kind
, homecls
, value
in ok
:
737 push(self
.document(getattr(object, name
), name
, mod
,
738 funcs
, classes
, mdict
, object))
742 def spilldescriptors(msg
, attrs
, predicate
):
743 ok
, attrs
= _split_list(attrs
, predicate
)
747 for name
, kind
, homecls
, value
in ok
:
748 push(self
._docdescriptor
(name
, value
, mod
))
751 def spilldata(msg
, attrs
, predicate
):
752 ok
, attrs
= _split_list(attrs
, predicate
)
756 for name
, kind
, homecls
, value
in ok
:
757 base
= self
.docother(getattr(object, name
), name
, mod
)
758 if callable(value
) or inspect
.isdatadescriptor(value
):
759 doc
= getattr(value
, "__doc__", None)
763 push('<dl><dt>%s</dl>\n' % base
)
765 doc
= self
.markup(getdoc(value
), self
.preformat
,
766 funcs
, classes
, mdict
)
767 doc
= '<dd><tt>%s</tt>' % doc
768 push('<dl><dt>%s%s</dl>\n' % (base
, doc
))
772 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
773 classify_class_attrs(object))
775 for key
, kind
, homecls
, value
in attrs
:
776 mdict
[key
] = anchor
= '#' + name
+ '-' + key
777 value
= getattr(object, key
)
779 # The value may not be hashable (e.g., a data attr with
780 # a dict or list value).
781 mdict
[value
] = anchor
787 thisclass
= mro
.popleft()
789 thisclass
= attrs
[0][2]
790 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
792 if thisclass
is __builtin__
.object:
795 elif thisclass
is object:
798 tag
= 'inherited from %s' % self
.classlink(thisclass
,
802 # Sort attrs by name.
804 attrs
.sort(key
=lambda t
: t
[0])
806 attrs
.sort(lambda t1
, t2
: cmp(t1
[0], t2
[0])) # 2.3 compat
808 # Pump out the attrs, segregated by kind.
809 attrs
= spill('Methods %s' % tag
, attrs
,
810 lambda t
: t
[1] == 'method')
811 attrs
= spill('Class methods %s' % tag
, attrs
,
812 lambda t
: t
[1] == 'class method')
813 attrs
= spill('Static methods %s' % tag
, attrs
,
814 lambda t
: t
[1] == 'static method')
815 attrs
= spilldescriptors('Data descriptors %s' % tag
, attrs
,
816 lambda t
: t
[1] == 'data descriptor')
817 attrs
= spilldata('Data and other attributes %s' % tag
, attrs
,
818 lambda t
: t
[1] == 'data')
822 contents
= ''.join(contents
)
825 title
= '<a name="%s">class <strong>%s</strong></a>' % (
828 title
= '<strong>%s</strong> = <a name="%s">class %s</a>' % (
829 name
, name
, realname
)
833 parents
.append(self
.classlink(base
, object.__module
__))
834 title
= title
+ '(%s)' % join(parents
, ', ')
835 doc
= self
.markup(getdoc(object), self
.preformat
, funcs
, classes
, mdict
)
836 doc
= doc
and '<tt>%s<br> </tt>' % doc
838 return self
.section(title
, '#000000', '#ffc8d8', contents
, 3, doc
)
840 def formatvalue(self
, object):
841 """Format an argument default value as text."""
842 return self
.grey('=' + self
.repr(object))
844 def docroutine(self
, object, name
=None, mod
=None,
845 funcs
={}, classes
={}, methods
={}, cl
=None):
846 """Produce HTML documentation for a function or method object."""
847 realname
= object.__name
__
848 name
= name
or realname
849 anchor
= (cl
and cl
.__name
__ or '') + '-' + name
852 if inspect
.ismethod(object):
853 imclass
= object.im_class
855 if imclass
is not cl
:
856 note
= ' from ' + self
.classlink(imclass
, mod
)
858 if object.im_self
is not None:
859 note
= ' method of %s instance' % self
.classlink(
860 object.im_self
.__class
__, mod
)
862 note
= ' unbound %s method' % self
.classlink(imclass
,mod
)
863 object = object.im_func
866 title
= '<a name="%s"><strong>%s</strong></a>' % (anchor
, realname
)
868 if (cl
and realname
in cl
.__dict
__ and
869 cl
.__dict
__[realname
] is object):
870 reallink
= '<a href="#%s">%s</a>' % (
871 cl
.__name
__ + '-' + realname
, realname
)
875 title
= '<a name="%s"><strong>%s</strong></a> = %s' % (
876 anchor
, name
, reallink
)
877 if inspect
.isfunction(object):
878 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
879 argspec
= inspect
.formatargspec(
880 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
881 if realname
== '<lambda>':
882 title
= '<strong>%s</strong> <em>lambda</em> ' % name
883 argspec
= argspec
[1:-1] # remove parentheses
887 decl
= title
+ argspec
+ (note
and self
.grey(
888 '<font face="helvetica, arial">%s</font>' % note
))
891 return '<dl><dt>%s</dt></dl>\n' % decl
894 getdoc(object), self
.preformat
, funcs
, classes
, methods
)
895 doc
= doc
and '<dd><tt>%s</tt></dd>' % doc
896 return '<dl><dt>%s</dt>%s</dl>\n' % (decl
, doc
)
898 def _docdescriptor(self
, name
, value
, mod
):
900 push
= results
.append
903 push('<dl><dt><strong>%s</strong></dt>\n' % name
)
904 if value
.__doc
__ is not None:
905 doc
= self
.markup(getdoc(value
), self
.preformat
)
906 push('<dd><tt>%s</tt></dd>\n' % doc
)
909 return ''.join(results
)
911 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
912 """Produce html documentation for a property."""
913 return self
._docdescriptor
(name
, object, mod
)
915 def docother(self
, object, name
=None, mod
=None, *ignored
):
916 """Produce HTML documentation for a data object."""
917 lhs
= name
and '<strong>%s</strong> = ' % name
or ''
918 return lhs
+ self
.repr(object)
920 def docdata(self
, object, name
=None, mod
=None, cl
=None):
921 """Produce html documentation for a data descriptor."""
922 return self
._docdescriptor
(name
, object, mod
)
924 def index(self
, dir, shadowed
=None):
925 """Generate an HTML index for a directory of modules."""
927 if shadowed
is None: shadowed
= {}
928 for importer
, name
, ispkg
in pkgutil
.iter_modules([dir]):
929 modpkgs
.append((name
, '', ispkg
, name
in shadowed
))
933 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
934 return self
.bigsection(dir, '#ffffff', '#ee77aa', contents
)
936 # -------------------------------------------- text documentation generator
938 class TextRepr(Repr
):
939 """Class for safely making a text representation of a Python object."""
942 self
.maxlist
= self
.maxtuple
= 20
944 self
.maxstring
= self
.maxother
= 100
946 def repr1(self
, x
, level
):
947 if hasattr(type(x
), '__name__'):
948 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
949 if hasattr(self
, methodname
):
950 return getattr(self
, methodname
)(x
, level
)
951 return cram(stripid(repr(x
)), self
.maxother
)
953 def repr_string(self
, x
, level
):
954 test
= cram(x
, self
.maxstring
)
955 testrepr
= repr(test
)
956 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
957 # Backslashes are only literal in the string and are never
958 # needed to make any special characters, so show a raw string.
959 return 'r' + testrepr
[0] + test
+ testrepr
[0]
962 repr_str
= repr_string
964 def repr_instance(self
, x
, level
):
966 return cram(stripid(repr(x
)), self
.maxstring
)
968 return '<%s instance>' % x
.__class
__.__name
__
971 """Formatter class for text documentation."""
973 # ------------------------------------------- text formatting utilities
975 _repr_instance
= TextRepr()
976 repr = _repr_instance
.repr
978 def bold(self
, text
):
979 """Format a string in bold by overstriking."""
980 return join(map(lambda ch
: ch
+ '\b' + ch
, text
), '')
982 def indent(self
, text
, prefix
=' '):
983 """Indent text by prepending a given prefix to each line."""
984 if not text
: return ''
985 lines
= split(text
, '\n')
986 lines
= map(lambda line
, prefix
=prefix
: prefix
+ line
, lines
)
987 if lines
: lines
[-1] = rstrip(lines
[-1])
988 return join(lines
, '\n')
990 def section(self
, title
, contents
):
991 """Format a section with a given heading."""
992 return self
.bold(title
) + '\n' + rstrip(self
.indent(contents
)) + '\n\n'
994 # ---------------------------------------------- type-specific routines
996 def formattree(self
, tree
, modname
, parent
=None, prefix
=''):
997 """Render in text a class tree as returned by inspect.getclasstree()."""
1000 if type(entry
) is type(()):
1002 result
= result
+ prefix
+ classname(c
, modname
)
1003 if bases
and bases
!= (parent
,):
1004 parents
= map(lambda c
, m
=modname
: classname(c
, m
), bases
)
1005 result
= result
+ '(%s)' % join(parents
, ', ')
1006 result
= result
+ '\n'
1007 elif type(entry
) is type([]):
1008 result
= result
+ self
.formattree(
1009 entry
, modname
, c
, prefix
+ ' ')
1012 def docmodule(self
, object, name
=None, mod
=None):
1013 """Produce text documentation for a given module object."""
1014 name
= object.__name
__ # ignore the passed-in name
1015 synop
, desc
= splitdoc(getdoc(object))
1016 result
= self
.section('NAME', name
+ (synop
and ' - ' + synop
))
1019 all
= object.__all
__
1020 except AttributeError:
1024 file = inspect
.getabsfile(object)
1027 result
= result
+ self
.section('FILE', file)
1029 docloc
= self
.getdocloc(object)
1030 if docloc
is not None:
1031 result
= result
+ self
.section('MODULE DOCS', docloc
)
1034 result
= result
+ self
.section('DESCRIPTION', desc
)
1037 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
1038 # if __all__ exists, believe it. Otherwise use old heuristic.
1040 or (inspect
.getmodule(value
) or object) is object):
1041 if visiblename(key
, all
):
1042 classes
.append((key
, value
))
1044 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
1045 # if __all__ exists, believe it. Otherwise use old heuristic.
1046 if (all
is not None or
1047 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
1048 if visiblename(key
, all
):
1049 funcs
.append((key
, value
))
1051 for key
, value
in inspect
.getmembers(object, isdata
):
1052 if visiblename(key
, all
):
1053 data
.append((key
, value
))
1056 modpkgs_names
= set()
1057 if hasattr(object, '__path__'):
1058 for importer
, modname
, ispkg
in pkgutil
.iter_modules(object.__path
__):
1059 modpkgs_names
.add(modname
)
1061 modpkgs
.append(modname
+ ' (package)')
1063 modpkgs
.append(modname
)
1066 result
= result
+ self
.section(
1067 'PACKAGE CONTENTS', join(modpkgs
, '\n'))
1069 # Detect submodules as sometimes created by C extensions
1071 for key
, value
in inspect
.getmembers(object, inspect
.ismodule
):
1072 if value
.__name
__.startswith(name
+ '.') and key
not in modpkgs_names
:
1073 submodules
.append(key
)
1076 result
= result
+ self
.section(
1077 'SUBMODULES', join(submodules
, '\n'))
1080 classlist
= map(lambda (key
, value
): value
, classes
)
1081 contents
= [self
.formattree(
1082 inspect
.getclasstree(classlist
, 1), name
)]
1083 for key
, value
in classes
:
1084 contents
.append(self
.document(value
, key
, name
))
1085 result
= result
+ self
.section('CLASSES', join(contents
, '\n'))
1089 for key
, value
in funcs
:
1090 contents
.append(self
.document(value
, key
, name
))
1091 result
= result
+ self
.section('FUNCTIONS', join(contents
, '\n'))
1095 for key
, value
in data
:
1096 contents
.append(self
.docother(value
, key
, name
, maxlen
=70))
1097 result
= result
+ self
.section('DATA', join(contents
, '\n'))
1099 if hasattr(object, '__version__'):
1100 version
= str(object.__version
__)
1101 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
1102 version
= strip(version
[11:-1])
1103 result
= result
+ self
.section('VERSION', version
)
1104 if hasattr(object, '__date__'):
1105 result
= result
+ self
.section('DATE', str(object.__date
__))
1106 if hasattr(object, '__author__'):
1107 result
= result
+ self
.section('AUTHOR', str(object.__author
__))
1108 if hasattr(object, '__credits__'):
1109 result
= result
+ self
.section('CREDITS', str(object.__credits
__))
1112 def docclass(self
, object, name
=None, mod
=None):
1113 """Produce text documentation for a given class object."""
1114 realname
= object.__name
__
1115 name
= name
or realname
1116 bases
= object.__bases
__
1118 def makename(c
, m
=object.__module
__):
1119 return classname(c
, m
)
1121 if name
== realname
:
1122 title
= 'class ' + self
.bold(realname
)
1124 title
= self
.bold(name
) + ' = class ' + realname
1126 parents
= map(makename
, bases
)
1127 title
= title
+ '(%s)' % join(parents
, ', ')
1129 doc
= getdoc(object)
1130 contents
= doc
and [doc
+ '\n'] or []
1131 push
= contents
.append
1133 # List the mro, if non-trivial.
1134 mro
= deque(inspect
.getmro(object))
1136 push("Method resolution order:")
1138 push(' ' + makename(base
))
1141 # Cute little class to pump out a horizontal rule between sections.
1142 class HorizontalRule
:
1149 hr
= HorizontalRule()
1151 def spill(msg
, attrs
, predicate
):
1152 ok
, attrs
= _split_list(attrs
, predicate
)
1156 for name
, kind
, homecls
, value
in ok
:
1157 push(self
.document(getattr(object, name
),
1161 def spilldescriptors(msg
, attrs
, predicate
):
1162 ok
, attrs
= _split_list(attrs
, predicate
)
1166 for name
, kind
, homecls
, value
in ok
:
1167 push(self
._docdescriptor
(name
, value
, mod
))
1170 def spilldata(msg
, attrs
, predicate
):
1171 ok
, attrs
= _split_list(attrs
, predicate
)
1175 for name
, kind
, homecls
, value
in ok
:
1176 if callable(value
) or inspect
.isdatadescriptor(value
):
1180 push(self
.docother(getattr(object, name
),
1181 name
, mod
, maxlen
=70, doc
=doc
) + '\n')
1184 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
1185 classify_class_attrs(object))
1188 thisclass
= mro
.popleft()
1190 thisclass
= attrs
[0][2]
1191 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
1193 if thisclass
is __builtin__
.object:
1196 elif thisclass
is object:
1197 tag
= "defined here"
1199 tag
= "inherited from %s" % classname(thisclass
,
1202 # Sort attrs by name.
1205 # Pump out the attrs, segregated by kind.
1206 attrs
= spill("Methods %s:\n" % tag
, attrs
,
1207 lambda t
: t
[1] == 'method')
1208 attrs
= spill("Class methods %s:\n" % tag
, attrs
,
1209 lambda t
: t
[1] == 'class method')
1210 attrs
= spill("Static methods %s:\n" % tag
, attrs
,
1211 lambda t
: t
[1] == 'static method')
1212 attrs
= spilldescriptors("Data descriptors %s:\n" % tag
, attrs
,
1213 lambda t
: t
[1] == 'data descriptor')
1214 attrs
= spilldata("Data and other attributes %s:\n" % tag
, attrs
,
1215 lambda t
: t
[1] == 'data')
1219 contents
= '\n'.join(contents
)
1222 return title
+ '\n' + self
.indent(rstrip(contents
), ' | ') + '\n'
1224 def formatvalue(self
, object):
1225 """Format an argument default value as text."""
1226 return '=' + self
.repr(object)
1228 def docroutine(self
, object, name
=None, mod
=None, cl
=None):
1229 """Produce text documentation for a function or method object."""
1230 realname
= object.__name
__
1231 name
= name
or realname
1234 if inspect
.ismethod(object):
1235 imclass
= object.im_class
1237 if imclass
is not cl
:
1238 note
= ' from ' + classname(imclass
, mod
)
1240 if object.im_self
is not None:
1241 note
= ' method of %s instance' % classname(
1242 object.im_self
.__class
__, mod
)
1244 note
= ' unbound %s method' % classname(imclass
,mod
)
1245 object = object.im_func
1247 if name
== realname
:
1248 title
= self
.bold(realname
)
1250 if (cl
and realname
in cl
.__dict
__ and
1251 cl
.__dict
__[realname
] is object):
1253 title
= self
.bold(name
) + ' = ' + realname
1254 if inspect
.isfunction(object):
1255 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
1256 argspec
= inspect
.formatargspec(
1257 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
1258 if realname
== '<lambda>':
1259 title
= self
.bold(name
) + ' lambda '
1260 argspec
= argspec
[1:-1] # remove parentheses
1263 decl
= title
+ argspec
+ note
1268 doc
= getdoc(object) or ''
1269 return decl
+ '\n' + (doc
and rstrip(self
.indent(doc
)) + '\n')
1271 def _docdescriptor(self
, name
, value
, mod
):
1273 push
= results
.append
1276 push(self
.bold(name
))
1278 doc
= getdoc(value
) or ''
1280 push(self
.indent(doc
))
1282 return ''.join(results
)
1284 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
1285 """Produce text documentation for a property."""
1286 return self
._docdescriptor
(name
, object, mod
)
1288 def docdata(self
, object, name
=None, mod
=None, cl
=None):
1289 """Produce text documentation for a data descriptor."""
1290 return self
._docdescriptor
(name
, object, mod
)
1292 def docother(self
, object, name
=None, mod
=None, parent
=None, maxlen
=None, doc
=None):
1293 """Produce text documentation for a data object."""
1294 repr = self
.repr(object)
1296 line
= (name
and name
+ ' = ' or '') + repr
1297 chop
= maxlen
- len(line
)
1298 if chop
< 0: repr = repr[:chop
] + '...'
1299 line
= (name
and self
.bold(name
) + ' = ' or '') + repr
1301 line
+= '\n' + self
.indent(str(doc
))
1304 # --------------------------------------------------------- user interfaces
1307 """The first time this is called, determine what kind of pager to use."""
1313 """Decide what method to use for paging through text."""
1314 if type(sys
.stdout
) is not types
.FileType
:
1316 if not sys
.stdin
.isatty() or not sys
.stdout
.isatty():
1318 if 'PAGER' in os
.environ
:
1319 if sys
.platform
== 'win32': # pipes completely broken in Windows
1320 return lambda text
: tempfilepager(plain(text
), os
.environ
['PAGER'])
1321 elif os
.environ
.get('TERM') in ('dumb', 'emacs'):
1322 return lambda text
: pipepager(plain(text
), os
.environ
['PAGER'])
1324 return lambda text
: pipepager(text
, os
.environ
['PAGER'])
1325 if os
.environ
.get('TERM') in ('dumb', 'emacs'):
1327 if sys
.platform
== 'win32' or sys
.platform
.startswith('os2'):
1328 return lambda text
: tempfilepager(plain(text
), 'more <')
1329 if hasattr(os
, 'system') and os
.system('(less) 2>/dev/null') == 0:
1330 return lambda text
: pipepager(text
, 'less')
1333 (fd
, filename
) = tempfile
.mkstemp()
1336 if hasattr(os
, 'system') and os
.system('more "%s"' % filename
) == 0:
1337 return lambda text
: pipepager(text
, 'more')
1344 """Remove boldface formatting from text."""
1345 return re
.sub('.\b', '', text
)
1347 def pipepager(text
, cmd
):
1348 """Page through text by feeding it to another program."""
1349 pipe
= os
.popen(cmd
, 'w')
1354 pass # Ignore broken pipes caused by quitting the pager program.
1356 def tempfilepager(text
, cmd
):
1357 """Page through text by invoking a program on a temporary file."""
1359 filename
= tempfile
.mktemp()
1360 file = open(filename
, 'w')
1364 os
.system(cmd
+ ' "' + filename
+ '"')
1369 """Page through text on a text terminal."""
1370 lines
= split(plain(text
), '\n')
1373 fd
= sys
.stdin
.fileno()
1374 old
= tty
.tcgetattr(fd
)
1376 getchar
= lambda: sys
.stdin
.read(1)
1377 except (ImportError, AttributeError):
1379 getchar
= lambda: sys
.stdin
.readline()[:-1][:1]
1382 r
= inc
= os
.environ
.get('LINES', 25) - 1
1383 sys
.stdout
.write(join(lines
[:inc
], '\n') + '\n')
1385 sys
.stdout
.write('-- more --')
1390 sys
.stdout
.write('\r \r')
1392 elif c
in ('\r', '\n'):
1393 sys
.stdout
.write('\r \r' + lines
[r
] + '\n')
1396 if c
in ('b', 'B', '\x1b'):
1399 sys
.stdout
.write('\n' + join(lines
[r
:r
+inc
], '\n') + '\n')
1404 tty
.tcsetattr(fd
, tty
.TCSAFLUSH
, old
)
1406 def plainpager(text
):
1407 """Simply print unformatted text. This is the ultimate fallback."""
1408 sys
.stdout
.write(plain(text
))
1410 def describe(thing
):
1411 """Produce a short description of the given thing."""
1412 if inspect
.ismodule(thing
):
1413 if thing
.__name
__ in sys
.builtin_module_names
:
1414 return 'built-in module ' + thing
.__name
__
1415 if hasattr(thing
, '__path__'):
1416 return 'package ' + thing
.__name
__
1418 return 'module ' + thing
.__name
__
1419 if inspect
.isbuiltin(thing
):
1420 return 'built-in function ' + thing
.__name
__
1421 if inspect
.isgetsetdescriptor(thing
):
1422 return 'getset descriptor %s.%s.%s' % (
1423 thing
.__objclass
__.__module
__, thing
.__objclass
__.__name
__,
1425 if inspect
.ismemberdescriptor(thing
):
1426 return 'member descriptor %s.%s.%s' % (
1427 thing
.__objclass
__.__module
__, thing
.__objclass
__.__name
__,
1429 if inspect
.isclass(thing
):
1430 return 'class ' + thing
.__name
__
1431 if inspect
.isfunction(thing
):
1432 return 'function ' + thing
.__name
__
1433 if inspect
.ismethod(thing
):
1434 return 'method ' + thing
.__name
__
1435 if type(thing
) is types
.InstanceType
:
1436 return 'instance of ' + thing
.__class
__.__name
__
1437 return type(thing
).__name
__
1439 def locate(path
, forceload
=0):
1440 """Locate an object by name or dotted path, importing as necessary."""
1441 parts
= [part
for part
in split(path
, '.') if part
]
1443 while n
< len(parts
):
1444 nextmodule
= safeimport(join(parts
[:n
+1], '.'), forceload
)
1445 if nextmodule
: module
, n
= nextmodule
, n
+ 1
1449 for part
in parts
[n
:]:
1450 try: object = getattr(object, part
)
1451 except AttributeError: return None
1454 if hasattr(__builtin__
, path
):
1455 return getattr(__builtin__
, path
)
1457 # --------------------------------------- interactive interpreter interface
1462 class _OldStyleClass
: pass
1463 _OLD_INSTANCE_TYPE
= type(_OldStyleClass())
1465 def resolve(thing
, forceload
=0):
1466 """Given an object or a path to an object, get the object and its name."""
1467 if isinstance(thing
, str):
1468 object = locate(thing
, forceload
)
1470 raise ImportError, 'no Python documentation found for %r' % thing
1471 return object, thing
1473 return thing
, getattr(thing
, '__name__', None)
1475 def render_doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1476 """Render text documentation, given an object or a path to an object."""
1477 object, name
= resolve(thing
, forceload
)
1478 desc
= describe(object)
1479 module
= inspect
.getmodule(object)
1480 if name
and '.' in name
:
1481 desc
+= ' in ' + name
[:name
.rfind('.')]
1482 elif module
and module
is not object:
1483 desc
+= ' in module ' + module
.__name
__
1484 if type(object) is _OLD_INSTANCE_TYPE
:
1485 # If the passed object is an instance of an old-style class,
1486 # document its available methods instead of its value.
1487 object = object.__class
__
1488 elif not (inspect
.ismodule(object) or
1489 inspect
.isclass(object) or
1490 inspect
.isroutine(object) or
1491 inspect
.isgetsetdescriptor(object) or
1492 inspect
.ismemberdescriptor(object) or
1493 isinstance(object, property)):
1494 # If the passed object is a piece of data or an instance,
1495 # document its available methods instead of its value.
1496 object = type(object)
1498 return title
% desc
+ '\n\n' + text
.document(object, name
)
1500 def doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1501 """Display text documentation, given an object or a path to an object."""
1503 pager(render_doc(thing
, title
, forceload
))
1504 except (ImportError, ErrorDuringImport
), value
:
1507 def writedoc(thing
, forceload
=0):
1508 """Write HTML documentation to a file in the current directory."""
1510 object, name
= resolve(thing
, forceload
)
1511 page
= html
.page(describe(object), html
.document(object, name
))
1512 file = open(name
+ '.html', 'w')
1515 print 'wrote', name
+ '.html'
1516 except (ImportError, ErrorDuringImport
), value
:
1519 def writedocs(dir, pkgpath
='', done
=None):
1520 """Write out HTML documentation for all modules in a directory tree."""
1521 if done
is None: done
= {}
1522 for importer
, modname
, ispkg
in pkgutil
.walk_packages([dir], pkgpath
):
1528 # These dictionaries map a topic name to either an alias, or a tuple
1529 # (label, seealso-items). The "label" is the label of the corresponding
1530 # section in the .rst file under Doc/ and an index into the dictionary
1531 # in pydoc_topics.py.
1533 # CAUTION: if you change one of these dictionaries, be sure to adapt the
1534 # list of needed labels in Doc/tools/sphinxext/pyspecific.py and
1535 # regenerate the pydoc_topics.py file by running
1537 # in Doc/ and copying the output file into the Lib/ directory.
1542 'assert': ('assert', ''),
1543 'break': ('break', 'while for'),
1544 'class': ('class', 'CLASSES SPECIALMETHODS'),
1545 'continue': ('continue', 'while for'),
1546 'def': ('function', ''),
1547 'del': ('del', 'BASICMETHODS'),
1549 'else': ('else', 'while for'),
1551 'exec': ('exec', ''),
1552 'finally': 'finally',
1553 'for': ('for', 'break continue while'),
1555 'global': ('global', 'NAMESPACES'),
1556 'if': ('if', 'TRUTHVALUE'),
1557 'import': ('import', 'MODULES'),
1558 'in': ('in', 'SEQUENCEMETHODS2'),
1560 'lambda': ('lambda', 'FUNCTIONS'),
1563 'pass': ('pass', ''),
1564 'print': ('print', ''),
1565 'raise': ('raise', 'EXCEPTIONS'),
1566 'return': ('return', 'FUNCTIONS'),
1567 'try': ('try', 'EXCEPTIONS'),
1568 'while': ('while', 'break continue if TRUTHVALUE'),
1569 'with': ('with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1570 'yield': ('yield', ''),
1574 'TYPES': ('types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS '
1575 'FUNCTIONS CLASSES MODULES FILES inspect'),
1576 'STRINGS': ('strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING '
1578 'STRINGMETHODS': ('string-methods', 'STRINGS FORMATTING'),
1579 'FORMATTING': ('formatstrings', 'OPERATORS'),
1580 'UNICODE': ('strings', 'encodings unicode SEQUENCES STRINGMETHODS '
1581 'FORMATTING TYPES'),
1582 'NUMBERS': ('numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1583 'INTEGER': ('integers', 'int range'),
1584 'FLOAT': ('floating', 'float math'),
1585 'COMPLEX': ('imaginary', 'complex cmath'),
1586 'SEQUENCES': ('typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1587 'MAPPINGS': 'DICTIONARIES',
1588 'FUNCTIONS': ('typesfunctions', 'def TYPES'),
1589 'METHODS': ('typesmethods', 'class def CLASSES TYPES'),
1590 'CODEOBJECTS': ('bltin-code-objects', 'compile FUNCTIONS TYPES'),
1591 'TYPEOBJECTS': ('bltin-type-objects', 'types TYPES'),
1592 'FRAMEOBJECTS': 'TYPES',
1593 'TRACEBACKS': 'TYPES',
1594 'NONE': ('bltin-null-object', ''),
1595 'ELLIPSIS': ('bltin-ellipsis-object', 'SLICINGS'),
1596 'FILES': ('bltin-file-objects', ''),
1597 'SPECIALATTRIBUTES': ('specialattrs', ''),
1598 'CLASSES': ('types', 'class SPECIALMETHODS PRIVATENAMES'),
1599 'MODULES': ('typesmodules', 'import'),
1600 'PACKAGES': 'import',
1601 'EXPRESSIONS': ('operator-summary', 'lambda or and not in is BOOLEAN '
1602 'COMPARISON BITWISE SHIFTING BINARY FORMATTING POWER '
1603 'UNARY ATTRIBUTES SUBSCRIPTS SLICINGS CALLS TUPLES '
1604 'LISTS DICTIONARIES BACKQUOTES'),
1605 'OPERATORS': 'EXPRESSIONS',
1606 'PRECEDENCE': 'EXPRESSIONS',
1607 'OBJECTS': ('objects', 'TYPES'),
1608 'SPECIALMETHODS': ('specialnames', 'BASICMETHODS ATTRIBUTEMETHODS '
1609 'CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS '
1610 'SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1611 'BASICMETHODS': ('customization', 'cmp hash repr str SPECIALMETHODS'),
1612 'ATTRIBUTEMETHODS': ('attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1613 'CALLABLEMETHODS': ('callable-types', 'CALLS SPECIALMETHODS'),
1614 'SEQUENCEMETHODS1': ('sequence-types', 'SEQUENCES SEQUENCEMETHODS2 '
1616 'SEQUENCEMETHODS2': ('sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 '
1618 'MAPPINGMETHODS': ('sequence-types', 'MAPPINGS SPECIALMETHODS'),
1619 'NUMBERMETHODS': ('numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT '
1621 'EXECUTION': ('execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1622 'NAMESPACES': ('naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1623 'DYNAMICFEATURES': ('dynamic-features', ''),
1624 'SCOPING': 'NAMESPACES',
1625 'FRAMES': 'NAMESPACES',
1626 'EXCEPTIONS': ('exceptions', 'try except finally raise'),
1627 'COERCIONS': ('coercion-rules','CONVERSIONS'),
1628 'CONVERSIONS': ('conversions', 'COERCIONS'),
1629 'IDENTIFIERS': ('identifiers', 'keywords SPECIALIDENTIFIERS'),
1630 'SPECIALIDENTIFIERS': ('id-classes', ''),
1631 'PRIVATENAMES': ('atom-identifiers', ''),
1632 'LITERALS': ('atom-literals', 'STRINGS BACKQUOTES NUMBERS '
1633 'TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1634 'TUPLES': 'SEQUENCES',
1635 'TUPLELITERALS': ('exprlists', 'TUPLES LITERALS'),
1636 'LISTS': ('typesseq-mutable', 'LISTLITERALS'),
1637 'LISTLITERALS': ('lists', 'LISTS LITERALS'),
1638 'DICTIONARIES': ('typesmapping', 'DICTIONARYLITERALS'),
1639 'DICTIONARYLITERALS': ('dict', 'DICTIONARIES LITERALS'),
1640 'BACKQUOTES': ('string-conversions', 'repr str STRINGS LITERALS'),
1641 'ATTRIBUTES': ('attribute-references', 'getattr hasattr setattr '
1642 'ATTRIBUTEMETHODS'),
1643 'SUBSCRIPTS': ('subscriptions', 'SEQUENCEMETHODS1'),
1644 'SLICINGS': ('slicings', 'SEQUENCEMETHODS2'),
1645 'CALLS': ('calls', 'EXPRESSIONS'),
1646 'POWER': ('power', 'EXPRESSIONS'),
1647 'UNARY': ('unary', 'EXPRESSIONS'),
1648 'BINARY': ('binary', 'EXPRESSIONS'),
1649 'SHIFTING': ('shifting', 'EXPRESSIONS'),
1650 'BITWISE': ('bitwise', 'EXPRESSIONS'),
1651 'COMPARISON': ('comparisons', 'EXPRESSIONS BASICMETHODS'),
1652 'BOOLEAN': ('booleans', 'EXPRESSIONS TRUTHVALUE'),
1653 'ASSERTION': 'assert',
1654 'ASSIGNMENT': ('assignment', 'AUGMENTEDASSIGNMENT'),
1655 'AUGMENTEDASSIGNMENT': ('augassign', 'NUMBERMETHODS'),
1657 'PRINTING': 'print',
1658 'RETURNING': 'return',
1659 'IMPORTING': 'import',
1660 'CONDITIONAL': 'if',
1661 'LOOPING': ('compound', 'for while break continue'),
1662 'TRUTHVALUE': ('truth', 'if while and or not BASICMETHODS'),
1663 'DEBUGGING': ('debugger', 'pdb'),
1664 'CONTEXTMANAGERS': ('context-managers', 'with'),
1667 def __init__(self
, input, output
):
1669 self
.output
= output
1672 if inspect
.stack()[1][3] == '?':
1675 return '<pydoc.Helper instance>'
1677 def __call__(self
, request
=None):
1678 if request
is not None:
1683 self
.output
.write('''
1684 You are now leaving help and returning to the Python interpreter.
1685 If you want to ask for help on a particular object directly from the
1686 interpreter, you can type "help(object)". Executing "help('string')"
1687 has the same effect as typing a particular string at the help> prompt.
1691 self
.output
.write('\n')
1694 request
= self
.getline('help> ')
1695 if not request
: break
1696 except (KeyboardInterrupt, EOFError):
1698 request
= strip(replace(request
, '"', '', "'", ''))
1699 if lower(request
) in ('q', 'quit'): break
1702 def getline(self
, prompt
):
1703 """Read one line, using raw_input when available."""
1704 if self
.input is sys
.stdin
:
1705 return raw_input(prompt
)
1707 self
.output
.write(prompt
)
1709 return self
.input.readline()
1711 def help(self
, request
):
1712 if type(request
) is type(''):
1713 if request
== 'help': self
.intro()
1714 elif request
== 'keywords': self
.listkeywords()
1715 elif request
== 'topics': self
.listtopics()
1716 elif request
== 'modules': self
.listmodules()
1717 elif request
[:8] == 'modules ':
1718 self
.listmodules(split(request
)[1])
1719 elif request
in self
.keywords
: self
.showtopic(request
)
1720 elif request
in self
.topics
: self
.showtopic(request
)
1721 elif request
: doc(request
, 'Help on %s:')
1722 elif isinstance(request
, Helper
): self()
1723 else: doc(request
, 'Help on %s:')
1724 self
.output
.write('\n')
1727 self
.output
.write('''
1728 Welcome to Python %s! This is the online help utility.
1730 If this is your first time using Python, you should definitely check out
1731 the tutorial on the Internet at http://docs.python.org/tutorial/.
1733 Enter the name of any module, keyword, or topic to get help on writing
1734 Python programs and using Python modules. To quit this help utility and
1735 return to the interpreter, just type "quit".
1737 To get a list of available modules, keywords, or topics, type "modules",
1738 "keywords", or "topics". Each module also comes with a one-line summary
1739 of what it does; to list the modules whose summaries contain a given word
1740 such as "spam", type "modules spam".
1741 ''' % sys
.version
[:3])
1743 def list(self
, items
, columns
=4, width
=80):
1746 colw
= width
/ columns
1747 rows
= (len(items
) + columns
- 1) / columns
1748 for row
in range(rows
):
1749 for col
in range(columns
):
1750 i
= col
* rows
+ row
1752 self
.output
.write(items
[i
])
1753 if col
< columns
- 1:
1754 self
.output
.write(' ' + ' ' * (colw
-1 - len(items
[i
])))
1755 self
.output
.write('\n')
1757 def listkeywords(self
):
1758 self
.output
.write('''
1759 Here is a list of the Python keywords. Enter any keyword to get more help.
1762 self
.list(self
.keywords
.keys())
1764 def listtopics(self
):
1765 self
.output
.write('''
1766 Here is a list of available topics. Enter any topic name to get more help.
1769 self
.list(self
.topics
.keys())
1771 def showtopic(self
, topic
):
1775 self
.output
.write('''
1776 Sorry, topic and keyword documentation is not available because the
1777 module "pydoc_topics" could not be found.
1780 target
= self
.topics
.get(topic
, self
.keywords
.get(topic
))
1782 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1784 if type(target
) is type(''):
1785 return self
.showtopic(target
)
1787 label
, xrefs
= target
1789 doc
= pydoc_topics
.topics
[label
]
1791 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1793 pager(strip(doc
) + '\n')
1795 import StringIO
, formatter
1796 buffer = StringIO
.StringIO()
1797 formatter
.DumbWriter(buffer).send_flowing_data(
1798 'Related help topics: ' + join(split(xrefs
), ', ') + '\n')
1799 self
.output
.write('\n%s\n' % buffer.getvalue())
1801 def listmodules(self
, key
=''):
1803 self
.output
.write('''
1804 Here is a list of matching modules. Enter any module name to get more help.
1809 self
.output
.write('''
1810 Please wait a moment while I gather a list of all available modules...
1814 def callback(path
, modname
, desc
, modules
=modules
):
1815 if modname
and modname
[-9:] == '.__init__':
1816 modname
= modname
[:-9] + ' (package)'
1817 if find(modname
, '.') < 0:
1818 modules
[modname
] = 1
1819 def onerror(modname
):
1820 callback(None, modname
, None)
1821 ModuleScanner().run(callback
, onerror
=onerror
)
1822 self
.list(modules
.keys())
1823 self
.output
.write('''
1824 Enter any module name to get more help. Or, type "modules spam" to search
1825 for modules whose descriptions contain the word "spam".
1828 help = Helper(sys
.stdin
, sys
.stdout
)
1831 """A generic tree iterator."""
1832 def __init__(self
, roots
, children
, descendp
):
1833 self
.roots
= roots
[:]
1835 self
.children
= children
1836 self
.descendp
= descendp
1842 root
= self
.roots
.pop(0)
1843 self
.state
= [(root
, self
.children(root
))]
1844 node
, children
= self
.state
[-1]
1848 child
= children
.pop(0)
1849 if self
.descendp(child
):
1850 self
.state
.append((child
, self
.children(child
)))
1854 class ModuleScanner
:
1855 """An interruptible scanner that searches module synopses."""
1857 def run(self
, callback
, key
=None, completer
=None, onerror
=None):
1858 if key
: key
= lower(key
)
1862 for modname
in sys
.builtin_module_names
:
1863 if modname
!= '__main__':
1866 callback(None, modname
, '')
1868 desc
= split(__import__(modname
).__doc
__ or '', '\n')[0]
1869 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1870 callback(None, modname
, desc
)
1872 for importer
, modname
, ispkg
in pkgutil
.walk_packages(onerror
=onerror
):
1876 callback(None, modname
, '')
1878 loader
= importer
.find_module(modname
)
1879 if hasattr(loader
,'get_source'):
1881 desc
= source_synopsis(
1882 StringIO
.StringIO(loader
.get_source(modname
))
1884 if hasattr(loader
,'get_filename'):
1885 path
= loader
.get_filename(modname
)
1889 module
= loader
.load_module(modname
)
1890 desc
= (module
.__doc
__ or '').splitlines()[0]
1891 path
= getattr(module
,'__file__',None)
1892 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1893 callback(path
, modname
, desc
)
1899 """Print all the one-line module summaries that contain a substring."""
1900 def callback(path
, modname
, desc
):
1901 if modname
[-9:] == '.__init__':
1902 modname
= modname
[:-9] + ' (package)'
1903 print modname
, desc
and '- ' + desc
1904 try: import warnings
1905 except ImportError: pass
1906 else: warnings
.filterwarnings('ignore') # ignore problems during import
1907 ModuleScanner().run(callback
, key
)
1909 # --------------------------------------------------- web browser interface
1911 def serve(port
, callback
=None, completer
=None):
1912 import BaseHTTPServer
, mimetools
, select
1914 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1915 class Message(mimetools
.Message
):
1916 def __init__(self
, fp
, seekable
=1):
1917 Message
= self
.__class
__
1918 Message
.__bases
__[0].__bases
__[0].__init
__(self
, fp
, seekable
)
1919 self
.encodingheader
= self
.getheader('content-transfer-encoding')
1920 self
.typeheader
= self
.getheader('content-type')
1924 class DocHandler(BaseHTTPServer
.BaseHTTPRequestHandler
):
1925 def send_document(self
, title
, contents
):
1927 self
.send_response(200)
1928 self
.send_header('Content-Type', 'text/html')
1930 self
.wfile
.write(html
.page(title
, contents
))
1931 except IOError: pass
1935 if path
[-5:] == '.html': path
= path
[:-5]
1936 if path
[:1] == '/': path
= path
[1:]
1937 if path
and path
!= '.':
1939 obj
= locate(path
, forceload
=1)
1940 except ErrorDuringImport
, value
:
1941 self
.send_document(path
, html
.escape(str(value
)))
1944 self
.send_document(describe(obj
), html
.document(obj
, path
))
1946 self
.send_document(path
,
1947 'no Python documentation found for %s' % repr(path
))
1949 heading
= html
.heading(
1950 '<big><big><strong>Python: Index of Modules</strong></big></big>',
1951 '#ffffff', '#7799ee')
1952 def bltinlink(name
):
1953 return '<a href="%s.html">%s</a>' % (name
, name
)
1954 names
= filter(lambda x
: x
!= '__main__',
1955 sys
.builtin_module_names
)
1956 contents
= html
.multicolumn(names
, bltinlink
)
1957 indices
= ['<p>' + html
.bigsection(
1958 'Built-in Modules', '#ffffff', '#ee77aa', contents
)]
1961 for dir in sys
.path
:
1962 indices
.append(html
.index(dir, seen
))
1963 contents
= heading
+ join(indices
) + '''<p align=right>
1964 <font color="#909090" face="helvetica, arial"><strong>
1965 pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>'''
1966 self
.send_document('Index of Modules', contents
)
1968 def log_message(self
, *args
): pass
1970 class DocServer(BaseHTTPServer
.HTTPServer
):
1971 def __init__(self
, port
, callback
):
1972 host
= (sys
.platform
== 'mac') and '127.0.0.1' or 'localhost'
1973 self
.address
= ('', port
)
1974 self
.url
= 'http://%s:%d/' % (host
, port
)
1975 self
.callback
= callback
1976 self
.base
.__init
__(self
, self
.address
, self
.handler
)
1978 def serve_until_quit(self
):
1981 while not self
.quit
:
1982 rd
, wr
, ex
= select
.select([self
.socket
.fileno()], [], [], 1)
1983 if rd
: self
.handle_request()
1985 def server_activate(self
):
1986 self
.base
.server_activate(self
)
1987 if self
.callback
: self
.callback(self
)
1989 DocServer
.base
= BaseHTTPServer
.HTTPServer
1990 DocServer
.handler
= DocHandler
1991 DocHandler
.MessageClass
= Message
1994 DocServer(port
, callback
).serve_until_quit()
1995 except (KeyboardInterrupt, select
.error
):
1998 if completer
: completer()
2000 # ----------------------------------------------------- graphical interface
2003 """Graphical interface (starts web server and pops up a control window)."""
2005 def __init__(self
, window
, port
=7464):
2006 self
.window
= window
2011 self
.server_frm
= Tkinter
.Frame(window
)
2012 self
.title_lbl
= Tkinter
.Label(self
.server_frm
,
2013 text
='Starting server...\n ')
2014 self
.open_btn
= Tkinter
.Button(self
.server_frm
,
2015 text
='open browser', command
=self
.open, state
='disabled')
2016 self
.quit_btn
= Tkinter
.Button(self
.server_frm
,
2017 text
='quit serving', command
=self
.quit
, state
='disabled')
2019 self
.search_frm
= Tkinter
.Frame(window
)
2020 self
.search_lbl
= Tkinter
.Label(self
.search_frm
, text
='Search for')
2021 self
.search_ent
= Tkinter
.Entry(self
.search_frm
)
2022 self
.search_ent
.bind('<Return>', self
.search
)
2023 self
.stop_btn
= Tkinter
.Button(self
.search_frm
,
2024 text
='stop', pady
=0, command
=self
.stop
, state
='disabled')
2025 if sys
.platform
== 'win32':
2026 # Trying to hide and show this button crashes under Windows.
2027 self
.stop_btn
.pack(side
='right')
2029 self
.window
.title('pydoc')
2030 self
.window
.protocol('WM_DELETE_WINDOW', self
.quit
)
2031 self
.title_lbl
.pack(side
='top', fill
='x')
2032 self
.open_btn
.pack(side
='left', fill
='x', expand
=1)
2033 self
.quit_btn
.pack(side
='right', fill
='x', expand
=1)
2034 self
.server_frm
.pack(side
='top', fill
='x')
2036 self
.search_lbl
.pack(side
='left')
2037 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2038 self
.search_frm
.pack(side
='top', fill
='x')
2039 self
.search_ent
.focus_set()
2041 font
= ('helvetica', sys
.platform
== 'win32' and 8 or 10)
2042 self
.result_lst
= Tkinter
.Listbox(window
, font
=font
, height
=6)
2043 self
.result_lst
.bind('<Button-1>', self
.select
)
2044 self
.result_lst
.bind('<Double-Button-1>', self
.goto
)
2045 self
.result_scr
= Tkinter
.Scrollbar(window
,
2046 orient
='vertical', command
=self
.result_lst
.yview
)
2047 self
.result_lst
.config(yscrollcommand
=self
.result_scr
.set)
2049 self
.result_frm
= Tkinter
.Frame(window
)
2050 self
.goto_btn
= Tkinter
.Button(self
.result_frm
,
2051 text
='go to selected', command
=self
.goto
)
2052 self
.hide_btn
= Tkinter
.Button(self
.result_frm
,
2053 text
='hide results', command
=self
.hide
)
2054 self
.goto_btn
.pack(side
='left', fill
='x', expand
=1)
2055 self
.hide_btn
.pack(side
='right', fill
='x', expand
=1)
2057 self
.window
.update()
2058 self
.minwidth
= self
.window
.winfo_width()
2059 self
.minheight
= self
.window
.winfo_height()
2060 self
.bigminheight
= (self
.server_frm
.winfo_reqheight() +
2061 self
.search_frm
.winfo_reqheight() +
2062 self
.result_lst
.winfo_reqheight() +
2063 self
.result_frm
.winfo_reqheight())
2064 self
.bigwidth
, self
.bigheight
= self
.minwidth
, self
.bigminheight
2066 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2067 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2068 self
.window
.tk
.willdispatch()
2072 target
=serve
, args
=(port
, self
.ready
, self
.quit
)).start()
2074 def ready(self
, server
):
2075 self
.server
= server
2076 self
.title_lbl
.config(
2077 text
='Python documentation server at\n' + server
.url
)
2078 self
.open_btn
.config(state
='normal')
2079 self
.quit_btn
.config(state
='normal')
2081 def open(self
, event
=None, url
=None):
2082 url
= url
or self
.server
.url
2085 webbrowser
.open(url
)
2086 except ImportError: # pre-webbrowser.py compatibility
2087 if sys
.platform
== 'win32':
2088 os
.system('start "%s"' % url
)
2089 elif sys
.platform
== 'mac':
2091 except ImportError: pass
2092 else: ic
.launchurl(url
)
2094 rc
= os
.system('netscape -remote "openURL(%s)" &' % url
)
2095 if rc
: os
.system('netscape "%s" &' % url
)
2097 def quit(self
, event
=None):
2099 self
.server
.quit
= 1
2102 def search(self
, event
=None):
2103 key
= self
.search_ent
.get()
2104 self
.stop_btn
.pack(side
='right')
2105 self
.stop_btn
.config(state
='normal')
2106 self
.search_lbl
.config(text
='Searching for "%s"...' % key
)
2107 self
.search_ent
.forget()
2108 self
.search_lbl
.pack(side
='left')
2109 self
.result_lst
.delete(0, 'end')
2110 self
.goto_btn
.config(state
='disabled')
2115 self
.scanner
.quit
= 1
2116 self
.scanner
= ModuleScanner()
2117 threading
.Thread(target
=self
.scanner
.run
,
2118 args
=(self
.update
, key
, self
.done
)).start()
2120 def update(self
, path
, modname
, desc
):
2121 if modname
[-9:] == '.__init__':
2122 modname
= modname
[:-9] + ' (package)'
2123 self
.result_lst
.insert('end',
2124 modname
+ ' - ' + (desc
or '(no description)'))
2126 def stop(self
, event
=None):
2128 self
.scanner
.quit
= 1
2133 self
.search_lbl
.config(text
='Search for')
2134 self
.search_lbl
.pack(side
='left')
2135 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2136 if sys
.platform
!= 'win32': self
.stop_btn
.forget()
2137 self
.stop_btn
.config(state
='disabled')
2139 def select(self
, event
=None):
2140 self
.goto_btn
.config(state
='normal')
2142 def goto(self
, event
=None):
2143 selection
= self
.result_lst
.curselection()
2145 modname
= split(self
.result_lst
.get(selection
[0]))[0]
2146 self
.open(url
=self
.server
.url
+ modname
+ '.html')
2149 if not self
.expanded
: return
2150 self
.result_frm
.forget()
2151 self
.result_scr
.forget()
2152 self
.result_lst
.forget()
2153 self
.bigwidth
= self
.window
.winfo_width()
2154 self
.bigheight
= self
.window
.winfo_height()
2155 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2156 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2160 if self
.expanded
: return
2161 self
.result_frm
.pack(side
='bottom', fill
='x')
2162 self
.result_scr
.pack(side
='right', fill
='y')
2163 self
.result_lst
.pack(side
='top', fill
='both', expand
=1)
2164 self
.window
.wm_geometry('%dx%d' % (self
.bigwidth
, self
.bigheight
))
2165 self
.window
.wm_minsize(self
.minwidth
, self
.bigminheight
)
2168 def hide(self
, event
=None):
2175 # Tk will crash if pythonw.exe has an XP .manifest
2176 # file and the root has is not destroyed explicitly.
2177 # If the problem is ever fixed in Tk, the explicit
2184 except KeyboardInterrupt:
2187 # -------------------------------------------------- command-line interface
2190 return isinstance(x
, str) and find(x
, os
.sep
) >= 0
2193 """Command-line interface (looks at sys.argv to decide what to do)."""
2195 class BadUsage
: pass
2197 # Scripts don't get the current directory in their path by default.
2198 scriptdir
= os
.path
.dirname(sys
.argv
[0])
2199 if scriptdir
in sys
.path
:
2200 sys
.path
.remove(scriptdir
)
2201 sys
.path
.insert(0, '.')
2204 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'gk:p:w')
2207 for opt
, val
in opts
:
2220 print 'pydoc server ready at %s' % server
.url
2222 print 'pydoc server stopped'
2223 serve(port
, ready
, stopped
)
2228 if not args
: raise BadUsage
2230 if ispath(arg
) and not os
.path
.exists(arg
):
2231 print 'file %r does not exist' % arg
2234 if ispath(arg
) and os
.path
.isfile(arg
):
2235 arg
= importfile(arg
)
2237 if ispath(arg
) and os
.path
.isdir(arg
):
2243 except ErrorDuringImport
, value
:
2246 except (getopt
.error
, BadUsage
):
2247 cmd
= os
.path
.basename(sys
.argv
[0])
2248 print """pydoc - the Python documentation tool
2251 Show text documentation on something. <name> may be the name of a
2252 Python keyword, topic, function, module, or package, or a dotted
2253 reference to a class or function within a module or module in a
2254 package. If <name> contains a '%s', it is used as the path to a
2255 Python source file to document. If name is 'keywords', 'topics',
2256 or 'modules', a listing of these things is displayed.
2259 Search for a keyword in the synopsis lines of all available modules.
2262 Start an HTTP server on the given port on the local machine.
2265 Pop up a graphical interface for finding and serving documentation.
2268 Write out the HTML documentation for a module to a file in the current
2269 directory. If <name> contains a '%s', it is treated as a filename; if
2270 it names a directory, documentation is written for all the contents.
2271 """ % (cmd
, os
.sep
, cmd
, cmd
, cmd
, cmd
, os
.sep
)
2273 if __name__
== '__main__': cli()