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
)
191 file = open(filename
)
192 if info
and 'b' in info
[2]: # binary modules have to be imported
193 try: module
= imp
.load_module('__temp__', file, filename
, info
[1:])
195 result
= split(module
.__doc
__ or '', '\n')[0]
196 del sys
.modules
['__temp__']
197 else: # text modules can be directly examined
198 line
= file.readline()
199 while line
[:1] == '#' or not strip(line
):
200 line
= file.readline()
203 if line
[:4] == 'r"""': line
= line
[1:]
204 if line
[:3] == '"""':
206 if line
[-1:] == '\\': line
= line
[:-1]
207 while not strip(line
):
208 line
= file.readline()
210 result
= strip(split(line
, '"""')[0])
213 cache
[filename
] = (mtime
, result
)
216 class ErrorDuringImport(Exception):
217 """Errors that occurred while trying to import something to document it."""
218 def __init__(self
, filename
, (exc
, value
, tb
)):
219 self
.filename
= filename
226 if type(exc
) is types
.ClassType
:
228 return 'problem in %s - %s: %s' % (self
.filename
, exc
, self
.value
)
230 def importfile(path
):
231 """Import a Python source file or compiled file given its path."""
232 magic
= imp
.get_magic()
233 file = open(path
, 'r')
234 if file.read(len(magic
)) == magic
:
235 kind
= imp
.PY_COMPILED
239 filename
= os
.path
.basename(path
)
240 name
, ext
= os
.path
.splitext(filename
)
241 file = open(path
, 'r')
243 module
= imp
.load_module(name
, file, path
, (ext
, 'r', kind
))
245 raise ErrorDuringImport(path
, sys
.exc_info())
249 def safeimport(path
, forceload
=0, cache
={}):
250 """Import a module; handle errors; return None if the module isn't found.
252 If the module *is* found but an exception occurs, it's wrapped in an
253 ErrorDuringImport exception and reraised. Unlike __import__, if a
254 package path is specified, the module at the end of the path is returned,
255 not the package at the beginning. If the optional 'forceload' argument
256 is 1, we reload the module from disk (unless it's a dynamic extension)."""
257 if forceload
and path
in sys
.modules
:
258 # This is the only way to be sure. Checking the mtime of the file
259 # isn't good enough (e.g. what if the module contains a class that
260 # inherits from another module that has changed?).
261 if path
not in sys
.builtin_module_names
:
262 # Python never loads a dynamic extension a second time from the
263 # same path, even if the file is changed or missing. Deleting
264 # the entry in sys.modules doesn't help for dynamic extensions,
265 # so we're not even going to try to keep them up to date.
266 info
= inspect
.getmoduleinfo(sys
.modules
[path
].__file
__)
267 if info
[3] != imp
.C_EXTENSION
:
268 cache
[path
] = sys
.modules
[path
] # prevent module from clearing
269 del sys
.modules
[path
]
271 module
= __import__(path
)
273 # Did the error occur before or after the module was found?
274 (exc
, value
, tb
) = info
= sys
.exc_info()
275 if path
in sys
.modules
:
276 # An error occurred while executing the imported module.
277 raise ErrorDuringImport(sys
.modules
[path
].__file
__, info
)
278 elif exc
is SyntaxError:
279 # A SyntaxError occurred before we could execute the module.
280 raise ErrorDuringImport(value
.filename
, info
)
281 elif exc
is ImportError and \
282 split(lower(str(value
)))[:2] == ['no', 'module']:
283 # The module was not found.
286 # Some other error occurred during the importing process.
287 raise ErrorDuringImport(path
, sys
.exc_info())
288 for part
in split(path
, '.')[1:]:
289 try: module
= getattr(module
, part
)
290 except AttributeError: return None
293 # ---------------------------------------------------- formatter base class
296 def document(self
, object, name
=None, *args
):
297 """Generate documentation for an object."""
298 args
= (object, name
) + args
299 # 'try' clause is to attempt to handle the possibility that inspect
300 # identifies something in a way that pydoc itself has issues handling;
301 # think 'super' and how it is a descriptor (which raises the exception
302 # by lacking a __name__ attribute) and an instance.
304 if inspect
.ismodule(object): return self
.docmodule(*args
)
305 if inspect
.isclass(object): return self
.docclass(*args
)
306 if inspect
.isroutine(object): return self
.docroutine(*args
)
307 except AttributeError:
309 if isinstance(object, property): return self
.docproperty(*args
)
310 return self
.docother(*args
)
312 def fail(self
, object, name
=None, *args
):
313 """Raise an exception for unimplemented types."""
314 message
= "don't know how to document object%s of type %s" % (
315 name
and ' ' + repr(name
), type(object).__name
__)
316 raise TypeError, message
318 docmodule
= docclass
= docroutine
= docother
= fail
320 def getdocloc(self
, object):
321 """Return the location of module docs or None"""
324 file = inspect
.getabsfile(object)
328 docloc
= os
.environ
.get("PYTHONDOCS",
329 "http://www.python.org/doc/current/lib")
330 basedir
= os
.path
.join(sys
.exec_prefix
, "lib",
331 "python"+sys
.version
[0:3])
332 if (isinstance(object, type(os
)) and
333 (object.__name
__ in ('errno', 'exceptions', 'gc', 'imp',
334 'marshal', 'posix', 'signal', 'sys',
335 'thread', 'zipimport') or
336 (file.startswith(basedir
) and
337 not file.startswith(os
.path
.join(basedir
, 'site-packages'))))):
338 htmlfile
= "module-%s.html" % object.__name
__
339 if docloc
.startswith("http://"):
340 docloc
= "%s/%s" % (docloc
.rstrip("/"), htmlfile
)
342 docloc
= os
.path
.join(docloc
, htmlfile
)
347 # -------------------------------------------- HTML documentation generator
349 class HTMLRepr(Repr
):
350 """Class for safely making an HTML representation of a Python object."""
353 self
.maxlist
= self
.maxtuple
= 20
355 self
.maxstring
= self
.maxother
= 100
357 def escape(self
, text
):
358 return replace(text
, '&', '&', '<', '<', '>', '>')
360 def repr(self
, object):
361 return Repr
.repr(self
, object)
363 def repr1(self
, x
, level
):
364 if hasattr(type(x
), '__name__'):
365 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
366 if hasattr(self
, methodname
):
367 return getattr(self
, methodname
)(x
, level
)
368 return self
.escape(cram(stripid(repr(x
)), self
.maxother
))
370 def repr_string(self
, x
, level
):
371 test
= cram(x
, self
.maxstring
)
372 testrepr
= repr(test
)
373 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
374 # Backslashes are only literal in the string and are never
375 # needed to make any special characters, so show a raw string.
376 return 'r' + testrepr
[0] + self
.escape(test
) + testrepr
[0]
377 return re
.sub(r
'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
378 r'<font color="#c040c0">\1</font>',
379 self
.escape(testrepr
))
381 repr_str
= repr_string
383 def repr_instance(self
, x
, level
):
385 return self
.escape(cram(stripid(repr(x
)), self
.maxstring
))
387 return self
.escape('<%s instance>' % x
.__class
__.__name
__)
389 repr_unicode
= repr_string
392 """Formatter class for HTML documentation."""
394 # ------------------------------------------- HTML formatting utilities
396 _repr_instance
= HTMLRepr()
397 repr = _repr_instance
.repr
398 escape
= _repr_instance
.escape
400 def page(self
, title
, contents
):
401 """Format an HTML page."""
403 <!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
404 <html><head><title>Python: %s</title>
405 </head><body bgcolor="#f0f0f8">
407 </body></html>''' % (title
, contents
)
409 def heading(self
, title
, fgcol
, bgcol
, extras
=''):
410 """Format a page heading."""
412 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
414 <td valign=bottom> <br>
415 <font color="%s" face="helvetica, arial"> <br>%s</font></td
416 ><td align=right valign=bottom
417 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
418 ''' % (bgcol
, fgcol
, title
, fgcol
, extras
or ' ')
420 def section(self
, title
, fgcol
, bgcol
, contents
, width
=6,
421 prelude
='', marginalia
=None, gap
=' '):
422 """Format a section with a heading."""
423 if marginalia
is None:
424 marginalia
= '<tt>' + ' ' * width
+ '</tt>'
426 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
428 <td colspan=3 valign=bottom> <br>
429 <font color="%s" face="helvetica, arial">%s</font></td></tr>
430 ''' % (bgcol
, fgcol
, title
)
432 result
= result
+ '''
433 <tr bgcolor="%s"><td rowspan=2>%s</td>
434 <td colspan=2>%s</td></tr>
435 <tr><td>%s</td>''' % (bgcol
, marginalia
, prelude
, gap
)
437 result
= result
+ '''
438 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol
, marginalia
, gap
)
440 return result
+ '\n<td width="100%%">%s</td></tr></table>' % contents
442 def bigsection(self
, title
, *args
):
443 """Format a section with a big heading."""
444 title
= '<big><strong>%s</strong></big>' % title
445 return self
.section(title
, *args
)
447 def preformat(self
, text
):
448 """Format literal preformatted text."""
449 text
= self
.escape(expandtabs(text
))
450 return replace(text
, '\n\n', '\n \n', '\n\n', '\n \n',
451 ' ', ' ', '\n', '<br>\n')
453 def multicolumn(self
, list, format
, cols
=4):
454 """Format a list of items into a multi-column list."""
456 rows
= (len(list)+cols
-1)/cols
457 for col
in range(cols
):
458 result
= result
+ '<td width="%d%%" valign=top>' % (100/cols
)
459 for i
in range(rows
*col
, rows
*col
+rows
):
461 result
= result
+ format(list[i
]) + '<br>\n'
462 result
= result
+ '</td>'
463 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
465 def grey(self
, text
): return '<font color="#909090">%s</font>' % text
467 def namelink(self
, name
, *dicts
):
468 """Make a link for an identifier, given name-to-URL mappings."""
471 return '<a href="%s">%s</a>' % (dict[name
], name
)
474 def classlink(self
, object, modname
):
475 """Make a link for a class."""
476 name
, module
= object.__name
__, sys
.modules
.get(object.__module
__)
477 if hasattr(module
, name
) and getattr(module
, name
) is object:
478 return '<a href="%s.html#%s">%s</a>' % (
479 module
.__name
__, name
, classname(object, modname
))
480 return classname(object, modname
)
482 def modulelink(self
, object):
483 """Make a link for a module."""
484 return '<a href="%s.html">%s</a>' % (object.__name
__, object.__name
__)
486 def modpkglink(self
, (name
, path
, ispackage
, shadowed
)):
487 """Make a link for a module or package to display in an index."""
489 return self
.grey(name
)
491 url
= '%s.%s.html' % (path
, name
)
493 url
= '%s.html' % name
495 text
= '<strong>%s</strong> (package)' % name
498 return '<a href="%s">%s</a>' % (url
, text
)
500 def markup(self
, text
, escape
=None, funcs
={}, classes
={}, methods
={}):
501 """Mark up some plain text, given a context of symbols to look for.
502 Each context dictionary maps object names to anchor names."""
503 escape
= escape
or self
.escape
506 pattern
= re
.compile(r
'\b((http|ftp)://\S+[\w/]|'
511 match
= pattern
.search(text
, here
)
513 start
, end
= match
.span()
514 results
.append(escape(text
[here
:start
]))
516 all
, scheme
, rfc
, pep
, selfdot
, name
= match
.groups()
518 url
= escape(all
).replace('"', '"')
519 results
.append('<a href="%s">%s</a>' % (url
, url
))
521 url
= 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc
)
522 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
524 url
= 'http://www.python.org/peps/pep-%04d.html' % int(pep
)
525 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
526 elif text
[end
:end
+1] == '(':
527 results
.append(self
.namelink(name
, methods
, funcs
, classes
))
529 results
.append('self.<strong>%s</strong>' % name
)
531 results
.append(self
.namelink(name
, classes
))
533 results
.append(escape(text
[here
:]))
534 return join(results
, '')
536 # ---------------------------------------------- type-specific routines
538 def formattree(self
, tree
, modname
, parent
=None):
539 """Produce HTML for a class tree as given by inspect.getclasstree()."""
542 if type(entry
) is type(()):
544 result
= result
+ '<dt><font face="helvetica, arial">'
545 result
= result
+ self
.classlink(c
, modname
)
546 if bases
and bases
!= (parent
,):
549 parents
.append(self
.classlink(base
, modname
))
550 result
= result
+ '(' + join(parents
, ', ') + ')'
551 result
= result
+ '\n</font></dt>'
552 elif type(entry
) is type([]):
553 result
= result
+ '<dd>\n%s</dd>\n' % self
.formattree(
555 return '<dl>\n%s</dl>\n' % result
557 def docmodule(self
, object, name
=None, mod
=None, *ignored
):
558 """Produce HTML documentation for a module object."""
559 name
= object.__name
__ # ignore the passed-in name
562 except AttributeError:
564 parts
= split(name
, '.')
566 for i
in range(len(parts
)-1):
568 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
569 (join(parts
[:i
+1], '.'), parts
[i
]))
570 linkedname
= join(links
+ parts
[-1:], '.')
571 head
= '<big><big><strong>%s</strong></big></big>' % linkedname
573 path
= inspect
.getabsfile(object)
575 if sys
.platform
== 'win32':
577 url
= nturl2path
.pathname2url(path
)
578 filelink
= '<a href="file:%s">%s</a>' % (url
, path
)
580 filelink
= '(built-in)'
582 if hasattr(object, '__version__'):
583 version
= str(object.__version
__)
584 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
585 version
= strip(version
[11:-1])
586 info
.append('version %s' % self
.escape(version
))
587 if hasattr(object, '__date__'):
588 info
.append(self
.escape(str(object.__date
__)))
590 head
= head
+ ' (%s)' % join(info
, ', ')
591 docloc
= self
.getdocloc(object)
592 if docloc
is not None:
593 docloc
= '<br><a href="%(docloc)s">Module Docs</a>' % locals()
596 result
= self
.heading(
597 head
, '#ffffff', '#7799ee',
598 '<a href=".">index</a><br>' + filelink
+ docloc
)
600 modules
= inspect
.getmembers(object, inspect
.ismodule
)
602 classes
, cdict
= [], {}
603 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
604 # if __all__ exists, believe it. Otherwise use old heuristic.
605 if (all
is not None or
606 (inspect
.getmodule(value
) or object) is object):
607 if visiblename(key
, all
):
608 classes
.append((key
, value
))
609 cdict
[key
] = cdict
[value
] = '#' + key
610 for key
, value
in classes
:
611 for base
in value
.__bases
__:
612 key
, modname
= base
.__name
__, base
.__module
__
613 module
= sys
.modules
.get(modname
)
614 if modname
!= name
and module
and hasattr(module
, key
):
615 if getattr(module
, key
) is base
:
617 cdict
[key
] = cdict
[base
] = modname
+ '.html#' + key
618 funcs
, fdict
= [], {}
619 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
620 # if __all__ exists, believe it. Otherwise use old heuristic.
621 if (all
is not None or
622 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
623 if visiblename(key
, all
):
624 funcs
.append((key
, value
))
625 fdict
[key
] = '#-' + key
626 if inspect
.isfunction(value
): fdict
[value
] = fdict
[key
]
628 for key
, value
in inspect
.getmembers(object, isdata
):
629 if visiblename(key
, all
):
630 data
.append((key
, value
))
632 doc
= self
.markup(getdoc(object), self
.preformat
, fdict
, cdict
)
633 doc
= doc
and '<tt>%s</tt>' % doc
634 result
= result
+ '<p>%s</p>\n' % doc
636 if hasattr(object, '__path__'):
639 for file in os
.listdir(object.__path
__[0]):
640 path
= os
.path
.join(object.__path
__[0], file)
641 modname
= inspect
.getmodulename(file)
642 if modname
!= '__init__':
643 if modname
and modname
not in modnames
:
644 modpkgs
.append((modname
, name
, 0, 0))
645 modnames
.append(modname
)
646 elif ispackage(path
):
647 modpkgs
.append((file, name
, 1, 0))
649 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
650 result
= result
+ self
.bigsection(
651 'Package Contents', '#ffffff', '#aa55cc', contents
)
653 contents
= self
.multicolumn(
654 modules
, lambda (key
, value
), s
=self
: s
.modulelink(value
))
655 result
= result
+ self
.bigsection(
656 'Modules', '#fffff', '#aa55cc', contents
)
659 classlist
= map(lambda (key
, value
): value
, classes
)
661 self
.formattree(inspect
.getclasstree(classlist
, 1), name
)]
662 for key
, value
in classes
:
663 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
664 result
= result
+ self
.bigsection(
665 'Classes', '#ffffff', '#ee77aa', join(contents
))
668 for key
, value
in funcs
:
669 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
670 result
= result
+ self
.bigsection(
671 'Functions', '#ffffff', '#eeaa77', join(contents
))
674 for key
, value
in data
:
675 contents
.append(self
.document(value
, key
))
676 result
= result
+ self
.bigsection(
677 'Data', '#ffffff', '#55aa55', join(contents
, '<br>\n'))
678 if hasattr(object, '__author__'):
679 contents
= self
.markup(str(object.__author
__), self
.preformat
)
680 result
= result
+ self
.bigsection(
681 'Author', '#ffffff', '#7799ee', contents
)
682 if hasattr(object, '__credits__'):
683 contents
= self
.markup(str(object.__credits
__), self
.preformat
)
684 result
= result
+ self
.bigsection(
685 'Credits', '#ffffff', '#7799ee', contents
)
689 def docclass(self
, object, name
=None, mod
=None, funcs
={}, classes
={},
691 """Produce HTML documentation for a class object."""
692 realname
= object.__name
__
693 name
= name
or realname
694 bases
= object.__bases
__
697 push
= contents
.append
699 # Cute little class to pump out a horizontal rule between sections.
700 class HorizontalRule
:
707 hr
= HorizontalRule()
709 # List the mro, if non-trivial.
710 mro
= deque(inspect
.getmro(object))
713 push('<dl><dt>Method resolution order:</dt>\n')
715 push('<dd>%s</dd>\n' % self
.classlink(base
,
719 def spill(msg
, attrs
, predicate
):
720 ok
, attrs
= _split_list(attrs
, predicate
)
724 for name
, kind
, homecls
, value
in ok
:
725 push(self
.document(getattr(object, name
), name
, mod
,
726 funcs
, classes
, mdict
, object))
730 def spilldescriptors(msg
, attrs
, predicate
):
731 ok
, attrs
= _split_list(attrs
, predicate
)
735 for name
, kind
, homecls
, value
in ok
:
736 push(self
._docdescriptor
(name
, value
, mod
))
739 def spilldata(msg
, attrs
, predicate
):
740 ok
, attrs
= _split_list(attrs
, predicate
)
744 for name
, kind
, homecls
, value
in ok
:
745 base
= self
.docother(getattr(object, name
), name
, mod
)
746 if callable(value
) or inspect
.isdatadescriptor(value
):
747 doc
= getattr(value
, "__doc__", None)
751 push('<dl><dt>%s</dl>\n' % base
)
753 doc
= self
.markup(getdoc(value
), self
.preformat
,
754 funcs
, classes
, mdict
)
755 doc
= '<dd><tt>%s</tt>' % doc
756 push('<dl><dt>%s%s</dl>\n' % (base
, doc
))
760 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
761 classify_class_attrs(object))
763 for key
, kind
, homecls
, value
in attrs
:
764 mdict
[key
] = anchor
= '#' + name
+ '-' + key
765 value
= getattr(object, key
)
767 # The value may not be hashable (e.g., a data attr with
768 # a dict or list value).
769 mdict
[value
] = anchor
775 thisclass
= mro
.popleft()
777 thisclass
= attrs
[0][2]
778 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
780 if thisclass
is __builtin__
.object:
783 elif thisclass
is object:
786 tag
= 'inherited from %s' % self
.classlink(thisclass
,
790 # Sort attrs by name.
791 attrs
.sort(key
=lambda t
: t
[0])
793 # Pump out the attrs, segregated by kind.
794 attrs
= spill('Methods %s' % tag
, attrs
,
795 lambda t
: t
[1] == 'method')
796 attrs
= spill('Class methods %s' % tag
, attrs
,
797 lambda t
: t
[1] == 'class method')
798 attrs
= spill('Static methods %s' % tag
, attrs
,
799 lambda t
: t
[1] == 'static method')
800 attrs
= spilldescriptors('Data descriptors %s' % tag
, attrs
,
801 lambda t
: t
[1] == 'data descriptor')
802 attrs
= spilldata('Data and other attributes %s' % tag
, attrs
,
803 lambda t
: t
[1] == 'data')
807 contents
= ''.join(contents
)
810 title
= '<a name="%s">class <strong>%s</strong></a>' % (
813 title
= '<strong>%s</strong> = <a name="%s">class %s</a>' % (
814 name
, name
, realname
)
818 parents
.append(self
.classlink(base
, object.__module
__))
819 title
= title
+ '(%s)' % join(parents
, ', ')
820 doc
= self
.markup(getdoc(object), self
.preformat
, funcs
, classes
, mdict
)
821 doc
= doc
and '<tt>%s<br> </tt>' % doc
823 return self
.section(title
, '#000000', '#ffc8d8', contents
, 3, doc
)
825 def formatvalue(self
, object):
826 """Format an argument default value as text."""
827 return self
.grey('=' + self
.repr(object))
829 def docroutine(self
, object, name
=None, mod
=None,
830 funcs
={}, classes
={}, methods
={}, cl
=None):
831 """Produce HTML documentation for a function or method object."""
832 realname
= object.__name
__
833 name
= name
or realname
834 anchor
= (cl
and cl
.__name
__ or '') + '-' + name
837 if inspect
.ismethod(object):
838 imclass
= object.im_class
840 if imclass
is not cl
:
841 note
= ' from ' + self
.classlink(imclass
, mod
)
844 note
= ' method of %s instance' % self
.classlink(
845 object.im_self
.__class
__, mod
)
847 note
= ' unbound %s method' % self
.classlink(imclass
,mod
)
848 object = object.im_func
851 title
= '<a name="%s"><strong>%s</strong></a>' % (anchor
, realname
)
853 if (cl
and realname
in cl
.__dict
__ and
854 cl
.__dict
__[realname
] is object):
855 reallink
= '<a href="#%s">%s</a>' % (
856 cl
.__name
__ + '-' + realname
, realname
)
860 title
= '<a name="%s"><strong>%s</strong></a> = %s' % (
861 anchor
, name
, reallink
)
862 if inspect
.isfunction(object):
863 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
864 argspec
= inspect
.formatargspec(
865 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
866 if realname
== '<lambda>':
867 title
= '<strong>%s</strong> <em>lambda</em> ' % name
868 argspec
= argspec
[1:-1] # remove parentheses
872 decl
= title
+ argspec
+ (note
and self
.grey(
873 '<font face="helvetica, arial">%s</font>' % note
))
876 return '<dl><dt>%s</dt></dl>\n' % decl
879 getdoc(object), self
.preformat
, funcs
, classes
, methods
)
880 doc
= doc
and '<dd><tt>%s</tt></dd>' % doc
881 return '<dl><dt>%s</dt>%s</dl>\n' % (decl
, doc
)
883 def _docdescriptor(self
, name
, value
, mod
):
885 push
= results
.append
888 push('<dl><dt><strong>%s</strong></dt>\n' % name
)
889 if value
.__doc
__ is not None:
890 doc
= self
.markup(getdoc(value
), self
.preformat
)
891 push('<dd><tt>%s</tt></dd>\n' % doc
)
894 return ''.join(results
)
896 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
897 """Produce html documentation for a property."""
898 return self
._docdescriptor
(name
, object, mod
)
900 def docother(self
, object, name
=None, mod
=None, *ignored
):
901 """Produce HTML documentation for a data object."""
902 lhs
= name
and '<strong>%s</strong> = ' % name
or ''
903 return lhs
+ self
.repr(object)
905 def index(self
, dir, shadowed
=None):
906 """Generate an HTML index for a directory of modules."""
908 if shadowed
is None: shadowed
= {}
910 files
= os
.listdir(dir)
912 def found(name
, ispackage
,
913 modpkgs
=modpkgs
, shadowed
=shadowed
, seen
=seen
):
915 modpkgs
.append((name
, '', ispackage
, name
in shadowed
))
919 # Package spam/__init__.py takes precedence over module spam.py.
921 path
= os
.path
.join(dir, file)
922 if ispackage(path
): found(file, 1)
924 path
= os
.path
.join(dir, file)
925 if os
.path
.isfile(path
):
926 modname
= inspect
.getmodulename(file)
927 if modname
: found(modname
, 0)
930 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
931 return self
.bigsection(dir, '#ffffff', '#ee77aa', contents
)
933 # -------------------------------------------- text documentation generator
935 class TextRepr(Repr
):
936 """Class for safely making a text representation of a Python object."""
939 self
.maxlist
= self
.maxtuple
= 20
941 self
.maxstring
= self
.maxother
= 100
943 def repr1(self
, x
, level
):
944 if hasattr(type(x
), '__name__'):
945 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
946 if hasattr(self
, methodname
):
947 return getattr(self
, methodname
)(x
, level
)
948 return cram(stripid(repr(x
)), self
.maxother
)
950 def repr_string(self
, x
, level
):
951 test
= cram(x
, self
.maxstring
)
952 testrepr
= repr(test
)
953 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
954 # Backslashes are only literal in the string and are never
955 # needed to make any special characters, so show a raw string.
956 return 'r' + testrepr
[0] + test
+ testrepr
[0]
959 repr_str
= repr_string
961 def repr_instance(self
, x
, level
):
963 return cram(stripid(repr(x
)), self
.maxstring
)
965 return '<%s instance>' % x
.__class
__.__name
__
968 """Formatter class for text documentation."""
970 # ------------------------------------------- text formatting utilities
972 _repr_instance
= TextRepr()
973 repr = _repr_instance
.repr
975 def bold(self
, text
):
976 """Format a string in bold by overstriking."""
977 return join(map(lambda ch
: ch
+ '\b' + ch
, text
), '')
979 def indent(self
, text
, prefix
=' '):
980 """Indent text by prepending a given prefix to each line."""
981 if not text
: return ''
982 lines
= split(text
, '\n')
983 lines
= map(lambda line
, prefix
=prefix
: prefix
+ line
, lines
)
984 if lines
: lines
[-1] = rstrip(lines
[-1])
985 return join(lines
, '\n')
987 def section(self
, title
, contents
):
988 """Format a section with a given heading."""
989 return self
.bold(title
) + '\n' + rstrip(self
.indent(contents
)) + '\n\n'
991 # ---------------------------------------------- type-specific routines
993 def formattree(self
, tree
, modname
, parent
=None, prefix
=''):
994 """Render in text a class tree as returned by inspect.getclasstree()."""
997 if type(entry
) is type(()):
999 result
= result
+ prefix
+ classname(c
, modname
)
1000 if bases
and bases
!= (parent
,):
1001 parents
= map(lambda c
, m
=modname
: classname(c
, m
), bases
)
1002 result
= result
+ '(%s)' % join(parents
, ', ')
1003 result
= result
+ '\n'
1004 elif type(entry
) is type([]):
1005 result
= result
+ self
.formattree(
1006 entry
, modname
, c
, prefix
+ ' ')
1009 def docmodule(self
, object, name
=None, mod
=None):
1010 """Produce text documentation for a given module object."""
1011 name
= object.__name
__ # ignore the passed-in name
1012 synop
, desc
= splitdoc(getdoc(object))
1013 result
= self
.section('NAME', name
+ (synop
and ' - ' + synop
))
1016 all
= object.__all
__
1017 except AttributeError:
1021 file = inspect
.getabsfile(object)
1024 result
= result
+ self
.section('FILE', file)
1026 docloc
= self
.getdocloc(object)
1027 if docloc
is not None:
1028 result
= result
+ self
.section('MODULE DOCS', docloc
)
1031 result
= result
+ self
.section('DESCRIPTION', desc
)
1034 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
1035 # if __all__ exists, believe it. Otherwise use old heuristic.
1037 or (inspect
.getmodule(value
) or object) is object):
1038 if visiblename(key
, all
):
1039 classes
.append((key
, value
))
1041 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
1042 # if __all__ exists, believe it. Otherwise use old heuristic.
1043 if (all
is not None or
1044 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
1045 if visiblename(key
, all
):
1046 funcs
.append((key
, value
))
1048 for key
, value
in inspect
.getmembers(object, isdata
):
1049 if visiblename(key
, all
):
1050 data
.append((key
, value
))
1052 if hasattr(object, '__path__'):
1054 for file in os
.listdir(object.__path
__[0]):
1055 path
= os
.path
.join(object.__path
__[0], file)
1056 modname
= inspect
.getmodulename(file)
1057 if modname
!= '__init__':
1058 if modname
and modname
not in modpkgs
:
1059 modpkgs
.append(modname
)
1060 elif ispackage(path
):
1061 modpkgs
.append(file + ' (package)')
1063 result
= result
+ self
.section(
1064 'PACKAGE CONTENTS', join(modpkgs
, '\n'))
1067 classlist
= map(lambda (key
, value
): value
, classes
)
1068 contents
= [self
.formattree(
1069 inspect
.getclasstree(classlist
, 1), name
)]
1070 for key
, value
in classes
:
1071 contents
.append(self
.document(value
, key
, name
))
1072 result
= result
+ self
.section('CLASSES', join(contents
, '\n'))
1076 for key
, value
in funcs
:
1077 contents
.append(self
.document(value
, key
, name
))
1078 result
= result
+ self
.section('FUNCTIONS', join(contents
, '\n'))
1082 for key
, value
in data
:
1083 contents
.append(self
.docother(value
, key
, name
, maxlen
=70))
1084 result
= result
+ self
.section('DATA', join(contents
, '\n'))
1086 if hasattr(object, '__version__'):
1087 version
= str(object.__version
__)
1088 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
1089 version
= strip(version
[11:-1])
1090 result
= result
+ self
.section('VERSION', version
)
1091 if hasattr(object, '__date__'):
1092 result
= result
+ self
.section('DATE', str(object.__date
__))
1093 if hasattr(object, '__author__'):
1094 result
= result
+ self
.section('AUTHOR', str(object.__author
__))
1095 if hasattr(object, '__credits__'):
1096 result
= result
+ self
.section('CREDITS', str(object.__credits
__))
1099 def docclass(self
, object, name
=None, mod
=None):
1100 """Produce text documentation for a given class object."""
1101 realname
= object.__name
__
1102 name
= name
or realname
1103 bases
= object.__bases
__
1105 def makename(c
, m
=object.__module
__):
1106 return classname(c
, m
)
1108 if name
== realname
:
1109 title
= 'class ' + self
.bold(realname
)
1111 title
= self
.bold(name
) + ' = class ' + realname
1113 parents
= map(makename
, bases
)
1114 title
= title
+ '(%s)' % join(parents
, ', ')
1116 doc
= getdoc(object)
1117 contents
= doc
and [doc
+ '\n'] or []
1118 push
= contents
.append
1120 # List the mro, if non-trivial.
1121 mro
= deque(inspect
.getmro(object))
1123 push("Method resolution order:")
1125 push(' ' + makename(base
))
1128 # Cute little class to pump out a horizontal rule between sections.
1129 class HorizontalRule
:
1136 hr
= HorizontalRule()
1138 def spill(msg
, attrs
, predicate
):
1139 ok
, attrs
= _split_list(attrs
, predicate
)
1143 for name
, kind
, homecls
, value
in ok
:
1144 push(self
.document(getattr(object, name
),
1148 def spilldescriptors(msg
, attrs
, predicate
):
1149 ok
, attrs
= _split_list(attrs
, predicate
)
1153 for name
, kind
, homecls
, value
in ok
:
1154 push(self
._docdescriptor
(name
, value
, mod
))
1157 def spilldata(msg
, attrs
, predicate
):
1158 ok
, attrs
= _split_list(attrs
, predicate
)
1162 for name
, kind
, homecls
, value
in ok
:
1163 if callable(value
) or inspect
.isdatadescriptor(value
):
1167 push(self
.docother(getattr(object, name
),
1168 name
, mod
, maxlen
=70, doc
=doc
) + '\n')
1171 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
1172 classify_class_attrs(object))
1175 thisclass
= mro
.popleft()
1177 thisclass
= attrs
[0][2]
1178 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
1180 if thisclass
is __builtin__
.object:
1183 elif thisclass
is object:
1184 tag
= "defined here"
1186 tag
= "inherited from %s" % classname(thisclass
,
1188 filter(lambda t
: not t
[0].startswith('_'), attrs
)
1190 # Sort attrs by name.
1193 # Pump out the attrs, segregated by kind.
1194 attrs
= spill("Methods %s:\n" % tag
, attrs
,
1195 lambda t
: t
[1] == 'method')
1196 attrs
= spill("Class methods %s:\n" % tag
, attrs
,
1197 lambda t
: t
[1] == 'class method')
1198 attrs
= spill("Static methods %s:\n" % tag
, attrs
,
1199 lambda t
: t
[1] == 'static method')
1200 attrs
= spilldescriptors("Data descriptors %s:\n" % tag
, attrs
,
1201 lambda t
: t
[1] == 'data descriptor')
1202 attrs
= spilldata("Data and other attributes %s:\n" % tag
, attrs
,
1203 lambda t
: t
[1] == 'data')
1207 contents
= '\n'.join(contents
)
1210 return title
+ '\n' + self
.indent(rstrip(contents
), ' | ') + '\n'
1212 def formatvalue(self
, object):
1213 """Format an argument default value as text."""
1214 return '=' + self
.repr(object)
1216 def docroutine(self
, object, name
=None, mod
=None, cl
=None):
1217 """Produce text documentation for a function or method object."""
1218 realname
= object.__name
__
1219 name
= name
or realname
1222 if inspect
.ismethod(object):
1223 imclass
= object.im_class
1225 if imclass
is not cl
:
1226 note
= ' from ' + classname(imclass
, mod
)
1229 note
= ' method of %s instance' % classname(
1230 object.im_self
.__class
__, mod
)
1232 note
= ' unbound %s method' % classname(imclass
,mod
)
1233 object = object.im_func
1235 if name
== realname
:
1236 title
= self
.bold(realname
)
1238 if (cl
and realname
in cl
.__dict
__ and
1239 cl
.__dict
__[realname
] is object):
1241 title
= self
.bold(name
) + ' = ' + realname
1242 if inspect
.isfunction(object):
1243 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
1244 argspec
= inspect
.formatargspec(
1245 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
1246 if realname
== '<lambda>':
1248 argspec
= argspec
[1:-1] # remove parentheses
1251 decl
= title
+ argspec
+ note
1256 doc
= getdoc(object) or ''
1257 return decl
+ '\n' + (doc
and rstrip(self
.indent(doc
)) + '\n')
1259 def _docdescriptor(self
, name
, value
, mod
):
1261 push
= results
.append
1264 push(self
.bold(name
))
1266 doc
= getdoc(value
) or ''
1268 push(self
.indent(doc
))
1270 return ''.join(results
)
1272 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
1273 """Produce text documentation for a property."""
1274 return self
._docdescriptor
(name
, object, mod
)
1276 def docother(self
, object, name
=None, mod
=None, parent
=None, maxlen
=None, doc
=None):
1277 """Produce text documentation for a data object."""
1278 repr = self
.repr(object)
1280 line
= (name
and name
+ ' = ' or '') + repr
1281 chop
= maxlen
- len(line
)
1282 if chop
< 0: repr = repr[:chop
] + '...'
1283 line
= (name
and self
.bold(name
) + ' = ' or '') + repr
1285 line
+= '\n' + self
.indent(str(doc
))
1288 # --------------------------------------------------------- user interfaces
1291 """The first time this is called, determine what kind of pager to use."""
1297 """Decide what method to use for paging through text."""
1298 if type(sys
.stdout
) is not types
.FileType
:
1300 if not sys
.stdin
.isatty() or not sys
.stdout
.isatty():
1302 if os
.environ
.get('TERM') in ('dumb', 'emacs'):
1304 if 'PAGER' in os
.environ
:
1305 if sys
.platform
== 'win32': # pipes completely broken in Windows
1306 return lambda text
: tempfilepager(plain(text
), os
.environ
['PAGER'])
1307 elif os
.environ
.get('TERM') in ('dumb', 'emacs'):
1308 return lambda text
: pipepager(plain(text
), os
.environ
['PAGER'])
1310 return lambda text
: pipepager(text
, os
.environ
['PAGER'])
1311 if sys
.platform
== 'win32' or sys
.platform
.startswith('os2'):
1312 return lambda text
: tempfilepager(plain(text
), 'more <')
1313 if hasattr(os
, 'system') and os
.system('(less) 2>/dev/null') == 0:
1314 return lambda text
: pipepager(text
, 'less')
1317 (fd
, filename
) = tempfile
.mkstemp()
1320 if hasattr(os
, 'system') and os
.system('more %s' % filename
) == 0:
1321 return lambda text
: pipepager(text
, 'more')
1328 """Remove boldface formatting from text."""
1329 return re
.sub('.\b', '', text
)
1331 def pipepager(text
, cmd
):
1332 """Page through text by feeding it to another program."""
1333 pipe
= os
.popen(cmd
, 'w')
1338 pass # Ignore broken pipes caused by quitting the pager program.
1340 def tempfilepager(text
, cmd
):
1341 """Page through text by invoking a program on a temporary file."""
1343 filename
= tempfile
.mktemp()
1344 file = open(filename
, 'w')
1348 os
.system(cmd
+ ' ' + filename
)
1353 """Page through text on a text terminal."""
1354 lines
= split(plain(text
), '\n')
1357 fd
= sys
.stdin
.fileno()
1358 old
= tty
.tcgetattr(fd
)
1360 getchar
= lambda: sys
.stdin
.read(1)
1361 except (ImportError, AttributeError):
1363 getchar
= lambda: sys
.stdin
.readline()[:-1][:1]
1366 r
= inc
= os
.environ
.get('LINES', 25) - 1
1367 sys
.stdout
.write(join(lines
[:inc
], '\n') + '\n')
1369 sys
.stdout
.write('-- more --')
1374 sys
.stdout
.write('\r \r')
1376 elif c
in ('\r', '\n'):
1377 sys
.stdout
.write('\r \r' + lines
[r
] + '\n')
1380 if c
in ('b', 'B', '\x1b'):
1383 sys
.stdout
.write('\n' + join(lines
[r
:r
+inc
], '\n') + '\n')
1388 tty
.tcsetattr(fd
, tty
.TCSAFLUSH
, old
)
1390 def plainpager(text
):
1391 """Simply print unformatted text. This is the ultimate fallback."""
1392 sys
.stdout
.write(plain(text
))
1394 def describe(thing
):
1395 """Produce a short description of the given thing."""
1396 if inspect
.ismodule(thing
):
1397 if thing
.__name
__ in sys
.builtin_module_names
:
1398 return 'built-in module ' + thing
.__name
__
1399 if hasattr(thing
, '__path__'):
1400 return 'package ' + thing
.__name
__
1402 return 'module ' + thing
.__name
__
1403 if inspect
.isbuiltin(thing
):
1404 return 'built-in function ' + thing
.__name
__
1405 if inspect
.isclass(thing
):
1406 return 'class ' + thing
.__name
__
1407 if inspect
.isfunction(thing
):
1408 return 'function ' + thing
.__name
__
1409 if inspect
.ismethod(thing
):
1410 return 'method ' + thing
.__name
__
1411 if type(thing
) is types
.InstanceType
:
1412 return 'instance of ' + thing
.__class
__.__name
__
1413 return type(thing
).__name
__
1415 def locate(path
, forceload
=0):
1416 """Locate an object by name or dotted path, importing as necessary."""
1417 parts
= [part
for part
in split(path
, '.') if part
]
1419 while n
< len(parts
):
1420 nextmodule
= safeimport(join(parts
[:n
+1], '.'), forceload
)
1421 if nextmodule
: module
, n
= nextmodule
, n
+ 1
1425 for part
in parts
[n
:]:
1426 try: object = getattr(object, part
)
1427 except AttributeError: return None
1430 if hasattr(__builtin__
, path
):
1431 return getattr(__builtin__
, path
)
1433 # --------------------------------------- interactive interpreter interface
1438 def resolve(thing
, forceload
=0):
1439 """Given an object or a path to an object, get the object and its name."""
1440 if isinstance(thing
, str):
1441 object = locate(thing
, forceload
)
1443 raise ImportError, 'no Python documentation found for %r' % thing
1444 return object, thing
1446 return thing
, getattr(thing
, '__name__', None)
1448 def doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1449 """Display text documentation, given an object or a path to an object."""
1451 object, name
= resolve(thing
, forceload
)
1452 desc
= describe(object)
1453 module
= inspect
.getmodule(object)
1454 if name
and '.' in name
:
1455 desc
+= ' in ' + name
[:name
.rfind('.')]
1456 elif module
and module
is not object:
1457 desc
+= ' in module ' + module
.__name
__
1458 if not (inspect
.ismodule(object) or
1459 inspect
.isclass(object) or
1460 inspect
.isroutine(object) or
1461 isinstance(object, property)):
1462 # If the passed object is a piece of data or an instance,
1463 # document its available methods instead of its value.
1464 object = type(object)
1466 pager(title
% desc
+ '\n\n' + text
.document(object, name
))
1467 except (ImportError, ErrorDuringImport
), value
:
1470 def writedoc(thing
, forceload
=0):
1471 """Write HTML documentation to a file in the current directory."""
1473 object, name
= resolve(thing
, forceload
)
1474 page
= html
.page(describe(object), html
.document(object, name
))
1475 file = open(name
+ '.html', 'w')
1478 print 'wrote', name
+ '.html'
1479 except (ImportError, ErrorDuringImport
), value
:
1482 def writedocs(dir, pkgpath
='', done
=None):
1483 """Write out HTML documentation for all modules in a directory tree."""
1484 if done
is None: done
= {}
1485 for file in os
.listdir(dir):
1486 path
= os
.path
.join(dir, file)
1488 writedocs(path
, pkgpath
+ file + '.', done
)
1489 elif os
.path
.isfile(path
):
1490 modname
= inspect
.getmodulename(path
)
1492 if modname
== '__init__':
1493 modname
= pkgpath
[:-1] # remove trailing period
1495 modname
= pkgpath
+ modname
1496 if modname
not in done
:
1503 'assert': ('ref/assert', ''),
1504 'break': ('ref/break', 'while for'),
1505 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1506 'continue': ('ref/continue', 'while for'),
1507 'def': ('ref/function', ''),
1508 'del': ('ref/del', 'BASICMETHODS'),
1510 'else': ('ref/if', 'while for'),
1512 'exec': ('ref/exec', ''),
1514 'for': ('ref/for', 'break continue while'),
1516 'global': ('ref/global', 'NAMESPACES'),
1517 'if': ('ref/if', 'TRUTHVALUE'),
1518 'import': ('ref/import', 'MODULES'),
1519 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1521 'lambda': ('ref/lambdas', 'FUNCTIONS'),
1524 'pass': ('ref/pass', ''),
1525 'print': ('ref/print', ''),
1526 'raise': ('ref/raise', 'EXCEPTIONS'),
1527 'return': ('ref/return', 'FUNCTIONS'),
1528 'try': ('ref/try', 'EXCEPTIONS'),
1529 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1530 'yield': ('ref/yield', ''),
1534 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
1535 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
1536 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1537 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
1538 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
1539 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1540 'INTEGER': ('ref/integers', 'int range'),
1541 'FLOAT': ('ref/floating', 'float math'),
1542 'COMPLEX': ('ref/imaginary', 'complex cmath'),
1543 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1544 'MAPPINGS': 'DICTIONARIES',
1545 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1546 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1547 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
1548 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
1549 'FRAMEOBJECTS': 'TYPES',
1550 'TRACEBACKS': 'TYPES',
1551 'NONE': ('lib/bltin-null-object', ''),
1552 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1553 'FILES': ('lib/bltin-file-objects', ''),
1554 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1555 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1556 'MODULES': ('lib/typesmodules', 'import'),
1557 'PACKAGES': 'import',
1558 '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'),
1559 'OPERATORS': 'EXPRESSIONS',
1560 'PRECEDENCE': 'EXPRESSIONS',
1561 'OBJECTS': ('ref/objects', 'TYPES'),
1562 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1563 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1564 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1565 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1566 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1567 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1568 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1569 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
1570 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1571 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1572 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
1573 'SCOPING': 'NAMESPACES',
1574 'FRAMES': 'NAMESPACES',
1575 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1576 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1577 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
1578 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1579 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
1580 'PRIVATENAMES': ('ref/atom-identifiers', ''),
1581 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1582 'TUPLES': 'SEQUENCES',
1583 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
1584 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
1585 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
1586 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
1587 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1588 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
1589 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1590 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1591 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1592 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1593 'POWER': ('ref/power', 'EXPRESSIONS'),
1594 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1595 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1596 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1597 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1598 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
1599 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
1600 'ASSERTION': 'assert',
1601 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
1602 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
1604 'PRINTING': 'print',
1605 'RETURNING': 'return',
1606 'IMPORTING': 'import',
1607 'CONDITIONAL': 'if',
1608 'LOOPING': ('ref/compound', 'for while break continue'),
1609 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
1610 'DEBUGGING': ('lib/module-pdb', 'pdb'),
1613 def __init__(self
, input, output
):
1615 self
.output
= output
1617 execdir
= os
.path
.dirname(sys
.executable
)
1618 homedir
= os
.environ
.get('PYTHONHOME')
1619 for dir in [os
.environ
.get('PYTHONDOCS'),
1620 homedir
and os
.path
.join(homedir
, 'doc'),
1621 os
.path
.join(execdir
, 'doc'),
1622 '/usr/doc/python-docs-' + split(sys
.version
)[0],
1623 '/usr/doc/python-' + split(sys
.version
)[0],
1624 '/usr/doc/python-docs-' + sys
.version
[:3],
1625 '/usr/doc/python-' + sys
.version
[:3],
1626 os
.path
.join(sys
.prefix
, 'Resources/English.lproj/Documentation')]:
1627 if dir and os
.path
.isdir(os
.path
.join(dir, 'lib')):
1631 if inspect
.stack()[1][3] == '?':
1634 return '<pydoc.Helper instance>'
1636 def __call__(self
, request
=None):
1637 if request
is not None:
1642 self
.output
.write('''
1643 You are now leaving help and returning to the Python interpreter.
1644 If you want to ask for help on a particular object directly from the
1645 interpreter, you can type "help(object)". Executing "help('string')"
1646 has the same effect as typing a particular string at the help> prompt.
1650 self
.output
.write('\n')
1653 request
= self
.getline('help> ')
1654 if not request
: break
1655 except (KeyboardInterrupt, EOFError):
1657 request
= strip(replace(request
, '"', '', "'", ''))
1658 if lower(request
) in ('q', 'quit'): break
1661 def getline(self
, prompt
):
1662 """Read one line, using raw_input when available."""
1663 if self
.input is sys
.stdin
:
1664 return raw_input(prompt
)
1666 self
.output
.write(prompt
)
1668 return self
.input.readline()
1670 def help(self
, request
):
1671 if type(request
) is type(''):
1672 if request
== 'help': self
.intro()
1673 elif request
== 'keywords': self
.listkeywords()
1674 elif request
== 'topics': self
.listtopics()
1675 elif request
== 'modules': self
.listmodules()
1676 elif request
[:8] == 'modules ':
1677 self
.listmodules(split(request
)[1])
1678 elif request
in self
.keywords
: self
.showtopic(request
)
1679 elif request
in self
.topics
: self
.showtopic(request
)
1680 elif request
: doc(request
, 'Help on %s:')
1681 elif isinstance(request
, Helper
): self()
1682 else: doc(request
, 'Help on %s:')
1683 self
.output
.write('\n')
1686 self
.output
.write('''
1687 Welcome to Python %s! This is the online help utility.
1689 If this is your first time using Python, you should definitely check out
1690 the tutorial on the Internet at http://www.python.org/doc/tut/.
1692 Enter the name of any module, keyword, or topic to get help on writing
1693 Python programs and using Python modules. To quit this help utility and
1694 return to the interpreter, just type "quit".
1696 To get a list of available modules, keywords, or topics, type "modules",
1697 "keywords", or "topics". Each module also comes with a one-line summary
1698 of what it does; to list the modules whose summaries contain a given word
1699 such as "spam", type "modules spam".
1700 ''' % sys
.version
[:3])
1702 def list(self
, items
, columns
=4, width
=80):
1705 colw
= width
/ columns
1706 rows
= (len(items
) + columns
- 1) / columns
1707 for row
in range(rows
):
1708 for col
in range(columns
):
1709 i
= col
* rows
+ row
1711 self
.output
.write(items
[i
])
1712 if col
< columns
- 1:
1713 self
.output
.write(' ' + ' ' * (colw
-1 - len(items
[i
])))
1714 self
.output
.write('\n')
1716 def listkeywords(self
):
1717 self
.output
.write('''
1718 Here is a list of the Python keywords. Enter any keyword to get more help.
1721 self
.list(self
.keywords
.keys())
1723 def listtopics(self
):
1724 self
.output
.write('''
1725 Here is a list of available topics. Enter any topic name to get more help.
1728 self
.list(self
.topics
.keys())
1730 def showtopic(self
, topic
):
1732 self
.output
.write('''
1733 Sorry, topic and keyword documentation is not available because the Python
1734 HTML documentation files could not be found. If you have installed them,
1735 please set the environment variable PYTHONDOCS to indicate their location.
1738 target
= self
.topics
.get(topic
, self
.keywords
.get(topic
))
1740 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1742 if type(target
) is type(''):
1743 return self
.showtopic(target
)
1745 filename
, xrefs
= target
1746 filename
= self
.docdir
+ '/' + filename
+ '.html'
1748 file = open(filename
)
1750 self
.output
.write('could not read docs from %s\n' % filename
)
1753 divpat
= re
.compile('<div[^>]*navigat.*?</div.*?>', re
.I | re
.S
)
1754 addrpat
= re
.compile('<address.*?>.*?</address.*?>', re
.I | re
.S
)
1755 document
= re
.sub(addrpat
, '', re
.sub(divpat
, '', file.read()))
1758 import htmllib
, formatter
, StringIO
1759 buffer = StringIO
.StringIO()
1760 parser
= htmllib
.HTMLParser(
1761 formatter
.AbstractFormatter(formatter
.DumbWriter(buffer)))
1762 parser
.start_table
= parser
.do_p
1763 parser
.end_table
= lambda parser
=parser
: parser
.do_p({})
1764 parser
.start_tr
= parser
.do_br
1765 parser
.start_td
= parser
.start_th
= lambda a
, b
=buffer: b
.write('\t')
1766 parser
.feed(document
)
1767 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1768 pager(' ' + strip(buffer) + '\n')
1770 buffer = StringIO
.StringIO()
1771 formatter
.DumbWriter(buffer).send_flowing_data(
1772 'Related help topics: ' + join(split(xrefs
), ', ') + '\n')
1773 self
.output
.write('\n%s\n' % buffer.getvalue())
1775 def listmodules(self
, key
=''):
1777 self
.output
.write('''
1778 Here is a list of matching modules. Enter any module name to get more help.
1783 self
.output
.write('''
1784 Please wait a moment while I gather a list of all available modules...
1788 def callback(path
, modname
, desc
, modules
=modules
):
1789 if modname
and modname
[-9:] == '.__init__':
1790 modname
= modname
[:-9] + ' (package)'
1791 if find(modname
, '.') < 0:
1792 modules
[modname
] = 1
1793 ModuleScanner().run(callback
)
1794 self
.list(modules
.keys())
1795 self
.output
.write('''
1796 Enter any module name to get more help. Or, type "modules spam" to search
1797 for modules whose descriptions contain the word "spam".
1800 help = Helper(sys
.stdin
, sys
.stdout
)
1803 """A generic tree iterator."""
1804 def __init__(self
, roots
, children
, descendp
):
1805 self
.roots
= roots
[:]
1807 self
.children
= children
1808 self
.descendp
= descendp
1814 root
= self
.roots
.pop(0)
1815 self
.state
= [(root
, self
.children(root
))]
1816 node
, children
= self
.state
[-1]
1820 child
= children
.pop(0)
1821 if self
.descendp(child
):
1822 self
.state
.append((child
, self
.children(child
)))
1825 class ModuleScanner(Scanner
):
1826 """An interruptible scanner that searches module synopses."""
1828 roots
= map(lambda dir: (dir, ''), pathdirs())
1829 Scanner
.__init
__(self
, roots
, self
.submodules
, self
.isnewpackage
)
1830 self
.inodes
= map(lambda (dir, pkg
): os
.stat(dir).st_ino
, roots
)
1832 def submodules(self
, (dir, package
)):
1834 for file in os
.listdir(dir):
1835 path
= os
.path
.join(dir, file)
1837 children
.append((path
, package
+ (package
and '.') + file))
1839 children
.append((path
, package
))
1840 children
.sort() # so that spam.py comes before spam.pyc or spam.pyo
1843 def isnewpackage(self
, (dir, package
)):
1844 inode
= os
.path
.exists(dir) and os
.stat(dir).st_ino
1845 if not (os
.path
.islink(dir) and inode
in self
.inodes
):
1846 self
.inodes
.append(inode
) # detect circular symbolic links
1847 return ispackage(dir)
1850 def run(self
, callback
, key
=None, completer
=None):
1851 if key
: key
= lower(key
)
1855 for modname
in sys
.builtin_module_names
:
1856 if modname
!= '__main__':
1859 callback(None, modname
, '')
1861 desc
= split(__import__(modname
).__doc
__ or '', '\n')[0]
1862 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1863 callback(None, modname
, desc
)
1865 while not self
.quit
:
1868 path
, package
= node
1869 modname
= inspect
.getmodulename(path
)
1870 if os
.path
.isfile(path
) and modname
:
1871 modname
= package
+ (package
and '.') + modname
1872 if not modname
in seen
:
1873 seen
[modname
] = 1 # if we see spam.py, skip spam.pyc
1875 callback(path
, modname
, '')
1877 desc
= synopsis(path
) or ''
1878 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1879 callback(path
, modname
, desc
)
1880 if completer
: completer()
1883 """Print all the one-line module summaries that contain a substring."""
1884 def callback(path
, modname
, desc
):
1885 if modname
[-9:] == '.__init__':
1886 modname
= modname
[:-9] + ' (package)'
1887 print modname
, desc
and '- ' + desc
1888 try: import warnings
1889 except ImportError: pass
1890 else: warnings
.filterwarnings('ignore') # ignore problems during import
1891 ModuleScanner().run(callback
, key
)
1893 # --------------------------------------------------- web browser interface
1895 def serve(port
, callback
=None, completer
=None):
1896 import BaseHTTPServer
, mimetools
, select
1898 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1899 class Message(mimetools
.Message
):
1900 def __init__(self
, fp
, seekable
=1):
1901 Message
= self
.__class
__
1902 Message
.__bases
__[0].__bases
__[0].__init
__(self
, fp
, seekable
)
1903 self
.encodingheader
= self
.getheader('content-transfer-encoding')
1904 self
.typeheader
= self
.getheader('content-type')
1908 class DocHandler(BaseHTTPServer
.BaseHTTPRequestHandler
):
1909 def send_document(self
, title
, contents
):
1911 self
.send_response(200)
1912 self
.send_header('Content-Type', 'text/html')
1914 self
.wfile
.write(html
.page(title
, contents
))
1915 except IOError: pass
1919 if path
[-5:] == '.html': path
= path
[:-5]
1920 if path
[:1] == '/': path
= path
[1:]
1921 if path
and path
!= '.':
1923 obj
= locate(path
, forceload
=1)
1924 except ErrorDuringImport
, value
:
1925 self
.send_document(path
, html
.escape(str(value
)))
1928 self
.send_document(describe(obj
), html
.document(obj
, path
))
1930 self
.send_document(path
,
1931 'no Python documentation found for %s' % repr(path
))
1933 heading
= html
.heading(
1934 '<big><big><strong>Python: Index of Modules</strong></big></big>',
1935 '#ffffff', '#7799ee')
1936 def bltinlink(name
):
1937 return '<a href="%s.html">%s</a>' % (name
, name
)
1938 names
= filter(lambda x
: x
!= '__main__',
1939 sys
.builtin_module_names
)
1940 contents
= html
.multicolumn(names
, bltinlink
)
1941 indices
= ['<p>' + html
.bigsection(
1942 'Built-in Modules', '#ffffff', '#ee77aa', contents
)]
1945 for dir in pathdirs():
1946 indices
.append(html
.index(dir, seen
))
1947 contents
= heading
+ join(indices
) + '''<p align=right>
1948 <font color="#909090" face="helvetica, arial"><strong>
1949 pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>'''
1950 self
.send_document('Index of Modules', contents
)
1952 def log_message(self
, *args
): pass
1954 class DocServer(BaseHTTPServer
.HTTPServer
):
1955 def __init__(self
, port
, callback
):
1956 host
= (sys
.platform
== 'mac') and '127.0.0.1' or 'localhost'
1957 self
.address
= ('', port
)
1958 self
.url
= 'http://%s:%d/' % (host
, port
)
1959 self
.callback
= callback
1960 self
.base
.__init
__(self
, self
.address
, self
.handler
)
1962 def serve_until_quit(self
):
1965 while not self
.quit
:
1966 rd
, wr
, ex
= select
.select([self
.socket
.fileno()], [], [], 1)
1967 if rd
: self
.handle_request()
1969 def server_activate(self
):
1970 self
.base
.server_activate(self
)
1971 if self
.callback
: self
.callback(self
)
1973 DocServer
.base
= BaseHTTPServer
.HTTPServer
1974 DocServer
.handler
= DocHandler
1975 DocHandler
.MessageClass
= Message
1978 DocServer(port
, callback
).serve_until_quit()
1979 except (KeyboardInterrupt, select
.error
):
1982 if completer
: completer()
1984 # ----------------------------------------------------- graphical interface
1987 """Graphical interface (starts web server and pops up a control window)."""
1989 def __init__(self
, window
, port
=7464):
1990 self
.window
= window
1995 self
.server_frm
= Tkinter
.Frame(window
)
1996 self
.title_lbl
= Tkinter
.Label(self
.server_frm
,
1997 text
='Starting server...\n ')
1998 self
.open_btn
= Tkinter
.Button(self
.server_frm
,
1999 text
='open browser', command
=self
.open, state
='disabled')
2000 self
.quit_btn
= Tkinter
.Button(self
.server_frm
,
2001 text
='quit serving', command
=self
.quit
, state
='disabled')
2003 self
.search_frm
= Tkinter
.Frame(window
)
2004 self
.search_lbl
= Tkinter
.Label(self
.search_frm
, text
='Search for')
2005 self
.search_ent
= Tkinter
.Entry(self
.search_frm
)
2006 self
.search_ent
.bind('<Return>', self
.search
)
2007 self
.stop_btn
= Tkinter
.Button(self
.search_frm
,
2008 text
='stop', pady
=0, command
=self
.stop
, state
='disabled')
2009 if sys
.platform
== 'win32':
2010 # Trying to hide and show this button crashes under Windows.
2011 self
.stop_btn
.pack(side
='right')
2013 self
.window
.title('pydoc')
2014 self
.window
.protocol('WM_DELETE_WINDOW', self
.quit
)
2015 self
.title_lbl
.pack(side
='top', fill
='x')
2016 self
.open_btn
.pack(side
='left', fill
='x', expand
=1)
2017 self
.quit_btn
.pack(side
='right', fill
='x', expand
=1)
2018 self
.server_frm
.pack(side
='top', fill
='x')
2020 self
.search_lbl
.pack(side
='left')
2021 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2022 self
.search_frm
.pack(side
='top', fill
='x')
2023 self
.search_ent
.focus_set()
2025 font
= ('helvetica', sys
.platform
== 'win32' and 8 or 10)
2026 self
.result_lst
= Tkinter
.Listbox(window
, font
=font
, height
=6)
2027 self
.result_lst
.bind('<Button-1>', self
.select
)
2028 self
.result_lst
.bind('<Double-Button-1>', self
.goto
)
2029 self
.result_scr
= Tkinter
.Scrollbar(window
,
2030 orient
='vertical', command
=self
.result_lst
.yview
)
2031 self
.result_lst
.config(yscrollcommand
=self
.result_scr
.set)
2033 self
.result_frm
= Tkinter
.Frame(window
)
2034 self
.goto_btn
= Tkinter
.Button(self
.result_frm
,
2035 text
='go to selected', command
=self
.goto
)
2036 self
.hide_btn
= Tkinter
.Button(self
.result_frm
,
2037 text
='hide results', command
=self
.hide
)
2038 self
.goto_btn
.pack(side
='left', fill
='x', expand
=1)
2039 self
.hide_btn
.pack(side
='right', fill
='x', expand
=1)
2041 self
.window
.update()
2042 self
.minwidth
= self
.window
.winfo_width()
2043 self
.minheight
= self
.window
.winfo_height()
2044 self
.bigminheight
= (self
.server_frm
.winfo_reqheight() +
2045 self
.search_frm
.winfo_reqheight() +
2046 self
.result_lst
.winfo_reqheight() +
2047 self
.result_frm
.winfo_reqheight())
2048 self
.bigwidth
, self
.bigheight
= self
.minwidth
, self
.bigminheight
2050 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2051 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2052 self
.window
.tk
.willdispatch()
2056 target
=serve
, args
=(port
, self
.ready
, self
.quit
)).start()
2058 def ready(self
, server
):
2059 self
.server
= server
2060 self
.title_lbl
.config(
2061 text
='Python documentation server at\n' + server
.url
)
2062 self
.open_btn
.config(state
='normal')
2063 self
.quit_btn
.config(state
='normal')
2065 def open(self
, event
=None, url
=None):
2066 url
= url
or self
.server
.url
2069 webbrowser
.open(url
)
2070 except ImportError: # pre-webbrowser.py compatibility
2071 if sys
.platform
== 'win32':
2072 os
.system('start "%s"' % url
)
2073 elif sys
.platform
== 'mac':
2075 except ImportError: pass
2076 else: ic
.launchurl(url
)
2078 rc
= os
.system('netscape -remote "openURL(%s)" &' % url
)
2079 if rc
: os
.system('netscape "%s" &' % url
)
2081 def quit(self
, event
=None):
2083 self
.server
.quit
= 1
2086 def search(self
, event
=None):
2087 key
= self
.search_ent
.get()
2088 self
.stop_btn
.pack(side
='right')
2089 self
.stop_btn
.config(state
='normal')
2090 self
.search_lbl
.config(text
='Searching for "%s"...' % key
)
2091 self
.search_ent
.forget()
2092 self
.search_lbl
.pack(side
='left')
2093 self
.result_lst
.delete(0, 'end')
2094 self
.goto_btn
.config(state
='disabled')
2099 self
.scanner
.quit
= 1
2100 self
.scanner
= ModuleScanner()
2101 threading
.Thread(target
=self
.scanner
.run
,
2102 args
=(self
.update
, key
, self
.done
)).start()
2104 def update(self
, path
, modname
, desc
):
2105 if modname
[-9:] == '.__init__':
2106 modname
= modname
[:-9] + ' (package)'
2107 self
.result_lst
.insert('end',
2108 modname
+ ' - ' + (desc
or '(no description)'))
2110 def stop(self
, event
=None):
2112 self
.scanner
.quit
= 1
2117 self
.search_lbl
.config(text
='Search for')
2118 self
.search_lbl
.pack(side
='left')
2119 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2120 if sys
.platform
!= 'win32': self
.stop_btn
.forget()
2121 self
.stop_btn
.config(state
='disabled')
2123 def select(self
, event
=None):
2124 self
.goto_btn
.config(state
='normal')
2126 def goto(self
, event
=None):
2127 selection
= self
.result_lst
.curselection()
2129 modname
= split(self
.result_lst
.get(selection
[0]))[0]
2130 self
.open(url
=self
.server
.url
+ modname
+ '.html')
2133 if not self
.expanded
: return
2134 self
.result_frm
.forget()
2135 self
.result_scr
.forget()
2136 self
.result_lst
.forget()
2137 self
.bigwidth
= self
.window
.winfo_width()
2138 self
.bigheight
= self
.window
.winfo_height()
2139 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2140 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2144 if self
.expanded
: return
2145 self
.result_frm
.pack(side
='bottom', fill
='x')
2146 self
.result_scr
.pack(side
='right', fill
='y')
2147 self
.result_lst
.pack(side
='top', fill
='both', expand
=1)
2148 self
.window
.wm_geometry('%dx%d' % (self
.bigwidth
, self
.bigheight
))
2149 self
.window
.wm_minsize(self
.minwidth
, self
.bigminheight
)
2152 def hide(self
, event
=None):
2159 # Tk will crash if pythonw.exe has an XP .manifest
2160 # file and the root has is not destroyed explicitly.
2161 # If the problem is ever fixed in Tk, the explicit
2168 except KeyboardInterrupt:
2171 # -------------------------------------------------- command-line interface
2174 return isinstance(x
, str) and find(x
, os
.sep
) >= 0
2177 """Command-line interface (looks at sys.argv to decide what to do)."""
2179 class BadUsage
: pass
2181 # Scripts don't get the current directory in their path by default.
2182 scriptdir
= os
.path
.dirname(sys
.argv
[0])
2183 if scriptdir
in sys
.path
:
2184 sys
.path
.remove(scriptdir
)
2185 sys
.path
.insert(0, '.')
2188 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'gk:p:w')
2191 for opt
, val
in opts
:
2204 print 'pydoc server ready at %s' % server
.url
2206 print 'pydoc server stopped'
2207 serve(port
, ready
, stopped
)
2212 if not args
: raise BadUsage
2214 if ispath(arg
) and not os
.path
.exists(arg
):
2215 print 'file %r does not exist' % arg
2218 if ispath(arg
) and os
.path
.isfile(arg
):
2219 arg
= importfile(arg
)
2221 if ispath(arg
) and os
.path
.isdir(arg
):
2227 except ErrorDuringImport
, value
:
2230 except (getopt
.error
, BadUsage
):
2231 cmd
= os
.path
.basename(sys
.argv
[0])
2232 print """pydoc - the Python documentation tool
2235 Show text documentation on something. <name> may be the name of a
2236 Python keyword, topic, function, module, or package, or a dotted
2237 reference to a class or function within a module or module in a
2238 package. If <name> contains a '%s', it is used as the path to a
2239 Python source file to document. If name is 'keywords', 'topics',
2240 or 'modules', a listing of these things is displayed.
2243 Search for a keyword in the synopsis lines of all available modules.
2246 Start an HTTP server on the given port on the local machine.
2249 Pop up a graphical interface for finding and serving documentation.
2252 Write out the HTML documentation for a module to a file in the current
2253 directory. If <name> contains a '%s', it is treated as a filename; if
2254 it names a directory, documentation is written for all the contents.
2255 """ % (cmd
, os
.sep
, cmd
, cmd
, cmd
, cmd
, os
.sep
)
2257 if __name__
== '__main__': cli()