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__
57 from string
import expandtabs
, find
, join
, lower
, split
, strip
, rfind
, rstrip
58 from collections
import deque
60 # --------------------------------------------------------- common routines
63 """Convert sys.path into a list of absolute, existing, unique paths."""
67 dir = os
.path
.abspath(dir or '.')
68 normdir
= os
.path
.normcase(dir)
69 if normdir
not in normdirs
and os
.path
.isdir(dir):
71 normdirs
.append(normdir
)
75 """Get the doc string or comments for an object."""
76 result
= inspect
.getdoc(object) or inspect
.getcomments(object)
77 return result
and re
.sub('^ *\n', '', rstrip(result
)) or ''
80 """Split a doc string into a synopsis line (if any) and the rest."""
81 lines
= split(strip(doc
), '\n')
84 elif len(lines
) >= 2 and not rstrip(lines
[1]):
85 return lines
[0], join(lines
[2:], '\n')
86 return '', join(lines
, '\n')
88 def classname(object, modname
):
89 """Get a class name and qualify it with a module name if necessary."""
90 name
= object.__name
__
91 if object.__module
__ != modname
:
92 name
= object.__module
__ + '.' + name
96 """Check if an object is of a type that probably means it's data."""
97 return not (inspect
.ismodule(object) or inspect
.isclass(object) or
98 inspect
.isroutine(object) or inspect
.isframe(object) or
99 inspect
.istraceback(object) or inspect
.iscode(object))
101 def replace(text
, *pairs
):
102 """Do a series of global replacements on a string."""
104 text
= join(split(text
, pairs
[0]), pairs
[1])
108 def cram(text
, maxlen
):
109 """Omit part of a string if needed to make it fit in a maximum length."""
110 if len(text
) > maxlen
:
111 pre
= max(0, (maxlen
-3)//2)
112 post
= max(0, maxlen
-3-pre
)
113 return text
[:pre
] + '...' + text
[len(text
)-post
:]
116 _re_stripid
= re
.compile(r
' at 0x[0-9a-f]{6,16}(>+)$', re
.IGNORECASE
)
118 """Remove the hexadecimal id from a Python object representation."""
119 # The behaviour of %p is implementation-dependent in terms of case.
120 if _re_stripid
.search(repr(Exception)):
121 return _re_stripid
.sub(r
'\1', text
)
124 def _is_some_method(obj
):
125 return inspect
.ismethod(obj
) or inspect
.ismethoddescriptor(obj
)
129 for key
, value
in inspect
.getmembers(cl
, _is_some_method
):
131 for base
in cl
.__bases
__:
132 methods
.update(allmethods(base
)) # all your base are belong to us
133 for key
in methods
.keys():
134 methods
[key
] = getattr(cl
, key
)
137 def _split_list(s
, predicate
):
138 """Split sequence s via predicate, and return pair ([true], [false]).
140 The return value is a 2-tuple of lists,
141 ([x for x in s if predicate(x)],
142 [x for x in s if not predicate(x)])
154 def visiblename(name
, all
=None):
155 """Decide whether to show documentation on a variable."""
156 # Certain special names are redundant.
157 if name
in ('__builtins__', '__doc__', '__file__', '__path__',
158 '__module__', '__name__', '__slots__'): return 0
159 # Private names are hidden, but special names are displayed.
160 if name
.startswith('__') and name
.endswith('__'): return 1
162 # only document that which the programmer exported in __all__
165 return not name
.startswith('_')
167 def classify_class_attrs(object):
168 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
169 def fixup((name
, kind
, cls
, value
)):
170 if inspect
.isdatadescriptor(value
):
171 kind
= 'data descriptor'
172 return name
, kind
, cls
, value
173 return map(fixup
, inspect
.classify_class_attrs(object))
175 # ----------------------------------------------------- module manipulation
178 """Guess whether a path refers to a package directory."""
179 if os
.path
.isdir(path
):
180 for ext
in ('.py', '.pyc', '.pyo'):
181 if os
.path
.isfile(os
.path
.join(path
, '__init__' + ext
)):
185 def synopsis(filename
, cache
={}):
186 """Get the one-line summary out of a module file."""
187 mtime
= os
.stat(filename
).st_mtime
188 lastupdate
, result
= cache
.get(filename
, (0, None))
189 if lastupdate
< mtime
:
190 info
= inspect
.getmoduleinfo(filename
)
192 file = open(filename
)
194 # module can't be opened, so skip it
196 if info
and 'b' in info
[2]: # binary modules have to be imported
197 try: module
= imp
.load_module('__temp__', file, filename
, info
[1:])
199 result
= split(module
.__doc
__ or '', '\n')[0]
200 del sys
.modules
['__temp__']
201 else: # text modules can be directly examined
202 line
= file.readline()
203 while line
[:1] == '#' or not strip(line
):
204 line
= file.readline()
207 if line
[:4] == 'r"""': line
= line
[1:]
208 if line
[:3] == '"""':
210 if line
[-1:] == '\\': line
= line
[:-1]
211 while not strip(line
):
212 line
= file.readline()
214 result
= strip(split(line
, '"""')[0])
217 cache
[filename
] = (mtime
, result
)
220 class ErrorDuringImport(Exception):
221 """Errors that occurred while trying to import something to document it."""
222 def __init__(self
, filename
, (exc
, value
, tb
)):
223 self
.filename
= filename
230 if type(exc
) is types
.ClassType
:
232 return 'problem in %s - %s: %s' % (self
.filename
, exc
, self
.value
)
234 def importfile(path
):
235 """Import a Python source file or compiled file given its path."""
236 magic
= imp
.get_magic()
237 file = open(path
, 'r')
238 if file.read(len(magic
)) == magic
:
239 kind
= imp
.PY_COMPILED
243 filename
= os
.path
.basename(path
)
244 name
, ext
= os
.path
.splitext(filename
)
245 file = open(path
, 'r')
247 module
= imp
.load_module(name
, file, path
, (ext
, 'r', kind
))
249 raise ErrorDuringImport(path
, sys
.exc_info())
253 def safeimport(path
, forceload
=0, cache
={}):
254 """Import a module; handle errors; return None if the module isn't found.
256 If the module *is* found but an exception occurs, it's wrapped in an
257 ErrorDuringImport exception and reraised. Unlike __import__, if a
258 package path is specified, the module at the end of the path is returned,
259 not the package at the beginning. If the optional 'forceload' argument
260 is 1, we reload the module from disk (unless it's a dynamic extension)."""
262 # If forceload is 1 and the module has been previously loaded from
263 # disk, we always have to reload the module. Checking the file's
264 # mtime isn't good enough (e.g. the module could contain a class
265 # that inherits from another module that has changed).
266 if forceload
and path
in sys
.modules
:
267 if path
not in sys
.builtin_module_names
:
268 # Avoid simply calling reload() because it leaves names in
269 # the currently loaded module lying around if they're not
270 # defined in the new source file. Instead, remove the
271 # module from sys.modules and re-import. Also remove any
272 # submodules because they won't appear in the newly loaded
273 # module's namespace if they're already in sys.modules.
274 subs
= [m
for m
in sys
.modules
if m
.startswith(path
+ '.')]
275 for key
in [path
] + subs
:
276 # Prevent garbage collection.
277 cache
[key
] = sys
.modules
[key
]
279 module
= __import__(path
)
281 # Did the error occur before or after the module was found?
282 (exc
, value
, tb
) = info
= sys
.exc_info()
283 if path
in sys
.modules
:
284 # An error occurred while executing the imported module.
285 raise ErrorDuringImport(sys
.modules
[path
].__file
__, info
)
286 elif exc
is SyntaxError:
287 # A SyntaxError occurred before we could execute the module.
288 raise ErrorDuringImport(value
.filename
, info
)
289 elif exc
is ImportError and \
290 split(lower(str(value
)))[:2] == ['no', 'module']:
291 # The module was not found.
294 # Some other error occurred during the importing process.
295 raise ErrorDuringImport(path
, sys
.exc_info())
296 for part
in split(path
, '.')[1:]:
297 try: module
= getattr(module
, part
)
298 except AttributeError: return None
301 # ---------------------------------------------------- formatter base class
304 def document(self
, object, name
=None, *args
):
305 """Generate documentation for an object."""
306 args
= (object, name
) + args
307 # 'try' clause is to attempt to handle the possibility that inspect
308 # identifies something in a way that pydoc itself has issues handling;
309 # think 'super' and how it is a descriptor (which raises the exception
310 # by lacking a __name__ attribute) and an instance.
312 if inspect
.ismodule(object): return self
.docmodule(*args
)
313 if inspect
.isclass(object): return self
.docclass(*args
)
314 if inspect
.isroutine(object): return self
.docroutine(*args
)
315 except AttributeError:
317 if isinstance(object, property): return self
.docproperty(*args
)
318 return self
.docother(*args
)
320 def fail(self
, object, name
=None, *args
):
321 """Raise an exception for unimplemented types."""
322 message
= "don't know how to document object%s of type %s" % (
323 name
and ' ' + repr(name
), type(object).__name
__)
324 raise TypeError, message
326 docmodule
= docclass
= docroutine
= docother
= fail
328 def getdocloc(self
, object):
329 """Return the location of module docs or None"""
332 file = inspect
.getabsfile(object)
336 docloc
= os
.environ
.get("PYTHONDOCS",
337 "http://www.python.org/doc/current/lib")
338 basedir
= os
.path
.join(sys
.exec_prefix
, "lib",
339 "python"+sys
.version
[0:3])
340 if (isinstance(object, type(os
)) and
341 (object.__name
__ in ('errno', 'exceptions', 'gc', 'imp',
342 'marshal', 'posix', 'signal', 'sys',
343 'thread', 'zipimport') or
344 (file.startswith(basedir
) and
345 not file.startswith(os
.path
.join(basedir
, 'site-packages'))))):
346 htmlfile
= "module-%s.html" % object.__name
__
347 if docloc
.startswith("http://"):
348 docloc
= "%s/%s" % (docloc
.rstrip("/"), htmlfile
)
350 docloc
= os
.path
.join(docloc
, htmlfile
)
355 # -------------------------------------------- HTML documentation generator
357 class HTMLRepr(Repr
):
358 """Class for safely making an HTML representation of a Python object."""
361 self
.maxlist
= self
.maxtuple
= 20
363 self
.maxstring
= self
.maxother
= 100
365 def escape(self
, text
):
366 return replace(text
, '&', '&', '<', '<', '>', '>')
368 def repr(self
, object):
369 return Repr
.repr(self
, object)
371 def repr1(self
, x
, level
):
372 if hasattr(type(x
), '__name__'):
373 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
374 if hasattr(self
, methodname
):
375 return getattr(self
, methodname
)(x
, level
)
376 return self
.escape(cram(stripid(repr(x
)), self
.maxother
))
378 def repr_string(self
, x
, level
):
379 test
= cram(x
, self
.maxstring
)
380 testrepr
= repr(test
)
381 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
382 # Backslashes are only literal in the string and are never
383 # needed to make any special characters, so show a raw string.
384 return 'r' + testrepr
[0] + self
.escape(test
) + testrepr
[0]
385 return re
.sub(r
'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
386 r'<font color="#c040c0">\1</font>',
387 self
.escape(testrepr
))
389 repr_str
= repr_string
391 def repr_instance(self
, x
, level
):
393 return self
.escape(cram(stripid(repr(x
)), self
.maxstring
))
395 return self
.escape('<%s instance>' % x
.__class
__.__name
__)
397 repr_unicode
= repr_string
400 """Formatter class for HTML documentation."""
402 # ------------------------------------------- HTML formatting utilities
404 _repr_instance
= HTMLRepr()
405 repr = _repr_instance
.repr
406 escape
= _repr_instance
.escape
408 def page(self
, title
, contents
):
409 """Format an HTML page."""
411 <!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
412 <html><head><title>Python: %s</title>
413 </head><body bgcolor="#f0f0f8">
415 </body></html>''' % (title
, contents
)
417 def heading(self
, title
, fgcol
, bgcol
, extras
=''):
418 """Format a page heading."""
420 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
422 <td valign=bottom> <br>
423 <font color="%s" face="helvetica, arial"> <br>%s</font></td
424 ><td align=right valign=bottom
425 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
426 ''' % (bgcol
, fgcol
, title
, fgcol
, extras
or ' ')
428 def section(self
, title
, fgcol
, bgcol
, contents
, width
=6,
429 prelude
='', marginalia
=None, gap
=' '):
430 """Format a section with a heading."""
431 if marginalia
is None:
432 marginalia
= '<tt>' + ' ' * width
+ '</tt>'
434 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
436 <td colspan=3 valign=bottom> <br>
437 <font color="%s" face="helvetica, arial">%s</font></td></tr>
438 ''' % (bgcol
, fgcol
, title
)
440 result
= result
+ '''
441 <tr bgcolor="%s"><td rowspan=2>%s</td>
442 <td colspan=2>%s</td></tr>
443 <tr><td>%s</td>''' % (bgcol
, marginalia
, prelude
, gap
)
445 result
= result
+ '''
446 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol
, marginalia
, gap
)
448 return result
+ '\n<td width="100%%">%s</td></tr></table>' % contents
450 def bigsection(self
, title
, *args
):
451 """Format a section with a big heading."""
452 title
= '<big><strong>%s</strong></big>' % title
453 return self
.section(title
, *args
)
455 def preformat(self
, text
):
456 """Format literal preformatted text."""
457 text
= self
.escape(expandtabs(text
))
458 return replace(text
, '\n\n', '\n \n', '\n\n', '\n \n',
459 ' ', ' ', '\n', '<br>\n')
461 def multicolumn(self
, list, format
, cols
=4):
462 """Format a list of items into a multi-column list."""
464 rows
= (len(list)+cols
-1)/cols
465 for col
in range(cols
):
466 result
= result
+ '<td width="%d%%" valign=top>' % (100/cols
)
467 for i
in range(rows
*col
, rows
*col
+rows
):
469 result
= result
+ format(list[i
]) + '<br>\n'
470 result
= result
+ '</td>'
471 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
473 def grey(self
, text
): return '<font color="#909090">%s</font>' % text
475 def namelink(self
, name
, *dicts
):
476 """Make a link for an identifier, given name-to-URL mappings."""
479 return '<a href="%s">%s</a>' % (dict[name
], name
)
482 def classlink(self
, object, modname
):
483 """Make a link for a class."""
484 name
, module
= object.__name
__, sys
.modules
.get(object.__module
__)
485 if hasattr(module
, name
) and getattr(module
, name
) is object:
486 return '<a href="%s.html#%s">%s</a>' % (
487 module
.__name
__, name
, classname(object, modname
))
488 return classname(object, modname
)
490 def modulelink(self
, object):
491 """Make a link for a module."""
492 return '<a href="%s.html">%s</a>' % (object.__name
__, object.__name
__)
494 def modpkglink(self
, (name
, path
, ispackage
, shadowed
)):
495 """Make a link for a module or package to display in an index."""
497 return self
.grey(name
)
499 url
= '%s.%s.html' % (path
, name
)
501 url
= '%s.html' % name
503 text
= '<strong>%s</strong> (package)' % name
506 return '<a href="%s">%s</a>' % (url
, text
)
508 def markup(self
, text
, escape
=None, funcs
={}, classes
={}, methods
={}):
509 """Mark up some plain text, given a context of symbols to look for.
510 Each context dictionary maps object names to anchor names."""
511 escape
= escape
or self
.escape
514 pattern
= re
.compile(r
'\b((http|ftp)://\S+[\w/]|'
519 match
= pattern
.search(text
, here
)
521 start
, end
= match
.span()
522 results
.append(escape(text
[here
:start
]))
524 all
, scheme
, rfc
, pep
, selfdot
, name
= match
.groups()
526 url
= escape(all
).replace('"', '"')
527 results
.append('<a href="%s">%s</a>' % (url
, url
))
529 url
= 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc
)
530 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
532 url
= 'http://www.python.org/peps/pep-%04d.html' % int(pep
)
533 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
534 elif text
[end
:end
+1] == '(':
535 results
.append(self
.namelink(name
, methods
, funcs
, classes
))
537 results
.append('self.<strong>%s</strong>' % name
)
539 results
.append(self
.namelink(name
, classes
))
541 results
.append(escape(text
[here
:]))
542 return join(results
, '')
544 # ---------------------------------------------- type-specific routines
546 def formattree(self
, tree
, modname
, parent
=None):
547 """Produce HTML for a class tree as given by inspect.getclasstree()."""
550 if type(entry
) is type(()):
552 result
= result
+ '<dt><font face="helvetica, arial">'
553 result
= result
+ self
.classlink(c
, modname
)
554 if bases
and bases
!= (parent
,):
557 parents
.append(self
.classlink(base
, modname
))
558 result
= result
+ '(' + join(parents
, ', ') + ')'
559 result
= result
+ '\n</font></dt>'
560 elif type(entry
) is type([]):
561 result
= result
+ '<dd>\n%s</dd>\n' % self
.formattree(
563 return '<dl>\n%s</dl>\n' % result
565 def docmodule(self
, object, name
=None, mod
=None, *ignored
):
566 """Produce HTML documentation for a module object."""
567 name
= object.__name
__ # ignore the passed-in name
570 except AttributeError:
572 parts
= split(name
, '.')
574 for i
in range(len(parts
)-1):
576 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
577 (join(parts
[:i
+1], '.'), parts
[i
]))
578 linkedname
= join(links
+ parts
[-1:], '.')
579 head
= '<big><big><strong>%s</strong></big></big>' % linkedname
581 path
= inspect
.getabsfile(object)
583 if sys
.platform
== 'win32':
585 url
= nturl2path
.pathname2url(path
)
586 filelink
= '<a href="file:%s">%s</a>' % (url
, path
)
588 filelink
= '(built-in)'
590 if hasattr(object, '__version__'):
591 version
= str(object.__version
__)
592 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
593 version
= strip(version
[11:-1])
594 info
.append('version %s' % self
.escape(version
))
595 if hasattr(object, '__date__'):
596 info
.append(self
.escape(str(object.__date
__)))
598 head
= head
+ ' (%s)' % join(info
, ', ')
599 docloc
= self
.getdocloc(object)
600 if docloc
is not None:
601 docloc
= '<br><a href="%(docloc)s">Module Docs</a>' % locals()
604 result
= self
.heading(
605 head
, '#ffffff', '#7799ee',
606 '<a href=".">index</a><br>' + filelink
+ docloc
)
608 modules
= inspect
.getmembers(object, inspect
.ismodule
)
610 classes
, cdict
= [], {}
611 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
612 # if __all__ exists, believe it. Otherwise use old heuristic.
613 if (all
is not None or
614 (inspect
.getmodule(value
) or object) is object):
615 if visiblename(key
, all
):
616 classes
.append((key
, value
))
617 cdict
[key
] = cdict
[value
] = '#' + key
618 for key
, value
in classes
:
619 for base
in value
.__bases
__:
620 key
, modname
= base
.__name
__, base
.__module
__
621 module
= sys
.modules
.get(modname
)
622 if modname
!= name
and module
and hasattr(module
, key
):
623 if getattr(module
, key
) is base
:
625 cdict
[key
] = cdict
[base
] = modname
+ '.html#' + key
626 funcs
, fdict
= [], {}
627 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
628 # if __all__ exists, believe it. Otherwise use old heuristic.
629 if (all
is not None or
630 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
631 if visiblename(key
, all
):
632 funcs
.append((key
, value
))
633 fdict
[key
] = '#-' + key
634 if inspect
.isfunction(value
): fdict
[value
] = fdict
[key
]
636 for key
, value
in inspect
.getmembers(object, isdata
):
637 if visiblename(key
, all
):
638 data
.append((key
, value
))
640 doc
= self
.markup(getdoc(object), self
.preformat
, fdict
, cdict
)
641 doc
= doc
and '<tt>%s</tt>' % doc
642 result
= result
+ '<p>%s</p>\n' % doc
644 if hasattr(object, '__path__'):
647 for file in os
.listdir(object.__path
__[0]):
648 path
= os
.path
.join(object.__path
__[0], file)
649 modname
= inspect
.getmodulename(file)
650 if modname
!= '__init__':
651 if modname
and modname
not in modnames
:
652 modpkgs
.append((modname
, name
, 0, 0))
653 modnames
.append(modname
)
654 elif ispackage(path
):
655 modpkgs
.append((file, name
, 1, 0))
657 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
658 result
= result
+ self
.bigsection(
659 'Package Contents', '#ffffff', '#aa55cc', contents
)
661 contents
= self
.multicolumn(
662 modules
, lambda (key
, value
), s
=self
: s
.modulelink(value
))
663 result
= result
+ self
.bigsection(
664 'Modules', '#fffff', '#aa55cc', contents
)
667 classlist
= map(lambda (key
, value
): value
, classes
)
669 self
.formattree(inspect
.getclasstree(classlist
, 1), name
)]
670 for key
, value
in classes
:
671 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
672 result
= result
+ self
.bigsection(
673 'Classes', '#ffffff', '#ee77aa', join(contents
))
676 for key
, value
in funcs
:
677 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
678 result
= result
+ self
.bigsection(
679 'Functions', '#ffffff', '#eeaa77', join(contents
))
682 for key
, value
in data
:
683 contents
.append(self
.document(value
, key
))
684 result
= result
+ self
.bigsection(
685 'Data', '#ffffff', '#55aa55', join(contents
, '<br>\n'))
686 if hasattr(object, '__author__'):
687 contents
= self
.markup(str(object.__author
__), self
.preformat
)
688 result
= result
+ self
.bigsection(
689 'Author', '#ffffff', '#7799ee', contents
)
690 if hasattr(object, '__credits__'):
691 contents
= self
.markup(str(object.__credits
__), self
.preformat
)
692 result
= result
+ self
.bigsection(
693 'Credits', '#ffffff', '#7799ee', contents
)
697 def docclass(self
, object, name
=None, mod
=None, funcs
={}, classes
={},
699 """Produce HTML documentation for a class object."""
700 realname
= object.__name
__
701 name
= name
or realname
702 bases
= object.__bases
__
705 push
= contents
.append
707 # Cute little class to pump out a horizontal rule between sections.
708 class HorizontalRule
:
715 hr
= HorizontalRule()
717 # List the mro, if non-trivial.
718 mro
= deque(inspect
.getmro(object))
721 push('<dl><dt>Method resolution order:</dt>\n')
723 push('<dd>%s</dd>\n' % self
.classlink(base
,
727 def spill(msg
, attrs
, predicate
):
728 ok
, attrs
= _split_list(attrs
, predicate
)
732 for name
, kind
, homecls
, value
in ok
:
733 push(self
.document(getattr(object, name
), name
, mod
,
734 funcs
, classes
, mdict
, object))
738 def spilldescriptors(msg
, attrs
, predicate
):
739 ok
, attrs
= _split_list(attrs
, predicate
)
743 for name
, kind
, homecls
, value
in ok
:
744 push(self
._docdescriptor
(name
, value
, mod
))
747 def spilldata(msg
, attrs
, predicate
):
748 ok
, attrs
= _split_list(attrs
, predicate
)
752 for name
, kind
, homecls
, value
in ok
:
753 base
= self
.docother(getattr(object, name
), name
, mod
)
754 if callable(value
) or inspect
.isdatadescriptor(value
):
755 doc
= getattr(value
, "__doc__", None)
759 push('<dl><dt>%s</dl>\n' % base
)
761 doc
= self
.markup(getdoc(value
), self
.preformat
,
762 funcs
, classes
, mdict
)
763 doc
= '<dd><tt>%s</tt>' % doc
764 push('<dl><dt>%s%s</dl>\n' % (base
, doc
))
768 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
769 classify_class_attrs(object))
771 for key
, kind
, homecls
, value
in attrs
:
772 mdict
[key
] = anchor
= '#' + name
+ '-' + key
773 value
= getattr(object, key
)
775 # The value may not be hashable (e.g., a data attr with
776 # a dict or list value).
777 mdict
[value
] = anchor
783 thisclass
= mro
.popleft()
785 thisclass
= attrs
[0][2]
786 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
788 if thisclass
is __builtin__
.object:
791 elif thisclass
is object:
794 tag
= 'inherited from %s' % self
.classlink(thisclass
,
798 # Sort attrs by name.
799 attrs
.sort(key
=lambda t
: t
[0])
801 # Pump out the attrs, segregated by kind.
802 attrs
= spill('Methods %s' % tag
, attrs
,
803 lambda t
: t
[1] == 'method')
804 attrs
= spill('Class methods %s' % tag
, attrs
,
805 lambda t
: t
[1] == 'class method')
806 attrs
= spill('Static methods %s' % tag
, attrs
,
807 lambda t
: t
[1] == 'static method')
808 attrs
= spilldescriptors('Data descriptors %s' % tag
, attrs
,
809 lambda t
: t
[1] == 'data descriptor')
810 attrs
= spilldata('Data and other attributes %s' % tag
, attrs
,
811 lambda t
: t
[1] == 'data')
815 contents
= ''.join(contents
)
818 title
= '<a name="%s">class <strong>%s</strong></a>' % (
821 title
= '<strong>%s</strong> = <a name="%s">class %s</a>' % (
822 name
, name
, realname
)
826 parents
.append(self
.classlink(base
, object.__module
__))
827 title
= title
+ '(%s)' % join(parents
, ', ')
828 doc
= self
.markup(getdoc(object), self
.preformat
, funcs
, classes
, mdict
)
829 doc
= doc
and '<tt>%s<br> </tt>' % doc
831 return self
.section(title
, '#000000', '#ffc8d8', contents
, 3, doc
)
833 def formatvalue(self
, object):
834 """Format an argument default value as text."""
835 return self
.grey('=' + self
.repr(object))
837 def docroutine(self
, object, name
=None, mod
=None,
838 funcs
={}, classes
={}, methods
={}, cl
=None):
839 """Produce HTML documentation for a function or method object."""
840 realname
= object.__name
__
841 name
= name
or realname
842 anchor
= (cl
and cl
.__name
__ or '') + '-' + name
845 if inspect
.ismethod(object):
846 imclass
= object.im_class
848 if imclass
is not cl
:
849 note
= ' from ' + self
.classlink(imclass
, mod
)
852 note
= ' method of %s instance' % self
.classlink(
853 object.im_self
.__class
__, mod
)
855 note
= ' unbound %s method' % self
.classlink(imclass
,mod
)
856 object = object.im_func
859 title
= '<a name="%s"><strong>%s</strong></a>' % (anchor
, realname
)
861 if (cl
and realname
in cl
.__dict
__ and
862 cl
.__dict
__[realname
] is object):
863 reallink
= '<a href="#%s">%s</a>' % (
864 cl
.__name
__ + '-' + realname
, realname
)
868 title
= '<a name="%s"><strong>%s</strong></a> = %s' % (
869 anchor
, name
, reallink
)
870 if inspect
.isfunction(object):
871 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
872 argspec
= inspect
.formatargspec(
873 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
874 if realname
== '<lambda>':
875 title
= '<strong>%s</strong> <em>lambda</em> ' % name
876 argspec
= argspec
[1:-1] # remove parentheses
880 decl
= title
+ argspec
+ (note
and self
.grey(
881 '<font face="helvetica, arial">%s</font>' % note
))
884 return '<dl><dt>%s</dt></dl>\n' % decl
887 getdoc(object), self
.preformat
, funcs
, classes
, methods
)
888 doc
= doc
and '<dd><tt>%s</tt></dd>' % doc
889 return '<dl><dt>%s</dt>%s</dl>\n' % (decl
, doc
)
891 def _docdescriptor(self
, name
, value
, mod
):
893 push
= results
.append
896 push('<dl><dt><strong>%s</strong></dt>\n' % name
)
897 if value
.__doc
__ is not None:
898 doc
= self
.markup(getdoc(value
), self
.preformat
)
899 push('<dd><tt>%s</tt></dd>\n' % doc
)
902 return ''.join(results
)
904 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
905 """Produce html documentation for a property."""
906 return self
._docdescriptor
(name
, object, mod
)
908 def docother(self
, object, name
=None, mod
=None, *ignored
):
909 """Produce HTML documentation for a data object."""
910 lhs
= name
and '<strong>%s</strong> = ' % name
or ''
911 return lhs
+ self
.repr(object)
913 def index(self
, dir, shadowed
=None):
914 """Generate an HTML index for a directory of modules."""
916 if shadowed
is None: shadowed
= {}
918 files
= os
.listdir(dir)
920 def found(name
, ispackage
,
921 modpkgs
=modpkgs
, shadowed
=shadowed
, seen
=seen
):
923 modpkgs
.append((name
, '', ispackage
, name
in shadowed
))
927 # Package spam/__init__.py takes precedence over module spam.py.
929 path
= os
.path
.join(dir, file)
930 if ispackage(path
): found(file, 1)
932 path
= os
.path
.join(dir, file)
933 if os
.path
.isfile(path
):
934 modname
= inspect
.getmodulename(file)
935 if modname
: found(modname
, 0)
938 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
939 return self
.bigsection(dir, '#ffffff', '#ee77aa', contents
)
941 # -------------------------------------------- text documentation generator
943 class TextRepr(Repr
):
944 """Class for safely making a text representation of a Python object."""
947 self
.maxlist
= self
.maxtuple
= 20
949 self
.maxstring
= self
.maxother
= 100
951 def repr1(self
, x
, level
):
952 if hasattr(type(x
), '__name__'):
953 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
954 if hasattr(self
, methodname
):
955 return getattr(self
, methodname
)(x
, level
)
956 return cram(stripid(repr(x
)), self
.maxother
)
958 def repr_string(self
, x
, level
):
959 test
= cram(x
, self
.maxstring
)
960 testrepr
= repr(test
)
961 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
962 # Backslashes are only literal in the string and are never
963 # needed to make any special characters, so show a raw string.
964 return 'r' + testrepr
[0] + test
+ testrepr
[0]
967 repr_str
= repr_string
969 def repr_instance(self
, x
, level
):
971 return cram(stripid(repr(x
)), self
.maxstring
)
973 return '<%s instance>' % x
.__class
__.__name
__
976 """Formatter class for text documentation."""
978 # ------------------------------------------- text formatting utilities
980 _repr_instance
= TextRepr()
981 repr = _repr_instance
.repr
983 def bold(self
, text
):
984 """Format a string in bold by overstriking."""
985 return join(map(lambda ch
: ch
+ '\b' + ch
, text
), '')
987 def indent(self
, text
, prefix
=' '):
988 """Indent text by prepending a given prefix to each line."""
989 if not text
: return ''
990 lines
= split(text
, '\n')
991 lines
= map(lambda line
, prefix
=prefix
: prefix
+ line
, lines
)
992 if lines
: lines
[-1] = rstrip(lines
[-1])
993 return join(lines
, '\n')
995 def section(self
, title
, contents
):
996 """Format a section with a given heading."""
997 return self
.bold(title
) + '\n' + rstrip(self
.indent(contents
)) + '\n\n'
999 # ---------------------------------------------- type-specific routines
1001 def formattree(self
, tree
, modname
, parent
=None, prefix
=''):
1002 """Render in text a class tree as returned by inspect.getclasstree()."""
1005 if type(entry
) is type(()):
1007 result
= result
+ prefix
+ classname(c
, modname
)
1008 if bases
and bases
!= (parent
,):
1009 parents
= map(lambda c
, m
=modname
: classname(c
, m
), bases
)
1010 result
= result
+ '(%s)' % join(parents
, ', ')
1011 result
= result
+ '\n'
1012 elif type(entry
) is type([]):
1013 result
= result
+ self
.formattree(
1014 entry
, modname
, c
, prefix
+ ' ')
1017 def docmodule(self
, object, name
=None, mod
=None):
1018 """Produce text documentation for a given module object."""
1019 name
= object.__name
__ # ignore the passed-in name
1020 synop
, desc
= splitdoc(getdoc(object))
1021 result
= self
.section('NAME', name
+ (synop
and ' - ' + synop
))
1024 all
= object.__all
__
1025 except AttributeError:
1029 file = inspect
.getabsfile(object)
1032 result
= result
+ self
.section('FILE', file)
1034 docloc
= self
.getdocloc(object)
1035 if docloc
is not None:
1036 result
= result
+ self
.section('MODULE DOCS', docloc
)
1039 result
= result
+ self
.section('DESCRIPTION', desc
)
1042 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
1043 # if __all__ exists, believe it. Otherwise use old heuristic.
1045 or (inspect
.getmodule(value
) or object) is object):
1046 if visiblename(key
, all
):
1047 classes
.append((key
, value
))
1049 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
1050 # if __all__ exists, believe it. Otherwise use old heuristic.
1051 if (all
is not None or
1052 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
1053 if visiblename(key
, all
):
1054 funcs
.append((key
, value
))
1056 for key
, value
in inspect
.getmembers(object, isdata
):
1057 if visiblename(key
, all
):
1058 data
.append((key
, value
))
1060 if hasattr(object, '__path__'):
1062 for file in os
.listdir(object.__path
__[0]):
1063 path
= os
.path
.join(object.__path
__[0], file)
1064 modname
= inspect
.getmodulename(file)
1065 if modname
!= '__init__':
1066 if modname
and modname
not in modpkgs
:
1067 modpkgs
.append(modname
)
1068 elif ispackage(path
):
1069 modpkgs
.append(file + ' (package)')
1071 result
= result
+ self
.section(
1072 'PACKAGE CONTENTS', join(modpkgs
, '\n'))
1075 classlist
= map(lambda (key
, value
): value
, classes
)
1076 contents
= [self
.formattree(
1077 inspect
.getclasstree(classlist
, 1), name
)]
1078 for key
, value
in classes
:
1079 contents
.append(self
.document(value
, key
, name
))
1080 result
= result
+ self
.section('CLASSES', join(contents
, '\n'))
1084 for key
, value
in funcs
:
1085 contents
.append(self
.document(value
, key
, name
))
1086 result
= result
+ self
.section('FUNCTIONS', join(contents
, '\n'))
1090 for key
, value
in data
:
1091 contents
.append(self
.docother(value
, key
, name
, maxlen
=70))
1092 result
= result
+ self
.section('DATA', join(contents
, '\n'))
1094 if hasattr(object, '__version__'):
1095 version
= str(object.__version
__)
1096 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
1097 version
= strip(version
[11:-1])
1098 result
= result
+ self
.section('VERSION', version
)
1099 if hasattr(object, '__date__'):
1100 result
= result
+ self
.section('DATE', str(object.__date
__))
1101 if hasattr(object, '__author__'):
1102 result
= result
+ self
.section('AUTHOR', str(object.__author
__))
1103 if hasattr(object, '__credits__'):
1104 result
= result
+ self
.section('CREDITS', str(object.__credits
__))
1107 def docclass(self
, object, name
=None, mod
=None):
1108 """Produce text documentation for a given class object."""
1109 realname
= object.__name
__
1110 name
= name
or realname
1111 bases
= object.__bases
__
1113 def makename(c
, m
=object.__module
__):
1114 return classname(c
, m
)
1116 if name
== realname
:
1117 title
= 'class ' + self
.bold(realname
)
1119 title
= self
.bold(name
) + ' = class ' + realname
1121 parents
= map(makename
, bases
)
1122 title
= title
+ '(%s)' % join(parents
, ', ')
1124 doc
= getdoc(object)
1125 contents
= doc
and [doc
+ '\n'] or []
1126 push
= contents
.append
1128 # List the mro, if non-trivial.
1129 mro
= deque(inspect
.getmro(object))
1131 push("Method resolution order:")
1133 push(' ' + makename(base
))
1136 # Cute little class to pump out a horizontal rule between sections.
1137 class HorizontalRule
:
1144 hr
= HorizontalRule()
1146 def spill(msg
, attrs
, predicate
):
1147 ok
, attrs
= _split_list(attrs
, predicate
)
1151 for name
, kind
, homecls
, value
in ok
:
1152 push(self
.document(getattr(object, name
),
1156 def spilldescriptors(msg
, attrs
, predicate
):
1157 ok
, attrs
= _split_list(attrs
, predicate
)
1161 for name
, kind
, homecls
, value
in ok
:
1162 push(self
._docdescriptor
(name
, value
, mod
))
1165 def spilldata(msg
, attrs
, predicate
):
1166 ok
, attrs
= _split_list(attrs
, predicate
)
1170 for name
, kind
, homecls
, value
in ok
:
1171 if callable(value
) or inspect
.isdatadescriptor(value
):
1175 push(self
.docother(getattr(object, name
),
1176 name
, mod
, maxlen
=70, doc
=doc
) + '\n')
1179 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
1180 classify_class_attrs(object))
1183 thisclass
= mro
.popleft()
1185 thisclass
= attrs
[0][2]
1186 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
1188 if thisclass
is __builtin__
.object:
1191 elif thisclass
is object:
1192 tag
= "defined here"
1194 tag
= "inherited from %s" % classname(thisclass
,
1196 filter(lambda t
: not t
[0].startswith('_'), attrs
)
1198 # Sort attrs by name.
1201 # Pump out the attrs, segregated by kind.
1202 attrs
= spill("Methods %s:\n" % tag
, attrs
,
1203 lambda t
: t
[1] == 'method')
1204 attrs
= spill("Class methods %s:\n" % tag
, attrs
,
1205 lambda t
: t
[1] == 'class method')
1206 attrs
= spill("Static methods %s:\n" % tag
, attrs
,
1207 lambda t
: t
[1] == 'static method')
1208 attrs
= spilldescriptors("Data descriptors %s:\n" % tag
, attrs
,
1209 lambda t
: t
[1] == 'data descriptor')
1210 attrs
= spilldata("Data and other attributes %s:\n" % tag
, attrs
,
1211 lambda t
: t
[1] == 'data')
1215 contents
= '\n'.join(contents
)
1218 return title
+ '\n' + self
.indent(rstrip(contents
), ' | ') + '\n'
1220 def formatvalue(self
, object):
1221 """Format an argument default value as text."""
1222 return '=' + self
.repr(object)
1224 def docroutine(self
, object, name
=None, mod
=None, cl
=None):
1225 """Produce text documentation for a function or method object."""
1226 realname
= object.__name
__
1227 name
= name
or realname
1230 if inspect
.ismethod(object):
1231 imclass
= object.im_class
1233 if imclass
is not cl
:
1234 note
= ' from ' + classname(imclass
, mod
)
1237 note
= ' method of %s instance' % classname(
1238 object.im_self
.__class
__, mod
)
1240 note
= ' unbound %s method' % classname(imclass
,mod
)
1241 object = object.im_func
1243 if name
== realname
:
1244 title
= self
.bold(realname
)
1246 if (cl
and realname
in cl
.__dict
__ and
1247 cl
.__dict
__[realname
] is object):
1249 title
= self
.bold(name
) + ' = ' + realname
1250 if inspect
.isfunction(object):
1251 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
1252 argspec
= inspect
.formatargspec(
1253 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
1254 if realname
== '<lambda>':
1255 title
= self
.bold(name
) + ' lambda '
1256 argspec
= argspec
[1:-1] # remove parentheses
1259 decl
= title
+ argspec
+ note
1264 doc
= getdoc(object) or ''
1265 return decl
+ '\n' + (doc
and rstrip(self
.indent(doc
)) + '\n')
1267 def _docdescriptor(self
, name
, value
, mod
):
1269 push
= results
.append
1272 push(self
.bold(name
))
1274 doc
= getdoc(value
) or ''
1276 push(self
.indent(doc
))
1278 return ''.join(results
)
1280 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
1281 """Produce text documentation for a property."""
1282 return self
._docdescriptor
(name
, object, mod
)
1284 def docother(self
, object, name
=None, mod
=None, parent
=None, maxlen
=None, doc
=None):
1285 """Produce text documentation for a data object."""
1286 repr = self
.repr(object)
1288 line
= (name
and name
+ ' = ' or '') + repr
1289 chop
= maxlen
- len(line
)
1290 if chop
< 0: repr = repr[:chop
] + '...'
1291 line
= (name
and self
.bold(name
) + ' = ' or '') + repr
1293 line
+= '\n' + self
.indent(str(doc
))
1296 # --------------------------------------------------------- user interfaces
1299 """The first time this is called, determine what kind of pager to use."""
1305 """Decide what method to use for paging through text."""
1306 if type(sys
.stdout
) is not types
.FileType
:
1308 if not sys
.stdin
.isatty() or not sys
.stdout
.isatty():
1310 if 'PAGER' in os
.environ
:
1311 if sys
.platform
== 'win32': # pipes completely broken in Windows
1312 return lambda text
: tempfilepager(plain(text
), os
.environ
['PAGER'])
1313 elif os
.environ
.get('TERM') in ('dumb', 'emacs'):
1314 return lambda text
: pipepager(plain(text
), os
.environ
['PAGER'])
1316 return lambda text
: pipepager(text
, os
.environ
['PAGER'])
1317 if os
.environ
.get('TERM') in ('dumb', 'emacs'):
1319 if sys
.platform
== 'win32' or sys
.platform
.startswith('os2'):
1320 return lambda text
: tempfilepager(plain(text
), 'more <')
1321 if hasattr(os
, 'system') and os
.system('(less) 2>/dev/null') == 0:
1322 return lambda text
: pipepager(text
, 'less')
1325 (fd
, filename
) = tempfile
.mkstemp()
1328 if hasattr(os
, 'system') and os
.system('more %s' % filename
) == 0:
1329 return lambda text
: pipepager(text
, 'more')
1336 """Remove boldface formatting from text."""
1337 return re
.sub('.\b', '', text
)
1339 def pipepager(text
, cmd
):
1340 """Page through text by feeding it to another program."""
1341 pipe
= os
.popen(cmd
, 'w')
1346 pass # Ignore broken pipes caused by quitting the pager program.
1348 def tempfilepager(text
, cmd
):
1349 """Page through text by invoking a program on a temporary file."""
1351 filename
= tempfile
.mktemp()
1352 file = open(filename
, 'w')
1356 os
.system(cmd
+ ' ' + filename
)
1361 """Page through text on a text terminal."""
1362 lines
= split(plain(text
), '\n')
1365 fd
= sys
.stdin
.fileno()
1366 old
= tty
.tcgetattr(fd
)
1368 getchar
= lambda: sys
.stdin
.read(1)
1369 except (ImportError, AttributeError):
1371 getchar
= lambda: sys
.stdin
.readline()[:-1][:1]
1374 r
= inc
= os
.environ
.get('LINES', 25) - 1
1375 sys
.stdout
.write(join(lines
[:inc
], '\n') + '\n')
1377 sys
.stdout
.write('-- more --')
1382 sys
.stdout
.write('\r \r')
1384 elif c
in ('\r', '\n'):
1385 sys
.stdout
.write('\r \r' + lines
[r
] + '\n')
1388 if c
in ('b', 'B', '\x1b'):
1391 sys
.stdout
.write('\n' + join(lines
[r
:r
+inc
], '\n') + '\n')
1396 tty
.tcsetattr(fd
, tty
.TCSAFLUSH
, old
)
1398 def plainpager(text
):
1399 """Simply print unformatted text. This is the ultimate fallback."""
1400 sys
.stdout
.write(plain(text
))
1402 def describe(thing
):
1403 """Produce a short description of the given thing."""
1404 if inspect
.ismodule(thing
):
1405 if thing
.__name
__ in sys
.builtin_module_names
:
1406 return 'built-in module ' + thing
.__name
__
1407 if hasattr(thing
, '__path__'):
1408 return 'package ' + thing
.__name
__
1410 return 'module ' + thing
.__name
__
1411 if inspect
.isbuiltin(thing
):
1412 return 'built-in function ' + thing
.__name
__
1413 if inspect
.isclass(thing
):
1414 return 'class ' + thing
.__name
__
1415 if inspect
.isfunction(thing
):
1416 return 'function ' + thing
.__name
__
1417 if inspect
.ismethod(thing
):
1418 return 'method ' + thing
.__name
__
1419 if type(thing
) is types
.InstanceType
:
1420 return 'instance of ' + thing
.__class
__.__name
__
1421 return type(thing
).__name
__
1423 def locate(path
, forceload
=0):
1424 """Locate an object by name or dotted path, importing as necessary."""
1425 parts
= [part
for part
in split(path
, '.') if part
]
1427 while n
< len(parts
):
1428 nextmodule
= safeimport(join(parts
[:n
+1], '.'), forceload
)
1429 if nextmodule
: module
, n
= nextmodule
, n
+ 1
1433 for part
in parts
[n
:]:
1434 try: object = getattr(object, part
)
1435 except AttributeError: return None
1438 if hasattr(__builtin__
, path
):
1439 return getattr(__builtin__
, path
)
1441 # --------------------------------------- interactive interpreter interface
1446 def resolve(thing
, forceload
=0):
1447 """Given an object or a path to an object, get the object and its name."""
1448 if isinstance(thing
, str):
1449 object = locate(thing
, forceload
)
1451 raise ImportError, 'no Python documentation found for %r' % thing
1452 return object, thing
1454 return thing
, getattr(thing
, '__name__', None)
1456 def doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1457 """Display text documentation, given an object or a path to an object."""
1459 object, name
= resolve(thing
, forceload
)
1460 desc
= describe(object)
1461 module
= inspect
.getmodule(object)
1462 if name
and '.' in name
:
1463 desc
+= ' in ' + name
[:name
.rfind('.')]
1464 elif module
and module
is not object:
1465 desc
+= ' in module ' + module
.__name
__
1466 if not (inspect
.ismodule(object) or
1467 inspect
.isclass(object) or
1468 inspect
.isroutine(object) or
1469 isinstance(object, property)):
1470 # If the passed object is a piece of data or an instance,
1471 # document its available methods instead of its value.
1472 object = type(object)
1474 pager(title
% desc
+ '\n\n' + text
.document(object, name
))
1475 except (ImportError, ErrorDuringImport
), value
:
1478 def writedoc(thing
, forceload
=0):
1479 """Write HTML documentation to a file in the current directory."""
1481 object, name
= resolve(thing
, forceload
)
1482 page
= html
.page(describe(object), html
.document(object, name
))
1483 file = open(name
+ '.html', 'w')
1486 print 'wrote', name
+ '.html'
1487 except (ImportError, ErrorDuringImport
), value
:
1490 def writedocs(dir, pkgpath
='', done
=None):
1491 """Write out HTML documentation for all modules in a directory tree."""
1492 if done
is None: done
= {}
1493 for file in os
.listdir(dir):
1494 path
= os
.path
.join(dir, file)
1496 writedocs(path
, pkgpath
+ file + '.', done
)
1497 elif os
.path
.isfile(path
):
1498 modname
= inspect
.getmodulename(path
)
1500 if modname
== '__init__':
1501 modname
= pkgpath
[:-1] # remove trailing period
1503 modname
= pkgpath
+ modname
1504 if modname
not in done
:
1511 'assert': ('ref/assert', ''),
1512 'break': ('ref/break', 'while for'),
1513 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1514 'continue': ('ref/continue', 'while for'),
1515 'def': ('ref/function', ''),
1516 'del': ('ref/del', 'BASICMETHODS'),
1518 'else': ('ref/if', 'while for'),
1520 'exec': ('ref/exec', ''),
1522 'for': ('ref/for', 'break continue while'),
1524 'global': ('ref/global', 'NAMESPACES'),
1525 'if': ('ref/if', 'TRUTHVALUE'),
1526 'import': ('ref/import', 'MODULES'),
1527 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1529 'lambda': ('ref/lambdas', 'FUNCTIONS'),
1532 'pass': ('ref/pass', ''),
1533 'print': ('ref/print', ''),
1534 'raise': ('ref/raise', 'EXCEPTIONS'),
1535 'return': ('ref/return', 'FUNCTIONS'),
1536 'try': ('ref/try', 'EXCEPTIONS'),
1537 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1538 'yield': ('ref/yield', ''),
1542 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
1543 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
1544 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1545 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
1546 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
1547 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1548 'INTEGER': ('ref/integers', 'int range'),
1549 'FLOAT': ('ref/floating', 'float math'),
1550 'COMPLEX': ('ref/imaginary', 'complex cmath'),
1551 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1552 'MAPPINGS': 'DICTIONARIES',
1553 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1554 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1555 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
1556 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
1557 'FRAMEOBJECTS': 'TYPES',
1558 'TRACEBACKS': 'TYPES',
1559 'NONE': ('lib/bltin-null-object', ''),
1560 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1561 'FILES': ('lib/bltin-file-objects', ''),
1562 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1563 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1564 'MODULES': ('lib/typesmodules', 'import'),
1565 'PACKAGES': 'import',
1566 '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'),
1567 'OPERATORS': 'EXPRESSIONS',
1568 'PRECEDENCE': 'EXPRESSIONS',
1569 'OBJECTS': ('ref/objects', 'TYPES'),
1570 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1571 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1572 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1573 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1574 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1575 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1576 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1577 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
1578 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1579 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1580 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
1581 'SCOPING': 'NAMESPACES',
1582 'FRAMES': 'NAMESPACES',
1583 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1584 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1585 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
1586 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1587 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
1588 'PRIVATENAMES': ('ref/atom-identifiers', ''),
1589 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1590 'TUPLES': 'SEQUENCES',
1591 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
1592 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
1593 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
1594 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
1595 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1596 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
1597 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1598 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1599 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1600 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1601 'POWER': ('ref/power', 'EXPRESSIONS'),
1602 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1603 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1604 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1605 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1606 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
1607 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
1608 'ASSERTION': 'assert',
1609 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
1610 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
1612 'PRINTING': 'print',
1613 'RETURNING': 'return',
1614 'IMPORTING': 'import',
1615 'CONDITIONAL': 'if',
1616 'LOOPING': ('ref/compound', 'for while break continue'),
1617 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
1618 'DEBUGGING': ('lib/module-pdb', 'pdb'),
1621 def __init__(self
, input, output
):
1623 self
.output
= output
1625 execdir
= os
.path
.dirname(sys
.executable
)
1626 homedir
= os
.environ
.get('PYTHONHOME')
1627 for dir in [os
.environ
.get('PYTHONDOCS'),
1628 homedir
and os
.path
.join(homedir
, 'doc'),
1629 os
.path
.join(execdir
, 'doc'),
1630 '/usr/doc/python-docs-' + split(sys
.version
)[0],
1631 '/usr/doc/python-' + split(sys
.version
)[0],
1632 '/usr/doc/python-docs-' + sys
.version
[:3],
1633 '/usr/doc/python-' + sys
.version
[:3],
1634 os
.path
.join(sys
.prefix
, 'Resources/English.lproj/Documentation')]:
1635 if dir and os
.path
.isdir(os
.path
.join(dir, 'lib')):
1639 if inspect
.stack()[1][3] == '?':
1642 return '<pydoc.Helper instance>'
1644 def __call__(self
, request
=None):
1645 if request
is not None:
1650 self
.output
.write('''
1651 You are now leaving help and returning to the Python interpreter.
1652 If you want to ask for help on a particular object directly from the
1653 interpreter, you can type "help(object)". Executing "help('string')"
1654 has the same effect as typing a particular string at the help> prompt.
1658 self
.output
.write('\n')
1661 request
= self
.getline('help> ')
1662 if not request
: break
1663 except (KeyboardInterrupt, EOFError):
1665 request
= strip(replace(request
, '"', '', "'", ''))
1666 if lower(request
) in ('q', 'quit'): break
1669 def getline(self
, prompt
):
1670 """Read one line, using raw_input when available."""
1671 if self
.input is sys
.stdin
:
1672 return raw_input(prompt
)
1674 self
.output
.write(prompt
)
1676 return self
.input.readline()
1678 def help(self
, request
):
1679 if type(request
) is type(''):
1680 if request
== 'help': self
.intro()
1681 elif request
== 'keywords': self
.listkeywords()
1682 elif request
== 'topics': self
.listtopics()
1683 elif request
== 'modules': self
.listmodules()
1684 elif request
[:8] == 'modules ':
1685 self
.listmodules(split(request
)[1])
1686 elif request
in self
.keywords
: self
.showtopic(request
)
1687 elif request
in self
.topics
: self
.showtopic(request
)
1688 elif request
: doc(request
, 'Help on %s:')
1689 elif isinstance(request
, Helper
): self()
1690 else: doc(request
, 'Help on %s:')
1691 self
.output
.write('\n')
1694 self
.output
.write('''
1695 Welcome to Python %s! This is the online help utility.
1697 If this is your first time using Python, you should definitely check out
1698 the tutorial on the Internet at http://www.python.org/doc/tut/.
1700 Enter the name of any module, keyword, or topic to get help on writing
1701 Python programs and using Python modules. To quit this help utility and
1702 return to the interpreter, just type "quit".
1704 To get a list of available modules, keywords, or topics, type "modules",
1705 "keywords", or "topics". Each module also comes with a one-line summary
1706 of what it does; to list the modules whose summaries contain a given word
1707 such as "spam", type "modules spam".
1708 ''' % sys
.version
[:3])
1710 def list(self
, items
, columns
=4, width
=80):
1713 colw
= width
/ columns
1714 rows
= (len(items
) + columns
- 1) / columns
1715 for row
in range(rows
):
1716 for col
in range(columns
):
1717 i
= col
* rows
+ row
1719 self
.output
.write(items
[i
])
1720 if col
< columns
- 1:
1721 self
.output
.write(' ' + ' ' * (colw
-1 - len(items
[i
])))
1722 self
.output
.write('\n')
1724 def listkeywords(self
):
1725 self
.output
.write('''
1726 Here is a list of the Python keywords. Enter any keyword to get more help.
1729 self
.list(self
.keywords
.keys())
1731 def listtopics(self
):
1732 self
.output
.write('''
1733 Here is a list of available topics. Enter any topic name to get more help.
1736 self
.list(self
.topics
.keys())
1738 def showtopic(self
, topic
):
1740 self
.output
.write('''
1741 Sorry, topic and keyword documentation is not available because the Python
1742 HTML documentation files could not be found. If you have installed them,
1743 please set the environment variable PYTHONDOCS to indicate their location.
1746 target
= self
.topics
.get(topic
, self
.keywords
.get(topic
))
1748 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1750 if type(target
) is type(''):
1751 return self
.showtopic(target
)
1753 filename
, xrefs
= target
1754 filename
= self
.docdir
+ '/' + filename
+ '.html'
1756 file = open(filename
)
1758 self
.output
.write('could not read docs from %s\n' % filename
)
1761 divpat
= re
.compile('<div[^>]*navigat.*?</div.*?>', re
.I | re
.S
)
1762 addrpat
= re
.compile('<address.*?>.*?</address.*?>', re
.I | re
.S
)
1763 document
= re
.sub(addrpat
, '', re
.sub(divpat
, '', file.read()))
1766 import htmllib
, formatter
, StringIO
1767 buffer = StringIO
.StringIO()
1768 parser
= htmllib
.HTMLParser(
1769 formatter
.AbstractFormatter(formatter
.DumbWriter(buffer)))
1770 parser
.start_table
= parser
.do_p
1771 parser
.end_table
= lambda parser
=parser
: parser
.do_p({})
1772 parser
.start_tr
= parser
.do_br
1773 parser
.start_td
= parser
.start_th
= lambda a
, b
=buffer: b
.write('\t')
1774 parser
.feed(document
)
1775 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1776 pager(' ' + strip(buffer) + '\n')
1778 buffer = StringIO
.StringIO()
1779 formatter
.DumbWriter(buffer).send_flowing_data(
1780 'Related help topics: ' + join(split(xrefs
), ', ') + '\n')
1781 self
.output
.write('\n%s\n' % buffer.getvalue())
1783 def listmodules(self
, key
=''):
1785 self
.output
.write('''
1786 Here is a list of matching modules. Enter any module name to get more help.
1791 self
.output
.write('''
1792 Please wait a moment while I gather a list of all available modules...
1796 def callback(path
, modname
, desc
, modules
=modules
):
1797 if modname
and modname
[-9:] == '.__init__':
1798 modname
= modname
[:-9] + ' (package)'
1799 if find(modname
, '.') < 0:
1800 modules
[modname
] = 1
1801 ModuleScanner().run(callback
)
1802 self
.list(modules
.keys())
1803 self
.output
.write('''
1804 Enter any module name to get more help. Or, type "modules spam" to search
1805 for modules whose descriptions contain the word "spam".
1808 help = Helper(sys
.stdin
, sys
.stdout
)
1811 """A generic tree iterator."""
1812 def __init__(self
, roots
, children
, descendp
):
1813 self
.roots
= roots
[:]
1815 self
.children
= children
1816 self
.descendp
= descendp
1822 root
= self
.roots
.pop(0)
1823 self
.state
= [(root
, self
.children(root
))]
1824 node
, children
= self
.state
[-1]
1828 child
= children
.pop(0)
1829 if self
.descendp(child
):
1830 self
.state
.append((child
, self
.children(child
)))
1833 class ModuleScanner(Scanner
):
1834 """An interruptible scanner that searches module synopses."""
1836 roots
= map(lambda dir: (dir, ''), pathdirs())
1837 Scanner
.__init
__(self
, roots
, self
.submodules
, self
.isnewpackage
)
1838 self
.inodes
= map(lambda (dir, pkg
): os
.stat(dir).st_ino
, roots
)
1840 def submodules(self
, (dir, package
)):
1842 for file in os
.listdir(dir):
1843 path
= os
.path
.join(dir, file)
1845 children
.append((path
, package
+ (package
and '.') + file))
1847 children
.append((path
, package
))
1848 children
.sort() # so that spam.py comes before spam.pyc or spam.pyo
1851 def isnewpackage(self
, (dir, package
)):
1852 inode
= os
.path
.exists(dir) and os
.stat(dir).st_ino
1853 if not (os
.path
.islink(dir) and inode
in self
.inodes
):
1854 self
.inodes
.append(inode
) # detect circular symbolic links
1855 return ispackage(dir)
1858 def run(self
, callback
, key
=None, completer
=None):
1859 if key
: key
= lower(key
)
1863 for modname
in sys
.builtin_module_names
:
1864 if modname
!= '__main__':
1867 callback(None, modname
, '')
1869 desc
= split(__import__(modname
).__doc
__ or '', '\n')[0]
1870 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1871 callback(None, modname
, desc
)
1873 while not self
.quit
:
1876 path
, package
= node
1877 modname
= inspect
.getmodulename(path
)
1878 if os
.path
.isfile(path
) and modname
:
1879 modname
= package
+ (package
and '.') + modname
1880 if not modname
in seen
:
1881 seen
[modname
] = 1 # if we see spam.py, skip spam.pyc
1883 callback(path
, modname
, '')
1885 desc
= synopsis(path
) or ''
1886 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1887 callback(path
, modname
, desc
)
1888 if completer
: completer()
1891 """Print all the one-line module summaries that contain a substring."""
1892 def callback(path
, modname
, desc
):
1893 if modname
[-9:] == '.__init__':
1894 modname
= modname
[:-9] + ' (package)'
1895 print modname
, desc
and '- ' + desc
1896 try: import warnings
1897 except ImportError: pass
1898 else: warnings
.filterwarnings('ignore') # ignore problems during import
1899 ModuleScanner().run(callback
, key
)
1901 # --------------------------------------------------- web browser interface
1903 def serve(port
, callback
=None, completer
=None):
1904 import BaseHTTPServer
, mimetools
, select
1906 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1907 class Message(mimetools
.Message
):
1908 def __init__(self
, fp
, seekable
=1):
1909 Message
= self
.__class
__
1910 Message
.__bases
__[0].__bases
__[0].__init
__(self
, fp
, seekable
)
1911 self
.encodingheader
= self
.getheader('content-transfer-encoding')
1912 self
.typeheader
= self
.getheader('content-type')
1916 class DocHandler(BaseHTTPServer
.BaseHTTPRequestHandler
):
1917 def send_document(self
, title
, contents
):
1919 self
.send_response(200)
1920 self
.send_header('Content-Type', 'text/html')
1922 self
.wfile
.write(html
.page(title
, contents
))
1923 except IOError: pass
1927 if path
[-5:] == '.html': path
= path
[:-5]
1928 if path
[:1] == '/': path
= path
[1:]
1929 if path
and path
!= '.':
1931 obj
= locate(path
, forceload
=1)
1932 except ErrorDuringImport
, value
:
1933 self
.send_document(path
, html
.escape(str(value
)))
1936 self
.send_document(describe(obj
), html
.document(obj
, path
))
1938 self
.send_document(path
,
1939 'no Python documentation found for %s' % repr(path
))
1941 heading
= html
.heading(
1942 '<big><big><strong>Python: Index of Modules</strong></big></big>',
1943 '#ffffff', '#7799ee')
1944 def bltinlink(name
):
1945 return '<a href="%s.html">%s</a>' % (name
, name
)
1946 names
= filter(lambda x
: x
!= '__main__',
1947 sys
.builtin_module_names
)
1948 contents
= html
.multicolumn(names
, bltinlink
)
1949 indices
= ['<p>' + html
.bigsection(
1950 'Built-in Modules', '#ffffff', '#ee77aa', contents
)]
1953 for dir in pathdirs():
1954 indices
.append(html
.index(dir, seen
))
1955 contents
= heading
+ join(indices
) + '''<p align=right>
1956 <font color="#909090" face="helvetica, arial"><strong>
1957 pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>'''
1958 self
.send_document('Index of Modules', contents
)
1960 def log_message(self
, *args
): pass
1962 class DocServer(BaseHTTPServer
.HTTPServer
):
1963 def __init__(self
, port
, callback
):
1964 host
= (sys
.platform
== 'mac') and '127.0.0.1' or 'localhost'
1965 self
.address
= ('', port
)
1966 self
.url
= 'http://%s:%d/' % (host
, port
)
1967 self
.callback
= callback
1968 self
.base
.__init
__(self
, self
.address
, self
.handler
)
1970 def serve_until_quit(self
):
1973 while not self
.quit
:
1974 rd
, wr
, ex
= select
.select([self
.socket
.fileno()], [], [], 1)
1975 if rd
: self
.handle_request()
1977 def server_activate(self
):
1978 self
.base
.server_activate(self
)
1979 if self
.callback
: self
.callback(self
)
1981 DocServer
.base
= BaseHTTPServer
.HTTPServer
1982 DocServer
.handler
= DocHandler
1983 DocHandler
.MessageClass
= Message
1986 DocServer(port
, callback
).serve_until_quit()
1987 except (KeyboardInterrupt, select
.error
):
1990 if completer
: completer()
1992 # ----------------------------------------------------- graphical interface
1995 """Graphical interface (starts web server and pops up a control window)."""
1997 def __init__(self
, window
, port
=7464):
1998 self
.window
= window
2003 self
.server_frm
= Tkinter
.Frame(window
)
2004 self
.title_lbl
= Tkinter
.Label(self
.server_frm
,
2005 text
='Starting server...\n ')
2006 self
.open_btn
= Tkinter
.Button(self
.server_frm
,
2007 text
='open browser', command
=self
.open, state
='disabled')
2008 self
.quit_btn
= Tkinter
.Button(self
.server_frm
,
2009 text
='quit serving', command
=self
.quit
, state
='disabled')
2011 self
.search_frm
= Tkinter
.Frame(window
)
2012 self
.search_lbl
= Tkinter
.Label(self
.search_frm
, text
='Search for')
2013 self
.search_ent
= Tkinter
.Entry(self
.search_frm
)
2014 self
.search_ent
.bind('<Return>', self
.search
)
2015 self
.stop_btn
= Tkinter
.Button(self
.search_frm
,
2016 text
='stop', pady
=0, command
=self
.stop
, state
='disabled')
2017 if sys
.platform
== 'win32':
2018 # Trying to hide and show this button crashes under Windows.
2019 self
.stop_btn
.pack(side
='right')
2021 self
.window
.title('pydoc')
2022 self
.window
.protocol('WM_DELETE_WINDOW', self
.quit
)
2023 self
.title_lbl
.pack(side
='top', fill
='x')
2024 self
.open_btn
.pack(side
='left', fill
='x', expand
=1)
2025 self
.quit_btn
.pack(side
='right', fill
='x', expand
=1)
2026 self
.server_frm
.pack(side
='top', fill
='x')
2028 self
.search_lbl
.pack(side
='left')
2029 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2030 self
.search_frm
.pack(side
='top', fill
='x')
2031 self
.search_ent
.focus_set()
2033 font
= ('helvetica', sys
.platform
== 'win32' and 8 or 10)
2034 self
.result_lst
= Tkinter
.Listbox(window
, font
=font
, height
=6)
2035 self
.result_lst
.bind('<Button-1>', self
.select
)
2036 self
.result_lst
.bind('<Double-Button-1>', self
.goto
)
2037 self
.result_scr
= Tkinter
.Scrollbar(window
,
2038 orient
='vertical', command
=self
.result_lst
.yview
)
2039 self
.result_lst
.config(yscrollcommand
=self
.result_scr
.set)
2041 self
.result_frm
= Tkinter
.Frame(window
)
2042 self
.goto_btn
= Tkinter
.Button(self
.result_frm
,
2043 text
='go to selected', command
=self
.goto
)
2044 self
.hide_btn
= Tkinter
.Button(self
.result_frm
,
2045 text
='hide results', command
=self
.hide
)
2046 self
.goto_btn
.pack(side
='left', fill
='x', expand
=1)
2047 self
.hide_btn
.pack(side
='right', fill
='x', expand
=1)
2049 self
.window
.update()
2050 self
.minwidth
= self
.window
.winfo_width()
2051 self
.minheight
= self
.window
.winfo_height()
2052 self
.bigminheight
= (self
.server_frm
.winfo_reqheight() +
2053 self
.search_frm
.winfo_reqheight() +
2054 self
.result_lst
.winfo_reqheight() +
2055 self
.result_frm
.winfo_reqheight())
2056 self
.bigwidth
, self
.bigheight
= self
.minwidth
, self
.bigminheight
2058 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2059 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2060 self
.window
.tk
.willdispatch()
2064 target
=serve
, args
=(port
, self
.ready
, self
.quit
)).start()
2066 def ready(self
, server
):
2067 self
.server
= server
2068 self
.title_lbl
.config(
2069 text
='Python documentation server at\n' + server
.url
)
2070 self
.open_btn
.config(state
='normal')
2071 self
.quit_btn
.config(state
='normal')
2073 def open(self
, event
=None, url
=None):
2074 url
= url
or self
.server
.url
2077 webbrowser
.open(url
)
2078 except ImportError: # pre-webbrowser.py compatibility
2079 if sys
.platform
== 'win32':
2080 os
.system('start "%s"' % url
)
2081 elif sys
.platform
== 'mac':
2083 except ImportError: pass
2084 else: ic
.launchurl(url
)
2086 rc
= os
.system('netscape -remote "openURL(%s)" &' % url
)
2087 if rc
: os
.system('netscape "%s" &' % url
)
2089 def quit(self
, event
=None):
2091 self
.server
.quit
= 1
2094 def search(self
, event
=None):
2095 key
= self
.search_ent
.get()
2096 self
.stop_btn
.pack(side
='right')
2097 self
.stop_btn
.config(state
='normal')
2098 self
.search_lbl
.config(text
='Searching for "%s"...' % key
)
2099 self
.search_ent
.forget()
2100 self
.search_lbl
.pack(side
='left')
2101 self
.result_lst
.delete(0, 'end')
2102 self
.goto_btn
.config(state
='disabled')
2107 self
.scanner
.quit
= 1
2108 self
.scanner
= ModuleScanner()
2109 threading
.Thread(target
=self
.scanner
.run
,
2110 args
=(self
.update
, key
, self
.done
)).start()
2112 def update(self
, path
, modname
, desc
):
2113 if modname
[-9:] == '.__init__':
2114 modname
= modname
[:-9] + ' (package)'
2115 self
.result_lst
.insert('end',
2116 modname
+ ' - ' + (desc
or '(no description)'))
2118 def stop(self
, event
=None):
2120 self
.scanner
.quit
= 1
2125 self
.search_lbl
.config(text
='Search for')
2126 self
.search_lbl
.pack(side
='left')
2127 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2128 if sys
.platform
!= 'win32': self
.stop_btn
.forget()
2129 self
.stop_btn
.config(state
='disabled')
2131 def select(self
, event
=None):
2132 self
.goto_btn
.config(state
='normal')
2134 def goto(self
, event
=None):
2135 selection
= self
.result_lst
.curselection()
2137 modname
= split(self
.result_lst
.get(selection
[0]))[0]
2138 self
.open(url
=self
.server
.url
+ modname
+ '.html')
2141 if not self
.expanded
: return
2142 self
.result_frm
.forget()
2143 self
.result_scr
.forget()
2144 self
.result_lst
.forget()
2145 self
.bigwidth
= self
.window
.winfo_width()
2146 self
.bigheight
= self
.window
.winfo_height()
2147 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2148 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2152 if self
.expanded
: return
2153 self
.result_frm
.pack(side
='bottom', fill
='x')
2154 self
.result_scr
.pack(side
='right', fill
='y')
2155 self
.result_lst
.pack(side
='top', fill
='both', expand
=1)
2156 self
.window
.wm_geometry('%dx%d' % (self
.bigwidth
, self
.bigheight
))
2157 self
.window
.wm_minsize(self
.minwidth
, self
.bigminheight
)
2160 def hide(self
, event
=None):
2167 # Tk will crash if pythonw.exe has an XP .manifest
2168 # file and the root has is not destroyed explicitly.
2169 # If the problem is ever fixed in Tk, the explicit
2176 except KeyboardInterrupt:
2179 # -------------------------------------------------- command-line interface
2182 return isinstance(x
, str) and find(x
, os
.sep
) >= 0
2185 """Command-line interface (looks at sys.argv to decide what to do)."""
2187 class BadUsage
: pass
2189 # Scripts don't get the current directory in their path by default.
2190 scriptdir
= os
.path
.dirname(sys
.argv
[0])
2191 if scriptdir
in sys
.path
:
2192 sys
.path
.remove(scriptdir
)
2193 sys
.path
.insert(0, '.')
2196 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'gk:p:w')
2199 for opt
, val
in opts
:
2212 print 'pydoc server ready at %s' % server
.url
2214 print 'pydoc server stopped'
2215 serve(port
, ready
, stopped
)
2220 if not args
: raise BadUsage
2222 if ispath(arg
) and not os
.path
.exists(arg
):
2223 print 'file %r does not exist' % arg
2226 if ispath(arg
) and os
.path
.isfile(arg
):
2227 arg
= importfile(arg
)
2229 if ispath(arg
) and os
.path
.isdir(arg
):
2235 except ErrorDuringImport
, value
:
2238 except (getopt
.error
, BadUsage
):
2239 cmd
= os
.path
.basename(sys
.argv
[0])
2240 print """pydoc - the Python documentation tool
2243 Show text documentation on something. <name> may be the name of a
2244 Python keyword, topic, function, module, or package, or a dotted
2245 reference to a class or function within a module or module in a
2246 package. If <name> contains a '%s', it is used as the path to a
2247 Python source file to document. If name is 'keywords', 'topics',
2248 or 'modules', a listing of these things is displayed.
2251 Search for a keyword in the synopsis lines of all available modules.
2254 Start an HTTP server on the given port on the local machine.
2257 Pop up a graphical interface for finding and serving documentation.
2260 Write out the HTML documentation for a module to a file in the current
2261 directory. If <name> contains a '%s', it is treated as a filename; if
2262 it names a directory, documentation is written for all the contents.
2263 """ % (cmd
, os
.sep
, cmd
, cmd
, cmd
, cmd
, os
.sep
)
2265 if __name__
== '__main__': cli()