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
, __builtin__
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 def visiblename(name
):
146 """Decide whether to show documentation on a variable."""
147 # Certain special names are redundant.
148 if name
in ['__builtins__', '__doc__', '__file__', '__path__',
149 '__module__', '__name__']: return 0
150 # Private names are hidden, but special names are displayed.
151 if name
.startswith('__') and name
.endswith('__'): return 1
152 return not name
.startswith('_')
154 # ----------------------------------------------------- module manipulation
157 """Guess whether a path refers to a package directory."""
158 if os
.path
.isdir(path
):
159 for ext
in ['.py', '.pyc', '.pyo']:
160 if os
.path
.isfile(os
.path
.join(path
, '__init__' + ext
)):
164 def synopsis(filename
, cache
={}):
165 """Get the one-line summary out of a module file."""
166 mtime
= os
.stat(filename
).st_mtime
167 lastupdate
, result
= cache
.get(filename
, (0, None))
168 if lastupdate
< mtime
:
169 info
= inspect
.getmoduleinfo(filename
)
170 file = open(filename
)
171 if info
and 'b' in info
[2]: # binary modules have to be imported
172 try: module
= imp
.load_module('__temp__', file, filename
, info
[1:])
174 result
= split(module
.__doc
__ or '', '\n')[0]
175 del sys
.modules
['__temp__']
176 else: # text modules can be directly examined
177 line
= file.readline()
178 while line
[:1] == '#' or not strip(line
):
179 line
= file.readline()
182 if line
[:4] == 'r"""': line
= line
[1:]
183 if line
[:3] == '"""':
185 if line
[-1:] == '\\': line
= line
[:-1]
186 while not strip(line
):
187 line
= file.readline()
189 result
= strip(split(line
, '"""')[0])
192 cache
[filename
] = (mtime
, result
)
195 class ErrorDuringImport(Exception):
196 """Errors that occurred while trying to import something to document it."""
197 def __init__(self
, filename
, (exc
, value
, tb
)):
198 self
.filename
= filename
205 if type(exc
) is types
.ClassType
:
207 return 'problem in %s - %s: %s' % (self
.filename
, exc
, self
.value
)
209 def importfile(path
):
210 """Import a Python source file or compiled file given its path."""
211 magic
= imp
.get_magic()
212 file = open(path
, 'r')
213 if file.read(len(magic
)) == magic
:
214 kind
= imp
.PY_COMPILED
218 filename
= os
.path
.basename(path
)
219 name
, ext
= os
.path
.splitext(filename
)
220 file = open(path
, 'r')
222 module
= imp
.load_module(name
, file, path
, (ext
, 'r', kind
))
224 raise ErrorDuringImport(path
, sys
.exc_info())
228 def safeimport(path
, forceload
=0, cache
={}):
229 """Import a module; handle errors; return None if the module isn't found.
231 If the module *is* found but an exception occurs, it's wrapped in an
232 ErrorDuringImport exception and reraised. Unlike __import__, if a
233 package path is specified, the module at the end of the path is returned,
234 not the package at the beginning. If the optional 'forceload' argument
235 is 1, we reload the module from disk (unless it's a dynamic extension)."""
236 if forceload
and path
in sys
.modules
:
237 # This is the only way to be sure. Checking the mtime of the file
238 # isn't good enough (e.g. what if the module contains a class that
239 # inherits from another module that has changed?).
240 if path
not in sys
.builtin_module_names
:
241 # Python never loads a dynamic extension a second time from the
242 # same path, even if the file is changed or missing. Deleting
243 # the entry in sys.modules doesn't help for dynamic extensions,
244 # so we're not even going to try to keep them up to date.
245 info
= inspect
.getmoduleinfo(sys
.modules
[path
].__file
__)
246 if info
[3] != imp
.C_EXTENSION
:
247 cache
[path
] = sys
.modules
[path
] # prevent module from clearing
248 del sys
.modules
[path
]
250 module
= __import__(path
)
252 # Did the error occur before or after the module was found?
253 (exc
, value
, tb
) = info
= sys
.exc_info()
254 if path
in sys
.modules
:
255 # An error occured while executing the imported module.
256 raise ErrorDuringImport(sys
.modules
[path
].__file
__, info
)
257 elif exc
is SyntaxError:
258 # A SyntaxError occurred before we could execute the module.
259 raise ErrorDuringImport(value
.filename
, info
)
260 elif exc
is ImportError and \
261 split(lower(str(value
)))[:2] == ['no', 'module']:
262 # The module was not found.
265 # Some other error occurred during the importing process.
266 raise ErrorDuringImport(path
, sys
.exc_info())
267 for part
in split(path
, '.')[1:]:
268 try: module
= getattr(module
, part
)
269 except AttributeError: return None
272 # ---------------------------------------------------- formatter base class
275 def document(self
, object, name
=None, *args
):
276 """Generate documentation for an object."""
277 args
= (object, name
) + args
278 if inspect
.ismodule(object): return self
.docmodule(*args
)
279 if inspect
.isclass(object): return self
.docclass(*args
)
280 if inspect
.isroutine(object): return self
.docroutine(*args
)
281 return self
.docother(*args
)
283 def fail(self
, object, name
=None, *args
):
284 """Raise an exception for unimplemented types."""
285 message
= "don't know how to document object%s of type %s" % (
286 name
and ' ' + repr(name
), type(object).__name
__)
287 raise TypeError, message
289 docmodule
= docclass
= docroutine
= docother
= fail
291 # -------------------------------------------- HTML documentation generator
293 class HTMLRepr(Repr
):
294 """Class for safely making an HTML representation of a Python object."""
297 self
.maxlist
= self
.maxtuple
= 20
299 self
.maxstring
= self
.maxother
= 100
301 def escape(self
, text
):
302 return replace(text
, '&', '&', '<', '<', '>', '>')
304 def repr(self
, object):
305 return Repr
.repr(self
, object)
307 def repr1(self
, x
, level
):
308 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
309 if hasattr(self
, methodname
):
310 return getattr(self
, methodname
)(x
, level
)
312 return self
.escape(cram(stripid(repr(x
)), self
.maxother
))
314 def repr_string(self
, x
, level
):
315 test
= cram(x
, self
.maxstring
)
316 testrepr
= repr(test
)
317 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
318 # Backslashes are only literal in the string and are never
319 # needed to make any special characters, so show a raw string.
320 return 'r' + testrepr
[0] + self
.escape(test
) + testrepr
[0]
321 return re
.sub(r
'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
322 r'<font color="#c040c0">\1</font>',
323 self
.escape(testrepr
))
325 repr_str
= repr_string
327 def repr_instance(self
, x
, level
):
329 return self
.escape(cram(stripid(repr(x
)), self
.maxstring
))
331 return self
.escape('<%s instance>' % x
.__class
__.__name
__)
333 repr_unicode
= repr_string
336 """Formatter class for HTML documentation."""
338 # ------------------------------------------- HTML formatting utilities
340 _repr_instance
= HTMLRepr()
341 repr = _repr_instance
.repr
342 escape
= _repr_instance
.escape
344 def page(self
, title
, contents
):
345 """Format an HTML page."""
347 <!doctype html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
348 <html><head><title>Python: %s</title>
349 </head><body bgcolor="#f0f0f8">
351 </body></html>''' % (title
, contents
)
353 def heading(self
, title
, fgcol
, bgcol
, extras
=''):
354 """Format a page heading."""
356 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="heading">
358 <td valign=bottom> <br>
359 <font color="%s" face="helvetica, arial"> <br>%s</font></td
360 ><td align=right valign=bottom
361 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
362 ''' % (bgcol
, fgcol
, title
, fgcol
, extras
or ' ')
364 def section(self
, title
, fgcol
, bgcol
, contents
, width
=6,
365 prelude
='', marginalia
=None, gap
=' '):
366 """Format a section with a heading."""
367 if marginalia
is None:
368 marginalia
= '<tt>' + ' ' * width
+ '</tt>'
370 <table width="100%%" cellspacing=0 cellpadding=2 border=0 summary="section">
372 <td colspan=3 valign=bottom> <br>
373 <font color="%s" face="helvetica, arial">%s</font></td></tr>
374 ''' % (bgcol
, fgcol
, title
)
376 result
= result
+ '''
377 <tr bgcolor="%s"><td rowspan=2>%s</td>
378 <td colspan=2>%s</td></tr>
379 <tr><td>%s</td>''' % (bgcol
, marginalia
, prelude
, gap
)
381 result
= result
+ '''
382 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol
, marginalia
, gap
)
384 return result
+ '\n<td width="100%%">%s</td></tr></table>' % contents
386 def bigsection(self
, title
, *args
):
387 """Format a section with a big heading."""
388 title
= '<big><strong>%s</strong></big>' % title
389 return self
.section(title
, *args
)
391 def preformat(self
, text
):
392 """Format literal preformatted text."""
393 text
= self
.escape(expandtabs(text
))
394 return replace(text
, '\n\n', '\n \n', '\n\n', '\n \n',
395 ' ', ' ', '\n', '<br>\n')
397 def multicolumn(self
, list, format
, cols
=4):
398 """Format a list of items into a multi-column list."""
400 rows
= (len(list)+cols
-1)/cols
401 for col
in range(cols
):
402 result
= result
+ '<td width="%d%%" valign=top>' % (100/cols
)
403 for i
in range(rows
*col
, rows
*col
+rows
):
405 result
= result
+ format(list[i
]) + '<br>\n'
406 result
= result
+ '</td>'
407 return '<table width="100%%" summary="list"><tr>%s</tr></table>' % result
409 def grey(self
, text
): return '<font color="#909090">%s</font>' % text
411 def namelink(self
, name
, *dicts
):
412 """Make a link for an identifier, given name-to-URL mappings."""
415 return '<a href="%s">%s</a>' % (dict[name
], name
)
418 def classlink(self
, object, modname
):
419 """Make a link for a class."""
420 name
, module
= object.__name
__, sys
.modules
.get(object.__module
__)
421 if hasattr(module
, name
) and getattr(module
, name
) is object:
422 return '<a href="%s.html#%s">%s</a>' % (
423 module
.__name
__, name
, classname(object, modname
))
424 return classname(object, modname
)
426 def modulelink(self
, object):
427 """Make a link for a module."""
428 return '<a href="%s.html">%s</a>' % (object.__name
__, object.__name
__)
430 def modpkglink(self
, (name
, path
, ispackage
, shadowed
)):
431 """Make a link for a module or package to display in an index."""
433 return self
.grey(name
)
435 url
= '%s.%s.html' % (path
, name
)
437 url
= '%s.html' % name
439 text
= '<strong>%s</strong> (package)' % name
442 return '<a href="%s">%s</a>' % (url
, text
)
444 def markup(self
, text
, escape
=None, funcs
={}, classes
={}, methods
={}):
445 """Mark up some plain text, given a context of symbols to look for.
446 Each context dictionary maps object names to anchor names."""
447 escape
= escape
or self
.escape
450 pattern
= re
.compile(r
'\b((http|ftp)://\S+[\w/]|'
455 match
= pattern
.search(text
, here
)
457 start
, end
= match
.span()
458 results
.append(escape(text
[here
:start
]))
460 all
, scheme
, rfc
, pep
, selfdot
, name
= match
.groups()
462 url
= escape(all
).replace('"', '"')
463 results
.append('<a href="%s">%s</a>' % (url
, url
))
465 url
= 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc
)
466 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
468 url
= 'http://www.python.org/peps/pep-%04d.html' % int(pep
)
469 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
470 elif text
[end
:end
+1] == '(':
471 results
.append(self
.namelink(name
, methods
, funcs
, classes
))
473 results
.append('self.<strong>%s</strong>' % name
)
475 results
.append(self
.namelink(name
, classes
))
477 results
.append(escape(text
[here
:]))
478 return join(results
, '')
480 # ---------------------------------------------- type-specific routines
482 def formattree(self
, tree
, modname
, parent
=None):
483 """Produce HTML for a class tree as given by inspect.getclasstree()."""
486 if type(entry
) is type(()):
488 result
= result
+ '<dt><font face="helvetica, arial">'
489 result
= result
+ self
.classlink(c
, modname
)
490 if bases
and bases
!= (parent
,):
493 parents
.append(self
.classlink(base
, modname
))
494 result
= result
+ '(' + join(parents
, ', ') + ')'
495 result
= result
+ '\n</font></dt>'
496 elif type(entry
) is type([]):
497 result
= result
+ '<dd>\n%s</dd>\n' % self
.formattree(
499 return '<dl>\n%s</dl>\n' % result
501 def docmodule(self
, object, name
=None, mod
=None, *ignored
):
502 """Produce HTML documentation for a module object."""
503 name
= object.__name
__ # ignore the passed-in name
504 parts
= split(name
, '.')
506 for i
in range(len(parts
)-1):
508 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
509 (join(parts
[:i
+1], '.'), parts
[i
]))
510 linkedname
= join(links
+ parts
[-1:], '.')
511 head
= '<big><big><strong>%s</strong></big></big>' % linkedname
513 path
= inspect
.getabsfile(object)
515 if sys
.platform
== 'win32':
517 url
= nturl2path
.pathname2url(path
)
518 filelink
= '<a href="file:%s">%s</a>' % (url
, path
)
520 filelink
= '(built-in)'
522 if hasattr(object, '__version__'):
523 version
= str(object.__version
__)
524 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
525 version
= strip(version
[11:-1])
526 info
.append('version %s' % self
.escape(version
))
527 if hasattr(object, '__date__'):
528 info
.append(self
.escape(str(object.__date
__)))
530 head
= head
+ ' (%s)' % join(info
, ', ')
531 result
= self
.heading(
532 head
, '#ffffff', '#7799ee', '<a href=".">index</a><br>' + filelink
)
534 modules
= inspect
.getmembers(object, inspect
.ismodule
)
536 classes
, cdict
= [], {}
537 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
538 if (inspect
.getmodule(value
) or object) is object:
540 classes
.append((key
, value
))
541 cdict
[key
] = cdict
[value
] = '#' + key
542 for key
, value
in classes
:
543 for base
in value
.__bases
__:
544 key
, modname
= base
.__name
__, base
.__module
__
545 module
= sys
.modules
.get(modname
)
546 if modname
!= name
and module
and hasattr(module
, key
):
547 if getattr(module
, key
) is base
:
549 cdict
[key
] = cdict
[base
] = modname
+ '.html#' + key
550 funcs
, fdict
= [], {}
551 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
552 if inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object:
554 funcs
.append((key
, value
))
555 fdict
[key
] = '#-' + key
556 if inspect
.isfunction(value
): fdict
[value
] = fdict
[key
]
558 for key
, value
in inspect
.getmembers(object, isdata
):
560 data
.append((key
, value
))
562 doc
= self
.markup(getdoc(object), self
.preformat
, fdict
, cdict
)
563 doc
= doc
and '<tt>%s</tt>' % doc
564 result
= result
+ '<p>%s</p>\n' % doc
566 if hasattr(object, '__path__'):
569 for file in os
.listdir(object.__path
__[0]):
570 path
= os
.path
.join(object.__path
__[0], file)
571 modname
= inspect
.getmodulename(file)
572 if modname
!= '__init__':
573 if modname
and modname
not in modnames
:
574 modpkgs
.append((modname
, name
, 0, 0))
575 modnames
.append(modname
)
576 elif ispackage(path
):
577 modpkgs
.append((file, name
, 1, 0))
579 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
580 result
= result
+ self
.bigsection(
581 'Package Contents', '#ffffff', '#aa55cc', contents
)
583 contents
= self
.multicolumn(
584 modules
, lambda (key
, value
), s
=self
: s
.modulelink(value
))
585 result
= result
+ self
.bigsection(
586 'Modules', '#fffff', '#aa55cc', contents
)
589 classlist
= map(lambda (key
, value
): value
, classes
)
591 self
.formattree(inspect
.getclasstree(classlist
, 1), name
)]
592 for key
, value
in classes
:
593 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
594 result
= result
+ self
.bigsection(
595 'Classes', '#ffffff', '#ee77aa', join(contents
))
598 for key
, value
in funcs
:
599 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
600 result
= result
+ self
.bigsection(
601 'Functions', '#ffffff', '#eeaa77', join(contents
))
604 for key
, value
in data
:
605 contents
.append(self
.document(value
, key
))
606 result
= result
+ self
.bigsection(
607 'Data', '#ffffff', '#55aa55', join(contents
, '<br>\n'))
608 if hasattr(object, '__author__'):
609 contents
= self
.markup(str(object.__author
__), self
.preformat
)
610 result
= result
+ self
.bigsection(
611 'Author', '#ffffff', '#7799ee', contents
)
612 if hasattr(object, '__credits__'):
613 contents
= self
.markup(str(object.__credits
__), self
.preformat
)
614 result
= result
+ self
.bigsection(
615 'Credits', '#ffffff', '#7799ee', contents
)
619 def docclass(self
, object, name
=None, mod
=None, funcs
={}, classes
={},
621 """Produce HTML documentation for a class object."""
622 realname
= object.__name
__
623 name
= name
or realname
624 bases
= object.__bases
__
627 push
= contents
.append
629 # Cute little class to pump out a horizontal rule between sections.
630 class HorizontalRule
:
637 hr
= HorizontalRule()
639 # List the mro, if non-trivial.
640 mro
= list(inspect
.getmro(object))
643 push('<dl><dt>Method resolution order:</dt>\n')
645 push('<dd>%s</dd>\n' % self
.classlink(base
,
649 def spill(msg
, attrs
, predicate
):
650 ok
, attrs
= _split_list(attrs
, predicate
)
654 for name
, kind
, homecls
, value
in ok
:
655 push(self
.document(getattr(object, name
), name
, mod
,
656 funcs
, classes
, mdict
, object))
660 def spillproperties(msg
, attrs
, predicate
):
661 ok
, attrs
= _split_list(attrs
, predicate
)
665 for name
, kind
, homecls
, value
in ok
:
666 push('<dl><dt><strong>%s</strong></dt>\n' % name
)
667 if value
.__doc
__ is not None:
668 doc
= self
.markup(value
.__doc
__, self
.preformat
,
669 funcs
, classes
, mdict
)
670 push('<dd><tt>%s</tt></dd>\n' % doc
)
671 for attr
, tag
in [('fget', '<em>get</em>'),
672 ('fset', '<em>set</em>'),
673 ('fdel', '<em>delete</em>')]:
674 func
= getattr(value
, attr
)
676 base
= self
.document(func
, tag
, mod
,
677 funcs
, classes
, mdict
, object)
678 push('<dd>%s</dd>\n' % base
)
682 def spilldata(msg
, attrs
, predicate
):
683 ok
, attrs
= _split_list(attrs
, predicate
)
687 for name
, kind
, homecls
, value
in ok
:
688 base
= self
.docother(getattr(object, name
), name
, mod
)
690 doc
= getattr(value
, "__doc__", None)
694 push('<dl><dt>%s</dl>\n' % base
)
696 doc
= self
.markup(getdoc(value
), self
.preformat
,
697 funcs
, classes
, mdict
)
698 doc
= '<dd><tt>%s</tt>' % doc
699 push('<dl><dt>%s%s</dl>\n' % (base
, doc
))
703 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
704 inspect
.classify_class_attrs(object))
706 for key
, kind
, homecls
, value
in attrs
:
707 mdict
[key
] = anchor
= '#' + name
+ '-' + key
708 value
= getattr(object, key
)
710 # The value may not be hashable (e.g., a data attr with
711 # a dict or list value).
712 mdict
[value
] = anchor
718 thisclass
= mro
.pop(0)
720 thisclass
= attrs
[0][2]
721 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
723 if thisclass
is __builtin__
.object:
726 elif thisclass
is object:
729 tag
= 'inherited from %s' % self
.classlink(thisclass
,
733 # Sort attrs by name.
734 attrs
.sort(lambda t1
, t2
: cmp(t1
[0], t2
[0]))
736 # Pump out the attrs, segregated by kind.
737 attrs
= spill('Methods %s' % tag
, attrs
,
738 lambda t
: t
[1] == 'method')
739 attrs
= spill('Class methods %s' % tag
, attrs
,
740 lambda t
: t
[1] == 'class method')
741 attrs
= spill('Static methods %s' % tag
, attrs
,
742 lambda t
: t
[1] == 'static method')
743 attrs
= spillproperties('Properties %s' % tag
, attrs
,
744 lambda t
: t
[1] == 'property')
745 attrs
= spilldata('Data and other attributes %s' % tag
, attrs
,
746 lambda t
: t
[1] == 'data')
750 contents
= ''.join(contents
)
753 title
= '<a name="%s">class <strong>%s</strong></a>' % (
756 title
= '<strong>%s</strong> = <a name="%s">class %s</a>' % (
757 name
, name
, realname
)
761 parents
.append(self
.classlink(base
, object.__module
__))
762 title
= title
+ '(%s)' % join(parents
, ', ')
763 doc
= self
.markup(getdoc(object), self
.preformat
, funcs
, classes
, mdict
)
764 doc
= doc
and '<tt>%s<br> </tt>' % doc
766 return self
.section(title
, '#000000', '#ffc8d8', contents
, 3, doc
)
768 def formatvalue(self
, object):
769 """Format an argument default value as text."""
770 return self
.grey('=' + self
.repr(object))
772 def docroutine(self
, object, name
=None, mod
=None,
773 funcs
={}, classes
={}, methods
={}, cl
=None):
774 """Produce HTML documentation for a function or method object."""
775 realname
= object.__name
__
776 name
= name
or realname
777 anchor
= (cl
and cl
.__name
__ or '') + '-' + name
780 if inspect
.ismethod(object):
781 imclass
= object.im_class
783 if imclass
is not cl
:
784 note
= ' from ' + self
.classlink(imclass
, mod
)
787 note
= ' method of %s instance' % self
.classlink(
788 object.im_self
.__class
__, mod
)
790 note
= ' unbound %s method' % self
.classlink(imclass
,mod
)
791 object = object.im_func
794 title
= '<a name="%s"><strong>%s</strong></a>' % (anchor
, realname
)
796 if (cl
and realname
in cl
.__dict
__ and
797 cl
.__dict
__[realname
] is object):
798 reallink
= '<a href="#%s">%s</a>' % (
799 cl
.__name
__ + '-' + realname
, realname
)
803 title
= '<a name="%s"><strong>%s</strong></a> = %s' % (
804 anchor
, name
, reallink
)
805 if inspect
.isfunction(object):
806 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
807 argspec
= inspect
.formatargspec(
808 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
809 if realname
== '<lambda>':
810 title
= '<strong>%s</strong> <em>lambda</em> ' % name
811 argspec
= argspec
[1:-1] # remove parentheses
815 decl
= title
+ argspec
+ (note
and self
.grey(
816 '<font face="helvetica, arial">%s</font>' % note
))
819 return '<dl><dt>%s</dt></dl>\n' % decl
822 getdoc(object), self
.preformat
, funcs
, classes
, methods
)
823 doc
= doc
and '<dd><tt>%s</tt></dd>' % doc
824 return '<dl><dt>%s</dt>%s</dl>\n' % (decl
, doc
)
826 def docother(self
, object, name
=None, mod
=None, *ignored
):
827 """Produce HTML documentation for a data object."""
828 lhs
= name
and '<strong>%s</strong> = ' % name
or ''
829 return lhs
+ self
.repr(object)
831 def index(self
, dir, shadowed
=None):
832 """Generate an HTML index for a directory of modules."""
834 if shadowed
is None: shadowed
= {}
836 files
= os
.listdir(dir)
838 def found(name
, ispackage
,
839 modpkgs
=modpkgs
, shadowed
=shadowed
, seen
=seen
):
841 modpkgs
.append((name
, '', ispackage
, name
in shadowed
))
845 # Package spam/__init__.py takes precedence over module spam.py.
847 path
= os
.path
.join(dir, file)
848 if ispackage(path
): found(file, 1)
850 path
= os
.path
.join(dir, file)
851 if os
.path
.isfile(path
):
852 modname
= inspect
.getmodulename(file)
853 if modname
: found(modname
, 0)
856 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
857 return self
.bigsection(dir, '#ffffff', '#ee77aa', contents
)
859 # -------------------------------------------- text documentation generator
861 class TextRepr(Repr
):
862 """Class for safely making a text representation of a Python object."""
865 self
.maxlist
= self
.maxtuple
= 20
867 self
.maxstring
= self
.maxother
= 100
869 def repr1(self
, x
, level
):
870 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
871 if hasattr(self
, methodname
):
872 return getattr(self
, methodname
)(x
, level
)
874 return cram(stripid(repr(x
)), self
.maxother
)
876 def repr_string(self
, x
, level
):
877 test
= cram(x
, self
.maxstring
)
878 testrepr
= repr(test
)
879 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
880 # Backslashes are only literal in the string and are never
881 # needed to make any special characters, so show a raw string.
882 return 'r' + testrepr
[0] + test
+ testrepr
[0]
885 repr_str
= repr_string
887 def repr_instance(self
, x
, level
):
889 return cram(stripid(repr(x
)), self
.maxstring
)
891 return '<%s instance>' % x
.__class
__.__name
__
894 """Formatter class for text documentation."""
896 # ------------------------------------------- text formatting utilities
898 _repr_instance
= TextRepr()
899 repr = _repr_instance
.repr
901 def bold(self
, text
):
902 """Format a string in bold by overstriking."""
903 return join(map(lambda ch
: ch
+ '\b' + ch
, text
), '')
905 def indent(self
, text
, prefix
=' '):
906 """Indent text by prepending a given prefix to each line."""
907 if not text
: return ''
908 lines
= split(text
, '\n')
909 lines
= map(lambda line
, prefix
=prefix
: prefix
+ line
, lines
)
910 if lines
: lines
[-1] = rstrip(lines
[-1])
911 return join(lines
, '\n')
913 def section(self
, title
, contents
):
914 """Format a section with a given heading."""
915 return self
.bold(title
) + '\n' + rstrip(self
.indent(contents
)) + '\n\n'
917 # ---------------------------------------------- type-specific routines
919 def formattree(self
, tree
, modname
, parent
=None, prefix
=''):
920 """Render in text a class tree as returned by inspect.getclasstree()."""
923 if type(entry
) is type(()):
925 result
= result
+ prefix
+ classname(c
, modname
)
926 if bases
and bases
!= (parent
,):
927 parents
= map(lambda c
, m
=modname
: classname(c
, m
), bases
)
928 result
= result
+ '(%s)' % join(parents
, ', ')
929 result
= result
+ '\n'
930 elif type(entry
) is type([]):
931 result
= result
+ self
.formattree(
932 entry
, modname
, c
, prefix
+ ' ')
935 def docmodule(self
, object, name
=None, mod
=None):
936 """Produce text documentation for a given module object."""
937 name
= object.__name
__ # ignore the passed-in name
938 synop
, desc
= splitdoc(getdoc(object))
939 result
= self
.section('NAME', name
+ (synop
and ' - ' + synop
))
942 file = inspect
.getabsfile(object)
945 result
= result
+ self
.section('FILE', file)
947 result
= result
+ self
.section('DESCRIPTION', desc
)
950 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
951 if (inspect
.getmodule(value
) or object) is object:
953 classes
.append((key
, value
))
955 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
956 if inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object:
958 funcs
.append((key
, value
))
960 for key
, value
in inspect
.getmembers(object, isdata
):
962 data
.append((key
, value
))
964 if hasattr(object, '__path__'):
966 for file in os
.listdir(object.__path
__[0]):
967 path
= os
.path
.join(object.__path
__[0], file)
968 modname
= inspect
.getmodulename(file)
969 if modname
!= '__init__':
970 if modname
and modname
not in modpkgs
:
971 modpkgs
.append(modname
)
972 elif ispackage(path
):
973 modpkgs
.append(file + ' (package)')
975 result
= result
+ self
.section(
976 'PACKAGE CONTENTS', join(modpkgs
, '\n'))
979 classlist
= map(lambda (key
, value
): value
, classes
)
980 contents
= [self
.formattree(
981 inspect
.getclasstree(classlist
, 1), name
)]
982 for key
, value
in classes
:
983 contents
.append(self
.document(value
, key
, name
))
984 result
= result
+ self
.section('CLASSES', join(contents
, '\n'))
988 for key
, value
in funcs
:
989 contents
.append(self
.document(value
, key
, name
))
990 result
= result
+ self
.section('FUNCTIONS', join(contents
, '\n'))
994 for key
, value
in data
:
995 contents
.append(self
.docother(value
, key
, name
, 70))
996 result
= result
+ self
.section('DATA', join(contents
, '\n'))
998 if hasattr(object, '__version__'):
999 version
= str(object.__version
__)
1000 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
1001 version
= strip(version
[11:-1])
1002 result
= result
+ self
.section('VERSION', version
)
1003 if hasattr(object, '__date__'):
1004 result
= result
+ self
.section('DATE', str(object.__date
__))
1005 if hasattr(object, '__author__'):
1006 result
= result
+ self
.section('AUTHOR', str(object.__author
__))
1007 if hasattr(object, '__credits__'):
1008 result
= result
+ self
.section('CREDITS', str(object.__credits
__))
1011 def docclass(self
, object, name
=None, mod
=None):
1012 """Produce text documentation for a given class object."""
1013 realname
= object.__name
__
1014 name
= name
or realname
1015 bases
= object.__bases
__
1017 def makename(c
, m
=object.__module
__):
1018 return classname(c
, m
)
1020 if name
== realname
:
1021 title
= 'class ' + self
.bold(realname
)
1023 title
= self
.bold(name
) + ' = class ' + realname
1025 parents
= map(makename
, bases
)
1026 title
= title
+ '(%s)' % join(parents
, ', ')
1028 doc
= getdoc(object)
1029 contents
= doc
and [doc
+ '\n'] or []
1030 push
= contents
.append
1032 # List the mro, if non-trivial.
1033 mro
= list(inspect
.getmro(object))
1035 push("Method resolution order:")
1037 push(' ' + makename(base
))
1040 # Cute little class to pump out a horizontal rule between sections.
1041 class HorizontalRule
:
1048 hr
= HorizontalRule()
1050 def spill(msg
, attrs
, predicate
):
1051 ok
, attrs
= _split_list(attrs
, predicate
)
1055 for name
, kind
, homecls
, value
in ok
:
1056 push(self
.document(getattr(object, name
),
1060 def spillproperties(msg
, attrs
, predicate
):
1061 ok
, attrs
= _split_list(attrs
, predicate
)
1065 for name
, kind
, homecls
, value
in ok
:
1067 need_blank_after_doc
= 0
1068 doc
= getdoc(value
) or ''
1070 push(self
.indent(doc
))
1071 need_blank_after_doc
= 1
1072 for attr
, tag
in [('fget', '<get>'),
1074 ('fdel', '<delete>')]:
1075 func
= getattr(value
, attr
)
1076 if func
is not None:
1077 if need_blank_after_doc
:
1079 need_blank_after_doc
= 0
1080 base
= self
.document(func
, tag
, mod
)
1081 push(self
.indent(base
))
1084 def spilldata(msg
, attrs
, predicate
):
1085 ok
, attrs
= _split_list(attrs
, predicate
)
1089 for name
, kind
, homecls
, value
in ok
:
1091 doc
= getattr(value
, "__doc__", None)
1094 push(self
.docother(getattr(object, name
),
1095 name
, mod
, 70, doc
) + '\n')
1098 attrs
= filter(lambda (name
, kind
, cls
, value
): visiblename(name
),
1099 inspect
.classify_class_attrs(object))
1102 thisclass
= mro
.pop(0)
1104 thisclass
= attrs
[0][2]
1105 attrs
, inherited
= _split_list(attrs
, lambda t
: t
[2] is thisclass
)
1107 if thisclass
is __builtin__
.object:
1110 elif thisclass
is object:
1111 tag
= "defined here"
1113 tag
= "inherited from %s" % classname(thisclass
,
1115 filter(lambda t
: not t
[0].startswith('_'), attrs
)
1117 # Sort attrs by name.
1120 # Pump out the attrs, segregated by kind.
1121 attrs
= spill("Methods %s:\n" % tag
, attrs
,
1122 lambda t
: t
[1] == 'method')
1123 attrs
= spill("Class methods %s:\n" % tag
, attrs
,
1124 lambda t
: t
[1] == 'class method')
1125 attrs
= spill("Static methods %s:\n" % tag
, attrs
,
1126 lambda t
: t
[1] == 'static method')
1127 attrs
= spillproperties("Properties %s:\n" % tag
, attrs
,
1128 lambda t
: t
[1] == 'property')
1129 attrs
= spilldata("Data and other attributes %s:\n" % tag
, attrs
,
1130 lambda t
: t
[1] == 'data')
1134 contents
= '\n'.join(contents
)
1137 return title
+ '\n' + self
.indent(rstrip(contents
), ' | ') + '\n'
1139 def formatvalue(self
, object):
1140 """Format an argument default value as text."""
1141 return '=' + self
.repr(object)
1143 def docroutine(self
, object, name
=None, mod
=None, cl
=None):
1144 """Produce text documentation for a function or method object."""
1145 realname
= object.__name
__
1146 name
= name
or realname
1149 if inspect
.ismethod(object):
1150 imclass
= object.im_class
1152 if imclass
is not cl
:
1153 note
= ' from ' + classname(imclass
, mod
)
1156 note
= ' method of %s instance' % classname(
1157 object.im_self
.__class
__, mod
)
1159 note
= ' unbound %s method' % classname(imclass
,mod
)
1160 object = object.im_func
1162 if name
== realname
:
1163 title
= self
.bold(realname
)
1165 if (cl
and realname
in cl
.__dict
__ and
1166 cl
.__dict
__[realname
] is object):
1168 title
= self
.bold(name
) + ' = ' + realname
1169 if inspect
.isfunction(object):
1170 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
1171 argspec
= inspect
.formatargspec(
1172 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
1173 if realname
== '<lambda>':
1175 argspec
= argspec
[1:-1] # remove parentheses
1178 decl
= title
+ argspec
+ note
1183 doc
= getdoc(object) or ''
1184 return decl
+ '\n' + (doc
and rstrip(self
.indent(doc
)) + '\n')
1186 def docother(self
, object, name
=None, mod
=None, maxlen
=None, doc
=None):
1187 """Produce text documentation for a data object."""
1188 repr = self
.repr(object)
1190 line
= (name
and name
+ ' = ' or '') + repr
1191 chop
= maxlen
- len(line
)
1192 if chop
< 0: repr = repr[:chop
] + '...'
1193 line
= (name
and self
.bold(name
) + ' = ' or '') + repr
1195 line
+= '\n' + self
.indent(str(doc
))
1198 # --------------------------------------------------------- user interfaces
1201 """The first time this is called, determine what kind of pager to use."""
1207 """Decide what method to use for paging through text."""
1208 if type(sys
.stdout
) is not types
.FileType
:
1210 if not sys
.stdin
.isatty() or not sys
.stdout
.isatty():
1212 if os
.environ
.get('TERM') in ['dumb', 'emacs']:
1214 if 'PAGER' in os
.environ
:
1215 if sys
.platform
== 'win32': # pipes completely broken in Windows
1216 return lambda text
: tempfilepager(plain(text
), os
.environ
['PAGER'])
1217 elif os
.environ
.get('TERM') in ['dumb', 'emacs']:
1218 return lambda text
: pipepager(plain(text
), os
.environ
['PAGER'])
1220 return lambda text
: pipepager(text
, os
.environ
['PAGER'])
1221 if sys
.platform
== 'win32' or sys
.platform
.startswith('os2'):
1222 return lambda text
: tempfilepager(plain(text
), 'more <')
1223 if hasattr(os
, 'system') and os
.system('(less) 2>/dev/null') == 0:
1224 return lambda text
: pipepager(text
, 'less')
1227 (fd
, filename
) = tempfile
.mkstemp()
1230 if hasattr(os
, 'system') and os
.system('more %s' % filename
) == 0:
1231 return lambda text
: pipepager(text
, 'more')
1238 """Remove boldface formatting from text."""
1239 return re
.sub('.\b', '', text
)
1241 def pipepager(text
, cmd
):
1242 """Page through text by feeding it to another program."""
1243 pipe
= os
.popen(cmd
, 'w')
1248 pass # Ignore broken pipes caused by quitting the pager program.
1250 def tempfilepager(text
, cmd
):
1251 """Page through text by invoking a program on a temporary file."""
1253 filename
= tempfile
.mktemp()
1254 file = open(filename
, 'w')
1258 os
.system(cmd
+ ' ' + filename
)
1263 """Page through text on a text terminal."""
1264 lines
= split(plain(text
), '\n')
1267 fd
= sys
.stdin
.fileno()
1268 old
= tty
.tcgetattr(fd
)
1270 getchar
= lambda: sys
.stdin
.read(1)
1271 except (ImportError, AttributeError):
1273 getchar
= lambda: sys
.stdin
.readline()[:-1][:1]
1276 r
= inc
= os
.environ
.get('LINES', 25) - 1
1277 sys
.stdout
.write(join(lines
[:inc
], '\n') + '\n')
1279 sys
.stdout
.write('-- more --')
1284 sys
.stdout
.write('\r \r')
1286 elif c
in ['\r', '\n']:
1287 sys
.stdout
.write('\r \r' + lines
[r
] + '\n')
1290 if c
in ['b', 'B', '\x1b']:
1293 sys
.stdout
.write('\n' + join(lines
[r
:r
+inc
], '\n') + '\n')
1298 tty
.tcsetattr(fd
, tty
.TCSAFLUSH
, old
)
1300 def plainpager(text
):
1301 """Simply print unformatted text. This is the ultimate fallback."""
1302 sys
.stdout
.write(plain(text
))
1304 def describe(thing
):
1305 """Produce a short description of the given thing."""
1306 if inspect
.ismodule(thing
):
1307 if thing
.__name
__ in sys
.builtin_module_names
:
1308 return 'built-in module ' + thing
.__name
__
1309 if hasattr(thing
, '__path__'):
1310 return 'package ' + thing
.__name
__
1312 return 'module ' + thing
.__name
__
1313 if inspect
.isbuiltin(thing
):
1314 return 'built-in function ' + thing
.__name
__
1315 if inspect
.isclass(thing
):
1316 return 'class ' + thing
.__name
__
1317 if inspect
.isfunction(thing
):
1318 return 'function ' + thing
.__name
__
1319 if inspect
.ismethod(thing
):
1320 return 'method ' + thing
.__name
__
1321 if type(thing
) is types
.InstanceType
:
1322 return 'instance of ' + thing
.__class
__.__name
__
1323 return type(thing
).__name
__
1325 def locate(path
, forceload
=0):
1326 """Locate an object by name or dotted path, importing as necessary."""
1327 parts
= [part
for part
in split(path
, '.') if part
]
1329 while n
< len(parts
):
1330 nextmodule
= safeimport(join(parts
[:n
+1], '.'), forceload
)
1331 if nextmodule
: module
, n
= nextmodule
, n
+ 1
1335 for part
in parts
[n
:]:
1336 try: object = getattr(object, part
)
1337 except AttributeError: return None
1340 if hasattr(__builtin__
, path
):
1341 return getattr(__builtin__
, path
)
1343 # --------------------------------------- interactive interpreter interface
1348 def resolve(thing
, forceload
=0):
1349 """Given an object or a path to an object, get the object and its name."""
1350 if isinstance(thing
, str):
1351 object = locate(thing
, forceload
)
1353 raise ImportError, 'no Python documentation found for %r' % thing
1354 return object, thing
1356 return thing
, getattr(thing
, '__name__', None)
1358 def doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1359 """Display text documentation, given an object or a path to an object."""
1361 object, name
= resolve(thing
, forceload
)
1362 desc
= describe(object)
1363 module
= inspect
.getmodule(object)
1364 if name
and '.' in name
:
1365 desc
+= ' in ' + name
[:name
.rfind('.')]
1366 elif module
and module
is not object:
1367 desc
+= ' in module ' + module
.__name
__
1368 pager(title
% desc
+ '\n\n' + text
.document(object, name
))
1369 except (ImportError, ErrorDuringImport
), value
:
1372 def writedoc(thing
, forceload
=0):
1373 """Write HTML documentation to a file in the current directory."""
1375 object, name
= resolve(thing
, forceload
)
1376 page
= html
.page(describe(object), html
.document(object, name
))
1377 file = open(name
+ '.html', 'w')
1380 print 'wrote', name
+ '.html'
1381 except (ImportError, ErrorDuringImport
), value
:
1384 def writedocs(dir, pkgpath
='', done
=None):
1385 """Write out HTML documentation for all modules in a directory tree."""
1386 if done
is None: done
= {}
1387 for file in os
.listdir(dir):
1388 path
= os
.path
.join(dir, file)
1390 writedocs(path
, pkgpath
+ file + '.', done
)
1391 elif os
.path
.isfile(path
):
1392 modname
= inspect
.getmodulename(path
)
1394 if modname
== '__init__':
1395 modname
= pkgpath
[:-1] # remove trailing period
1397 modname
= pkgpath
+ modname
1398 if modname
not in done
:
1405 'assert': ('ref/assert', ''),
1406 'break': ('ref/break', 'while for'),
1407 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1408 'continue': ('ref/continue', 'while for'),
1409 'def': ('ref/function', ''),
1410 'del': ('ref/del', 'BASICMETHODS'),
1412 'else': ('ref/if', 'while for'),
1414 'exec': ('ref/exec', ''),
1416 'for': ('ref/for', 'break continue while'),
1418 'global': ('ref/global', 'NAMESPACES'),
1419 'if': ('ref/if', 'TRUTHVALUE'),
1420 'import': ('ref/import', 'MODULES'),
1421 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1423 'lambda': ('ref/lambdas', 'FUNCTIONS'),
1426 'pass': ('ref/pass', ''),
1427 'print': ('ref/print', ''),
1428 'raise': ('ref/raise', 'EXCEPTIONS'),
1429 'return': ('ref/return', 'FUNCTIONS'),
1430 'try': ('ref/try', 'EXCEPTIONS'),
1431 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1432 'yield': ('ref/yield', ''),
1436 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
1437 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
1438 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1439 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
1440 'UNICODE': ('ref/strings', 'encodings unicode TYPES STRING'),
1441 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1442 'INTEGER': ('ref/integers', 'int range'),
1443 'FLOAT': ('ref/floating', 'float math'),
1444 'COMPLEX': ('ref/imaginary', 'complex cmath'),
1445 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1446 'MAPPINGS': 'DICTIONARIES',
1447 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1448 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1449 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
1450 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
1451 'FRAMEOBJECTS': 'TYPES',
1452 'TRACEBACKS': 'TYPES',
1453 'NONE': ('lib/bltin-null-object', ''),
1454 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1455 'FILES': ('lib/bltin-file-objects', ''),
1456 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1457 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1458 'MODULES': ('lib/typesmodules', 'import'),
1459 'PACKAGES': 'import',
1460 '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'),
1461 'OPERATORS': 'EXPRESSIONS',
1462 'PRECEDENCE': 'EXPRESSIONS',
1463 'OBJECTS': ('ref/objects', 'TYPES'),
1464 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1465 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1466 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1467 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1468 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1469 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1470 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1471 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
1472 'EXECUTION': ('ref/naming', ''),
1473 'NAMESPACES': ('ref/naming', 'global ASSIGNMENT DELETION'),
1474 'SCOPING': 'NAMESPACES',
1475 'FRAMES': 'NAMESPACES',
1476 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1477 'COERCIONS': 'CONVERSIONS',
1478 'CONVERSIONS': ('ref/conversions', ''),
1479 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1480 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
1481 'PRIVATENAMES': ('ref/atom-identifiers', ''),
1482 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1483 'TUPLES': 'SEQUENCES',
1484 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
1485 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
1486 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
1487 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
1488 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1489 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
1490 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1491 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1492 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1493 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1494 'POWER': ('ref/power', 'EXPRESSIONS'),
1495 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1496 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1497 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1498 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1499 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
1500 'BOOLEAN': ('ref/Booleans', 'EXPRESSIONS TRUTHVALUE'),
1501 'ASSERTION': 'assert',
1502 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
1503 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
1505 'PRINTING': 'print',
1506 'RETURNING': 'return',
1507 'IMPORTING': 'import',
1508 'CONDITIONAL': 'if',
1509 'LOOPING': ('ref/compound', 'for while break continue'),
1510 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
1511 'DEBUGGING': ('lib/module-pdb', 'pdb'),
1514 def __init__(self
, input, output
):
1516 self
.output
= output
1518 execdir
= os
.path
.dirname(sys
.executable
)
1519 homedir
= os
.environ
.get('PYTHONHOME')
1520 for dir in [os
.environ
.get('PYTHONDOCS'),
1521 homedir
and os
.path
.join(homedir
, 'doc'),
1522 os
.path
.join(execdir
, 'doc'),
1523 '/usr/doc/python-docs-' + split(sys
.version
)[0],
1524 '/usr/doc/python-' + split(sys
.version
)[0],
1525 '/usr/doc/python-docs-' + sys
.version
[:3],
1526 '/usr/doc/python-' + sys
.version
[:3],
1527 os
.path
.join(sys
.prefix
, 'Resources/English.lproj/Documentation')]:
1528 if dir and os
.path
.isdir(os
.path
.join(dir, 'lib')):
1532 if inspect
.stack()[1][3] == '?':
1535 return '<pydoc.Helper instance>'
1537 def __call__(self
, request
=None):
1538 if request
is not None:
1543 self
.output
.write('''
1544 You are now leaving help and returning to the Python interpreter.
1545 If you want to ask for help on a particular object directly from the
1546 interpreter, you can type "help(object)". Executing "help('string')"
1547 has the same effect as typing a particular string at the help> prompt.
1551 self
.output
.write('\n')
1553 self
.output
.write('help> ')
1556 request
= self
.input.readline()
1557 if not request
: break
1558 except KeyboardInterrupt: break
1559 request
= strip(replace(request
, '"', '', "'", ''))
1560 if lower(request
) in ['q', 'quit']: break
1563 def help(self
, request
):
1564 if type(request
) is type(''):
1565 if request
== 'help': self
.intro()
1566 elif request
== 'keywords': self
.listkeywords()
1567 elif request
== 'topics': self
.listtopics()
1568 elif request
== 'modules': self
.listmodules()
1569 elif request
[:8] == 'modules ':
1570 self
.listmodules(split(request
)[1])
1571 elif request
in self
.keywords
: self
.showtopic(request
)
1572 elif request
in self
.topics
: self
.showtopic(request
)
1573 elif request
: doc(request
, 'Help on %s:')
1574 elif isinstance(request
, Helper
): self()
1575 else: doc(request
, 'Help on %s:')
1576 self
.output
.write('\n')
1579 self
.output
.write('''
1580 Welcome to Python %s! This is the online help utility.
1582 If this is your first time using Python, you should definitely check out
1583 the tutorial on the Internet at http://www.python.org/doc/tut/.
1585 Enter the name of any module, keyword, or topic to get help on writing
1586 Python programs and using Python modules. To quit this help utility and
1587 return to the interpreter, just type "quit".
1589 To get a list of available modules, keywords, or topics, type "modules",
1590 "keywords", or "topics". Each module also comes with a one-line summary
1591 of what it does; to list the modules whose summaries contain a given word
1592 such as "spam", type "modules spam".
1593 ''' % sys
.version
[:3])
1595 def list(self
, items
, columns
=4, width
=80):
1598 colw
= width
/ columns
1599 rows
= (len(items
) + columns
- 1) / columns
1600 for row
in range(rows
):
1601 for col
in range(columns
):
1602 i
= col
* rows
+ row
1604 self
.output
.write(items
[i
])
1605 if col
< columns
- 1:
1606 self
.output
.write(' ' + ' ' * (colw
-1 - len(items
[i
])))
1607 self
.output
.write('\n')
1609 def listkeywords(self
):
1610 self
.output
.write('''
1611 Here is a list of the Python keywords. Enter any keyword to get more help.
1614 self
.list(self
.keywords
.keys())
1616 def listtopics(self
):
1617 self
.output
.write('''
1618 Here is a list of available topics. Enter any topic name to get more help.
1621 self
.list(self
.topics
.keys())
1623 def showtopic(self
, topic
):
1625 self
.output
.write('''
1626 Sorry, topic and keyword documentation is not available because the Python
1627 HTML documentation files could not be found. If you have installed them,
1628 please set the environment variable PYTHONDOCS to indicate their location.
1631 target
= self
.topics
.get(topic
, self
.keywords
.get(topic
))
1633 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1635 if type(target
) is type(''):
1636 return self
.showtopic(target
)
1638 filename
, xrefs
= target
1639 filename
= self
.docdir
+ '/' + filename
+ '.html'
1641 file = open(filename
)
1643 self
.output
.write('could not read docs from %s\n' % filename
)
1646 divpat
= re
.compile('<div[^>]*navigat.*?</div.*?>', re
.I | re
.S
)
1647 addrpat
= re
.compile('<address.*?>.*?</address.*?>', re
.I | re
.S
)
1648 document
= re
.sub(addrpat
, '', re
.sub(divpat
, '', file.read()))
1651 import htmllib
, formatter
, StringIO
1652 buffer = StringIO
.StringIO()
1653 parser
= htmllib
.HTMLParser(
1654 formatter
.AbstractFormatter(formatter
.DumbWriter(buffer)))
1655 parser
.start_table
= parser
.do_p
1656 parser
.end_table
= lambda parser
=parser
: parser
.do_p({})
1657 parser
.start_tr
= parser
.do_br
1658 parser
.start_td
= parser
.start_th
= lambda a
, b
=buffer: b
.write('\t')
1659 parser
.feed(document
)
1660 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1661 pager(' ' + strip(buffer) + '\n')
1663 buffer = StringIO
.StringIO()
1664 formatter
.DumbWriter(buffer).send_flowing_data(
1665 'Related help topics: ' + join(split(xrefs
), ', ') + '\n')
1666 self
.output
.write('\n%s\n' % buffer.getvalue())
1668 def listmodules(self
, key
=''):
1670 self
.output
.write('''
1671 Here is a list of matching modules. Enter any module name to get more help.
1676 self
.output
.write('''
1677 Please wait a moment while I gather a list of all available modules...
1681 def callback(path
, modname
, desc
, modules
=modules
):
1682 if modname
and modname
[-9:] == '.__init__':
1683 modname
= modname
[:-9] + ' (package)'
1684 if find(modname
, '.') < 0:
1685 modules
[modname
] = 1
1686 ModuleScanner().run(callback
)
1687 self
.list(modules
.keys())
1688 self
.output
.write('''
1689 Enter any module name to get more help. Or, type "modules spam" to search
1690 for modules whose descriptions contain the word "spam".
1693 help = Helper(sys
.stdin
, sys
.stdout
)
1696 """A generic tree iterator."""
1697 def __init__(self
, roots
, children
, descendp
):
1698 self
.roots
= roots
[:]
1700 self
.children
= children
1701 self
.descendp
= descendp
1707 root
= self
.roots
.pop(0)
1708 self
.state
= [(root
, self
.children(root
))]
1709 node
, children
= self
.state
[-1]
1713 child
= children
.pop(0)
1714 if self
.descendp(child
):
1715 self
.state
.append((child
, self
.children(child
)))
1718 class ModuleScanner(Scanner
):
1719 """An interruptible scanner that searches module synopses."""
1721 roots
= map(lambda dir: (dir, ''), pathdirs())
1722 Scanner
.__init
__(self
, roots
, self
.submodules
, self
.isnewpackage
)
1723 self
.inodes
= map(lambda (dir, pkg
): os
.stat(dir).st_ino
, roots
)
1725 def submodules(self
, (dir, package
)):
1727 for file in os
.listdir(dir):
1728 path
= os
.path
.join(dir, file)
1730 children
.append((path
, package
+ (package
and '.') + file))
1732 children
.append((path
, package
))
1733 children
.sort() # so that spam.py comes before spam.pyc or spam.pyo
1736 def isnewpackage(self
, (dir, package
)):
1737 inode
= os
.path
.exists(dir) and os
.stat(dir).st_ino
1738 if not (os
.path
.islink(dir) and inode
in self
.inodes
):
1739 self
.inodes
.append(inode
) # detect circular symbolic links
1740 return ispackage(dir)
1743 def run(self
, callback
, key
=None, completer
=None):
1744 if key
: key
= lower(key
)
1748 for modname
in sys
.builtin_module_names
:
1749 if modname
!= '__main__':
1752 callback(None, modname
, '')
1754 desc
= split(__import__(modname
).__doc
__ or '', '\n')[0]
1755 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1756 callback(None, modname
, desc
)
1758 while not self
.quit
:
1761 path
, package
= node
1762 modname
= inspect
.getmodulename(path
)
1763 if os
.path
.isfile(path
) and modname
:
1764 modname
= package
+ (package
and '.') + modname
1765 if not modname
in seen
:
1766 seen
[modname
] = 1 # if we see spam.py, skip spam.pyc
1768 callback(path
, modname
, '')
1770 desc
= synopsis(path
) or ''
1771 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1772 callback(path
, modname
, desc
)
1773 if completer
: completer()
1776 """Print all the one-line module summaries that contain a substring."""
1777 def callback(path
, modname
, desc
):
1778 if modname
[-9:] == '.__init__':
1779 modname
= modname
[:-9] + ' (package)'
1780 print modname
, desc
and '- ' + desc
1781 try: import warnings
1782 except ImportError: pass
1783 else: warnings
.filterwarnings('ignore') # ignore problems during import
1784 ModuleScanner().run(callback
, key
)
1786 # --------------------------------------------------- web browser interface
1788 def serve(port
, callback
=None, completer
=None):
1789 import BaseHTTPServer
, mimetools
, select
1791 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1792 class Message(mimetools
.Message
):
1793 def __init__(self
, fp
, seekable
=1):
1794 Message
= self
.__class
__
1795 Message
.__bases
__[0].__bases
__[0].__init
__(self
, fp
, seekable
)
1796 self
.encodingheader
= self
.getheader('content-transfer-encoding')
1797 self
.typeheader
= self
.getheader('content-type')
1801 class DocHandler(BaseHTTPServer
.BaseHTTPRequestHandler
):
1802 def send_document(self
, title
, contents
):
1804 self
.send_response(200)
1805 self
.send_header('Content-Type', 'text/html')
1807 self
.wfile
.write(html
.page(title
, contents
))
1808 except IOError: pass
1812 if path
[-5:] == '.html': path
= path
[:-5]
1813 if path
[:1] == '/': path
= path
[1:]
1814 if path
and path
!= '.':
1816 obj
= locate(path
, forceload
=1)
1817 except ErrorDuringImport
, value
:
1818 self
.send_document(path
, html
.escape(str(value
)))
1821 self
.send_document(describe(obj
), html
.document(obj
, path
))
1823 self
.send_document(path
,
1824 'no Python documentation found for %s' % repr(path
))
1826 heading
= html
.heading(
1827 '<big><big><strong>Python: Index of Modules</strong></big></big>',
1828 '#ffffff', '#7799ee')
1829 def bltinlink(name
):
1830 return '<a href="%s.html">%s</a>' % (name
, name
)
1831 names
= filter(lambda x
: x
!= '__main__',
1832 sys
.builtin_module_names
)
1833 contents
= html
.multicolumn(names
, bltinlink
)
1834 indices
= ['<p>' + html
.bigsection(
1835 'Built-in Modules', '#ffffff', '#ee77aa', contents
)]
1838 for dir in pathdirs():
1839 indices
.append(html
.index(dir, seen
))
1840 contents
= heading
+ join(indices
) + '''<p align=right>
1841 <font color="#909090" face="helvetica, arial"><strong>
1842 pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font>'''
1843 self
.send_document('Index of Modules', contents
)
1845 def log_message(self
, *args
): pass
1847 class DocServer(BaseHTTPServer
.HTTPServer
):
1848 def __init__(self
, port
, callback
):
1849 host
= (sys
.platform
== 'mac') and '127.0.0.1' or 'localhost'
1850 self
.address
= ('', port
)
1851 self
.url
= 'http://%s:%d/' % (host
, port
)
1852 self
.callback
= callback
1853 self
.base
.__init
__(self
, self
.address
, self
.handler
)
1855 def serve_until_quit(self
):
1858 while not self
.quit
:
1859 rd
, wr
, ex
= select
.select([self
.socket
.fileno()], [], [], 1)
1860 if rd
: self
.handle_request()
1862 def server_activate(self
):
1863 self
.base
.server_activate(self
)
1864 if self
.callback
: self
.callback(self
)
1866 DocServer
.base
= BaseHTTPServer
.HTTPServer
1867 DocServer
.handler
= DocHandler
1868 DocHandler
.MessageClass
= Message
1871 DocServer(port
, callback
).serve_until_quit()
1872 except (KeyboardInterrupt, select
.error
):
1875 if completer
: completer()
1877 # ----------------------------------------------------- graphical interface
1880 """Graphical interface (starts web server and pops up a control window)."""
1882 def __init__(self
, window
, port
=7464):
1883 self
.window
= window
1888 self
.server_frm
= Tkinter
.Frame(window
)
1889 self
.title_lbl
= Tkinter
.Label(self
.server_frm
,
1890 text
='Starting server...\n ')
1891 self
.open_btn
= Tkinter
.Button(self
.server_frm
,
1892 text
='open browser', command
=self
.open, state
='disabled')
1893 self
.quit_btn
= Tkinter
.Button(self
.server_frm
,
1894 text
='quit serving', command
=self
.quit
, state
='disabled')
1896 self
.search_frm
= Tkinter
.Frame(window
)
1897 self
.search_lbl
= Tkinter
.Label(self
.search_frm
, text
='Search for')
1898 self
.search_ent
= Tkinter
.Entry(self
.search_frm
)
1899 self
.search_ent
.bind('<Return>', self
.search
)
1900 self
.stop_btn
= Tkinter
.Button(self
.search_frm
,
1901 text
='stop', pady
=0, command
=self
.stop
, state
='disabled')
1902 if sys
.platform
== 'win32':
1903 # Trying to hide and show this button crashes under Windows.
1904 self
.stop_btn
.pack(side
='right')
1906 self
.window
.title('pydoc')
1907 self
.window
.protocol('WM_DELETE_WINDOW', self
.quit
)
1908 self
.title_lbl
.pack(side
='top', fill
='x')
1909 self
.open_btn
.pack(side
='left', fill
='x', expand
=1)
1910 self
.quit_btn
.pack(side
='right', fill
='x', expand
=1)
1911 self
.server_frm
.pack(side
='top', fill
='x')
1913 self
.search_lbl
.pack(side
='left')
1914 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
1915 self
.search_frm
.pack(side
='top', fill
='x')
1916 self
.search_ent
.focus_set()
1918 font
= ('helvetica', sys
.platform
== 'win32' and 8 or 10)
1919 self
.result_lst
= Tkinter
.Listbox(window
, font
=font
, height
=6)
1920 self
.result_lst
.bind('<Button-1>', self
.select
)
1921 self
.result_lst
.bind('<Double-Button-1>', self
.goto
)
1922 self
.result_scr
= Tkinter
.Scrollbar(window
,
1923 orient
='vertical', command
=self
.result_lst
.yview
)
1924 self
.result_lst
.config(yscrollcommand
=self
.result_scr
.set)
1926 self
.result_frm
= Tkinter
.Frame(window
)
1927 self
.goto_btn
= Tkinter
.Button(self
.result_frm
,
1928 text
='go to selected', command
=self
.goto
)
1929 self
.hide_btn
= Tkinter
.Button(self
.result_frm
,
1930 text
='hide results', command
=self
.hide
)
1931 self
.goto_btn
.pack(side
='left', fill
='x', expand
=1)
1932 self
.hide_btn
.pack(side
='right', fill
='x', expand
=1)
1934 self
.window
.update()
1935 self
.minwidth
= self
.window
.winfo_width()
1936 self
.minheight
= self
.window
.winfo_height()
1937 self
.bigminheight
= (self
.server_frm
.winfo_reqheight() +
1938 self
.search_frm
.winfo_reqheight() +
1939 self
.result_lst
.winfo_reqheight() +
1940 self
.result_frm
.winfo_reqheight())
1941 self
.bigwidth
, self
.bigheight
= self
.minwidth
, self
.bigminheight
1943 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
1944 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
1945 self
.window
.tk
.willdispatch()
1949 target
=serve
, args
=(port
, self
.ready
, self
.quit
)).start()
1951 def ready(self
, server
):
1952 self
.server
= server
1953 self
.title_lbl
.config(
1954 text
='Python documentation server at\n' + server
.url
)
1955 self
.open_btn
.config(state
='normal')
1956 self
.quit_btn
.config(state
='normal')
1958 def open(self
, event
=None, url
=None):
1959 url
= url
or self
.server
.url
1962 webbrowser
.open(url
)
1963 except ImportError: # pre-webbrowser.py compatibility
1964 if sys
.platform
== 'win32':
1965 os
.system('start "%s"' % url
)
1966 elif sys
.platform
== 'mac':
1968 except ImportError: pass
1969 else: ic
.launchurl(url
)
1971 rc
= os
.system('netscape -remote "openURL(%s)" &' % url
)
1972 if rc
: os
.system('netscape "%s" &' % url
)
1974 def quit(self
, event
=None):
1976 self
.server
.quit
= 1
1979 def search(self
, event
=None):
1980 key
= self
.search_ent
.get()
1981 self
.stop_btn
.pack(side
='right')
1982 self
.stop_btn
.config(state
='normal')
1983 self
.search_lbl
.config(text
='Searching for "%s"...' % key
)
1984 self
.search_ent
.forget()
1985 self
.search_lbl
.pack(side
='left')
1986 self
.result_lst
.delete(0, 'end')
1987 self
.goto_btn
.config(state
='disabled')
1992 self
.scanner
.quit
= 1
1993 self
.scanner
= ModuleScanner()
1994 threading
.Thread(target
=self
.scanner
.run
,
1995 args
=(self
.update
, key
, self
.done
)).start()
1997 def update(self
, path
, modname
, desc
):
1998 if modname
[-9:] == '.__init__':
1999 modname
= modname
[:-9] + ' (package)'
2000 self
.result_lst
.insert('end',
2001 modname
+ ' - ' + (desc
or '(no description)'))
2003 def stop(self
, event
=None):
2005 self
.scanner
.quit
= 1
2010 self
.search_lbl
.config(text
='Search for')
2011 self
.search_lbl
.pack(side
='left')
2012 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
2013 if sys
.platform
!= 'win32': self
.stop_btn
.forget()
2014 self
.stop_btn
.config(state
='disabled')
2016 def select(self
, event
=None):
2017 self
.goto_btn
.config(state
='normal')
2019 def goto(self
, event
=None):
2020 selection
= self
.result_lst
.curselection()
2022 modname
= split(self
.result_lst
.get(selection
[0]))[0]
2023 self
.open(url
=self
.server
.url
+ modname
+ '.html')
2026 if not self
.expanded
: return
2027 self
.result_frm
.forget()
2028 self
.result_scr
.forget()
2029 self
.result_lst
.forget()
2030 self
.bigwidth
= self
.window
.winfo_width()
2031 self
.bigheight
= self
.window
.winfo_height()
2032 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
2033 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
2037 if self
.expanded
: return
2038 self
.result_frm
.pack(side
='bottom', fill
='x')
2039 self
.result_scr
.pack(side
='right', fill
='y')
2040 self
.result_lst
.pack(side
='top', fill
='both', expand
=1)
2041 self
.window
.wm_geometry('%dx%d' % (self
.bigwidth
, self
.bigheight
))
2042 self
.window
.wm_minsize(self
.minwidth
, self
.bigminheight
)
2045 def hide(self
, event
=None):
2051 gui
= GUI(Tkinter
.Tk())
2053 except KeyboardInterrupt:
2056 # -------------------------------------------------- command-line interface
2059 return isinstance(x
, str) and find(x
, os
.sep
) >= 0
2062 """Command-line interface (looks at sys.argv to decide what to do)."""
2064 class BadUsage
: pass
2066 # Scripts don't get the current directory in their path by default.
2067 scriptdir
= os
.path
.dirname(sys
.argv
[0])
2068 if scriptdir
in sys
.path
:
2069 sys
.path
.remove(scriptdir
)
2070 sys
.path
.insert(0, '.')
2073 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'gk:p:w')
2076 for opt
, val
in opts
:
2089 print 'pydoc server ready at %s' % server
.url
2091 print 'pydoc server stopped'
2092 serve(port
, ready
, stopped
)
2097 if not args
: raise BadUsage
2099 if ispath(arg
) and not os
.path
.exists(arg
):
2100 print 'file %r does not exist' % arg
2103 if ispath(arg
) and os
.path
.isfile(arg
):
2104 arg
= importfile(arg
)
2106 if ispath(arg
) and os
.path
.isdir(arg
):
2112 except ErrorDuringImport
, value
:
2115 except (getopt
.error
, BadUsage
):
2117 print """pydoc - the Python documentation tool
2120 Show text documentation on something. <name> may be the name of a
2121 function, module, or package, or a dotted reference to a class or
2122 function within a module or module in a package. If <name> contains
2123 a '%s', it is used as the path to a Python source file to document.
2126 Search for a keyword in the synopsis lines of all available modules.
2129 Start an HTTP server on the given port on the local machine.
2132 Pop up a graphical interface for finding and serving documentation.
2135 Write out the HTML documentation for a module to a file in the current
2136 directory. If <name> contains a '%s', it is treated as a filename; if
2137 it names a directory, documentation is written for all the contents.
2138 """ % (cmd
, os
.sep
, cmd
, cmd
, cmd
, cmd
, os
.sep
)
2140 if __name__
== '__main__': cli()