2 # -*- coding: Latin-1 -*-
3 """Generate Python documentation in HTML or text for interactive use.
5 In the Python interpreter, do "from pydoc import help" to provide online
6 help. Calling help(thing) on a Python object documents the object.
8 Or, at the shell command line outside of Python:
10 Run "pydoc <name>" to show documentation on something. <name> may be
11 the name of a function, module, package, or a dotted reference to a
12 class or function within a module or module in a package. If the
13 argument contains a path segment delimiter (e.g. slash on Unix,
14 backslash on Windows) it is treated as the path to a Python source file.
16 Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
17 of all available modules.
19 Run "pydoc -p <port>" to start an HTTP server on a given port on the
20 local machine to generate documentation web pages.
22 For platforms without a command line, "pydoc -g" starts the HTTP server
23 and also pops up a little window for controlling it.
25 Run "pydoc -w <name>" to write out the HTML documentation for a module
26 to a file named "<name>.html".
28 Module docs for core modules are assumed to be in
30 http://docs.python.org/library/
32 This can be overridden by setting the PYTHONDOCS environment variable
33 to a different URL or to a local directory containing the Library
34 Reference Manual pages.
37 __author__
= "Ka-Ping Yee <ping@lfw.org>"
38 __date__
= "26 February 2001"
40 __version__
= "$Revision$"
41 __credits__
= """Guido van Rossum, for an excellent programming language.
42 Tommy Burnette, the original creator of manpy.
43 Paul Prescod, for all his work on onlinehelp.
44 Richard Chamberlain, for the first implementation of textdoc.
47 # Known bugs that can't be fixed here:
48 # - imp.load_module() cannot be prevented from clobbering existing
49 # loaded modules, so calling synopsis() on a binary module file
50 # changes the contents of any existing module with the same name.
51 # - If the __file__ attribute on a module is a relative path and
52 # the current directory is changed with os.chdir(), an incorrect
53 # path will be displayed.
55 import sys
, imp
, os
, re
, types
, inspect
, __builtin__
, pkgutil
56 from reprlib
import Repr
57 from string
import expandtabs
, find
, join
, lower
, split
, strip
, rfind
, rstrip
59 from collections
import deque
61 # Python 2.3 compatibility
66 # --------------------------------------------------------- common routines
69 """Convert sys.path into a list of absolute, existing, unique paths."""
73 dir = os
.path
.abspath(dir or '.')
74 normdir
= os
.path
.normcase(dir)
75 if normdir
not in normdirs
and os
.path
.isdir(dir):
77 normdirs
.append(normdir
)
81 """Get the doc string or comments for an object."""
82 result
= inspect
.getdoc(object) or inspect
.getcomments(object)
83 return result
and re
.sub('^ *\n', '', rstrip(result
)) or ''
86 """Split a doc string into a synopsis line (if any) and the rest."""
87 lines
= split(strip(doc
), '\n')
90 elif len(lines
) >= 2 and not rstrip(lines
[1]):
91 return lines
[0], join(lines
[2:], '\n')
92 return '', join(lines
, '\n')
94 def classname(object, modname
):
95 """Get a class name and qualify it with a module name if necessary."""
96 name
= object.__name
__
97 if object.__module
__ != modname
:
98 name
= object.__module
__ + '.' + name
102 """Check if an object is of a type that probably means it's data."""
103 return not (inspect
.ismodule(object) or inspect
.isclass(object) or
104 inspect
.isroutine(object) or inspect
.isframe(object) or
105 inspect
.istraceback(object) or inspect
.iscode(object))
107 def replace(text
, *pairs
):
108 """Do a series of global replacements on a string."""
110 text
= join(split(text
, pairs
[0]), pairs
[1])
114 def cram(text
, maxlen
):
115 """Omit part of a string if needed to make it fit in a maximum length."""
116 if len(text
) > maxlen
:
117 pre
= max(0, (maxlen
-3)//2)
118 post
= max(0, maxlen
-3-pre
)
119 return text
[:pre
] + '...' + text
[len(text
)-post
:]
122 _re_stripid
= re
.compile(r
' at 0x[0-9a-f]{6,16}(>+)$', re
.IGNORECASE
)
124 """Remove the hexadecimal id from a Python object representation."""
125 # The behaviour of %p is implementation-dependent in terms of case.
126 if _re_stripid
.search(repr(Exception)):
127 return _re_stripid
.sub(r
'\1', text
)
130 def _is_some_method(obj
):
131 return inspect
.ismethod(obj
) or inspect
.ismethoddescriptor(obj
)
135 for key
, value
in inspect
.getmembers(cl
, _is_some_method
):
137 for base
in cl
.__bases
__:
138 methods
.update(allmethods(base
)) # all your base are belong to us
139 for key
in methods
.keys():
140 methods
[key
] = getattr(cl
, key
)
143 def _split_list(s
, predicate
):
144 """Split sequence s via predicate, and return pair ([true], [false]).
146 The return value is a 2-tuple of lists,
147 ([x for x in s if predicate(x)],
148 [x for x in s if not predicate(x)])
160 def visiblename(name
, all
=None):
161 """Decide whether to show documentation on a variable."""
162 # Certain special names are redundant.
163 if name
in ('__builtins__', '__doc__', '__file__', '__path__',
164 '__module__', '__name__', '__slots__'): return 0
165 # Private names are hidden, but special names are displayed.
166 if name
.startswith('__') and name
.endswith('__'): return 1
168 # only document that which the programmer exported in __all__
171 return not name
.startswith('_')
173 def classify_class_attrs(object):
174 """Wrap inspect.classify_class_attrs, with fixup for data descriptors."""
175 def fixup((name
, kind
, cls
, value
)):
176 if inspect
.isdatadescriptor(value
):
177 kind
= 'data descriptor'
178 return name
, kind
, cls
, value
179 return map(fixup
, inspect
.classify_class_attrs(object))
181 # ----------------------------------------------------- module manipulation
184 """Guess whether a path refers to a package directory."""
185 if os
.path
.isdir(path
):
186 for ext
in ('.py', '.pyc', '.pyo'):
187 if os
.path
.isfile(os
.path
.join(path
, '__init__' + ext
)):
191 def source_synopsis(file):
192 line
= file.readline()
193 while line
[:1] == '#' or not strip(line
):
194 line
= file.readline()
197 if line
[:4] == 'r"""': line
= line
[1:]
198 if line
[:3] == '"""':
200 if line
[-1:] == '\\': line
= line
[:-1]
201 while not strip(line
):
202 line
= file.readline()
204 result
= strip(split(line
, '"""')[0])
208 def synopsis(filename
, cache
={}):
209 """Get the one-line summary out of a module file."""
210 mtime
= os
.stat(filename
).st_mtime
211 lastupdate
, result
= cache
.get(filename
, (0, None))
212 if lastupdate
< mtime
:
213 info
= inspect
.getmoduleinfo(filename
)
215 file = open(filename
)
217 # module can't be opened, so skip it
219 if info
and 'b' in info
[2]: # binary modules have to be imported
220 try: module
= imp
.load_module('__temp__', file, filename
, info
[1:])
222 result
= (module
.__doc
__ or '').splitlines()[0]
223 del sys
.modules
['__temp__']
224 else: # text modules can be directly examined
225 result
= source_synopsis(file)
227 cache
[filename
] = (mtime
, result
)
230 class ErrorDuringImport(Exception):
231 """Errors that occurred while trying to import something to document it."""
232 def __init__(self
, filename
, (exc
, value
, tb
)):
233 self
.filename
= filename
240 if type(exc
) is types
.ClassType
:
242 return 'problem in %s - %s: %s' % (self
.filename
, exc
, self
.value
)
244 def importfile(path
):
245 """Import a Python source file or compiled file given its path."""
246 magic
= imp
.get_magic()
247 file = open(path
, 'r')
248 if file.read(len(magic
)) == magic
:
249 kind
= imp
.PY_COMPILED
253 filename
= os
.path
.basename(path
)
254 name
, ext
= os
.path
.splitext(filename
)
255 file = open(path
, 'r')
257 module
= imp
.load_module(name
, file, path
, (ext
, 'r', kind
))
259 raise ErrorDuringImport(path
, sys
.exc_info())
263 def safeimport(path
, forceload
=0, cache
={}):
264 """Import a module; handle errors; return None if the module isn't found.
266 If the module *is* found but an exception occurs, it's wrapped in an
267 ErrorDuringImport exception and reraised. Unlike __import__, if a
268 package path is specified, the module at the end of the path is returned,
269 not the package at the beginning. If the optional 'forceload' argument
270 is 1, we reload the module from disk (unless it's a dynamic extension)."""
272 # If forceload is 1 and the module has been previously loaded from
273 # disk, we always have to reload the module. Checking the file's
274 # mtime isn't good enough (e.g. the module could contain a class
275 # that inherits from another module that has changed).
276 if forceload
and path
in sys
.modules
:
277 if path
not in sys
.builtin_module_names
:
278 # Avoid simply calling reload() because it leaves names in
279 # the currently loaded module lying around if they're not
280 # defined in the new source file. Instead, remove the
281 # module from sys.modules and re-import. Also remove any
282 # submodules because they won't appear in the newly loaded
283 # module's namespace if they're already in sys.modules.
284 subs
= [m
for m
in sys
.modules
if m
.startswith(path
+ '.')]
285 for key
in [path
] + subs
:
286 # Prevent garbage collection.
287 cache
[key
] = sys
.modules
[key
]
289 module
= __import__(path
)
291 # Did the error occur before or after the module was found?
292 (exc
, value
, tb
) = info
= sys
.exc_info()
293 if path
in sys
.modules
:
294 # An error occurred while executing the imported module.
295 raise ErrorDuringImport(sys
.modules
[path
].__file
__, info
)
296 elif exc
is SyntaxError:
297 # A SyntaxError occurred before we could execute the module.
298 raise ErrorDuringImport(value
.filename
, info
)
299 elif exc
is ImportError and \
300 split(lower(str(value
)))[:2] == ['no', 'module']:
301 # The module was not found.
304 # Some other error occurred during the importing process.
305 raise ErrorDuringImport(path
, sys
.exc_info())
306 for part
in split(path
, '.')[1:]:
307 try: module
= getattr(module
, part
)
308 except AttributeError: return None
311 # ---------------------------------------------------- formatter base class
314 def document(self
, object, name
=None, *args
):
315 """Generate documentation for an object."""
316 args
= (object, name
) + args
317 # 'try' clause is to attempt to handle the possibility that inspect
318 # identifies something in a way that pydoc itself has issues handling;
319 # think 'super' and how it is a descriptor (which raises the exception
320 # by lacking a __name__ attribute) and an instance.
321 if inspect
.isgetsetdescriptor(object): return self
.docdata(*args
)
322 if inspect
.ismemberdescriptor(object): return self
.docdata(*args
)
324 if inspect
.ismodule(object): return self
.docmodule(*args
)
325 if inspect
.isclass(object): return self
.docclass(*args
)
326 if inspect
.isroutine(object): return self
.docroutine(*args
)
327 except AttributeError:
329 if isinstance(object, property): return self
.docproperty(*args
)
330 return self
.docother(*args
)
332 def fail(self
, object, name
=None, *args
):
333 """Raise an exception for unimplemented types."""
334 message
= "don't know how to document object%s of type %s" % (
335 name
and ' ' + repr(name
), type(object).__name
__)
336 raise TypeError, message
338 docmodule
= docclass
= docroutine
= docother
= docproperty
= docdata
= fail
340 def getdocloc(self
, object):
341 """Return the location of module docs or None"""
344 file = inspect
.getabsfile(object)
348 docloc
= os
.environ
.get("PYTHONDOCS",
349 "http://docs.python.org/library")
350 basedir
= os
.path
.join(sys
.exec_prefix
, "lib",
351 "python"+sys
.version
[0:3])
352 if (isinstance(object, type(os
)) and
353 (object.__name
__ in ('errno', 'exceptions', 'gc', 'imp',
354 'marshal', 'posix', 'signal', 'sys',
355 'thread', 'zipimport') or
356 (file.startswith(basedir
) and
357 not file.startswith(os
.path
.join(basedir
, 'site-packages'))))):
358 if docloc
.startswith("http://"):
359 docloc
= "%s/%s" % (docloc
.rstrip("/"), object.__name
__)
361 docloc
= os
.path
.join(docloc
, object.__name
__ + ".html")
366 # -------------------------------------------- HTML documentation generator
368 class HTMLRepr(Repr
):
369 """Class for safely making an HTML representation of a Python object."""
372 self
.maxlist
= self
.maxtuple
= 20
374 self
.maxstring
= self
.maxother
= 100
376 def escape(self
, text
):
377 return replace(text
, '&', '&', '<', '<', '>', '>')
379 def repr(self
, object):
380 return Repr
.repr(self
, object)
382 def repr1(self
, x
, level
):
383 if hasattr(type(x
), '__name__'):
384 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
385 if hasattr(self
, methodname
):
386 return getattr(self
, methodname
)(x
, level
)
387 return self
.escape(cram(stripid(repr(x
)), self
.maxother
))
389 def repr_string(self
, x
, level
):
390 test
= cram(x
, self
.maxstring
)
391 testrepr
= repr(test
)
392 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
393 # Backslashes are only literal in the string and are never
394 # needed to make any special characters, so show a raw string.
395 return 'r' + testrepr
[0] + self
.escape(test
) + testrepr
[0]
396 return re
.sub(r
'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
397 r'<font color="#c040c0">\1</font>',
398 self
.escape(testrepr
))
400 repr_str
= repr_string
402 def repr_instance(self
, x
, level
):
404 return self
.escape(cram(stripid(repr(x
)), self
.maxstring
))
406 return self
.escape('<%s instance>' % x
.__class
__.__name
__)
408 repr_unicode
= repr_string
411 """Formatter class for HTML documentation."""
413 # ------------------------------------------- HTML formatting utilities
415 _repr_instance
= HTMLRepr()
416 repr = _repr_instance
.repr
417 escape
= _repr_instance
.escape
419 def page(self
, title
, contents
):
420 """Format an HTML page."""
422 <!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
423 <html><head><title>Python: %s</title>
424 </head><body bgcolor="#f0f0f8">
426 </body></html>''' % (title
, contents
)
428 def heading(self
, title
, fgcol
, bgcol
, extras
=''):
429 """Format a page heading."""
431 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
433 <td valign=bottom> <br>
434 <font color="%s" face="helvetica, arial"> <br>%s</font></td
435 ><td align=right valign=bottom
436 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
437 ''' % (bgcol
, fgcol
, title
, fgcol
, extras
or ' ')
439 def section(self
, title
, fgcol
, bgcol
, contents
, width
=6,
440 prelude
='', marginalia
=None, gap
=' '):
441 """Format a section with a heading."""
442 if marginalia
is None:
443 marginalia
= '<tt>' + ' ' * width
+ '</tt>'
445 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
447 <td colspan=3 valign=bottom> <br>
448 <font color="%s" face="helvetica, arial">%s</font></td></tr>
449 ''' % (bgcol
, fgcol
, title
)
451 result
= result
+ '''
452 <tr bgcolor="%s"><td rowspan=2>%s</td>
453 <td colspan=2>%s</td></tr>
454 <tr><td>%s</td>''' % (bgcol
, marginalia
, prelude
, gap
)
456 result
= result
+ '''
457 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol
, marginalia
, gap
)
459 return result
+ '\n<td width="100%%">%s</td></tr></table>' % contents
461 def bigsection(self
, title
, *args
):
462 """Format a section with a big heading."""
463 title
= '<big><strong>%s</strong></big>' % title
464 return self
.section(title
, *args
)
466 def preformat(self
, text
):
467 """Format literal preformatted text."""
468 text
= self
.escape(expandtabs(text
))
469 return replace(text
, '\n\n', '\n \n', '\n\n', '\n \n',
470 ' ', ' ', '\n', '<br>\n')
472 def multicolumn(self
, list, format
, cols
=4):
473 """Format a list of items into a multi-column list."""
475 rows
= (len(list)+cols
-1)/cols
476 for col
in range(cols
):
477 result
= result
+ '<td width="%d%%" valign=top>' % (100/cols
)
478 for i
in range(rows
*col
, rows
*col
+rows
):
480 result
= result
+ format(list[i
]) + '<br>\n'
481 result
= result
+ '</td>'
482 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
484 def grey(self
, text
): return '<font color="#909090">%s</font>' % text
486 def namelink(self
, name
, *dicts
):
487 """Make a link for an identifier, given name-to-URL mappings."""
490 return '<a href="%s">%s</a>' % (dict[name
], name
)
493 def classlink(self
, object, modname
):
494 """Make a link for a class."""
495 name
, module
= object.__name
__, sys
.modules
.get(object.__module
__)
496 if hasattr(module
, name
) and getattr(module
, name
) is object:
497 return '<a href="%s.html#%s">%s</a>' % (
498 module
.__name
__, name
, classname(object, modname
))
499 return classname(object, modname
)
501 def modulelink(self
, object):
502 """Make a link for a module."""
503 return '<a href="%s.html">%s</a>' % (object.__name
__, object.__name
__)
505 def modpkglink(self
, (name
, path
, ispackage
, shadowed
)):
506 """Make a link for a module or package to display in an index."""
508 return self
.grey(name
)
510 url
= '%s.%s.html' % (path
, name
)
512 url
= '%s.html' % name
514 text
= '<strong>%s</strong> (package)' % name
517 return '<a href="%s">%s</a>' % (url
, text
)
519 def markup(self
, text
, escape
=None, funcs
={}, classes
={}, methods
={}):
520 """Mark up some plain text, given a context of symbols to look for.
521 Each context dictionary maps object names to anchor names."""
522 escape
= escape
or self
.escape
525 pattern
= re
.compile(r
'\b((http|ftp)://\S+[\w/]|'
530 match
= pattern
.search(text
, here
)
532 start
, end
= match
.span()
533 results
.append(escape(text
[here
:start
]))
535 all
, scheme
, rfc
, pep
, selfdot
, name
= match
.groups()
537 url
= escape(all
).replace('"', '"')
538 results
.append('<a href="%s">%s</a>' % (url
, url
))
540 url
= 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc
)
541 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
543 url
= 'http://www.python.org/dev/peps/pep-%04d/' % int(pep
)
544 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
545 elif text
[end
:end
+1] == '(':
546 results
.append(self
.namelink(name
, methods
, funcs
, classes
))
548 results
.append('self.<strong>%s</strong>' % name
)
550 results
.append(self
.namelink(name
, classes
))
552 results
.append(escape(text
[here
:]))
553 return join(results
, '')
555 # ---------------------------------------------- type-specific routines
557 def formattree(self
, tree
, modname
, parent
=None):
558 """Produce HTML for a class tree as given by inspect.getclasstree()."""
561 if type(entry
) is type(()):
563 result
= result
+ '<dt><font face="helvetica, arial">'
564 result
= result
+ self
.classlink(c
, modname
)
565 if bases
and bases
!= (parent
,):
568 parents
.append(self
.classlink(base
, modname
))
569 result
= result
+ '(' + join(parents
, ', ') + ')'
570 result
= result
+ '\n</font></dt>'
571 elif type(entry
) is type([]):
572 result
= result
+ '<dd>\n%s</dd>\n' % self
.formattree(
574 return '<dl>\n%s</dl>\n' % result
576 def docmodule(self
, object, name
=None, mod
=None, *ignored
):
577 """Produce HTML documentation for a module object."""
578 name
= object.__name
__ # ignore the passed-in name
581 except AttributeError:
583 parts
= split(name
, '.')
585 for i
in range(len(parts
)-1):
587 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
588 (join(parts
[:i
+1], '.'), parts
[i
]))
589 linkedname
= join(links
+ parts
[-1:], '.')
590 head
= '<big><big><strong>%s</strong></big></big>' % linkedname
592 path
= inspect
.getabsfile(object)
594 if sys
.platform
== 'win32':
596 url
= nturl2path
.pathname2url(path
)
597 filelink
= '<a href="file:%s">%s</a>' % (url
, path
)
599 filelink
= '(built-in)'
601 if hasattr(object, '__version__'):
602 version
= str(object.__version
__)
603 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
604 version
= strip(version
[11:-1])
605 info
.append('version %s' % self
.escape(version
))
606 if hasattr(object, '__date__'):
607 info
.append(self
.escape(str(object.__date
__)))
609 head
= head
+ ' (%s)' % join(info
, ', ')
610 docloc
= self
.getdocloc(object)
611 if docloc
is not None:
612 docloc
= '<br><a href="%(docloc)s">Module Docs</a>' % locals()
615 result
= self
.heading(
616 head
, '#ffffff', '#7799ee',
617 '<a href=".">index</a><br>' + filelink
+ docloc
)
619 modules
= inspect
.getmembers(object, inspect
.ismodule
)
621 classes
, cdict
= [], {}
622 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
623 # if __all__ exists, believe it. Otherwise use old heuristic.
624 if (all
is not None or
625 (inspect
.getmodule(value
) or object) is object):
626 if visiblename(key
, all
):
627 classes
.append((key
, value
))
628 cdict
[key
] = cdict
[value
] = '#' + key
629 for key
, value
in classes
:
630 for base
in value
.__bases
__:
631 key
, modname
= base
.__name
__, base
.__module
__
632 module
= sys
.modules
.get(modname
)
633 if modname
!= name
and module
and hasattr(module
, key
):
634 if getattr(module
, key
) is base
:
636 cdict
[key
] = cdict
[base
] = modname
+ '.html#' + key
637 funcs
, fdict
= [], {}
638 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
639 # if __all__ exists, believe it. Otherwise use old heuristic.
640 if (all
is not None or
641 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
642 if visiblename(key
, all
):
643 funcs
.append((key
, value
))
644 fdict
[key
] = '#-' + key
645 if inspect
.isfunction(value
): fdict
[value
] = fdict
[key
]
647 for key
, value
in inspect
.getmembers(object, isdata
):
648 if visiblename(key
, all
):
649 data
.append((key
, value
))
651 doc
= self
.markup(getdoc(object), self
.preformat
, fdict
, cdict
)
652 doc
= doc
and '<tt>%s</tt>' % doc
653 result
= result
+ '<p>%s</p>\n' % doc
655 if hasattr(object, '__path__'):
657 for importer
, modname
, ispkg
in pkgutil
.iter_modules(object.__path
__):
658 modpkgs
.append((modname
, name
, ispkg
, 0))
660 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
661 result
= result
+ self
.bigsection(
662 'Package Contents', '#ffffff', '#aa55cc', contents
)
664 contents
= self
.multicolumn(
665 modules
, lambda (key
, value
), s
=self
: s
.modulelink(value
))
666 result
= result
+ self
.bigsection(
667 'Modules', '#ffffff', '#aa55cc', contents
)
670 classlist
= map(lambda (key
, value
): value
, classes
)
672 self
.formattree(inspect
.getclasstree(classlist
, 1), name
)]
673 for key
, value
in classes
:
674 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
675 result
= result
+ self
.bigsection(
676 'Classes', '#ffffff', '#ee77aa', join(contents
))
679 for key
, value
in funcs
:
680 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
681 result
= result
+ self
.bigsection(
682 'Functions', '#ffffff', '#eeaa77', join(contents
))
685 for key
, value
in data
:
686 contents
.append(self
.document(value
, key
))
687 result
= result
+ self
.bigsection(
688 'Data', '#ffffff', '#55aa55', join(contents
, '<br>\n'))
689 if hasattr(object, '__author__'):
690 contents
= self
.markup(str(object.__author
__), self
.preformat
)
691 result
= result
+ self
.bigsection(
692 'Author', '#ffffff', '#7799ee', contents
)
693 if hasattr(object, '__credits__'):
694 contents
= self
.markup(str(object.__credits
__), self
.preformat
)
695 result
= result
+ self
.bigsection(
696 'Credits', '#ffffff', '#7799ee', contents
)
700 def docclass(self
, object, name
=None, mod
=None, funcs
={}, classes
={},
702 """Produce HTML documentation for a class object."""
703 realname
= object.__name
__
704 name
= name
or realname
705 bases
= object.__bases
__
708 push
= contents
.append
710 # Cute little class to pump out a horizontal rule between sections.
711 class HorizontalRule
:
718 hr
= HorizontalRule()
720 # List the mro, if non-trivial.
721 mro
= deque(inspect
.getmro(object))
724 push('<dl><dt>Method resolution order:</dt>\n')
726 push('<dd>%s</dd>\n' % self
.classlink(base
,
730 def spill(msg
, attrs
, predicate
):
731 ok
, attrs
= _split_list(attrs
, predicate
)
735 for name
, kind
, homecls
, value
in ok
:
736 push(self
.document(getattr(object, name
), name
, mod
,
737 funcs
, classes
, mdict
, object))
741 def spilldescriptors(msg
, attrs
, predicate
):
742 ok
, attrs
= _split_list(attrs
, predicate
)
746 for name
, kind
, homecls
, value
in ok
:
747 push(self
._docdescriptor
(name
, value
, mod
))
750 def spilldata(msg
, attrs
, predicate
):
751 ok
, attrs
= _split_list(attrs
, predicate
)
755 for name
, kind
, homecls
, value
in ok
:
756 base
= self
.docother(getattr(object, name
), name
, mod
)
757 if callable(value
) or inspect
.isdatadescriptor(value
):
758 doc
= getattr(value
, "__doc__", None)
762 push('<dl><dt>%s</dl>\n' % base
)
764 doc
= self
.markup(getdoc(value
), self
.preformat
,
765 funcs
, classes
, mdict
)
766 doc
= '<dd><tt>%s</tt>' % doc
767 push('<dl><dt>%s%s</dl>\n' % (base
, doc
))
771 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
772 classify_class_attrs(object))
774 for key
, kind
, homecls
, value
in attrs
:
775 mdict
[key
] = anchor
= '#' + name
+ '-' + key
776 value
= getattr(object, key
)
778 # The value may not be hashable (e.g., a data attr with
779 # a dict or list value).
780 mdict
[value
] = anchor
786 thisclass
= mro
.popleft()
788 thisclass
= attrs
[0][2]
789 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
791 if thisclass
is __builtin__
.object:
794 elif thisclass
is object:
797 tag
= 'inherited from %s' % self
.classlink(thisclass
,
801 # Sort attrs by name.
803 attrs
.sort(key
=lambda t
: t
[0])
805 attrs
.sort(lambda t1
, t2
: cmp(t1
[0], t2
[0])) # 2.3 compat
807 # Pump out the attrs, segregated by kind.
808 attrs
= spill('Methods %s' % tag
, attrs
,
809 lambda t
: t
[1] == 'method')
810 attrs
= spill('Class methods %s' % tag
, attrs
,
811 lambda t
: t
[1] == 'class method')
812 attrs
= spill('Static methods %s' % tag
, attrs
,
813 lambda t
: t
[1] == 'static method')
814 attrs
= spilldescriptors('Data descriptors %s' % tag
, attrs
,
815 lambda t
: t
[1] == 'data descriptor')
816 attrs
= spilldata('Data and other attributes %s' % tag
, attrs
,
817 lambda t
: t
[1] == 'data')
821 contents
= ''.join(contents
)
824 title
= '<a name="%s">class <strong>%s</strong></a>' % (
827 title
= '<strong>%s</strong> = <a name="%s">class %s</a>' % (
828 name
, name
, realname
)
832 parents
.append(self
.classlink(base
, object.__module
__))
833 title
= title
+ '(%s)' % join(parents
, ', ')
834 doc
= self
.markup(getdoc(object), self
.preformat
, funcs
, classes
, mdict
)
835 doc
= doc
and '<tt>%s<br> </tt>' % doc
837 return self
.section(title
, '#000000', '#ffc8d8', contents
, 3, doc
)
839 def formatvalue(self
, object):
840 """Format an argument default value as text."""
841 return self
.grey('=' + self
.repr(object))
843 def docroutine(self
, object, name
=None, mod
=None,
844 funcs
={}, classes
={}, methods
={}, cl
=None):
845 """Produce HTML documentation for a function or method object."""
846 realname
= object.__name
__
847 name
= name
or realname
848 anchor
= (cl
and cl
.__name
__ or '') + '-' + name
851 if inspect
.ismethod(object):
852 imclass
= object.im_class
854 if imclass
is not cl
:
855 note
= ' from ' + self
.classlink(imclass
, mod
)
857 if object.im_self
is not None:
858 note
= ' method of %s instance' % self
.classlink(
859 object.im_self
.__class
__, mod
)
861 note
= ' unbound %s method' % self
.classlink(imclass
,mod
)
862 object = object.im_func
865 title
= '<a name="%s"><strong>%s</strong></a>' % (anchor
, realname
)
867 if (cl
and realname
in cl
.__dict
__ and
868 cl
.__dict
__[realname
] is object):
869 reallink
= '<a href="#%s">%s</a>' % (
870 cl
.__name
__ + '-' + realname
, realname
)
874 title
= '<a name="%s"><strong>%s</strong></a> = %s' % (
875 anchor
, name
, reallink
)
876 if inspect
.isfunction(object):
877 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
878 argspec
= inspect
.formatargspec(
879 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
880 if realname
== '<lambda>':
881 title
= '<strong>%s</strong> <em>lambda</em> ' % name
882 argspec
= argspec
[1:-1] # remove parentheses
886 decl
= title
+ argspec
+ (note
and self
.grey(
887 '<font face="helvetica, arial">%s</font>' % note
))
890 return '<dl><dt>%s</dt></dl>\n' % decl
893 getdoc(object), self
.preformat
, funcs
, classes
, methods
)
894 doc
= doc
and '<dd><tt>%s</tt></dd>' % doc
895 return '<dl><dt>%s</dt>%s</dl>\n' % (decl
, doc
)
897 def _docdescriptor(self
, name
, value
, mod
):
899 push
= results
.append
902 push('<dl><dt><strong>%s</strong></dt>\n' % name
)
903 if value
.__doc
__ is not None:
904 doc
= self
.markup(getdoc(value
), self
.preformat
)
905 push('<dd><tt>%s</tt></dd>\n' % doc
)
908 return ''.join(results
)
910 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
911 """Produce html documentation for a property."""
912 return self
._docdescriptor
(name
, object, mod
)
914 def docother(self
, object, name
=None, mod
=None, *ignored
):
915 """Produce HTML documentation for a data object."""
916 lhs
= name
and '<strong>%s</strong> = ' % name
or ''
917 return lhs
+ self
.repr(object)
919 def docdata(self
, object, name
=None, mod
=None, cl
=None):
920 """Produce html documentation for a data descriptor."""
921 return self
._docdescriptor
(name
, object, mod
)
923 def index(self
, dir, shadowed
=None):
924 """Generate an HTML index for a directory of modules."""
926 if shadowed
is None: shadowed
= {}
927 for importer
, name
, ispkg
in pkgutil
.iter_modules([dir]):
928 modpkgs
.append((name
, '', ispkg
, name
in shadowed
))
932 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
933 return self
.bigsection(dir, '#ffffff', '#ee77aa', contents
)
935 # -------------------------------------------- text documentation generator
937 class TextRepr(Repr
):
938 """Class for safely making a text representation of a Python object."""
941 self
.maxlist
= self
.maxtuple
= 20
943 self
.maxstring
= self
.maxother
= 100
945 def repr1(self
, x
, level
):
946 if hasattr(type(x
), '__name__'):
947 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
948 if hasattr(self
, methodname
):
949 return getattr(self
, methodname
)(x
, level
)
950 return cram(stripid(repr(x
)), self
.maxother
)
952 def repr_string(self
, x
, level
):
953 test
= cram(x
, self
.maxstring
)
954 testrepr
= repr(test
)
955 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
956 # Backslashes are only literal in the string and are never
957 # needed to make any special characters, so show a raw string.
958 return 'r' + testrepr
[0] + test
+ testrepr
[0]
961 repr_str
= repr_string
963 def repr_instance(self
, x
, level
):
965 return cram(stripid(repr(x
)), self
.maxstring
)
967 return '<%s instance>' % x
.__class
__.__name
__
970 """Formatter class for text documentation."""
972 # ------------------------------------------- text formatting utilities
974 _repr_instance
= TextRepr()
975 repr = _repr_instance
.repr
977 def bold(self
, text
):
978 """Format a string in bold by overstriking."""
979 return join(map(lambda ch
: ch
+ '\b' + ch
, text
), '')
981 def indent(self
, text
, prefix
=' '):
982 """Indent text by prepending a given prefix to each line."""
983 if not text
: return ''
984 lines
= split(text
, '\n')
985 lines
= map(lambda line
, prefix
=prefix
: prefix
+ line
, lines
)
986 if lines
: lines
[-1] = rstrip(lines
[-1])
987 return join(lines
, '\n')
989 def section(self
, title
, contents
):
990 """Format a section with a given heading."""
991 return self
.bold(title
) + '\n' + rstrip(self
.indent(contents
)) + '\n\n'
993 # ---------------------------------------------- type-specific routines
995 def formattree(self
, tree
, modname
, parent
=None, prefix
=''):
996 """Render in text a class tree as returned by inspect.getclasstree()."""
999 if type(entry
) is type(()):
1001 result
= result
+ prefix
+ classname(c
, modname
)
1002 if bases
and bases
!= (parent
,):
1003 parents
= map(lambda c
, m
=modname
: classname(c
, m
), bases
)
1004 result
= result
+ '(%s)' % join(parents
, ', ')
1005 result
= result
+ '\n'
1006 elif type(entry
) is type([]):
1007 result
= result
+ self
.formattree(
1008 entry
, modname
, c
, prefix
+ ' ')
1011 def docmodule(self
, object, name
=None, mod
=None):
1012 """Produce text documentation for a given module object."""
1013 name
= object.__name
__ # ignore the passed-in name
1014 synop
, desc
= splitdoc(getdoc(object))
1015 result
= self
.section('NAME', name
+ (synop
and ' - ' + synop
))
1018 all
= object.__all
__
1019 except AttributeError:
1023 file = inspect
.getabsfile(object)
1026 result
= result
+ self
.section('FILE', file)
1028 docloc
= self
.getdocloc(object)
1029 if docloc
is not None:
1030 result
= result
+ self
.section('MODULE DOCS', docloc
)
1033 result
= result
+ self
.section('DESCRIPTION', desc
)
1036 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
1037 # if __all__ exists, believe it. Otherwise use old heuristic.
1039 or (inspect
.getmodule(value
) or object) is object):
1040 if visiblename(key
, all
):
1041 classes
.append((key
, value
))
1043 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
1044 # if __all__ exists, believe it. Otherwise use old heuristic.
1045 if (all
is not None or
1046 inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object):
1047 if visiblename(key
, all
):
1048 funcs
.append((key
, value
))
1050 for key
, value
in inspect
.getmembers(object, isdata
):
1051 if visiblename(key
, all
):
1052 data
.append((key
, value
))
1055 modpkgs_names
= set()
1056 if hasattr(object, '__path__'):
1057 for importer
, modname
, ispkg
in pkgutil
.iter_modules(object.__path
__):
1058 modpkgs_names
.add(modname
)
1060 modpkgs
.append(modname
+ ' (package)')
1062 modpkgs
.append(modname
)
1065 result
= result
+ self
.section(
1066 'PACKAGE CONTENTS', join(modpkgs
, '\n'))
1068 # Detect submodules as sometimes created by C extensions
1070 for key
, value
in inspect
.getmembers(object, inspect
.ismodule
):
1071 if value
.__name
__.startswith(name
+ '.') and key
not in modpkgs_names
:
1072 submodules
.append(key
)
1075 result
= result
+ self
.section(
1076 'SUBMODULES', join(submodules
, '\n'))
1079 classlist
= map(lambda (key
, value
): value
, classes
)
1080 contents
= [self
.formattree(
1081 inspect
.getclasstree(classlist
, 1), name
)]
1082 for key
, value
in classes
:
1083 contents
.append(self
.document(value
, key
, name
))
1084 result
= result
+ self
.section('CLASSES', join(contents
, '\n'))
1088 for key
, value
in funcs
:
1089 contents
.append(self
.document(value
, key
, name
))
1090 result
= result
+ self
.section('FUNCTIONS', join(contents
, '\n'))
1094 for key
, value
in data
:
1095 contents
.append(self
.docother(value
, key
, name
, maxlen
=70))
1096 result
= result
+ self
.section('DATA', join(contents
, '\n'))
1098 if hasattr(object, '__version__'):
1099 version
= str(object.__version
__)
1100 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
1101 version
= strip(version
[11:-1])
1102 result
= result
+ self
.section('VERSION', version
)
1103 if hasattr(object, '__date__'):
1104 result
= result
+ self
.section('DATE', str(object.__date
__))
1105 if hasattr(object, '__author__'):
1106 result
= result
+ self
.section('AUTHOR', str(object.__author
__))
1107 if hasattr(object, '__credits__'):
1108 result
= result
+ self
.section('CREDITS', str(object.__credits
__))
1111 def docclass(self
, object, name
=None, mod
=None):
1112 """Produce text documentation for a given class object."""
1113 realname
= object.__name
__
1114 name
= name
or realname
1115 bases
= object.__bases
__
1117 def makename(c
, m
=object.__module
__):
1118 return classname(c
, m
)
1120 if name
== realname
:
1121 title
= 'class ' + self
.bold(realname
)
1123 title
= self
.bold(name
) + ' = class ' + realname
1125 parents
= map(makename
, bases
)
1126 title
= title
+ '(%s)' % join(parents
, ', ')
1128 doc
= getdoc(object)
1129 contents
= doc
and [doc
+ '\n'] or []
1130 push
= contents
.append
1132 # List the mro, if non-trivial.
1133 mro
= deque(inspect
.getmro(object))
1135 push("Method resolution order:")
1137 push(' ' + makename(base
))
1140 # Cute little class to pump out a horizontal rule between sections.
1141 class HorizontalRule
:
1148 hr
= HorizontalRule()
1150 def spill(msg
, attrs
, predicate
):
1151 ok
, attrs
= _split_list(attrs
, predicate
)
1155 for name
, kind
, homecls
, value
in ok
:
1156 push(self
.document(getattr(object, name
),
1160 def spilldescriptors(msg
, attrs
, predicate
):
1161 ok
, attrs
= _split_list(attrs
, predicate
)
1165 for name
, kind
, homecls
, value
in ok
:
1166 push(self
._docdescriptor
(name
, value
, mod
))
1169 def spilldata(msg
, attrs
, predicate
):
1170 ok
, attrs
= _split_list(attrs
, predicate
)
1174 for name
, kind
, homecls
, value
in ok
:
1175 if callable(value
) or inspect
.isdatadescriptor(value
):
1179 push(self
.docother(getattr(object, name
),
1180 name
, mod
, maxlen
=70, doc
=doc
) + '\n')
1183 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
1184 classify_class_attrs(object))
1187 thisclass
= mro
.popleft()
1189 thisclass
= attrs
[0][2]
1190 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
1192 if thisclass
is __builtin__
.object:
1195 elif thisclass
is object:
1196 tag
= "defined here"
1198 tag
= "inherited from %s" % classname(thisclass
,
1201 # Sort attrs by name.
1204 # Pump out the attrs, segregated by kind.
1205 attrs
= spill("Methods %s:\n" % tag
, attrs
,
1206 lambda t
: t
[1] == 'method')
1207 attrs
= spill("Class methods %s:\n" % tag
, attrs
,
1208 lambda t
: t
[1] == 'class method')
1209 attrs
= spill("Static methods %s:\n" % tag
, attrs
,
1210 lambda t
: t
[1] == 'static method')
1211 attrs
= spilldescriptors("Data descriptors %s:\n" % tag
, attrs
,
1212 lambda t
: t
[1] == 'data descriptor')
1213 attrs
= spilldata("Data and other attributes %s:\n" % tag
, attrs
,
1214 lambda t
: t
[1] == 'data')
1218 contents
= '\n'.join(contents
)
1221 return title
+ '\n' + self
.indent(rstrip(contents
), ' | ') + '\n'
1223 def formatvalue(self
, object):
1224 """Format an argument default value as text."""
1225 return '=' + self
.repr(object)
1227 def docroutine(self
, object, name
=None, mod
=None, cl
=None):
1228 """Produce text documentation for a function or method object."""
1229 realname
= object.__name
__
1230 name
= name
or realname
1233 if inspect
.ismethod(object):
1234 imclass
= object.im_class
1236 if imclass
is not cl
:
1237 note
= ' from ' + classname(imclass
, mod
)
1239 if object.im_self
is not None:
1240 note
= ' method of %s instance' % classname(
1241 object.im_self
.__class
__, mod
)
1243 note
= ' unbound %s method' % classname(imclass
,mod
)
1244 object = object.im_func
1246 if name
== realname
:
1247 title
= self
.bold(realname
)
1249 if (cl
and realname
in cl
.__dict
__ and
1250 cl
.__dict
__[realname
] is object):
1252 title
= self
.bold(name
) + ' = ' + realname
1253 if inspect
.isfunction(object):
1254 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
1255 argspec
= inspect
.formatargspec(
1256 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
1257 if realname
== '<lambda>':
1258 title
= self
.bold(name
) + ' lambda '
1259 argspec
= argspec
[1:-1] # remove parentheses
1262 decl
= title
+ argspec
+ note
1267 doc
= getdoc(object) or ''
1268 return decl
+ '\n' + (doc
and rstrip(self
.indent(doc
)) + '\n')
1270 def _docdescriptor(self
, name
, value
, mod
):
1272 push
= results
.append
1275 push(self
.bold(name
))
1277 doc
= getdoc(value
) or ''
1279 push(self
.indent(doc
))
1281 return ''.join(results
)
1283 def docproperty(self
, object, name
=None, mod
=None, cl
=None):
1284 """Produce text documentation for a property."""
1285 return self
._docdescriptor
(name
, object, mod
)
1287 def docdata(self
, object, name
=None, mod
=None, cl
=None):
1288 """Produce text documentation for a data descriptor."""
1289 return self
._docdescriptor
(name
, object, mod
)
1291 def docother(self
, object, name
=None, mod
=None, parent
=None, maxlen
=None, doc
=None):
1292 """Produce text documentation for a data object."""
1293 repr = self
.repr(object)
1295 line
= (name
and name
+ ' = ' or '') + repr
1296 chop
= maxlen
- len(line
)
1297 if chop
< 0: repr = repr[:chop
] + '...'
1298 line
= (name
and self
.bold(name
) + ' = ' or '') + repr
1300 line
+= '\n' + self
.indent(str(doc
))
1303 # --------------------------------------------------------- user interfaces
1306 """The first time this is called, determine what kind of pager to use."""
1312 """Decide what method to use for paging through text."""
1313 if type(sys
.stdout
) is not types
.FileType
:
1315 if not sys
.stdin
.isatty() or not sys
.stdout
.isatty():
1317 if 'PAGER' in os
.environ
:
1318 if sys
.platform
== 'win32': # pipes completely broken in Windows
1319 return lambda text
: tempfilepager(plain(text
), os
.environ
['PAGER'])
1320 elif os
.environ
.get('TERM') in ('dumb', 'emacs'):
1321 return lambda text
: pipepager(plain(text
), os
.environ
['PAGER'])
1323 return lambda text
: pipepager(text
, os
.environ
['PAGER'])
1324 if os
.environ
.get('TERM') in ('dumb', 'emacs'):
1326 if sys
.platform
== 'win32' or sys
.platform
.startswith('os2'):
1327 return lambda text
: tempfilepager(plain(text
), 'more <')
1328 if hasattr(os
, 'system') and os
.system('(less) 2>/dev/null') == 0:
1329 return lambda text
: pipepager(text
, 'less')
1332 (fd
, filename
) = tempfile
.mkstemp()
1335 if hasattr(os
, 'system') and os
.system('more %s' % filename
) == 0:
1336 return lambda text
: pipepager(text
, 'more')
1343 """Remove boldface formatting from text."""
1344 return re
.sub('.\b', '', text
)
1346 def pipepager(text
, cmd
):
1347 """Page through text by feeding it to another program."""
1348 pipe
= os
.popen(cmd
, 'w')
1353 pass # Ignore broken pipes caused by quitting the pager program.
1355 def tempfilepager(text
, cmd
):
1356 """Page through text by invoking a program on a temporary file."""
1358 filename
= tempfile
.mktemp()
1359 file = open(filename
, 'w')
1363 os
.system(cmd
+ ' ' + filename
)
1368 """Page through text on a text terminal."""
1369 lines
= split(plain(text
), '\n')
1372 fd
= sys
.stdin
.fileno()
1373 old
= tty
.tcgetattr(fd
)
1375 getchar
= lambda: sys
.stdin
.read(1)
1376 except (ImportError, AttributeError):
1378 getchar
= lambda: sys
.stdin
.readline()[:-1][:1]
1381 r
= inc
= os
.environ
.get('LINES', 25) - 1
1382 sys
.stdout
.write(join(lines
[:inc
], '\n') + '\n')
1384 sys
.stdout
.write('-- more --')
1389 sys
.stdout
.write('\r \r')
1391 elif c
in ('\r', '\n'):
1392 sys
.stdout
.write('\r \r' + lines
[r
] + '\n')
1395 if c
in ('b', 'B', '\x1b'):
1398 sys
.stdout
.write('\n' + join(lines
[r
:r
+inc
], '\n') + '\n')
1403 tty
.tcsetattr(fd
, tty
.TCSAFLUSH
, old
)
1405 def plainpager(text
):
1406 """Simply print unformatted text. This is the ultimate fallback."""
1407 sys
.stdout
.write(plain(text
))
1409 def describe(thing
):
1410 """Produce a short description of the given thing."""
1411 if inspect
.ismodule(thing
):
1412 if thing
.__name
__ in sys
.builtin_module_names
:
1413 return 'built-in module ' + thing
.__name
__
1414 if hasattr(thing
, '__path__'):
1415 return 'package ' + thing
.__name
__
1417 return 'module ' + thing
.__name
__
1418 if inspect
.isbuiltin(thing
):
1419 return 'built-in function ' + thing
.__name
__
1420 if inspect
.isgetsetdescriptor(thing
):
1421 return 'getset descriptor %s.%s.%s' % (
1422 thing
.__objclass
__.__module
__, thing
.__objclass
__.__name
__,
1424 if inspect
.ismemberdescriptor(thing
):
1425 return 'member descriptor %s.%s.%s' % (
1426 thing
.__objclass
__.__module
__, thing
.__objclass
__.__name
__,
1428 if inspect
.isclass(thing
):
1429 return 'class ' + thing
.__name
__
1430 if inspect
.isfunction(thing
):
1431 return 'function ' + thing
.__name
__
1432 if inspect
.ismethod(thing
):
1433 return 'method ' + thing
.__name
__
1434 if type(thing
) is types
.InstanceType
:
1435 return 'instance of ' + thing
.__class
__.__name
__
1436 return type(thing
).__name
__
1438 def locate(path
, forceload
=0):
1439 """Locate an object by name or dotted path, importing as necessary."""
1440 parts
= [part
for part
in split(path
, '.') if part
]
1442 while n
< len(parts
):
1443 nextmodule
= safeimport(join(parts
[:n
+1], '.'), forceload
)
1444 if nextmodule
: module
, n
= nextmodule
, n
+ 1
1448 for part
in parts
[n
:]:
1449 try: object = getattr(object, part
)
1450 except AttributeError: return None
1453 if hasattr(__builtin__
, path
):
1454 return getattr(__builtin__
, path
)
1456 # --------------------------------------- interactive interpreter interface
1461 class _OldStyleClass
: pass
1462 _OLD_INSTANCE_TYPE
= type(_OldStyleClass())
1464 def resolve(thing
, forceload
=0):
1465 """Given an object or a path to an object, get the object and its name."""
1466 if isinstance(thing
, str):
1467 object = locate(thing
, forceload
)
1469 raise ImportError, 'no Python documentation found for %r' % thing
1470 return object, thing
1472 return thing
, getattr(thing
, '__name__', None)
1474 def render_doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1475 """Render text documentation, given an object or a path to an object."""
1476 object, name
= resolve(thing
, forceload
)
1477 desc
= describe(object)
1478 module
= inspect
.getmodule(object)
1479 if name
and '.' in name
:
1480 desc
+= ' in ' + name
[:name
.rfind('.')]
1481 elif module
and module
is not object:
1482 desc
+= ' in module ' + module
.__name
__
1483 if type(object) is _OLD_INSTANCE_TYPE
:
1484 # If the passed object is an instance of an old-style class,
1485 # document its available methods instead of its value.
1486 object = object.__class
__
1487 elif not (inspect
.ismodule(object) or
1488 inspect
.isclass(object) or
1489 inspect
.isroutine(object) or
1490 inspect
.isgetsetdescriptor(object) or
1491 inspect
.ismemberdescriptor(object) or
1492 isinstance(object, property)):
1493 # If the passed object is a piece of data or an instance,
1494 # document its available methods instead of its value.
1495 object = type(object)
1497 return title
% desc
+ '\n\n' + text
.document(object, name
)
1499 def doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1500 """Display text documentation, given an object or a path to an object."""
1502 pager(render_doc(thing
, title
, forceload
))
1503 except (ImportError, ErrorDuringImport
), value
:
1506 def writedoc(thing
, forceload
=0):
1507 """Write HTML documentation to a file in the current directory."""
1509 object, name
= resolve(thing
, forceload
)
1510 page
= html
.page(describe(object), html
.document(object, name
))
1511 file = open(name
+ '.html', 'w')
1514 print 'wrote', name
+ '.html'
1515 except (ImportError, ErrorDuringImport
), value
:
1518 def writedocs(dir, pkgpath
='', done
=None):
1519 """Write out HTML documentation for all modules in a directory tree."""
1520 if done
is None: done
= {}
1521 for importer
, modname
, ispkg
in pkgutil
.walk_packages([dir], pkgpath
):
1529 'assert': ('ref/assert', ''),
1530 'break': ('ref/break', 'while for'),
1531 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1532 'continue': ('ref/continue', 'while for'),
1533 'def': ('ref/function', ''),
1534 'del': ('ref/del', 'BASICMETHODS'),
1536 'else': ('ref/if', 'while for'),
1538 'exec': ('ref/exec', ''),
1540 'for': ('ref/for', 'break continue while'),
1542 'global': ('ref/global', 'NAMESPACES'),
1543 'if': ('ref/if', 'TRUTHVALUE'),
1544 'import': ('ref/import', 'MODULES'),
1545 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1547 'lambda': ('ref/lambdas', 'FUNCTIONS'),
1550 'pass': ('ref/pass', ''),
1551 'print': ('ref/print', ''),
1552 'raise': ('ref/raise', 'EXCEPTIONS'),
1553 'return': ('ref/return', 'FUNCTIONS'),
1554 'try': ('ref/try', 'EXCEPTIONS'),
1555 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1556 'with': ('ref/with', 'CONTEXTMANAGERS EXCEPTIONS yield'),
1557 'yield': ('ref/yield', ''),
1561 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
1562 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
1563 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1564 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
1565 'UNICODE': ('ref/strings', 'encodings unicode SEQUENCES STRINGMETHODS FORMATTING TYPES'),
1566 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1567 'INTEGER': ('ref/integers', 'int range'),
1568 'FLOAT': ('ref/floating', 'float math'),
1569 'COMPLEX': ('ref/imaginary', 'complex cmath'),
1570 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1571 'MAPPINGS': 'DICTIONARIES',
1572 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1573 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1574 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
1575 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
1576 'FRAMEOBJECTS': 'TYPES',
1577 'TRACEBACKS': 'TYPES',
1578 'NONE': ('lib/bltin-null-object', ''),
1579 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1580 'FILES': ('lib/bltin-file-objects', ''),
1581 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1582 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1583 'MODULES': ('lib/typesmodules', 'import'),
1584 'PACKAGES': 'import',
1585 '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'),
1586 'OPERATORS': 'EXPRESSIONS',
1587 'PRECEDENCE': 'EXPRESSIONS',
1588 'OBJECTS': ('ref/objects', 'TYPES'),
1589 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1590 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1591 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1592 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1593 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1594 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1595 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1596 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
1597 'EXECUTION': ('ref/execmodel', 'NAMESPACES DYNAMICFEATURES EXCEPTIONS'),
1598 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION DYNAMICFEATURES'),
1599 'DYNAMICFEATURES': ('ref/dynamic-features', ''),
1600 'SCOPING': 'NAMESPACES',
1601 'FRAMES': 'NAMESPACES',
1602 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1603 'COERCIONS': ('ref/coercion-rules','CONVERSIONS'),
1604 'CONVERSIONS': ('ref/conversions', 'COERCIONS'),
1605 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1606 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
1607 'PRIVATENAMES': ('ref/atom-identifiers', ''),
1608 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1609 'TUPLES': 'SEQUENCES',
1610 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
1611 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
1612 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
1613 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
1614 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1615 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
1616 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1617 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1618 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1619 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1620 'POWER': ('ref/power', 'EXPRESSIONS'),
1621 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1622 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1623 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1624 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1625 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
1626 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
1627 'ASSERTION': 'assert',
1628 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
1629 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
1631 'PRINTING': 'print',
1632 'RETURNING': 'return',
1633 'IMPORTING': 'import',
1634 'CONDITIONAL': 'if',
1635 'LOOPING': ('ref/compound', 'for while break continue'),
1636 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
1637 'DEBUGGING': ('lib/module-pdb', 'pdb'),
1638 'CONTEXTMANAGERS': ('ref/context-managers', 'with'),
1641 def __init__(self
, input, output
):
1643 self
.output
= output
1645 execdir
= os
.path
.dirname(sys
.executable
)
1646 homedir
= os
.environ
.get('PYTHONHOME')
1648 for dir in [os
.environ
.get('PYTHONDOCS'),
1649 homedir
and os
.path
.join(homedir
, 'doc'),
1650 join(execdir
, 'doc'), # for Windows
1651 join(sys
.prefix
, 'doc/python-docs-' + split(sys
.version
)[0]),
1652 join(sys
.prefix
, 'doc/python-' + split(sys
.version
)[0]),
1653 join(sys
.prefix
, 'doc/python-docs-' + sys
.version
[:3]),
1654 join(sys
.prefix
, 'doc/python-' + sys
.version
[:3]),
1655 join(sys
.prefix
, 'Resources/English.lproj/Documentation')]:
1656 if dir and os
.path
.isdir(join(dir, 'lib')):
1659 if dir and os
.path
.isdir(join(dir, 'html', 'lib')):
1660 self
.docdir
= join(dir, 'html')
1664 if inspect
.stack()[1][3] == '?':
1667 return '<pydoc.Helper instance>'
1669 def __call__(self
, request
=None):
1670 if request
is not None:
1675 self
.output
.write('''
1676 You are now leaving help and returning to the Python interpreter.
1677 If you want to ask for help on a particular object directly from the
1678 interpreter, you can type "help(object)". Executing "help('string')"
1679 has the same effect as typing a particular string at the help> prompt.
1683 self
.output
.write('\n')
1686 request
= self
.getline('help> ')
1687 if not request
: break
1688 except (KeyboardInterrupt, EOFError):
1690 request
= strip(replace(request
, '"', '', "'", ''))
1691 if lower(request
) in ('q', 'quit'): break
1694 def getline(self
, prompt
):
1695 """Read one line, using raw_input when available."""
1696 if self
.input is sys
.stdin
:
1697 return raw_input(prompt
)
1699 self
.output
.write(prompt
)
1701 return self
.input.readline()
1703 def help(self
, request
):
1704 if type(request
) is type(''):
1705 if request
== 'help': self
.intro()
1706 elif request
== 'keywords': self
.listkeywords()
1707 elif request
== 'topics': self
.listtopics()
1708 elif request
== 'modules': self
.listmodules()
1709 elif request
[:8] == 'modules ':
1710 self
.listmodules(split(request
)[1])
1711 elif request
in self
.keywords
: self
.showtopic(request
)
1712 elif request
in self
.topics
: self
.showtopic(request
)
1713 elif request
: doc(request
, 'Help on %s:')
1714 elif isinstance(request
, Helper
): self()
1715 else: doc(request
, 'Help on %s:')
1716 self
.output
.write('\n')
1719 self
.output
.write('''
1720 Welcome to Python %s! This is the online help utility.
1722 If this is your first time using Python, you should definitely check out
1723 the tutorial on the Internet at http://docs.python.org/tutorial/.
1725 Enter the name of any module, keyword, or topic to get help on writing
1726 Python programs and using Python modules. To quit this help utility and
1727 return to the interpreter, just type "quit".
1729 To get a list of available modules, keywords, or topics, type "modules",
1730 "keywords", or "topics". Each module also comes with a one-line summary
1731 of what it does; to list the modules whose summaries contain a given word
1732 such as "spam", type "modules spam".
1733 ''' % sys
.version
[:3])
1735 def list(self
, items
, columns
=4, width
=80):
1738 colw
= width
/ columns
1739 rows
= (len(items
) + columns
- 1) / columns
1740 for row
in range(rows
):
1741 for col
in range(columns
):
1742 i
= col
* rows
+ row
1744 self
.output
.write(items
[i
])
1745 if col
< columns
- 1:
1746 self
.output
.write(' ' + ' ' * (colw
-1 - len(items
[i
])))
1747 self
.output
.write('\n')
1749 def listkeywords(self
):
1750 self
.output
.write('''
1751 Here is a list of the Python keywords. Enter any keyword to get more help.
1754 self
.list(self
.keywords
.keys())
1756 def listtopics(self
):
1757 self
.output
.write('''
1758 Here is a list of available topics. Enter any topic name to get more help.
1761 self
.list(self
.topics
.keys())
1763 def showtopic(self
, topic
):
1765 self
.output
.write('''
1766 Sorry, topic and keyword documentation is not available because the Python
1767 HTML documentation files could not be found. If you have installed them,
1768 please set the environment variable PYTHONDOCS to indicate their location.
1770 On the Microsoft Windows operating system, the files can be built by
1771 running "hh -decompile . PythonNN.chm" in the C:\PythonNN\Doc> directory.
1774 target
= self
.topics
.get(topic
, self
.keywords
.get(topic
))
1776 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1778 if type(target
) is type(''):
1779 return self
.showtopic(target
)
1781 filename
, xrefs
= target
1782 filename
= self
.docdir
+ '/' + filename
+ '.html'
1784 file = open(filename
)
1786 self
.output
.write('could not read docs from %s\n' % filename
)
1789 divpat
= re
.compile('<div[^>]*navigat.*?</div.*?>', re
.I | re
.S
)
1790 addrpat
= re
.compile('<address.*?>.*?</address.*?>', re
.I | re
.S
)
1791 document
= re
.sub(addrpat
, '', re
.sub(divpat
, '', file.read()))
1794 import htmllib
, formatter
, StringIO
1795 buffer = StringIO
.StringIO()
1796 parser
= htmllib
.HTMLParser(
1797 formatter
.AbstractFormatter(formatter
.DumbWriter(buffer)))
1798 parser
.start_table
= parser
.do_p
1799 parser
.end_table
= lambda parser
=parser
: parser
.do_p({})
1800 parser
.start_tr
= parser
.do_br
1801 parser
.start_td
= parser
.start_th
= lambda a
, b
=buffer: b
.write('\t')
1802 parser
.feed(document
)
1803 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1804 pager(' ' + strip(buffer) + '\n')
1806 buffer = StringIO
.StringIO()
1807 formatter
.DumbWriter(buffer).send_flowing_data(
1808 'Related help topics: ' + join(split(xrefs
), ', ') + '\n')
1809 self
.output
.write('\n%s\n' % buffer.getvalue())
1811 def listmodules(self
, key
=''):
1813 self
.output
.write('''
1814 Here is a list of matching modules. Enter any module name to get more help.
1819 self
.output
.write('''
1820 Please wait a moment while I gather a list of all available modules...
1824 def callback(path
, modname
, desc
, modules
=modules
):
1825 if modname
and modname
[-9:] == '.__init__':
1826 modname
= modname
[:-9] + ' (package)'
1827 if find(modname
, '.') < 0:
1828 modules
[modname
] = 1
1829 def onerror(modname
):
1830 callback(None, modname
, None)
1831 ModuleScanner().run(callback
, onerror
=onerror
)
1832 self
.list(modules
.keys())
1833 self
.output
.write('''
1834 Enter any module name to get more help. Or, type "modules spam" to search
1835 for modules whose descriptions contain the word "spam".
1838 help = Helper(sys
.stdin
, sys
.stdout
)
1841 """A generic tree iterator."""
1842 def __init__(self
, roots
, children
, descendp
):
1843 self
.roots
= roots
[:]
1845 self
.children
= children
1846 self
.descendp
= descendp
1852 root
= self
.roots
.pop(0)
1853 self
.state
= [(root
, self
.children(root
))]
1854 node
, children
= self
.state
[-1]
1858 child
= children
.pop(0)
1859 if self
.descendp(child
):
1860 self
.state
.append((child
, self
.children(child
)))
1864 class ModuleScanner
:
1865 """An interruptible scanner that searches module synopses."""
1867 def run(self
, callback
, key
=None, completer
=None, onerror
=None):
1868 if key
: key
= lower(key
)
1872 for modname
in sys
.builtin_module_names
:
1873 if modname
!= '__main__':
1876 callback(None, modname
, '')
1878 desc
= split(__import__(modname
).__doc
__ or '', '\n')[0]
1879 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1880 callback(None, modname
, desc
)
1882 for importer
, modname
, ispkg
in pkgutil
.walk_packages(onerror
=onerror
):
1886 callback(None, modname
, '')
1888 loader
= importer
.find_module(modname
)
1889 if hasattr(loader
,'get_source'):
1891 desc
= source_synopsis(
1892 StringIO
.StringIO(loader
.get_source(modname
))
1894 if hasattr(loader
,'get_filename'):
1895 path
= loader
.get_filename(modname
)
1899 module
= loader
.load_module(modname
)
1900 desc
= (module
.__doc
__ or '').splitlines()[0]
1901 path
= getattr(module
,'__file__',None)
1902 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1903 callback(path
, modname
, desc
)
1909 """Print all the one-line module summaries that contain a substring."""
1910 def callback(path
, modname
, desc
):
1911 if modname
[-9:] == '.__init__':
1912 modname
= modname
[:-9] + ' (package)'
1913 print modname
, desc
and '- ' + desc
1914 try: import warnings
1915 except ImportError: pass
1916 else: warnings
.filterwarnings('ignore') # ignore problems during import
1917 ModuleScanner().run(callback
, key
)
1919 # --------------------------------------------------- web browser interface
1921 def serve(port
, callback
=None, completer
=None):
1922 import BaseHTTPServer
, mimetools
, select
1924 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1925 class Message(mimetools
.Message
):
1926 def __init__(self
, fp
, seekable
=1):
1927 Message
= self
.__class
__
1928 Message
.__bases
__[0].__bases
__[0].__init
__(self
, fp
, seekable
)
1929 self
.encodingheader
= self
.getheader('content-transfer-encoding')
1930 self
.typeheader
= self
.getheader('content-type')
1934 class DocHandler(BaseHTTPServer
.BaseHTTPRequestHandler
):
1935 def send_document(self
, title
, contents
):
1937 self
.send_response(200)
1938 self
.send_header('Content-Type', 'text/html')
1940 self
.wfile
.write(html
.page(title
, contents
))
1941 except IOError: pass
1945 if path
[-5:] == '.html': path
= path
[:-5]
1946 if path
[:1] == '/': path
= path
[1:]
1947 if path
and path
!= '.':
1949 obj
= locate(path
, forceload
=1)
1950 except ErrorDuringImport
, value
:
1951 self
.send_document(path
, html
.escape(str(value
)))
1954 self
.send_document(describe(obj
), html
.document(obj
, path
))
1956 self
.send_document(path
,
1957 'no Python documentation found for %s' % repr(path
))
1959 heading
= html
.heading(
1960 '<big><big><strong>Python: Index of Modules</strong></big></big>',
1961 '#ffffff', '#7799ee')
1962 def bltinlink(name
):
1963 return '<a href="%s.html">%s</a>' % (name
, name
)
1964 names
= filter(lambda x
: x
!= '__main__',
1965 sys
.builtin_module_names
)
1966 contents
= html
.multicolumn(names
, bltinlink
)
1967 indices
= ['<p>' + html
.bigsection(
1968 'Built-in Modules', '#ffffff', '#ee77aa', contents
)]
1971 for dir in sys
.path
:
1972 indices
.append(html
.index(dir, seen
))
1973 contents
= heading
+ join(indices
) + '''<p align=right>
1974 <font color="#909090" face="helvetica, arial"><strong>
1975 pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>'''
1976 self
.send_document('Index of Modules', contents
)
1978 def log_message(self
, *args
): pass
1980 class DocServer(BaseHTTPServer
.HTTPServer
):
1981 def __init__(self
, port
, callback
):
1982 host
= (sys
.platform
== 'mac') and '127.0.0.1' or 'localhost'
1983 self
.address
= ('', port
)
1984 self
.url
= 'http://%s:%d/' % (host
, port
)
1985 self
.callback
= callback
1986 self
.base
.__init
__(self
, self
.address
, self
.handler
)
1988 def serve_until_quit(self
):
1991 while not self
.quit
:
1992 rd
, wr
, ex
= select
.select([self
.socket
.fileno()], [], [], 1)
1993 if rd
: self
.handle_request()
1995 def server_activate(self
):
1996 self
.base
.server_activate(self
)
1997 if self
.callback
: self
.callback(self
)
1999 DocServer
.base
= BaseHTTPServer
.HTTPServer
2000 DocServer
.handler
= DocHandler
2001 DocHandler
.MessageClass
= Message
2004 DocServer(port
, callback
).serve_until_quit()
2005 except (KeyboardInterrupt, select
.error
):
2008 if completer
: completer()
2010 # ----------------------------------------------------- graphical interface
2013 """Graphical interface (starts web server and pops up a control window)."""
2015 def __init__(self
, window
, port
=7464):
2016 self
.window
= window
2021 self
.server_frm
= Tkinter
.Frame(window
)
2022 self
.title_lbl
= Tkinter
.Label(self
.server_frm
,
2023 text
='Starting server...\n ')
2024 self
.open_btn
= Tkinter
.Button(self
.server_frm
,
2025 text
='open browser', command
=self
.open, state
='disabled')
2026 self
.quit_btn
= Tkinter
.Button(self
.server_frm
,
2027 text
='quit serving', command
=self
.quit
, state
='disabled')
2029 self
.search_frm
= Tkinter
.Frame(window
)
2030 self
.search_lbl
= Tkinter
.Label(self
.search_frm
, text
='Search for')
2031 self
.search_ent
= Tkinter
.Entry(self
.search_frm
)
2032 self
.search_ent
.bind('<Return>', self
.search
)
2033 self
.stop_btn
= Tkinter
.Button(self
.search_frm
,
2034 text
='stop', pady
=0, command
=self
.stop
, state
='disabled')
2035 if sys
.platform
== 'win32':
2036 # Trying to hide and show this button crashes under Windows.
2037 self
.stop_btn
.pack(side
='right')
2039 self
.window
.title('pydoc')
2040 self
.window
.protocol('WM_DELETE_WINDOW', self
.quit
)
2041 self
.title_lbl
.pack(side
='top', fill
='x')
2042 self
.open_btn
.pack(side
='left', fill
='x', expand
=1)
2043 self
.quit_btn
.pack(side
='right', fill
='x', expand
=1)
2044 self
.server_frm
.pack(side
='top', fill
='x')
2046 self
.search_lbl
.pack(side
='left')
2047 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2048 self
.search_frm
.pack(side
='top', fill
='x')
2049 self
.search_ent
.focus_set()
2051 font
= ('helvetica', sys
.platform
== 'win32' and 8 or 10)
2052 self
.result_lst
= Tkinter
.Listbox(window
, font
=font
, height
=6)
2053 self
.result_lst
.bind('<Button-1>', self
.select
)
2054 self
.result_lst
.bind('<Double-Button-1>', self
.goto
)
2055 self
.result_scr
= Tkinter
.Scrollbar(window
,
2056 orient
='vertical', command
=self
.result_lst
.yview
)
2057 self
.result_lst
.config(yscrollcommand
=self
.result_scr
.set)
2059 self
.result_frm
= Tkinter
.Frame(window
)
2060 self
.goto_btn
= Tkinter
.Button(self
.result_frm
,
2061 text
='go to selected', command
=self
.goto
)
2062 self
.hide_btn
= Tkinter
.Button(self
.result_frm
,
2063 text
='hide results', command
=self
.hide
)
2064 self
.goto_btn
.pack(side
='left', fill
='x', expand
=1)
2065 self
.hide_btn
.pack(side
='right', fill
='x', expand
=1)
2067 self
.window
.update()
2068 self
.minwidth
= self
.window
.winfo_width()
2069 self
.minheight
= self
.window
.winfo_height()
2070 self
.bigminheight
= (self
.server_frm
.winfo_reqheight() +
2071 self
.search_frm
.winfo_reqheight() +
2072 self
.result_lst
.winfo_reqheight() +
2073 self
.result_frm
.winfo_reqheight())
2074 self
.bigwidth
, self
.bigheight
= self
.minwidth
, self
.bigminheight
2076 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2077 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2078 self
.window
.tk
.willdispatch()
2082 target
=serve
, args
=(port
, self
.ready
, self
.quit
)).start()
2084 def ready(self
, server
):
2085 self
.server
= server
2086 self
.title_lbl
.config(
2087 text
='Python documentation server at\n' + server
.url
)
2088 self
.open_btn
.config(state
='normal')
2089 self
.quit_btn
.config(state
='normal')
2091 def open(self
, event
=None, url
=None):
2092 url
= url
or self
.server
.url
2095 webbrowser
.open(url
)
2096 except ImportError: # pre-webbrowser.py compatibility
2097 if sys
.platform
== 'win32':
2098 os
.system('start "%s"' % url
)
2099 elif sys
.platform
== 'mac':
2101 except ImportError: pass
2102 else: ic
.launchurl(url
)
2104 rc
= os
.system('netscape -remote "openURL(%s)" &' % url
)
2105 if rc
: os
.system('netscape "%s" &' % url
)
2107 def quit(self
, event
=None):
2109 self
.server
.quit
= 1
2112 def search(self
, event
=None):
2113 key
= self
.search_ent
.get()
2114 self
.stop_btn
.pack(side
='right')
2115 self
.stop_btn
.config(state
='normal')
2116 self
.search_lbl
.config(text
='Searching for "%s"...' % key
)
2117 self
.search_ent
.forget()
2118 self
.search_lbl
.pack(side
='left')
2119 self
.result_lst
.delete(0, 'end')
2120 self
.goto_btn
.config(state
='disabled')
2125 self
.scanner
.quit
= 1
2126 self
.scanner
= ModuleScanner()
2127 threading
.Thread(target
=self
.scanner
.run
,
2128 args
=(self
.update
, key
, self
.done
)).start()
2130 def update(self
, path
, modname
, desc
):
2131 if modname
[-9:] == '.__init__':
2132 modname
= modname
[:-9] + ' (package)'
2133 self
.result_lst
.insert('end',
2134 modname
+ ' - ' + (desc
or '(no description)'))
2136 def stop(self
, event
=None):
2138 self
.scanner
.quit
= 1
2143 self
.search_lbl
.config(text
='Search for')
2144 self
.search_lbl
.pack(side
='left')
2145 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2146 if sys
.platform
!= 'win32': self
.stop_btn
.forget()
2147 self
.stop_btn
.config(state
='disabled')
2149 def select(self
, event
=None):
2150 self
.goto_btn
.config(state
='normal')
2152 def goto(self
, event
=None):
2153 selection
= self
.result_lst
.curselection()
2155 modname
= split(self
.result_lst
.get(selection
[0]))[0]
2156 self
.open(url
=self
.server
.url
+ modname
+ '.html')
2159 if not self
.expanded
: return
2160 self
.result_frm
.forget()
2161 self
.result_scr
.forget()
2162 self
.result_lst
.forget()
2163 self
.bigwidth
= self
.window
.winfo_width()
2164 self
.bigheight
= self
.window
.winfo_height()
2165 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2166 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2170 if self
.expanded
: return
2171 self
.result_frm
.pack(side
='bottom', fill
='x')
2172 self
.result_scr
.pack(side
='right', fill
='y')
2173 self
.result_lst
.pack(side
='top', fill
='both', expand
=1)
2174 self
.window
.wm_geometry('%dx%d' % (self
.bigwidth
, self
.bigheight
))
2175 self
.window
.wm_minsize(self
.minwidth
, self
.bigminheight
)
2178 def hide(self
, event
=None):
2185 # Tk will crash if pythonw.exe has an XP .manifest
2186 # file and the root has is not destroyed explicitly.
2187 # If the problem is ever fixed in Tk, the explicit
2194 except KeyboardInterrupt:
2197 # -------------------------------------------------- command-line interface
2200 return isinstance(x
, str) and find(x
, os
.sep
) >= 0
2203 """Command-line interface (looks at sys.argv to decide what to do)."""
2205 class BadUsage
: pass
2207 # Scripts don't get the current directory in their path by default.
2208 scriptdir
= os
.path
.dirname(sys
.argv
[0])
2209 if scriptdir
in sys
.path
:
2210 sys
.path
.remove(scriptdir
)
2211 sys
.path
.insert(0, '.')
2214 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'gk:p:w')
2217 for opt
, val
in opts
:
2230 print 'pydoc server ready at %s' % server
.url
2232 print 'pydoc server stopped'
2233 serve(port
, ready
, stopped
)
2238 if not args
: raise BadUsage
2240 if ispath(arg
) and not os
.path
.exists(arg
):
2241 print 'file %r does not exist' % arg
2244 if ispath(arg
) and os
.path
.isfile(arg
):
2245 arg
= importfile(arg
)
2247 if ispath(arg
) and os
.path
.isdir(arg
):
2253 except ErrorDuringImport
, value
:
2256 except (getopt
.error
, BadUsage
):
2257 cmd
= os
.path
.basename(sys
.argv
[0])
2258 print """pydoc - the Python documentation tool
2261 Show text documentation on something. <name> may be the name of a
2262 Python keyword, topic, function, module, or package, or a dotted
2263 reference to a class or function within a module or module in a
2264 package. If <name> contains a '%s', it is used as the path to a
2265 Python source file to document. If name is 'keywords', 'topics',
2266 or 'modules', a listing of these things is displayed.
2269 Search for a keyword in the synopsis lines of all available modules.
2272 Start an HTTP server on the given port on the local machine.
2275 Pop up a graphical interface for finding and serving documentation.
2278 Write out the HTML documentation for a module to a file in the current
2279 directory. If <name> contains a '%s', it is treated as a filename; if
2280 it names a directory, documentation is written for all the contents.
2281 """ % (cmd
, os
.sep
, cmd
, cmd
, cmd
, cmd
, os
.sep
)
2283 if __name__
== '__main__': cli()