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".
29 __author__
= "Ka-Ping Yee <ping@lfw.org>"
30 __date__
= "26 February 2001"
31 __version__
= "$Revision$"
32 __credits__
= """Guido van Rossum, for an excellent programming language.
33 Tommy Burnette, the original creator of manpy.
34 Paul Prescod, for all his work on onlinehelp.
35 Richard Chamberlain, for the first implementation of textdoc.
37 Mynd you, møøse bites Kan be pretty nasti..."""
39 # Known bugs that can't be fixed here:
40 # - imp.load_module() cannot be prevented from clobbering existing
41 # loaded modules, so calling synopsis() on a binary module file
42 # changes the contents of any existing module with the same name.
43 # - If the __file__ attribute on a module is a relative path and
44 # the current directory is changed with os.chdir(), an incorrect
45 # path will be displayed.
47 import sys
, imp
, os
, re
, types
, inspect
49 from string
import expandtabs
, find
, join
, lower
, split
, strip
, rfind
, rstrip
51 # --------------------------------------------------------- common routines
54 """Convert sys.path into a list of absolute, existing, unique paths."""
58 dir = os
.path
.abspath(dir or '.')
59 normdir
= os
.path
.normcase(dir)
60 if normdir
not in normdirs
and os
.path
.isdir(dir):
62 normdirs
.append(normdir
)
66 """Get the doc string or comments for an object."""
67 result
= inspect
.getdoc(object) or inspect
.getcomments(object)
68 return result
and re
.sub('^ *\n', '', rstrip(result
)) or ''
71 """Split a doc string into a synopsis line (if any) and the rest."""
72 lines
= split(strip(doc
), '\n')
75 elif len(lines
) >= 2 and not rstrip(lines
[1]):
76 return lines
[0], join(lines
[2:], '\n')
77 return '', join(lines
, '\n')
79 def classname(object, modname
):
80 """Get a class name and qualify it with a module name if necessary."""
81 name
= object.__name
__
82 if object.__module
__ != modname
:
83 name
= object.__module
__ + '.' + name
87 """Check if an object is of a type that probably means it's data."""
88 return not (inspect
.ismodule(object) or inspect
.isclass(object) or
89 inspect
.isroutine(object) or inspect
.isframe(object) or
90 inspect
.istraceback(object) or inspect
.iscode(object))
92 def replace(text
, *pairs
):
93 """Do a series of global replacements on a string."""
95 text
= join(split(text
, pairs
[0]), pairs
[1])
99 def cram(text
, maxlen
):
100 """Omit part of a string if needed to make it fit in a maximum length."""
101 if len(text
) > maxlen
:
102 pre
= max(0, (maxlen
-3)/2)
103 post
= max(0, maxlen
-3-pre
)
104 return text
[:pre
] + '...' + text
[len(text
)-post
:]
108 """Remove the hexadecimal id from a Python object representation."""
109 # The behaviour of %p is implementation-dependent; we check two cases.
110 for pattern
in [' at 0x[0-9a-f]{6,}(>+)$', ' at [0-9A-F]{8,}(>+)$']:
111 if re
.search(pattern
, repr(Exception)):
112 return re
.sub(pattern
, '\\1', text
)
115 def _is_some_method(object):
116 return inspect
.ismethod(object) or inspect
.ismethoddescriptor(object)
120 for key
, value
in inspect
.getmembers(cl
, _is_some_method
):
122 for base
in cl
.__bases
__:
123 methods
.update(allmethods(base
)) # all your base are belong to us
124 for key
in methods
.keys():
125 methods
[key
] = getattr(cl
, key
)
128 def _split_list(s
, predicate
):
129 """Split sequence s via predicate, and return pair ([true], [false]).
131 The return value is a 2-tuple of lists,
132 ([x for x in s if predicate(x)],
133 [x for x in s if not predicate(x)])
145 # ----------------------------------------------------- module manipulation
148 """Guess whether a path refers to a package directory."""
149 if os
.path
.isdir(path
):
150 for ext
in ['.py', '.pyc', '.pyo']:
151 if os
.path
.isfile(os
.path
.join(path
, '__init__' + ext
)):
155 def synopsis(filename
, cache
={}):
156 """Get the one-line summary out of a module file."""
157 mtime
= os
.stat(filename
).st_mtime
158 lastupdate
, result
= cache
.get(filename
, (0, None))
159 if lastupdate
< mtime
:
160 info
= inspect
.getmoduleinfo(filename
)
161 file = open(filename
)
162 if info
and 'b' in info
[2]: # binary modules have to be imported
163 try: module
= imp
.load_module('__temp__', file, filename
, info
[1:])
165 result
= split(module
.__doc
__ or '', '\n')[0]
166 del sys
.modules
['__temp__']
167 else: # text modules can be directly examined
168 line
= file.readline()
169 while line
[:1] == '#' or not strip(line
):
170 line
= file.readline()
173 if line
[:4] == 'r"""': line
= line
[1:]
174 if line
[:3] == '"""':
176 if line
[-1:] == '\\': line
= line
[:-1]
177 while not strip(line
):
178 line
= file.readline()
180 result
= strip(split(line
, '"""')[0])
183 cache
[filename
] = (mtime
, result
)
186 class ErrorDuringImport(Exception):
187 """Errors that occurred while trying to import something to document it."""
188 def __init__(self
, filename
, (exc
, value
, tb
)):
189 self
.filename
= filename
196 if type(exc
) is types
.ClassType
:
198 return 'problem in %s - %s: %s' % (self
.filename
, exc
, self
.value
)
200 def importfile(path
):
201 """Import a Python source file or compiled file given its path."""
202 magic
= imp
.get_magic()
203 file = open(path
, 'r')
204 if file.read(len(magic
)) == magic
:
205 kind
= imp
.PY_COMPILED
209 filename
= os
.path
.basename(path
)
210 name
, ext
= os
.path
.splitext(filename
)
211 file = open(path
, 'r')
213 module
= imp
.load_module(name
, file, path
, (ext
, 'r', kind
))
215 raise ErrorDuringImport(path
, sys
.exc_info())
219 def safeimport(path
, forceload
=0, cache
={}):
220 """Import a module; handle errors; return None if the module isn't found.
222 If the module *is* found but an exception occurs, it's wrapped in an
223 ErrorDuringImport exception and reraised. Unlike __import__, if a
224 package path is specified, the module at the end of the path is returned,
225 not the package at the beginning. If the optional 'forceload' argument
226 is 1, we reload the module from disk (unless it's a dynamic extension)."""
227 if forceload
and path
in sys
.modules
:
228 # This is the only way to be sure. Checking the mtime of the file
229 # isn't good enough (e.g. what if the module contains a class that
230 # inherits from another module that has changed?).
231 if path
not in sys
.builtin_module_names
:
232 # Python never loads a dynamic extension a second time from the
233 # same path, even if the file is changed or missing. Deleting
234 # the entry in sys.modules doesn't help for dynamic extensions,
235 # so we're not even going to try to keep them up to date.
236 info
= inspect
.getmoduleinfo(sys
.modules
[path
].__file
__)
237 if info
[3] != imp
.C_EXTENSION
:
238 cache
[path
] = sys
.modules
[path
] # prevent module from clearing
239 del sys
.modules
[path
]
241 module
= __import__(path
)
243 # Did the error occur before or after the module was found?
244 (exc
, value
, tb
) = info
= sys
.exc_info()
245 if path
in sys
.modules
:
246 # An error occured while executing the imported module.
247 raise ErrorDuringImport(sys
.modules
[path
].__file
__, info
)
248 elif exc
is SyntaxError:
249 # A SyntaxError occurred before we could execute the module.
250 raise ErrorDuringImport(value
.filename
, info
)
251 elif exc
is ImportError and \
252 split(lower(str(value
)))[:2] == ['no', 'module']:
253 # The module was not found.
256 # Some other error occurred during the importing process.
257 raise ErrorDuringImport(path
, sys
.exc_info())
258 for part
in split(path
, '.')[1:]:
259 try: module
= getattr(module
, part
)
260 except AttributeError: return None
263 # ---------------------------------------------------- formatter base class
266 def document(self
, object, name
=None, *args
):
267 """Generate documentation for an object."""
268 args
= (object, name
) + args
269 if inspect
.ismodule(object): return apply(self
.docmodule
, args
)
270 if inspect
.isclass(object): return apply(self
.docclass
, args
)
271 if inspect
.isroutine(object): return apply(self
.docroutine
, args
)
272 return apply(self
.docother
, args
)
274 def fail(self
, object, name
=None, *args
):
275 """Raise an exception for unimplemented types."""
276 message
= "don't know how to document object%s of type %s" % (
277 name
and ' ' + repr(name
), type(object).__name
__)
278 raise TypeError, message
280 docmodule
= docclass
= docroutine
= docother
= fail
282 # -------------------------------------------- HTML documentation generator
284 class HTMLRepr(Repr
):
285 """Class for safely making an HTML representation of a Python object."""
288 self
.maxlist
= self
.maxtuple
= 20
290 self
.maxstring
= self
.maxother
= 100
292 def escape(self
, text
):
293 return replace(text
, '&', '&', '<', '<', '>', '>')
295 def repr(self
, object):
296 return Repr
.repr(self
, object)
298 def repr1(self
, x
, level
):
299 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
300 if hasattr(self
, methodname
):
301 return getattr(self
, methodname
)(x
, level
)
303 return self
.escape(cram(stripid(repr(x
)), self
.maxother
))
305 def repr_string(self
, x
, level
):
306 test
= cram(x
, self
.maxstring
)
307 testrepr
= repr(test
)
308 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
309 # Backslashes are only literal in the string and are never
310 # needed to make any special characters, so show a raw string.
311 return 'r' + testrepr
[0] + self
.escape(test
) + testrepr
[0]
312 return re
.sub(r
'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
313 r'<font color="#c040c0">\1</font>',
314 self
.escape(testrepr
))
316 repr_str
= repr_string
318 def repr_instance(self
, x
, level
):
320 return self
.escape(cram(stripid(repr(x
)), self
.maxstring
))
322 return self
.escape('<%s instance>' % x
.__class
__.__name
__)
324 repr_unicode
= repr_string
327 """Formatter class for HTML documentation."""
329 # ------------------------------------------- HTML formatting utilities
331 _repr_instance
= HTMLRepr()
332 repr = _repr_instance
.repr
333 escape
= _repr_instance
.escape
335 def page(self
, title
, contents
):
336 """Format an HTML page."""
338 <!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
339 <html><head><title>Python: %s</title>
340 <style type="text/css"><!--
341 TT { font-family: lucidatypewriter, lucida console, courier }
342 --></style></head><body bgcolor="#f0f0f8">
344 </body></html>''' % (title
, contents
)
346 def heading(self
, title
, fgcol
, bgcol
, extras
=''):
347 """Format a page heading."""
349 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
351 <td valign=bottom> <br>
352 <font color="%s" face="helvetica, arial"> <br>%s</font></td
353 ><td align=right valign=bottom
354 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
355 ''' % (bgcol
, fgcol
, title
, fgcol
, extras
or ' ')
357 def section(self
, title
, fgcol
, bgcol
, contents
, width
=10,
358 prelude
='', marginalia
=None, gap
=' '):
359 """Format a section with a heading."""
360 if marginalia
is None:
361 marginalia
= '<tt>' + ' ' * width
+ '</tt>'
363 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
365 <td colspan=3 valign=bottom> <br>
366 <font color="%s" face="helvetica, arial">%s</font></td></tr>
367 ''' % (bgcol
, fgcol
, title
)
369 result
= result
+ '''
370 <tr bgcolor="%s"><td rowspan=2>%s</td>
371 <td colspan=2>%s</td></tr>
372 <tr><td>%s</td>''' % (bgcol
, marginalia
, prelude
, gap
)
374 result
= result
+ '''
375 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol
, marginalia
, gap
)
377 return result
+ '\n<td width="100%%">%s</td></tr></table>' % contents
379 def bigsection(self
, title
, *args
):
380 """Format a section with a big heading."""
381 title
= '<big><strong>%s</strong></big>' % title
382 return apply(self
.section
, (title
,) + args
)
384 def preformat(self
, text
):
385 """Format literal preformatted text."""
386 text
= self
.escape(expandtabs(text
))
387 return replace(text
, '\n\n', '\n \n', '\n\n', '\n \n',
388 ' ', ' ', '\n', '<br>\n')
390 def multicolumn(self
, list, format
, cols
=4):
391 """Format a list of items into a multi-column list."""
393 rows
= (len(list)+cols
-1)/cols
394 for col
in range(cols
):
395 result
= result
+ '<td width="%d%%" valign=top>' % (100/cols
)
396 for i
in range(rows
*col
, rows
*col
+rows
):
398 result
= result
+ format(list[i
]) + '<br>\n'
399 result
= result
+ '</td>'
400 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
402 def grey(self
, text
): return '<font color="#909090">%s</font>' % text
404 def namelink(self
, name
, *dicts
):
405 """Make a link for an identifier, given name-to-URL mappings."""
408 return '<a href="%s">%s</a>' % (dict[name
], name
)
411 def classlink(self
, object, modname
):
412 """Make a link for a class."""
413 name
, module
= object.__name
__, sys
.modules
.get(object.__module
__)
414 if hasattr(module
, name
) and getattr(module
, name
) is object:
415 return '<a href="%s.html#%s">%s</a>' % (
416 module
.__name
__, name
, classname(object, modname
))
417 return classname(object, modname
)
419 def modulelink(self
, object):
420 """Make a link for a module."""
421 return '<a href="%s.html">%s</a>' % (object.__name
__, object.__name
__)
423 def modpkglink(self
, (name
, path
, ispackage
, shadowed
)):
424 """Make a link for a module or package to display in an index."""
426 return self
.grey(name
)
428 url
= '%s.%s.html' % (path
, name
)
430 url
= '%s.html' % name
432 text
= '<strong>%s</strong> (package)' % name
435 return '<a href="%s">%s</a>' % (url
, text
)
437 def markup(self
, text
, escape
=None, funcs
={}, classes
={}, methods
={}):
438 """Mark up some plain text, given a context of symbols to look for.
439 Each context dictionary maps object names to anchor names."""
440 escape
= escape
or self
.escape
443 pattern
= re
.compile(r
'\b((http|ftp)://\S+[\w/]|'
448 match
= pattern
.search(text
, here
)
450 start
, end
= match
.span()
451 results
.append(escape(text
[here
:start
]))
453 all
, scheme
, rfc
, pep
, selfdot
, name
= match
.groups()
455 url
= escape(all
).replace('"', '"')
456 results
.append('<a href="%s">%s</a>' % (url
, url
))
458 url
= 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc
)
459 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
461 url
= 'http://www.python.org/peps/pep-%04d.html' % int(pep
)
462 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
463 elif text
[end
:end
+1] == '(':
464 results
.append(self
.namelink(name
, methods
, funcs
, classes
))
466 results
.append('self.<strong>%s</strong>' % name
)
468 results
.append(self
.namelink(name
, classes
))
470 results
.append(escape(text
[here
:]))
471 return join(results
, '')
473 # ---------------------------------------------- type-specific routines
475 def formattree(self
, tree
, modname
, parent
=None):
476 """Produce HTML for a class tree as given by inspect.getclasstree()."""
479 if type(entry
) is type(()):
481 result
= result
+ '<dt><font face="helvetica, arial">'
482 result
= result
+ self
.classlink(c
, modname
)
483 if bases
and bases
!= (parent
,):
486 parents
.append(self
.classlink(base
, modname
))
487 result
= result
+ '(' + join(parents
, ', ') + ')'
488 result
= result
+ '\n</font></dt>'
489 elif type(entry
) is type([]):
490 result
= result
+ '<dd>\n%s</dd>\n' % self
.formattree(
492 return '<dl>\n%s</dl>\n' % result
494 def docmodule(self
, object, name
=None, mod
=None, *ignored
):
495 """Produce HTML documentation for a module object."""
496 name
= object.__name
__ # ignore the passed-in name
497 parts
= split(name
, '.')
499 for i
in range(len(parts
)-1):
501 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
502 (join(parts
[:i
+1], '.'), parts
[i
]))
503 linkedname
= join(links
+ parts
[-1:], '.')
504 head
= '<big><big><strong>%s</strong></big></big>' % linkedname
506 path
= inspect
.getabsfile(object)
508 if sys
.platform
== 'win32':
510 url
= nturl2path
.pathname2url(path
)
511 filelink
= '<a href="file:%s">%s</a>' % (url
, path
)
513 filelink
= '(built-in)'
515 if hasattr(object, '__version__'):
516 version
= str(object.__version
__)
517 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
518 version
= strip(version
[11:-1])
519 info
.append('version %s' % self
.escape(version
))
520 if hasattr(object, '__date__'):
521 info
.append(self
.escape(str(object.__date
__)))
523 head
= head
+ ' (%s)' % join(info
, ', ')
524 result
= self
.heading(
525 head
, '#ffffff', '#7799ee', '<a href=".">index</a><br>' + filelink
)
527 modules
= inspect
.getmembers(object, inspect
.ismodule
)
529 classes
, cdict
= [], {}
530 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
531 if (inspect
.getmodule(value
) or object) is object:
532 classes
.append((key
, value
))
533 cdict
[key
] = cdict
[value
] = '#' + key
534 for key
, value
in classes
:
535 for base
in value
.__bases
__:
536 key
, modname
= base
.__name
__, base
.__module
__
537 module
= sys
.modules
.get(modname
)
538 if modname
!= name
and module
and hasattr(module
, key
):
539 if getattr(module
, key
) is base
:
541 cdict
[key
] = cdict
[base
] = modname
+ '.html#' + key
542 funcs
, fdict
= [], {}
543 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
544 if inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object:
545 funcs
.append((key
, value
))
546 fdict
[key
] = '#-' + key
547 if inspect
.isfunction(value
): fdict
[value
] = fdict
[key
]
549 for key
, value
in inspect
.getmembers(object, isdata
):
550 if key
not in ['__builtins__', '__doc__']:
551 data
.append((key
, value
))
553 doc
= self
.markup(getdoc(object), self
.preformat
, fdict
, cdict
)
554 doc
= doc
and '<tt>%s</tt>' % doc
555 result
= result
+ '<p>%s</p>\n' % doc
557 if hasattr(object, '__path__'):
560 for file in os
.listdir(object.__path
__[0]):
561 path
= os
.path
.join(object.__path
__[0], file)
562 modname
= inspect
.getmodulename(file)
563 if modname
and modname
not in modnames
:
564 modpkgs
.append((modname
, name
, 0, 0))
565 modnames
.append(modname
)
566 elif ispackage(path
):
567 modpkgs
.append((file, name
, 1, 0))
569 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
570 result
= result
+ self
.bigsection(
571 'Package Contents', '#ffffff', '#aa55cc', contents
)
573 contents
= self
.multicolumn(
574 modules
, lambda (key
, value
), s
=self
: s
.modulelink(value
))
575 result
= result
+ self
.bigsection(
576 'Modules', '#fffff', '#aa55cc', contents
)
579 classlist
= map(lambda (key
, value
): value
, classes
)
581 self
.formattree(inspect
.getclasstree(classlist
, 1), name
)]
582 for key
, value
in classes
:
583 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
584 result
= result
+ self
.bigsection(
585 'Classes', '#ffffff', '#ee77aa', join(contents
))
588 for key
, value
in funcs
:
589 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
590 result
= result
+ self
.bigsection(
591 'Functions', '#ffffff', '#eeaa77', join(contents
))
594 for key
, value
in data
:
595 contents
.append(self
.document(value
, key
))
596 result
= result
+ self
.bigsection(
597 'Data', '#ffffff', '#55aa55', join(contents
, '<br>\n'))
598 if hasattr(object, '__author__'):
599 contents
= self
.markup(str(object.__author
__), self
.preformat
)
600 result
= result
+ self
.bigsection(
601 'Author', '#ffffff', '#7799ee', contents
)
602 if hasattr(object, '__credits__'):
603 contents
= self
.markup(str(object.__credits
__), self
.preformat
)
604 result
= result
+ self
.bigsection(
605 'Credits', '#ffffff', '#7799ee', contents
)
609 def docclass(self
, object, name
=None, mod
=None, funcs
={}, classes
={},
611 """Produce HTML documentation for a class object."""
612 realname
= object.__name
__
613 name
= name
or realname
614 bases
= object.__bases
__
617 push
= contents
.append
619 # Cute little class to pump out a horizontal rule between sections.
620 class HorizontalRule
:
627 hr
= HorizontalRule()
629 # List the mro, if non-trivial.
630 mro
= list(inspect
.getmro(object))
633 push('<dl><dt>Method resolution order:</dt>\n')
635 push('<dd>%s</dd>\n' % self
.classlink(base
,
639 def spill(msg
, attrs
, predicate
):
640 ok
, attrs
= _split_list(attrs
, predicate
)
644 for name
, kind
, homecls
, value
in ok
:
645 push(self
.document(getattr(object, name
), name
, mod
,
646 funcs
, classes
, mdict
, object))
650 def spillproperties(msg
, attrs
, predicate
):
651 ok
, attrs
= _split_list(attrs
, predicate
)
655 for name
, kind
, homecls
, value
in ok
:
656 push('<dl><dt><strong>%s</strong></dt>\n' % name
)
657 if value
.__doc
__ is not None:
658 doc
= self
.markup(value
.__doc
__, self
.preformat
,
659 funcs
, classes
, mdict
)
660 push('<dd><tt>%s</tt></dd>\n' % doc
)
661 for attr
, tag
in [("fget", " getter"),
663 ("fdel", " deleter")]:
664 func
= getattr(value
, attr
)
666 base
= self
.document(func
, name
+ tag
, mod
,
667 funcs
, classes
, mdict
, object)
668 push('<dd>%s</dd>\n' % base
)
672 def spilldata(msg
, attrs
, predicate
):
673 ok
, attrs
= _split_list(attrs
, predicate
)
677 for name
, kind
, homecls
, value
in ok
:
678 base
= self
.docother(getattr(object, name
), name
, mod
)
680 doc
= getattr(value
, "__doc__", None)
684 push('<dl><dt>%s</dl>\n' % base
)
686 doc
= self
.markup(getdoc(value
), self
.preformat
,
687 funcs
, classes
, mdict
)
688 doc
= '<dd><tt>%s</tt>' % doc
689 push('<dl><dt>%s%s</dl>\n' % (base
, doc
))
693 attrs
= inspect
.classify_class_attrs(object)
695 for key
, kind
, homecls
, value
in attrs
:
696 mdict
[key
] = anchor
= '#' + name
+ '-' + key
697 value
= getattr(object, key
)
699 # The value may not be hashable (e.g., a data attr with
700 # a dict or list value).
701 mdict
[value
] = anchor
707 thisclass
= mro
.pop(0)
709 thisclass
= attrs
[0][2]
710 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
712 if thisclass
is object:
715 tag
= "inherited from %s" % self
.classlink(thisclass
,
719 # Sort attrs by name.
720 attrs
.sort(lambda t1
, t2
: cmp(t1
[0], t2
[0]))
722 # Pump out the attrs, segregated by kind.
723 attrs
= spill("Methods %s" % tag
, attrs
,
724 lambda t
: t
[1] == 'method')
725 attrs
= spill("Class methods %s" % tag
, attrs
,
726 lambda t
: t
[1] == 'class method')
727 attrs
= spill("Static methods %s" % tag
, attrs
,
728 lambda t
: t
[1] == 'static method')
729 attrs
= spillproperties("Properties %s" % tag
, attrs
,
730 lambda t
: t
[1] == 'property')
731 attrs
= spilldata("Data and non-method functions %s" % tag
, attrs
,
732 lambda t
: t
[1] == 'data')
736 contents
= ''.join(contents
)
739 title
= '<a name="%s">class <strong>%s</strong></a>' % (
742 title
= '<strong>%s</strong> = <a name="%s">class %s</a>' % (
743 name
, name
, realname
)
747 parents
.append(self
.classlink(base
, object.__module
__))
748 title
= title
+ '(%s)' % join(parents
, ', ')
749 doc
= self
.markup(getdoc(object), self
.preformat
, funcs
, classes
, mdict
)
750 doc
= doc
and '<tt>%s<br> </tt>' % doc
or ' '
752 return self
.section(title
, '#000000', '#ffc8d8', contents
, 5, doc
)
754 def formatvalue(self
, object):
755 """Format an argument default value as text."""
756 return self
.grey('=' + self
.repr(object))
758 def docroutine(self
, object, name
=None, mod
=None,
759 funcs
={}, classes
={}, methods
={}, cl
=None):
760 """Produce HTML documentation for a function or method object."""
761 realname
= object.__name
__
762 name
= name
or realname
763 anchor
= (cl
and cl
.__name
__ or '') + '-' + name
766 if inspect
.ismethod(object):
767 imclass
= object.im_class
769 if imclass
is not cl
:
770 note
= ' from ' + self
.classlink(imclass
, mod
)
773 note
= ' method of %s instance' % self
.classlink(
774 object.im_self
.__class
__, mod
)
776 note
= ' unbound %s method' % self
.classlink(imclass
,mod
)
777 object = object.im_func
780 title
= '<a name="%s"><strong>%s</strong></a>' % (anchor
, realname
)
782 if (cl
and realname
in cl
.__dict
__ and
783 cl
.__dict
__[realname
] is object):
784 reallink
= '<a href="#%s">%s</a>' % (
785 cl
.__name
__ + '-' + realname
, realname
)
789 title
= '<a name="%s"><strong>%s</strong></a> = %s' % (
790 anchor
, name
, reallink
)
791 if inspect
.isfunction(object):
792 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
793 argspec
= inspect
.formatargspec(
794 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
795 if realname
== '<lambda>':
796 title
= '<strong>%s</strong> <em>lambda</em> ' % name
797 argspec
= argspec
[1:-1] # remove parentheses
801 decl
= title
+ argspec
+ (note
and self
.grey(
802 '<font face="helvetica, arial">%s</font>' % note
))
805 return '<dl><dt>%s</dt></dl>\n' % decl
808 getdoc(object), self
.preformat
, funcs
, classes
, methods
)
809 doc
= doc
and '<dd><tt>%s</tt></dd>' % doc
810 return '<dl><dt>%s</dt>%s</dl>\n' % (decl
, doc
)
812 def docother(self
, object, name
=None, mod
=None, *ignored
):
813 """Produce HTML documentation for a data object."""
814 lhs
= name
and '<strong>%s</strong> = ' % name
or ''
815 return lhs
+ self
.repr(object)
817 def index(self
, dir, shadowed
=None):
818 """Generate an HTML index for a directory of modules."""
820 if shadowed
is None: shadowed
= {}
822 files
= os
.listdir(dir)
824 def found(name
, ispackage
,
825 modpkgs
=modpkgs
, shadowed
=shadowed
, seen
=seen
):
827 modpkgs
.append((name
, '', ispackage
, name
)) in shadowed
831 # Package spam/__init__.py takes precedence over module spam.py.
833 path
= os
.path
.join(dir, file)
834 if ispackage(path
): found(file, 1)
836 path
= os
.path
.join(dir, file)
837 if os
.path
.isfile(path
):
838 modname
= inspect
.getmodulename(file)
839 if modname
: found(modname
, 0)
842 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
843 return self
.bigsection(dir, '#ffffff', '#ee77aa', contents
)
845 # -------------------------------------------- text documentation generator
847 class TextRepr(Repr
):
848 """Class for safely making a text representation of a Python object."""
851 self
.maxlist
= self
.maxtuple
= 20
853 self
.maxstring
= self
.maxother
= 100
855 def repr1(self
, x
, level
):
856 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
857 if hasattr(self
, methodname
):
858 return getattr(self
, methodname
)(x
, level
)
860 return cram(stripid(repr(x
)), self
.maxother
)
862 def repr_string(self
, x
, level
):
863 test
= cram(x
, self
.maxstring
)
864 testrepr
= repr(test
)
865 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
866 # Backslashes are only literal in the string and are never
867 # needed to make any special characters, so show a raw string.
868 return 'r' + testrepr
[0] + test
+ testrepr
[0]
871 repr_str
= repr_string
873 def repr_instance(self
, x
, level
):
875 return cram(stripid(repr(x
)), self
.maxstring
)
877 return '<%s instance>' % x
.__class
__.__name
__
880 """Formatter class for text documentation."""
882 # ------------------------------------------- text formatting utilities
884 _repr_instance
= TextRepr()
885 repr = _repr_instance
.repr
887 def bold(self
, text
):
888 """Format a string in bold by overstriking."""
889 return join(map(lambda ch
: ch
+ '\b' + ch
, text
), '')
891 def indent(self
, text
, prefix
=' '):
892 """Indent text by prepending a given prefix to each line."""
893 if not text
: return ''
894 lines
= split(text
, '\n')
895 lines
= map(lambda line
, prefix
=prefix
: prefix
+ line
, lines
)
896 if lines
: lines
[-1] = rstrip(lines
[-1])
897 return join(lines
, '\n')
899 def section(self
, title
, contents
):
900 """Format a section with a given heading."""
901 return self
.bold(title
) + '\n' + rstrip(self
.indent(contents
)) + '\n\n'
903 # ---------------------------------------------- type-specific routines
905 def formattree(self
, tree
, modname
, parent
=None, prefix
=''):
906 """Render in text a class tree as returned by inspect.getclasstree()."""
909 if type(entry
) is type(()):
911 result
= result
+ prefix
+ classname(c
, modname
)
912 if bases
and bases
!= (parent
,):
913 parents
= map(lambda c
, m
=modname
: classname(c
, m
), bases
)
914 result
= result
+ '(%s)' % join(parents
, ', ')
915 result
= result
+ '\n'
916 elif type(entry
) is type([]):
917 result
= result
+ self
.formattree(
918 entry
, modname
, c
, prefix
+ ' ')
921 def docmodule(self
, object, name
=None, mod
=None):
922 """Produce text documentation for a given module object."""
923 name
= object.__name
__ # ignore the passed-in name
924 synop
, desc
= splitdoc(getdoc(object))
925 result
= self
.section('NAME', name
+ (synop
and ' - ' + synop
))
928 file = inspect
.getabsfile(object)
931 result
= result
+ self
.section('FILE', file)
933 result
= result
+ self
.section('DESCRIPTION', desc
)
936 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
937 if (inspect
.getmodule(value
) or object) is object:
938 classes
.append((key
, value
))
940 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
941 if inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object:
942 funcs
.append((key
, value
))
944 for key
, value
in inspect
.getmembers(object, isdata
):
945 if key
not in ['__builtins__', '__doc__']:
946 data
.append((key
, value
))
948 if hasattr(object, '__path__'):
950 for file in os
.listdir(object.__path
__[0]):
951 path
= os
.path
.join(object.__path
__[0], file)
952 modname
= inspect
.getmodulename(file)
953 if modname
and modname
not in modpkgs
:
954 modpkgs
.append(modname
)
955 elif ispackage(path
):
956 modpkgs
.append(file + ' (package)')
958 result
= result
+ self
.section(
959 'PACKAGE CONTENTS', join(modpkgs
, '\n'))
962 classlist
= map(lambda (key
, value
): value
, classes
)
963 contents
= [self
.formattree(
964 inspect
.getclasstree(classlist
, 1), name
)]
965 for key
, value
in classes
:
966 contents
.append(self
.document(value
, key
, name
))
967 result
= result
+ self
.section('CLASSES', join(contents
, '\n'))
971 for key
, value
in funcs
:
972 contents
.append(self
.document(value
, key
, name
))
973 result
= result
+ self
.section('FUNCTIONS', join(contents
, '\n'))
977 for key
, value
in data
:
978 contents
.append(self
.docother(value
, key
, name
, 70))
979 result
= result
+ self
.section('DATA', join(contents
, '\n'))
981 if hasattr(object, '__version__'):
982 version
= str(object.__version
__)
983 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
984 version
= strip(version
[11:-1])
985 result
= result
+ self
.section('VERSION', version
)
986 if hasattr(object, '__date__'):
987 result
= result
+ self
.section('DATE', str(object.__date
__))
988 if hasattr(object, '__author__'):
989 result
= result
+ self
.section('AUTHOR', str(object.__author
__))
990 if hasattr(object, '__credits__'):
991 result
= result
+ self
.section('CREDITS', str(object.__credits
__))
994 def docclass(self
, object, name
=None, mod
=None):
995 """Produce text documentation for a given class object."""
996 realname
= object.__name
__
997 name
= name
or realname
998 bases
= object.__bases
__
1000 def makename(c
, m
=object.__module
__):
1001 return classname(c
, m
)
1003 if name
== realname
:
1004 title
= 'class ' + self
.bold(realname
)
1006 title
= self
.bold(name
) + ' = class ' + realname
1008 parents
= map(makename
, bases
)
1009 title
= title
+ '(%s)' % join(parents
, ', ')
1011 doc
= getdoc(object)
1012 contents
= doc
and [doc
+ '\n'] or []
1013 push
= contents
.append
1015 # List the mro, if non-trivial.
1016 mro
= list(inspect
.getmro(object))
1018 push("Method resolution order:")
1020 push(' ' + makename(base
))
1023 # Cute little class to pump out a horizontal rule between sections.
1024 class HorizontalRule
:
1031 hr
= HorizontalRule()
1033 def spill(msg
, attrs
, predicate
):
1034 ok
, attrs
= _split_list(attrs
, predicate
)
1038 for name
, kind
, homecls
, value
in ok
:
1039 push(self
.document(getattr(object, name
),
1043 def spillproperties(msg
, attrs
, predicate
):
1044 ok
, attrs
= _split_list(attrs
, predicate
)
1048 for name
, kind
, homecls
, value
in ok
:
1050 need_blank_after_doc
= 0
1051 doc
= getdoc(value
) or ''
1053 push(self
.indent(doc
))
1054 need_blank_after_doc
= 1
1055 for attr
, tag
in [("fget", " getter"),
1056 ("fset", " setter"),
1057 ("fdel", " deleter")]:
1058 func
= getattr(value
, attr
)
1059 if func
is not None:
1060 if need_blank_after_doc
:
1062 need_blank_after_doc
= 0
1063 base
= self
.docother(func
, name
+ tag
, mod
, 70)
1064 push(self
.indent(base
))
1068 def spilldata(msg
, attrs
, predicate
):
1069 ok
, attrs
= _split_list(attrs
, predicate
)
1073 for name
, kind
, homecls
, value
in ok
:
1075 doc
= getattr(value
, "__doc__", None)
1078 push(self
.docother(getattr(object, name
),
1079 name
, mod
, 70, doc
) + '\n')
1082 attrs
= inspect
.classify_class_attrs(object)
1085 thisclass
= mro
.pop(0)
1087 thisclass
= attrs
[0][2]
1088 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
1090 if thisclass
is object:
1091 tag
= "defined here"
1093 tag
= "inherited from %s" % classname(thisclass
,
1096 # Sort attrs by name.
1097 attrs
.sort(lambda t1
, t2
: cmp(t1
[0], t2
[0]))
1099 # Pump out the attrs, segregated by kind.
1100 attrs
= spill("Methods %s:\n" % tag
, attrs
,
1101 lambda t
: t
[1] == 'method')
1102 attrs
= spill("Class methods %s:\n" % tag
, attrs
,
1103 lambda t
: t
[1] == 'class method')
1104 attrs
= spill("Static methods %s:\n" % tag
, attrs
,
1105 lambda t
: t
[1] == 'static method')
1106 attrs
= spillproperties("Properties %s:\n" % tag
, attrs
,
1107 lambda t
: t
[1] == 'property')
1108 attrs
= spilldata("Data and non-method functions %s:\n" % tag
,
1109 attrs
, lambda t
: t
[1] == 'data')
1113 contents
= '\n'.join(contents
)
1116 return title
+ '\n' + self
.indent(rstrip(contents
), ' | ') + '\n'
1118 def formatvalue(self
, object):
1119 """Format an argument default value as text."""
1120 return '=' + self
.repr(object)
1122 def docroutine(self
, object, name
=None, mod
=None, cl
=None):
1123 """Produce text documentation for a function or method object."""
1124 realname
= object.__name
__
1125 name
= name
or realname
1128 if inspect
.ismethod(object):
1129 imclass
= object.im_class
1131 if imclass
is not cl
:
1132 note
= ' from ' + classname(imclass
, mod
)
1135 note
= ' method of %s instance' % classname(
1136 object.im_self
.__class
__, mod
)
1138 note
= ' unbound %s method' % classname(imclass
,mod
)
1139 object = object.im_func
1141 if name
== realname
:
1142 title
= self
.bold(realname
)
1144 if (cl
and realname
in cl
.__dict
__ and
1145 cl
.__dict
__[realname
] is object):
1147 title
= self
.bold(name
) + ' = ' + realname
1148 if inspect
.isfunction(object):
1149 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
1150 argspec
= inspect
.formatargspec(
1151 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
1152 if realname
== '<lambda>':
1154 argspec
= argspec
[1:-1] # remove parentheses
1157 decl
= title
+ argspec
+ note
1162 doc
= getdoc(object) or ''
1163 return decl
+ '\n' + (doc
and rstrip(self
.indent(doc
)) + '\n')
1165 def docother(self
, object, name
=None, mod
=None, maxlen
=None, doc
=None):
1166 """Produce text documentation for a data object."""
1167 repr = self
.repr(object)
1169 line
= (name
and name
+ ' = ' or '') + repr
1170 chop
= maxlen
- len(line
)
1171 if chop
< 0: repr = repr[:chop
] + '...'
1172 line
= (name
and self
.bold(name
) + ' = ' or '') + repr
1174 line
+= '\n' + self
.indent(str(doc
))
1177 # --------------------------------------------------------- user interfaces
1180 """The first time this is called, determine what kind of pager to use."""
1186 """Decide what method to use for paging through text."""
1187 if type(sys
.stdout
) is not types
.FileType
:
1189 if not sys
.stdin
.isatty() or not sys
.stdout
.isatty():
1191 if os
.environ
.get('TERM') in ['dumb', 'emacs']:
1193 if 'PAGER' in os
.environ
:
1194 if sys
.platform
== 'win32': # pipes completely broken in Windows
1195 return lambda text
: tempfilepager(plain(text
), os
.environ
['PAGER'])
1196 elif os
.environ
.get('TERM') in ['dumb', 'emacs']:
1197 return lambda text
: pipepager(plain(text
), os
.environ
['PAGER'])
1199 return lambda text
: pipepager(text
, os
.environ
['PAGER'])
1200 if sys
.platform
== 'win32' or sys
.platform
.startswith('os2'):
1201 return lambda text
: tempfilepager(plain(text
), 'more <')
1202 if hasattr(os
, 'system') and os
.system('(less) 2>/dev/null') == 0:
1203 return lambda text
: pipepager(text
, 'less')
1206 (fd
, filename
) = tempfile
.mkstemp()
1209 if hasattr(os
, 'system') and os
.system('more %s' % filename
) == 0:
1210 return lambda text
: pipepager(text
, 'more')
1217 """Remove boldface formatting from text."""
1218 return re
.sub('.\b', '', text
)
1220 def pipepager(text
, cmd
):
1221 """Page through text by feeding it to another program."""
1222 pipe
= os
.popen(cmd
, 'w')
1227 pass # Ignore broken pipes caused by quitting the pager program.
1229 def tempfilepager(text
, cmd
):
1230 """Page through text by invoking a program on a temporary file."""
1232 (fd
, filename
) = tempfile
.mkstemp()
1233 file = os
.fdopen(fd
, 'w')
1237 os
.system(cmd
+ ' ' + filename
)
1242 """Page through text on a text terminal."""
1243 lines
= split(plain(text
), '\n')
1246 fd
= sys
.stdin
.fileno()
1247 old
= tty
.tcgetattr(fd
)
1249 getchar
= lambda: sys
.stdin
.read(1)
1250 except (ImportError, AttributeError):
1252 getchar
= lambda: sys
.stdin
.readline()[:-1][:1]
1255 r
= inc
= os
.environ
.get('LINES', 25) - 1
1256 sys
.stdout
.write(join(lines
[:inc
], '\n') + '\n')
1258 sys
.stdout
.write('-- more --')
1263 sys
.stdout
.write('\r \r')
1265 elif c
in ['\r', '\n']:
1266 sys
.stdout
.write('\r \r' + lines
[r
] + '\n')
1269 if c
in ['b', 'B', '\x1b']:
1272 sys
.stdout
.write('\n' + join(lines
[r
:r
+inc
], '\n') + '\n')
1277 tty
.tcsetattr(fd
, tty
.TCSAFLUSH
, old
)
1279 def plainpager(text
):
1280 """Simply print unformatted text. This is the ultimate fallback."""
1281 sys
.stdout
.write(plain(text
))
1283 def describe(thing
):
1284 """Produce a short description of the given thing."""
1285 if inspect
.ismodule(thing
):
1286 if thing
.__name
__ in sys
.builtin_module_names
:
1287 return 'built-in module ' + thing
.__name
__
1288 if hasattr(thing
, '__path__'):
1289 return 'package ' + thing
.__name
__
1291 return 'module ' + thing
.__name
__
1292 if inspect
.isbuiltin(thing
):
1293 return 'built-in function ' + thing
.__name
__
1294 if inspect
.isclass(thing
):
1295 return 'class ' + thing
.__name
__
1296 if inspect
.isfunction(thing
):
1297 return 'function ' + thing
.__name
__
1298 if inspect
.ismethod(thing
):
1299 return 'method ' + thing
.__name
__
1300 if type(thing
) is types
.InstanceType
:
1301 return 'instance of ' + thing
.__class
__.__name
__
1302 return type(thing
).__name
__
1304 def locate(path
, forceload
=0):
1305 """Locate an object by name or dotted path, importing as necessary."""
1306 parts
= split(path
, '.')
1308 while n
< len(parts
):
1309 nextmodule
= safeimport(join(parts
[:n
+1], '.'), forceload
)
1310 if nextmodule
: module
, n
= nextmodule
, n
+ 1
1314 for part
in parts
[n
:]:
1315 try: object = getattr(object, part
)
1316 except AttributeError: return None
1320 if hasattr(__builtin__
, path
):
1321 return getattr(__builtin__
, path
)
1323 # --------------------------------------- interactive interpreter interface
1328 def resolve(thing
, forceload
=0):
1329 """Given an object or a path to an object, get the object and its name."""
1330 if isinstance(thing
, str):
1331 object = locate(thing
, forceload
)
1333 raise ImportError, 'no Python documentation found for %r' % thing
1334 return object, thing
1336 return thing
, getattr(thing
, '__name__', None)
1338 def doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1339 """Display text documentation, given an object or a path to an object."""
1341 object, name
= resolve(thing
, forceload
)
1342 desc
= describe(object)
1343 module
= inspect
.getmodule(object)
1344 if name
and '.' in name
:
1345 desc
+= ' in ' + name
[:name
.rfind('.')]
1346 elif module
and module
is not object:
1347 desc
+= ' in module ' + module
.__name
__
1348 pager(title
% desc
+ '\n\n' + text
.document(object, name
))
1349 except (ImportError, ErrorDuringImport
), value
:
1352 def writedoc(thing
, forceload
=0):
1353 """Write HTML documentation to a file in the current directory."""
1355 object, name
= resolve(thing
, forceload
)
1356 page
= html
.page(describe(object), html
.document(object, name
))
1357 file = open(name
+ '.html', 'w')
1360 print 'wrote', name
+ '.html'
1361 except (ImportError, ErrorDuringImport
), value
:
1364 def writedocs(dir, pkgpath
='', done
=None):
1365 """Write out HTML documentation for all modules in a directory tree."""
1366 if done
is None: done
= {}
1367 for file in os
.listdir(dir):
1368 path
= os
.path
.join(dir, file)
1370 writedocs(path
, pkgpath
+ file + '.', done
)
1371 elif os
.path
.isfile(path
):
1372 modname
= inspect
.getmodulename(path
)
1374 modname
= pkgpath
+ modname
1375 if not modname
in done
:
1382 'assert': ('ref/assert', ''),
1383 'break': ('ref/break', 'while for'),
1384 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1385 'continue': ('ref/continue', 'while for'),
1386 'def': ('ref/function', ''),
1387 'del': ('ref/del', 'BASICMETHODS'),
1389 'else': ('ref/if', 'while for'),
1391 'exec': ('ref/exec', ''),
1393 'for': ('ref/for', 'break continue while'),
1395 'global': ('ref/global', 'NAMESPACES'),
1396 'if': ('ref/if', 'TRUTHVALUE'),
1397 'import': ('ref/import', 'MODULES'),
1398 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1400 'lambda': ('ref/lambda', 'FUNCTIONS'),
1404 'print': ('ref/print', ''),
1405 'raise': ('ref/raise', 'EXCEPTIONS'),
1406 'return': ('ref/return', 'FUNCTIONS'),
1407 'try': ('ref/try', 'EXCEPTIONS'),
1408 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1412 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
1413 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
1414 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1415 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
1416 'UNICODE': ('ref/unicode', 'encodings unicode TYPES STRING'),
1417 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1418 'INTEGER': ('ref/integers', 'int range'),
1419 'FLOAT': ('ref/floating', 'float math'),
1420 'COMPLEX': ('ref/imaginary', 'complex cmath'),
1421 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1422 'MAPPINGS': 'DICTIONARIES',
1423 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1424 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1425 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
1426 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
1427 'FRAMEOBJECTS': 'TYPES',
1428 'TRACEBACKS': 'TYPES',
1429 'NONE': ('lib/bltin-null-object', ''),
1430 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1431 'FILES': ('lib/bltin-file-objects', ''),
1432 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1433 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1434 'MODULES': ('lib/typesmodules', 'import'),
1435 'PACKAGES': 'import',
1436 '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'),
1437 'OPERATORS': 'EXPRESSIONS',
1438 'PRECEDENCE': 'EXPRESSIONS',
1439 'OBJECTS': ('ref/objects', 'TYPES'),
1440 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1441 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1442 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1443 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1444 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1445 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1446 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1447 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
1448 'EXECUTION': ('ref/execframes', ''),
1449 'NAMESPACES': ('ref/execframes', 'global ASSIGNMENT DELETION'),
1450 'SCOPING': 'NAMESPACES',
1451 'FRAMES': 'NAMESPACES',
1452 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1453 'COERCIONS': 'CONVERSIONS',
1454 'CONVERSIONS': ('ref/conversions', ''),
1455 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1456 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
1457 'PRIVATENAMES': ('ref/atom-identifiers', ''),
1458 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1459 'TUPLES': 'SEQUENCES',
1460 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
1461 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
1462 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
1463 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
1464 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1465 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
1466 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1467 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1468 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1469 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1470 'POWER': ('ref/power', 'EXPRESSIONS'),
1471 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1472 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1473 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1474 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1475 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
1476 'BOOLEAN': ('ref/lambda', 'EXPRESSIONS TRUTHVALUE'),
1477 'ASSERTION': 'assert',
1478 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
1479 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
1481 'PRINTING': 'print',
1482 'RETURNING': 'return',
1483 'IMPORTING': 'import',
1484 'CONDITIONAL': 'if',
1485 'LOOPING': ('ref/compound', 'for while break continue'),
1486 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
1487 'DEBUGGING': ('lib/module-pdb', 'pdb'),
1490 def __init__(self
, input, output
):
1492 self
.output
= output
1494 execdir
= os
.path
.dirname(sys
.executable
)
1495 homedir
= os
.environ
.get('PYTHONHOME')
1496 for dir in [os
.environ
.get('PYTHONDOCS'),
1497 homedir
and os
.path
.join(homedir
, 'doc'),
1498 os
.path
.join(execdir
, 'doc'),
1499 '/usr/doc/python-docs-' + split(sys
.version
)[0],
1500 '/usr/doc/python-' + split(sys
.version
)[0],
1501 '/usr/doc/python-docs-' + sys
.version
[:3],
1502 '/usr/doc/python-' + sys
.version
[:3],
1503 os
.path
.join(sys
.prefix
, 'Resources/English.lproj/Documentation')]:
1504 if dir and os
.path
.isdir(os
.path
.join(dir, 'lib')):
1508 if inspect
.stack()[1][3] == '?':
1511 return '<pydoc.Helper instance>'
1513 def __call__(self
, request
=None):
1514 if request
is not None:
1519 self
.output
.write('''
1520 You are now leaving help and returning to the Python interpreter.
1521 If you want to ask for help on a particular object directly from the
1522 interpreter, you can type "help(object)". Executing "help('string')"
1523 has the same effect as typing a particular string at the help> prompt.
1527 self
.output
.write('\n')
1529 self
.output
.write('help> ')
1532 request
= self
.input.readline()
1533 if not request
: break
1534 except KeyboardInterrupt: break
1535 request
= strip(replace(request
, '"', '', "'", ''))
1536 if lower(request
) in ['q', 'quit']: break
1539 def help(self
, request
):
1540 if type(request
) is type(''):
1541 if request
== 'help': self
.intro()
1542 elif request
== 'keywords': self
.listkeywords()
1543 elif request
== 'topics': self
.listtopics()
1544 elif request
== 'modules': self
.listmodules()
1545 elif request
[:8] == 'modules ':
1546 self
.listmodules(split(request
)[1])
1547 elif request
in self
.keywords
: self
.showtopic(request
)
1548 elif request
in self
.topics
: self
.showtopic(request
)
1549 elif request
: doc(request
, 'Help on %s:')
1550 elif isinstance(request
, Helper
): self()
1551 else: doc(request
, 'Help on %s:')
1552 self
.output
.write('\n')
1555 self
.output
.write('''
1556 Welcome to Python %s! This is the online help utility.
1558 If this is your first time using Python, you should definitely check out
1559 the tutorial on the Internet at http://www.python.org/doc/tut/.
1561 Enter the name of any module, keyword, or topic to get help on writing
1562 Python programs and using Python modules. To quit this help utility and
1563 return to the interpreter, just type "quit".
1565 To get a list of available modules, keywords, or topics, type "modules",
1566 "keywords", or "topics". Each module also comes with a one-line summary
1567 of what it does; to list the modules whose summaries contain a given word
1568 such as "spam", type "modules spam".
1569 ''' % sys
.version
[:3])
1571 def list(self
, items
, columns
=4, width
=80):
1574 colw
= width
/ columns
1575 rows
= (len(items
) + columns
- 1) / columns
1576 for row
in range(rows
):
1577 for col
in range(columns
):
1578 i
= col
* rows
+ row
1580 self
.output
.write(items
[i
])
1581 if col
< columns
- 1:
1582 self
.output
.write(' ' + ' ' * (colw
-1 - len(items
[i
])))
1583 self
.output
.write('\n')
1585 def listkeywords(self
):
1586 self
.output
.write('''
1587 Here is a list of the Python keywords. Enter any keyword to get more help.
1590 self
.list(self
.keywords
.keys())
1592 def listtopics(self
):
1593 self
.output
.write('''
1594 Here is a list of available topics. Enter any topic name to get more help.
1597 self
.list(self
.topics
.keys())
1599 def showtopic(self
, topic
):
1601 self
.output
.write('''
1602 Sorry, topic and keyword documentation is not available because the Python
1603 HTML documentation files could not be found. If you have installed them,
1604 please set the environment variable PYTHONDOCS to indicate their location.
1607 target
= self
.topics
.get(topic
, self
.keywords
.get(topic
))
1609 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1611 if type(target
) is type(''):
1612 return self
.showtopic(target
)
1614 filename
, xrefs
= target
1615 filename
= self
.docdir
+ '/' + filename
+ '.html'
1617 file = open(filename
)
1619 self
.output
.write('could not read docs from %s\n' % filename
)
1622 divpat
= re
.compile('<div[^>]*navigat.*?</div.*?>', re
.I | re
.S
)
1623 addrpat
= re
.compile('<address.*?>.*?</address.*?>', re
.I | re
.S
)
1624 document
= re
.sub(addrpat
, '', re
.sub(divpat
, '', file.read()))
1627 import htmllib
, formatter
, StringIO
1628 buffer = StringIO
.StringIO()
1629 parser
= htmllib
.HTMLParser(
1630 formatter
.AbstractFormatter(formatter
.DumbWriter(buffer)))
1631 parser
.start_table
= parser
.do_p
1632 parser
.end_table
= lambda parser
=parser
: parser
.do_p({})
1633 parser
.start_tr
= parser
.do_br
1634 parser
.start_td
= parser
.start_th
= lambda a
, b
=buffer: b
.write('\t')
1635 parser
.feed(document
)
1636 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1637 pager(' ' + strip(buffer) + '\n')
1639 buffer = StringIO
.StringIO()
1640 formatter
.DumbWriter(buffer).send_flowing_data(
1641 'Related help topics: ' + join(split(xrefs
), ', ') + '\n')
1642 self
.output
.write('\n%s\n' % buffer.getvalue())
1644 def listmodules(self
, key
=''):
1646 self
.output
.write('''
1647 Here is a list of matching modules. Enter any module name to get more help.
1652 self
.output
.write('''
1653 Please wait a moment while I gather a list of all available modules...
1657 def callback(path
, modname
, desc
, modules
=modules
):
1658 if modname
and modname
[-9:] == '.__init__':
1659 modname
= modname
[:-9] + ' (package)'
1660 if find(modname
, '.') < 0:
1661 modules
[modname
] = 1
1662 ModuleScanner().run(callback
)
1663 self
.list(modules
.keys())
1664 self
.output
.write('''
1665 Enter any module name to get more help. Or, type "modules spam" to search
1666 for modules whose descriptions contain the word "spam".
1669 help = Helper(sys
.stdin
, sys
.stdout
)
1672 """A generic tree iterator."""
1673 def __init__(self
, roots
, children
, descendp
):
1674 self
.roots
= roots
[:]
1676 self
.children
= children
1677 self
.descendp
= descendp
1683 root
= self
.roots
.pop(0)
1684 self
.state
= [(root
, self
.children(root
))]
1685 node
, children
= self
.state
[-1]
1689 child
= children
.pop(0)
1690 if self
.descendp(child
):
1691 self
.state
.append((child
, self
.children(child
)))
1694 class ModuleScanner(Scanner
):
1695 """An interruptible scanner that searches module synopses."""
1697 roots
= map(lambda dir: (dir, ''), pathdirs())
1698 Scanner
.__init
__(self
, roots
, self
.submodules
, self
.isnewpackage
)
1699 self
.inodes
= map(lambda (dir, pkg
): os
.stat(dir).st_ino
, roots
)
1701 def submodules(self
, (dir, package
)):
1703 for file in os
.listdir(dir):
1704 path
= os
.path
.join(dir, file)
1706 children
.append((path
, package
+ (package
and '.') + file))
1708 children
.append((path
, package
))
1709 children
.sort() # so that spam.py comes before spam.pyc or spam.pyo
1712 def isnewpackage(self
, (dir, package
)):
1713 inode
= os
.path
.exists(dir) and os
.stat(dir).st_ino
1714 if not (os
.path
.islink(dir) and inode
in self
.inodes
):
1715 self
.inodes
.append(inode
) # detect circular symbolic links
1716 return ispackage(dir)
1719 def run(self
, callback
, key
=None, completer
=None):
1720 if key
: key
= lower(key
)
1724 for modname
in sys
.builtin_module_names
:
1725 if modname
!= '__main__':
1728 callback(None, modname
, '')
1730 desc
= split(__import__(modname
).__doc
__ or '', '\n')[0]
1731 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1732 callback(None, modname
, desc
)
1734 while not self
.quit
:
1737 path
, package
= node
1738 modname
= inspect
.getmodulename(path
)
1739 if os
.path
.isfile(path
) and modname
:
1740 modname
= package
+ (package
and '.') + modname
1741 if not modname
in seen
:
1742 seen
[modname
] = 1 # if we see spam.py, skip spam.pyc
1744 callback(path
, modname
, '')
1746 desc
= synopsis(path
) or ''
1747 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1748 callback(path
, modname
, desc
)
1749 if completer
: completer()
1752 """Print all the one-line module summaries that contain a substring."""
1753 def callback(path
, modname
, desc
):
1754 if modname
[-9:] == '.__init__':
1755 modname
= modname
[:-9] + ' (package)'
1756 print modname
, desc
and '- ' + desc
1757 try: import warnings
1758 except ImportError: pass
1759 else: warnings
.filterwarnings('ignore') # ignore problems during import
1760 ModuleScanner().run(callback
, key
)
1762 # --------------------------------------------------- web browser interface
1764 def serve(port
, callback
=None, completer
=None):
1765 import BaseHTTPServer
, mimetools
, select
1767 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1768 class Message(mimetools
.Message
):
1769 def __init__(self
, fp
, seekable
=1):
1770 Message
= self
.__class
__
1771 Message
.__bases
__[0].__bases
__[0].__init
__(self
, fp
, seekable
)
1772 self
.encodingheader
= self
.getheader('content-transfer-encoding')
1773 self
.typeheader
= self
.getheader('content-type')
1777 class DocHandler(BaseHTTPServer
.BaseHTTPRequestHandler
):
1778 def send_document(self
, title
, contents
):
1780 self
.send_response(200)
1781 self
.send_header('Content-Type', 'text/html')
1783 self
.wfile
.write(html
.page(title
, contents
))
1784 except IOError: pass
1788 if path
[-5:] == '.html': path
= path
[:-5]
1789 if path
[:1] == '/': path
= path
[1:]
1790 if path
and path
!= '.':
1792 obj
= locate(path
, forceload
=1)
1793 except ErrorDuringImport
, value
:
1794 self
.send_document(path
, html
.escape(str(value
)))
1797 self
.send_document(describe(obj
), html
.document(obj
, path
))
1799 self
.send_document(path
,
1800 'no Python documentation found for %s' % repr(path
))
1802 heading
= html
.heading(
1803 '<big><big><strong>Python: Index of Modules</strong></big></big>',
1804 '#ffffff', '#7799ee')
1805 def bltinlink(name
):
1806 return '<a href="%s.html">%s</a>' % (name
, name
)
1807 names
= filter(lambda x
: x
!= '__main__',
1808 sys
.builtin_module_names
)
1809 contents
= html
.multicolumn(names
, bltinlink
)
1810 indices
= ['<p>' + html
.bigsection(
1811 'Built-in Modules', '#ffffff', '#ee77aa', contents
)]
1814 for dir in pathdirs():
1815 indices
.append(html
.index(dir, seen
))
1816 contents
= heading
+ join(indices
) + '''<p align=right>
1817 <font color="#909090" face="helvetica, arial"><strong>
1818 pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>'''
1819 self
.send_document('Index of Modules', contents
)
1821 def log_message(self
, *args
): pass
1823 class DocServer(BaseHTTPServer
.HTTPServer
):
1824 def __init__(self
, port
, callback
):
1825 host
= (sys
.platform
== 'mac') and '127.0.0.1' or 'localhost'
1826 self
.address
= ('', port
)
1827 self
.url
= 'http://%s:%d/' % (host
, port
)
1828 self
.callback
= callback
1829 self
.base
.__init
__(self
, self
.address
, self
.handler
)
1831 def serve_until_quit(self
):
1834 while not self
.quit
:
1835 rd
, wr
, ex
= select
.select([self
.socket
.fileno()], [], [], 1)
1836 if rd
: self
.handle_request()
1838 def server_activate(self
):
1839 self
.base
.server_activate(self
)
1840 if self
.callback
: self
.callback(self
)
1842 DocServer
.base
= BaseHTTPServer
.HTTPServer
1843 DocServer
.handler
= DocHandler
1844 DocHandler
.MessageClass
= Message
1847 DocServer(port
, callback
).serve_until_quit()
1848 except (KeyboardInterrupt, select
.error
):
1851 if completer
: completer()
1853 # ----------------------------------------------------- graphical interface
1856 """Graphical interface (starts web server and pops up a control window)."""
1858 def __init__(self
, window
, port
=7464):
1859 self
.window
= window
1864 self
.server_frm
= Tkinter
.Frame(window
)
1865 self
.title_lbl
= Tkinter
.Label(self
.server_frm
,
1866 text
='Starting server...\n ')
1867 self
.open_btn
= Tkinter
.Button(self
.server_frm
,
1868 text
='open browser', command
=self
.open, state
='disabled')
1869 self
.quit_btn
= Tkinter
.Button(self
.server_frm
,
1870 text
='quit serving', command
=self
.quit
, state
='disabled')
1872 self
.search_frm
= Tkinter
.Frame(window
)
1873 self
.search_lbl
= Tkinter
.Label(self
.search_frm
, text
='Search for')
1874 self
.search_ent
= Tkinter
.Entry(self
.search_frm
)
1875 self
.search_ent
.bind('<Return>', self
.search
)
1876 self
.stop_btn
= Tkinter
.Button(self
.search_frm
,
1877 text
='stop', pady
=0, command
=self
.stop
, state
='disabled')
1878 if sys
.platform
== 'win32':
1879 # Trying to hide and show this button crashes under Windows.
1880 self
.stop_btn
.pack(side
='right')
1882 self
.window
.title('pydoc')
1883 self
.window
.protocol('WM_DELETE_WINDOW', self
.quit
)
1884 self
.title_lbl
.pack(side
='top', fill
='x')
1885 self
.open_btn
.pack(side
='left', fill
='x', expand
=1)
1886 self
.quit_btn
.pack(side
='right', fill
='x', expand
=1)
1887 self
.server_frm
.pack(side
='top', fill
='x')
1889 self
.search_lbl
.pack(side
='left')
1890 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
1891 self
.search_frm
.pack(side
='top', fill
='x')
1892 self
.search_ent
.focus_set()
1894 font
= ('helvetica', sys
.platform
== 'win32' and 8 or 10)
1895 self
.result_lst
= Tkinter
.Listbox(window
, font
=font
, height
=6)
1896 self
.result_lst
.bind('<Button-1>', self
.select
)
1897 self
.result_lst
.bind('<Double-Button-1>', self
.goto
)
1898 self
.result_scr
= Tkinter
.Scrollbar(window
,
1899 orient
='vertical', command
=self
.result_lst
.yview
)
1900 self
.result_lst
.config(yscrollcommand
=self
.result_scr
.set)
1902 self
.result_frm
= Tkinter
.Frame(window
)
1903 self
.goto_btn
= Tkinter
.Button(self
.result_frm
,
1904 text
='go to selected', command
=self
.goto
)
1905 self
.hide_btn
= Tkinter
.Button(self
.result_frm
,
1906 text
='hide results', command
=self
.hide
)
1907 self
.goto_btn
.pack(side
='left', fill
='x', expand
=1)
1908 self
.hide_btn
.pack(side
='right', fill
='x', expand
=1)
1910 self
.window
.update()
1911 self
.minwidth
= self
.window
.winfo_width()
1912 self
.minheight
= self
.window
.winfo_height()
1913 self
.bigminheight
= (self
.server_frm
.winfo_reqheight() +
1914 self
.search_frm
.winfo_reqheight() +
1915 self
.result_lst
.winfo_reqheight() +
1916 self
.result_frm
.winfo_reqheight())
1917 self
.bigwidth
, self
.bigheight
= self
.minwidth
, self
.bigminheight
1919 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
1920 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
1924 target
=serve
, args
=(port
, self
.ready
, self
.quit
)).start()
1926 def ready(self
, server
):
1927 self
.server
= server
1928 self
.title_lbl
.config(
1929 text
='Python documentation server at\n' + server
.url
)
1930 self
.open_btn
.config(state
='normal')
1931 self
.quit_btn
.config(state
='normal')
1933 def open(self
, event
=None, url
=None):
1934 url
= url
or self
.server
.url
1937 webbrowser
.open(url
)
1938 except ImportError: # pre-webbrowser.py compatibility
1939 if sys
.platform
== 'win32':
1940 os
.system('start "%s"' % url
)
1941 elif sys
.platform
== 'mac':
1943 except ImportError: pass
1944 else: ic
.launchurl(url
)
1946 rc
= os
.system('netscape -remote "openURL(%s)" &' % url
)
1947 if rc
: os
.system('netscape "%s" &' % url
)
1949 def quit(self
, event
=None):
1951 self
.server
.quit
= 1
1954 def search(self
, event
=None):
1955 key
= self
.search_ent
.get()
1956 self
.stop_btn
.pack(side
='right')
1957 self
.stop_btn
.config(state
='normal')
1958 self
.search_lbl
.config(text
='Searching for "%s"...' % key
)
1959 self
.search_ent
.forget()
1960 self
.search_lbl
.pack(side
='left')
1961 self
.result_lst
.delete(0, 'end')
1962 self
.goto_btn
.config(state
='disabled')
1967 self
.scanner
.quit
= 1
1968 self
.scanner
= ModuleScanner()
1969 threading
.Thread(target
=self
.scanner
.run
,
1970 args
=(self
.update
, key
, self
.done
)).start()
1972 def update(self
, path
, modname
, desc
):
1973 if modname
[-9:] == '.__init__':
1974 modname
= modname
[:-9] + ' (package)'
1975 self
.result_lst
.insert('end',
1976 modname
+ ' - ' + (desc
or '(no description)'))
1978 def stop(self
, event
=None):
1980 self
.scanner
.quit
= 1
1985 self
.search_lbl
.config(text
='Search for')
1986 self
.search_lbl
.pack(side
='left')
1987 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
1988 if sys
.platform
!= 'win32': self
.stop_btn
.forget()
1989 self
.stop_btn
.config(state
='disabled')
1991 def select(self
, event
=None):
1992 self
.goto_btn
.config(state
='normal')
1994 def goto(self
, event
=None):
1995 selection
= self
.result_lst
.curselection()
1997 modname
= split(self
.result_lst
.get(selection
[0]))[0]
1998 self
.open(url
=self
.server
.url
+ modname
+ '.html')
2001 if not self
.expanded
: return
2002 self
.result_frm
.forget()
2003 self
.result_scr
.forget()
2004 self
.result_lst
.forget()
2005 self
.bigwidth
= self
.window
.winfo_width()
2006 self
.bigheight
= self
.window
.winfo_height()
2007 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2008 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2012 if self
.expanded
: return
2013 self
.result_frm
.pack(side
='bottom', fill
='x')
2014 self
.result_scr
.pack(side
='right', fill
='y')
2015 self
.result_lst
.pack(side
='top', fill
='both', expand
=1)
2016 self
.window
.wm_geometry('%dx%d' % (self
.bigwidth
, self
.bigheight
))
2017 self
.window
.wm_minsize(self
.minwidth
, self
.bigminheight
)
2020 def hide(self
, event
=None):
2026 gui
= GUI(Tkinter
.Tk())
2028 except KeyboardInterrupt:
2031 # -------------------------------------------------- command-line interface
2034 return isinstance(x
, str) and find(x
, os
.sep
) >= 0
2037 """Command-line interface (looks at sys.argv to decide what to do)."""
2039 class BadUsage
: pass
2041 # Scripts don't get the current directory in their path by default.
2042 scriptdir
= os
.path
.dirname(sys
.argv
[0])
2043 if scriptdir
in sys
.path
:
2044 sys
.path
.remove(scriptdir
)
2045 sys
.path
.insert(0, '.')
2048 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'gk:p:w')
2051 for opt
, val
in opts
:
2064 print 'pydoc server ready at %s' % server
.url
2066 print 'pydoc server stopped'
2067 serve(port
, ready
, stopped
)
2072 if not args
: raise BadUsage
2074 if ispath(arg
) and not os
.path
.exists(arg
):
2075 print 'file %r does not exist' % arg
2078 if ispath(arg
) and os
.path
.isfile(arg
):
2079 arg
= importfile(arg
)
2081 if ispath(arg
) and os
.path
.isdir(arg
):
2087 except ErrorDuringImport
, value
:
2090 except (getopt
.error
, BadUsage
):
2092 print """pydoc - the Python documentation tool
2095 Show text documentation on something. <name> may be the name of a
2096 function, module, or package, or a dotted reference to a class or
2097 function within a module or module in a package. If <name> contains
2098 a '%s', it is used as the path to a Python source file to document.
2101 Search for a keyword in the synopsis lines of all available modules.
2104 Start an HTTP server on the given port on the local machine.
2107 Pop up a graphical interface for finding and serving documentation.
2110 Write out the HTML documentation for a module to a file in the current
2111 directory. If <name> contains a '%s', it is treated as a filename; if
2112 it names a directory, documentation is written for all the contents.
2113 """ % (cmd
, os
.sep
, cmd
, cmd
, cmd
, cmd
, os
.sep
)
2115 if __name__
== '__main__': cli()