2 """Generate Python documentation in HTML or text for interactive use.
4 In the Python interpreter, do "from pydoc import help" to provide online
5 help. Calling help(thing) on a Python object documents the object.
7 Or, at the shell command line outside of Python:
9 Run "pydoc <name>" to show documentation on something. <name> may be
10 the name of a function, module, package, or a dotted reference to a
11 class or function within a module or module in a package. If the
12 argument contains a path segment delimiter (e.g. slash on Unix,
13 backslash on Windows) it is treated as the path to a Python source file.
15 Run "pydoc -k <keyword>" to search for a keyword in the synopsis lines
16 of all available modules.
18 Run "pydoc -p <port>" to start an HTTP server on a given port on the
19 local machine to generate documentation web pages.
21 For platforms without a command line, "pydoc -g" starts the HTTP server
22 and also pops up a little window for controlling it.
24 Run "pydoc -w <name>" to write out the HTML documentation for a module
25 to a file named "<name>.html".
28 __author__
= "Ka-Ping Yee <ping@lfw.org>"
29 __date__
= "26 February 2001"
30 __version__
= "$Revision$"
31 __credits__
= """Guido van Rossum, for an excellent programming language.
32 Tommy Burnette, the original creator of manpy.
33 Paul Prescod, for all his work on onlinehelp.
34 Richard Chamberlain, for the first implementation of textdoc.
36 Mynd you, møøse bites Kan be pretty nasti..."""
38 # Note: this module is designed to deploy instantly and run under any
39 # version of Python from 1.5 and up. That's why it's a single file and
40 # some 2.0 features (like string methods) are conspicuously absent.
42 # Known bugs that can't be fixed here:
43 # - imp.load_module() cannot be prevented from clobbering existing
44 # loaded modules, so calling synopsis() on a binary module file
45 # changes the contents of any existing module with the same name.
46 # - If the __file__ attribute on a module is a relative path and
47 # the current directory is changed with os.chdir(), an incorrect
48 # path will be displayed.
50 import sys
, imp
, os
, stat
, re
, types
, inspect
52 from string
import expandtabs
, find
, join
, lower
, split
, strip
, rfind
, rstrip
54 # --------------------------------------------------------- common routines
57 """Convert sys.path into a list of absolute, existing, unique paths."""
61 dir = os
.path
.abspath(dir or '.')
62 normdir
= os
.path
.normcase(dir)
63 if normdir
not in normdirs
and os
.path
.isdir(dir):
65 normdirs
.append(normdir
)
69 """Get the doc string or comments for an object."""
70 result
= inspect
.getdoc(object) or inspect
.getcomments(object)
71 return result
and re
.sub('^ *\n', '', rstrip(result
)) or ''
74 """Split a doc string into a synopsis line (if any) and the rest."""
75 lines
= split(strip(doc
), '\n')
78 elif len(lines
) >= 2 and not rstrip(lines
[1]):
79 return lines
[0], join(lines
[2:], '\n')
80 return '', join(lines
, '\n')
82 def classname(object, modname
):
83 """Get a class name and qualify it with a module name if necessary."""
84 name
= object.__name
__
85 if object.__module
__ != modname
:
86 name
= object.__module
__ + '.' + name
90 """Check if an object is of a type that probably means it's data."""
91 return not (inspect
.ismodule(object) or inspect
.isclass(object) or
92 inspect
.isroutine(object) or inspect
.isframe(object) or
93 inspect
.istraceback(object) or inspect
.iscode(object))
95 def replace(text
, *pairs
):
96 """Do a series of global replacements on a string."""
98 text
= join(split(text
, pairs
[0]), pairs
[1])
102 def cram(text
, maxlen
):
103 """Omit part of a string if needed to make it fit in a maximum length."""
104 if len(text
) > maxlen
:
105 pre
= max(0, (maxlen
-3)/2)
106 post
= max(0, maxlen
-3-pre
)
107 return text
[:pre
] + '...' + text
[len(text
)-post
:]
111 """Remove the hexadecimal id from a Python object representation."""
112 # The behaviour of %p is implementation-dependent; we check two cases.
113 for pattern
in [' at 0x[0-9a-f]{6,}>$', ' at [0-9A-F]{8,}>$']:
114 if re
.search(pattern
, repr(Exception)):
115 return re
.sub(pattern
, '>', text
)
120 for key
, value
in inspect
.getmembers(cl
, inspect
.ismethod
):
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 # ----------------------------------------------------- module manipulation
131 """Guess whether a path refers to a package directory."""
132 if os
.path
.isdir(path
):
133 for ext
in ['.py', '.pyc', '.pyo']:
134 if os
.path
.isfile(os
.path
.join(path
, '__init__' + ext
)):
137 def synopsis(filename
, cache
={}):
138 """Get the one-line summary out of a module file."""
139 mtime
= os
.stat(filename
)[stat
.ST_MTIME
]
140 lastupdate
, result
= cache
.get(filename
, (0, None))
141 if lastupdate
< mtime
:
142 info
= inspect
.getmoduleinfo(filename
)
143 file = open(filename
)
144 if info
and 'b' in info
[2]: # binary modules have to be imported
145 try: module
= imp
.load_module('__temp__', file, filename
, info
[1:])
147 result
= split(module
.__doc
__ or '', '\n')[0]
148 del sys
.modules
['__temp__']
149 else: # text modules can be directly examined
150 line
= file.readline()
151 while line
[:1] == '#' or not strip(line
):
152 line
= file.readline()
155 if line
[:4] == 'r"""': line
= line
[1:]
156 if line
[:3] == '"""':
158 if line
[-1:] == '\\': line
= line
[:-1]
159 while not strip(line
):
160 line
= file.readline()
162 result
= strip(split(line
, '"""')[0])
165 cache
[filename
] = (mtime
, result
)
168 class ErrorDuringImport(Exception):
169 """Errors that occurred while trying to import something to document it."""
170 def __init__(self
, filename
, (exc
, value
, tb
)):
171 self
.filename
= filename
178 if type(exc
) is types
.ClassType
:
180 return 'problem in %s - %s: %s' % (self
.filename
, exc
, self
.value
)
182 def importfile(path
):
183 """Import a Python source file or compiled file given its path."""
184 magic
= imp
.get_magic()
185 file = open(path
, 'r')
186 if file.read(len(magic
)) == magic
:
187 kind
= imp
.PY_COMPILED
191 filename
= os
.path
.basename(path
)
192 name
, ext
= os
.path
.splitext(filename
)
193 file = open(path
, 'r')
195 module
= imp
.load_module(name
, file, path
, (ext
, 'r', kind
))
197 raise ErrorDuringImport(path
, sys
.exc_info())
201 def safeimport(path
, forceload
=0, cache
={}):
202 """Import a module; handle errors; return None if the module isn't found.
204 If the module *is* found but an exception occurs, it's wrapped in an
205 ErrorDuringImport exception and reraised. Unlike __import__, if a
206 package path is specified, the module at the end of the path is returned,
207 not the package at the beginning. If the optional 'forceload' argument
208 is 1, we reload the module from disk (unless it's a dynamic extension)."""
209 if forceload
and sys
.modules
.has_key(path
):
210 # This is the only way to be sure. Checking the mtime of the file
211 # isn't good enough (e.g. what if the module contains a class that
212 # inherits from another module that has changed?).
213 if path
not in sys
.builtin_module_names
:
214 # Python never loads a dynamic extension a second time from the
215 # same path, even if the file is changed or missing. Deleting
216 # the entry in sys.modules doesn't help for dynamic extensions,
217 # so we're not even going to try to keep them up to date.
218 info
= inspect
.getmoduleinfo(sys
.modules
[path
].__file
__)
219 if info
[3] != imp
.C_EXTENSION
:
220 cache
[path
] = sys
.modules
[path
] # prevent module from clearing
221 del sys
.modules
[path
]
223 module
= __import__(path
)
225 # Did the error occur before or after the module was found?
226 (exc
, value
, tb
) = info
= sys
.exc_info()
227 if sys
.modules
.has_key(path
):
228 # An error occured while executing the imported module.
229 raise ErrorDuringImport(sys
.modules
[path
].__file
__, info
)
230 elif exc
is SyntaxError:
231 # A SyntaxError occurred before we could execute the module.
232 raise ErrorDuringImport(value
.filename
, info
)
233 elif exc
is ImportError and \
234 split(lower(str(value
)))[:2] == ['no', 'module']:
235 # The module was not found.
238 # Some other error occurred during the importing process.
239 raise ErrorDuringImport(path
, sys
.exc_info())
240 for part
in split(path
, '.')[1:]:
241 try: module
= getattr(module
, part
)
242 except AttributeError: return None
245 # ---------------------------------------------------- formatter base class
248 def document(self
, object, name
=None, *args
):
249 """Generate documentation for an object."""
250 args
= (object, name
) + args
251 if inspect
.ismodule(object): return apply(self
.docmodule
, args
)
252 if inspect
.isclass(object): return apply(self
.docclass
, args
)
253 if inspect
.isroutine(object): return apply(self
.docroutine
, args
)
254 return apply(self
.docother
, args
)
256 def fail(self
, object, name
=None, *args
):
257 """Raise an exception for unimplemented types."""
258 message
= "don't know how to document object%s of type %s" % (
259 name
and ' ' + repr(name
), type(object).__name
__)
260 raise TypeError, message
262 docmodule
= docclass
= docroutine
= docother
= fail
264 # -------------------------------------------- HTML documentation generator
266 class HTMLRepr(Repr
):
267 """Class for safely making an HTML representation of a Python object."""
270 self
.maxlist
= self
.maxtuple
= 20
272 self
.maxstring
= self
.maxother
= 100
274 def escape(self
, text
):
275 return replace(text
, '&', '&', '<', '<', '>', '>')
277 def repr(self
, object):
278 return Repr
.repr(self
, object)
280 def repr1(self
, x
, level
):
281 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
282 if hasattr(self
, methodname
):
283 return getattr(self
, methodname
)(x
, level
)
285 return self
.escape(cram(stripid(repr(x
)), self
.maxother
))
287 def repr_string(self
, x
, level
):
288 test
= cram(x
, self
.maxstring
)
289 testrepr
= repr(test
)
290 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
291 # Backslashes are only literal in the string and are never
292 # needed to make any special characters, so show a raw string.
293 return 'r' + testrepr
[0] + self
.escape(test
) + testrepr
[0]
294 return re
.sub(r
'((\\[\\abfnrtv\'"]|\\[0-9]..|\\x..|\\u....)+)',
295 r'<font color="#c040c0">\1</font>',
296 self
.escape(testrepr
))
298 def repr_instance(self
, x
, level
):
300 return self
.escape(cram(stripid(repr(x
)), self
.maxstring
))
302 return self
.escape('<%s instance>' % x
.__class
__.__name
__)
304 repr_unicode
= repr_string
307 """Formatter class for HTML documentation."""
309 # ------------------------------------------- HTML formatting utilities
311 _repr_instance
= HTMLRepr()
312 repr = _repr_instance
.repr
313 escape
= _repr_instance
.escape
315 def page(self
, title
, contents
):
316 """Format an HTML page."""
318 <!doctype html public "-//W3C//DTD HTML 4.0 Transitional//EN">
319 <html><head><title>Python: %s</title>
320 <style type="text/css"><!--
321 TT { font-family: lucidatypewriter, lucida console, courier }
322 --></style></head><body bgcolor="#f0f0f8">
324 </body></html>''' % (title
, contents
)
326 def heading(self
, title
, fgcol
, bgcol
, extras
=''):
327 """Format a page heading."""
329 <table width="100%%" cellspacing=0 cellpadding=2 border=0>
331 <td valign=bottom><small> <br></small
332 ><font color="%s" face="helvetica, arial"> <br>%s</font></td
333 ><td align=right valign=bottom
334 ><font color="%s" face="helvetica, arial">%s</font></td></tr></table>
335 ''' % (bgcol
, fgcol
, title
, fgcol
, extras
or ' ')
337 def section(self
, title
, fgcol
, bgcol
, contents
, width
=10,
338 prelude
='', marginalia
=None, gap
=' '):
339 """Format a section with a heading."""
340 if marginalia
is None:
341 marginalia
= '<tt>' + ' ' * width
+ '</tt>'
343 <p><table width="100%%" cellspacing=0 cellpadding=2 border=0>
345 <td colspan=3 valign=bottom><small><small> <br></small></small
346 ><font color="%s" face="helvetica, arial">%s</font></td></tr>
347 ''' % (bgcol
, fgcol
, title
)
349 result
= result
+ '''
350 <tr bgcolor="%s"><td rowspan=2>%s</td>
351 <td colspan=2>%s</td></tr>
352 <tr><td>%s</td>''' % (bgcol
, marginalia
, prelude
, gap
)
354 result
= result
+ '''
355 <tr><td bgcolor="%s">%s</td><td>%s</td>''' % (bgcol
, marginalia
, gap
)
357 return result
+ '\n<td width="100%%">%s</td></tr></table>' % contents
359 def bigsection(self
, title
, *args
):
360 """Format a section with a big heading."""
361 title
= '<big><strong>%s</strong></big>' % title
362 return apply(self
.section
, (title
,) + args
)
364 def preformat(self
, text
):
365 """Format literal preformatted text."""
366 text
= self
.escape(expandtabs(text
))
367 return replace(text
, '\n\n', '\n \n', '\n\n', '\n \n',
368 ' ', ' ', '\n', '<br>\n')
370 def multicolumn(self
, list, format
, cols
=4):
371 """Format a list of items into a multi-column list."""
373 rows
= (len(list)+cols
-1)/cols
374 for col
in range(cols
):
375 result
= result
+ '<td width="%d%%" valign=top>' % (100/cols
)
376 for i
in range(rows
*col
, rows
*col
+rows
):
378 result
= result
+ format(list[i
]) + '<br>\n'
379 result
= result
+ '</td>'
380 return '<table width="100%%"><tr>%s</tr></table>' % result
382 def small(self
, text
): return '<small>%s</small>' % text
383 def grey(self
, text
): return '<font color="#909090">%s</font>' % text
385 def namelink(self
, name
, *dicts
):
386 """Make a link for an identifier, given name-to-URL mappings."""
388 if dict.has_key(name
):
389 return '<a href="%s">%s</a>' % (dict[name
], name
)
392 def classlink(self
, object, modname
):
393 """Make a link for a class."""
394 name
, module
= object.__name
__, sys
.modules
.get(object.__module
__)
395 if hasattr(module
, name
) and getattr(module
, name
) is object:
396 return '<a href="%s.html#%s">%s</a>' % (
397 module
.__name
__, name
, classname(object, modname
))
398 return classname(object, modname
)
400 def modulelink(self
, object):
401 """Make a link for a module."""
402 return '<a href="%s.html">%s</a>' % (object.__name
__, object.__name
__)
404 def modpkglink(self
, (name
, path
, ispackage
, shadowed
)):
405 """Make a link for a module or package to display in an index."""
407 return self
.grey(name
)
409 url
= '%s.%s.html' % (path
, name
)
411 url
= '%s.html' % name
413 text
= '<strong>%s</strong> (package)' % name
416 return '<a href="%s">%s</a>' % (url
, text
)
418 def markup(self
, text
, escape
=None, funcs
={}, classes
={}, methods
={}):
419 """Mark up some plain text, given a context of symbols to look for.
420 Each context dictionary maps object names to anchor names."""
421 escape
= escape
or self
.escape
424 pattern
= re
.compile(r
'\b((http|ftp)://\S+[\w/]|'
427 r
'(self\.)?(\w+))\b')
429 match
= pattern
.search(text
, here
)
431 start
, end
= match
.span()
432 results
.append(escape(text
[here
:start
]))
434 all
, scheme
, rfc
, pep
, selfdot
, name
= match
.groups()
436 results
.append('<a href="%s">%s</a>' % (all
, escape(all
)))
438 url
= 'http://www.rfc-editor.org/rfc/rfc%d.txt' % int(rfc
)
439 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
441 url
= 'http://www.python.org/peps/pep-%04d.html' % int(pep
)
442 results
.append('<a href="%s">%s</a>' % (url
, escape(all
)))
443 elif text
[end
:end
+1] == '(':
444 results
.append(self
.namelink(name
, methods
, funcs
, classes
))
446 results
.append('self.<strong>%s</strong>' % name
)
448 results
.append(self
.namelink(name
, classes
))
450 results
.append(escape(text
[here
:]))
451 return join(results
, '')
453 # ---------------------------------------------- type-specific routines
455 def formattree(self
, tree
, modname
, parent
=None):
456 """Produce HTML for a class tree as given by inspect.getclasstree()."""
459 if type(entry
) is type(()):
461 result
= result
+ '<dt><font face="helvetica, arial"><small>'
462 result
= result
+ self
.classlink(c
, modname
)
463 if bases
and bases
!= (parent
,):
466 parents
.append(self
.classlink(base
, modname
))
467 result
= result
+ '(' + join(parents
, ', ') + ')'
468 result
= result
+ '\n</small></font></dt>'
469 elif type(entry
) is type([]):
470 result
= result
+ '<dd>\n%s</dd>\n' % self
.formattree(
472 return '<dl>\n%s</dl>\n' % result
474 def docmodule(self
, object, name
=None, mod
=None):
475 """Produce HTML documentation for a module object."""
476 name
= object.__name
__ # ignore the passed-in name
477 parts
= split(name
, '.')
479 for i
in range(len(parts
)-1):
481 '<a href="%s.html"><font color="#ffffff">%s</font></a>' %
482 (join(parts
[:i
+1], '.'), parts
[i
]))
483 linkedname
= join(links
+ parts
[-1:], '.')
484 head
= '<big><big><strong>%s</strong></big></big>' % linkedname
486 path
= inspect
.getabsfile(object)
488 if sys
.platform
== 'win32':
490 url
= nturl2path
.pathname2url(path
)
491 filelink
= '<a href="file:%s">%s</a>' % (url
, path
)
493 filelink
= '(built-in)'
495 if hasattr(object, '__version__'):
496 version
= str(object.__version
__)
497 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
498 version
= strip(version
[11:-1])
499 info
.append('version %s' % self
.escape(version
))
500 if hasattr(object, '__date__'):
501 info
.append(self
.escape(str(object.__date
__)))
503 head
= head
+ ' (%s)' % join(info
, ', ')
504 result
= self
.heading(
505 head
, '#ffffff', '#7799ee', '<a href=".">index</a><br>' + filelink
)
507 modules
= inspect
.getmembers(object, inspect
.ismodule
)
509 classes
, cdict
= [], {}
510 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
511 if (inspect
.getmodule(value
) or object) is object:
512 classes
.append((key
, value
))
513 cdict
[key
] = cdict
[value
] = '#' + key
514 for key
, value
in classes
:
515 for base
in value
.__bases
__:
516 key
, modname
= base
.__name
__, base
.__module
__
517 module
= sys
.modules
.get(modname
)
518 if modname
!= name
and module
and hasattr(module
, key
):
519 if getattr(module
, key
) is base
:
520 if not cdict
.has_key(key
):
521 cdict
[key
] = cdict
[base
] = modname
+ '.html#' + key
522 funcs
, fdict
= [], {}
523 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
524 if inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object:
525 funcs
.append((key
, value
))
526 fdict
[key
] = '#-' + key
527 if inspect
.isfunction(value
): fdict
[value
] = fdict
[key
]
529 for key
, value
in inspect
.getmembers(object, isdata
):
530 if key
not in ['__builtins__', '__doc__']:
531 data
.append((key
, value
))
533 doc
= self
.markup(getdoc(object), self
.preformat
, fdict
, cdict
)
534 doc
= doc
and '<tt>%s</tt>' % doc
535 result
= result
+ '<p>%s</p>\n' % self
.small(doc
)
537 if hasattr(object, '__path__'):
540 for file in os
.listdir(object.__path
__[0]):
541 path
= os
.path
.join(object.__path
__[0], file)
542 modname
= inspect
.getmodulename(file)
543 if modname
and modname
not in modnames
:
544 modpkgs
.append((modname
, name
, 0, 0))
545 modnames
.append(modname
)
546 elif ispackage(path
):
547 modpkgs
.append((file, name
, 1, 0))
549 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
550 result
= result
+ self
.bigsection(
551 'Package Contents', '#ffffff', '#aa55cc', contents
)
553 contents
= self
.multicolumn(
554 modules
, lambda (key
, value
), s
=self
: s
.modulelink(value
))
555 result
= result
+ self
.bigsection(
556 'Modules', '#fffff', '#aa55cc', contents
)
559 classlist
= map(lambda (key
, value
): value
, classes
)
561 self
.formattree(inspect
.getclasstree(classlist
, 1), name
)]
562 for key
, value
in classes
:
563 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
564 result
= result
+ self
.bigsection(
565 'Classes', '#ffffff', '#ee77aa', join(contents
))
568 for key
, value
in funcs
:
569 contents
.append(self
.document(value
, key
, name
, fdict
, cdict
))
570 result
= result
+ self
.bigsection(
571 'Functions', '#ffffff', '#eeaa77', join(contents
))
574 for key
, value
in data
:
575 contents
.append(self
.document(value
, key
))
576 result
= result
+ self
.bigsection(
577 'Data', '#ffffff', '#55aa55', join(contents
, '<br>\n'))
578 if hasattr(object, '__author__'):
579 contents
= self
.markup(str(object.__author
__), self
.preformat
)
580 result
= result
+ self
.bigsection(
581 'Author', '#ffffff', '#7799ee', contents
)
582 if hasattr(object, '__credits__'):
583 contents
= self
.markup(str(object.__credits
__), self
.preformat
)
584 result
= result
+ self
.bigsection(
585 'Credits', '#ffffff', '#7799ee', contents
)
589 def docclass(self
, object, name
=None, mod
=None, funcs
={}, classes
={}):
590 """Produce HTML documentation for a class object."""
591 realname
= object.__name
__
592 name
= name
or realname
593 bases
= object.__bases
__
596 methods
, mdict
= allmethods(object).items(), {}
598 for key
, value
in methods
:
599 mdict
[key
] = mdict
[value
] = '#' + name
+ '-' + key
600 for key
, value
in methods
:
601 contents
= contents
+ self
.document(
602 value
, key
, mod
, funcs
, classes
, mdict
, object)
605 title
= '<a name="%s">class <strong>%s</strong></a>' % (
608 title
= '<strong>%s</strong> = <a name="%s">class %s</a>' % (
609 name
, name
, realname
)
613 parents
.append(self
.classlink(base
, object.__module
__))
614 title
= title
+ '(%s)' % join(parents
, ', ')
616 getdoc(object), self
.preformat
, funcs
, classes
, mdict
)
617 doc
= self
.small(doc
and '<tt>%s<br> </tt>' % doc
or
618 self
.small(' '))
619 return self
.section(title
, '#000000', '#ffc8d8', contents
, 5, doc
)
621 def formatvalue(self
, object):
622 """Format an argument default value as text."""
623 return self
.small(self
.grey('=' + self
.repr(object)))
625 def docroutine(self
, object, name
=None, mod
=None,
626 funcs
={}, classes
={}, methods
={}, cl
=None):
627 """Produce HTML documentation for a function or method object."""
628 realname
= object.__name
__
629 name
= name
or realname
630 anchor
= (cl
and cl
.__name
__ or '') + '-' + name
633 if inspect
.ismethod(object):
634 imclass
= object.im_class
636 if imclass
is not cl
:
637 note
= ' from ' + self
.classlink(imclass
, mod
)
641 note
= ' method of %s instance' % self
.classlink(
642 object.im_self
.__class
__, mod
)
644 note
= ' unbound %s method' % self
.classlink(imclass
,mod
)
645 object = object.im_func
648 title
= '<a name="%s"><strong>%s</strong></a>' % (anchor
, realname
)
650 if (cl
and cl
.__dict
__.has_key(realname
) and
651 cl
.__dict
__[realname
] is object):
652 reallink
= '<a href="#%s">%s</a>' % (
653 cl
.__name
__ + '-' + realname
, realname
)
657 title
= '<a name="%s"><strong>%s</strong></a> = %s' % (
658 anchor
, name
, reallink
)
659 if inspect
.isbuiltin(object):
662 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
663 argspec
= inspect
.formatargspec(
664 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
665 if realname
== '<lambda>':
666 decl
= '<em>lambda</em>'
667 argspec
= argspec
[1:-1] # remove parentheses
669 decl
= title
+ argspec
+ (note
and self
.small(self
.grey(
670 '<font face="helvetica, arial">%s</font>' % note
)))
673 return '<dl><dt>%s</dl>\n' % decl
676 getdoc(object), self
.preformat
, funcs
, classes
, methods
)
677 doc
= doc
and '<dd>' + self
.small('<tt>%s</tt>' % doc
)
678 return '<dl><dt>%s%s</dl>\n' % (decl
, doc
)
680 def docother(self
, object, name
=None, mod
=None):
681 """Produce HTML documentation for a data object."""
682 lhs
= name
and '<strong>%s</strong> = ' % name
or ''
683 return lhs
+ self
.repr(object)
685 def index(self
, dir, shadowed
=None):
686 """Generate an HTML index for a directory of modules."""
688 if shadowed
is None: shadowed
= {}
690 files
= os
.listdir(dir)
692 def found(name
, ispackage
,
693 modpkgs
=modpkgs
, shadowed
=shadowed
, seen
=seen
):
694 if not seen
.has_key(name
):
695 modpkgs
.append((name
, '', ispackage
, shadowed
.has_key(name
)))
699 # Package spam/__init__.py takes precedence over module spam.py.
701 path
= os
.path
.join(dir, file)
702 if ispackage(path
): found(file, 1)
704 path
= os
.path
.join(dir, file)
705 if os
.path
.isfile(path
):
706 modname
= inspect
.getmodulename(file)
707 if modname
: found(modname
, 0)
710 contents
= self
.multicolumn(modpkgs
, self
.modpkglink
)
711 return self
.bigsection(dir, '#ffffff', '#ee77aa', contents
)
713 # -------------------------------------------- text documentation generator
715 class TextRepr(Repr
):
716 """Class for safely making a text representation of a Python object."""
719 self
.maxlist
= self
.maxtuple
= 20
721 self
.maxstring
= self
.maxother
= 100
723 def repr1(self
, x
, level
):
724 methodname
= 'repr_' + join(split(type(x
).__name
__), '_')
725 if hasattr(self
, methodname
):
726 return getattr(self
, methodname
)(x
, level
)
728 return cram(stripid(repr(x
)), self
.maxother
)
730 def repr_string(self
, x
, level
):
731 test
= cram(x
, self
.maxstring
)
732 testrepr
= repr(test
)
733 if '\\' in test
and '\\' not in replace(testrepr
, r
'\\', ''):
734 # Backslashes are only literal in the string and are never
735 # needed to make any special characters, so show a raw string.
736 return 'r' + testrepr
[0] + test
+ testrepr
[0]
739 def repr_instance(self
, x
, level
):
741 return cram(stripid(repr(x
)), self
.maxstring
)
743 return '<%s instance>' % x
.__class
__.__name
__
746 """Formatter class for text documentation."""
748 # ------------------------------------------- text formatting utilities
750 _repr_instance
= TextRepr()
751 repr = _repr_instance
.repr
753 def bold(self
, text
):
754 """Format a string in bold by overstriking."""
755 return join(map(lambda ch
: ch
+ '\b' + ch
, text
), '')
757 def indent(self
, text
, prefix
=' '):
758 """Indent text by prepending a given prefix to each line."""
759 if not text
: return ''
760 lines
= split(text
, '\n')
761 lines
= map(lambda line
, prefix
=prefix
: prefix
+ line
, lines
)
762 if lines
: lines
[-1] = rstrip(lines
[-1])
763 return join(lines
, '\n')
765 def section(self
, title
, contents
):
766 """Format a section with a given heading."""
767 return self
.bold(title
) + '\n' + rstrip(self
.indent(contents
)) + '\n\n'
769 # ---------------------------------------------- type-specific routines
771 def formattree(self
, tree
, modname
, parent
=None, prefix
=''):
772 """Render in text a class tree as returned by inspect.getclasstree()."""
775 if type(entry
) is type(()):
777 result
= result
+ prefix
+ classname(c
, modname
)
778 if bases
and bases
!= (parent
,):
779 parents
= map(lambda c
, m
=modname
: classname(c
, m
), bases
)
780 result
= result
+ '(%s)' % join(parents
, ', ')
781 result
= result
+ '\n'
782 elif type(entry
) is type([]):
783 result
= result
+ self
.formattree(
784 entry
, modname
, c
, prefix
+ ' ')
787 def docmodule(self
, object, name
=None, mod
=None):
788 """Produce text documentation for a given module object."""
789 name
= object.__name
__ # ignore the passed-in name
790 synop
, desc
= splitdoc(getdoc(object))
791 result
= self
.section('NAME', name
+ (synop
and ' - ' + synop
))
794 file = inspect
.getabsfile(object)
797 result
= result
+ self
.section('FILE', file)
799 result
= result
+ self
.section('DESCRIPTION', desc
)
802 for key
, value
in inspect
.getmembers(object, inspect
.isclass
):
803 if (inspect
.getmodule(value
) or object) is object:
804 classes
.append((key
, value
))
806 for key
, value
in inspect
.getmembers(object, inspect
.isroutine
):
807 if inspect
.isbuiltin(value
) or inspect
.getmodule(value
) is object:
808 funcs
.append((key
, value
))
810 for key
, value
in inspect
.getmembers(object, isdata
):
811 if key
not in ['__builtins__', '__doc__']:
812 data
.append((key
, value
))
814 if hasattr(object, '__path__'):
816 for file in os
.listdir(object.__path
__[0]):
817 path
= os
.path
.join(object.__path
__[0], file)
818 modname
= inspect
.getmodulename(file)
819 if modname
and modname
not in modpkgs
:
820 modpkgs
.append(modname
)
821 elif ispackage(path
):
822 modpkgs
.append(file + ' (package)')
824 result
= result
+ self
.section(
825 'PACKAGE CONTENTS', join(modpkgs
, '\n'))
828 classlist
= map(lambda (key
, value
): value
, classes
)
829 contents
= [self
.formattree(
830 inspect
.getclasstree(classlist
, 1), name
)]
831 for key
, value
in classes
:
832 contents
.append(self
.document(value
, key
, name
))
833 result
= result
+ self
.section('CLASSES', join(contents
, '\n'))
837 for key
, value
in funcs
:
838 contents
.append(self
.document(value
, key
, name
))
839 result
= result
+ self
.section('FUNCTIONS', join(contents
, '\n'))
843 for key
, value
in data
:
844 contents
.append(self
.docother(value
, key
, name
, 70))
845 result
= result
+ self
.section('DATA', join(contents
, '\n'))
847 if hasattr(object, '__version__'):
848 version
= str(object.__version
__)
849 if version
[:11] == '$' + 'Revision: ' and version
[-1:] == '$':
850 version
= strip(version
[11:-1])
851 result
= result
+ self
.section('VERSION', version
)
852 if hasattr(object, '__date__'):
853 result
= result
+ self
.section('DATE', str(object.__date
__))
854 if hasattr(object, '__author__'):
855 result
= result
+ self
.section('AUTHOR', str(object.__author
__))
856 if hasattr(object, '__credits__'):
857 result
= result
+ self
.section('CREDITS', str(object.__credits
__))
860 def docclass(self
, object, name
=None, mod
=None):
861 """Produce text documentation for a given class object."""
862 realname
= object.__name
__
863 name
= name
or realname
864 bases
= object.__bases
__
867 title
= 'class ' + self
.bold(realname
)
869 title
= self
.bold(name
) + ' = class ' + realname
871 def makename(c
, m
=object.__module
__): return classname(c
, m
)
872 parents
= map(makename
, bases
)
873 title
= title
+ '(%s)' % join(parents
, ', ')
876 contents
= doc
and doc
+ '\n'
877 methods
= allmethods(object).items()
879 for key
, value
in methods
:
880 contents
= contents
+ '\n' + self
.document(value
, key
, mod
, object)
882 if not contents
: return title
+ '\n'
883 return title
+ '\n' + self
.indent(rstrip(contents
), ' | ') + '\n'
885 def formatvalue(self
, object):
886 """Format an argument default value as text."""
887 return '=' + self
.repr(object)
889 def docroutine(self
, object, name
=None, mod
=None, cl
=None):
890 """Produce text documentation for a function or method object."""
891 realname
= object.__name
__
892 name
= name
or realname
895 if inspect
.ismethod(object):
896 imclass
= object.im_class
898 if imclass
is not cl
:
899 note
= ' from ' + classname(imclass
, mod
)
903 note
= ' method of %s instance' % classname(
904 object.im_self
.__class
__, mod
)
906 note
= ' unbound %s method' % classname(imclass
,mod
)
907 object = object.im_func
910 title
= self
.bold(realname
)
912 if (cl
and cl
.__dict
__.has_key(realname
) and
913 cl
.__dict
__[realname
] is object):
915 title
= self
.bold(name
) + ' = ' + realname
916 if inspect
.isbuiltin(object):
919 args
, varargs
, varkw
, defaults
= inspect
.getargspec(object)
920 argspec
= inspect
.formatargspec(
921 args
, varargs
, varkw
, defaults
, formatvalue
=self
.formatvalue
)
922 if realname
== '<lambda>':
924 argspec
= argspec
[1:-1] # remove parentheses
925 decl
= title
+ argspec
+ note
930 doc
= getdoc(object) or ''
931 return decl
+ '\n' + (doc
and rstrip(self
.indent(doc
)) + '\n')
933 def docother(self
, object, name
=None, mod
=None, maxlen
=None):
934 """Produce text documentation for a data object."""
935 repr = self
.repr(object)
937 line
= (name
and name
+ ' = ' or '') + repr
938 chop
= maxlen
- len(line
)
939 if chop
< 0: repr = repr[:chop
] + '...'
940 line
= (name
and self
.bold(name
) + ' = ' or '') + repr
943 # --------------------------------------------------------- user interfaces
946 """The first time this is called, determine what kind of pager to use."""
952 """Decide what method to use for paging through text."""
953 if type(sys
.stdout
) is not types
.FileType
:
955 if not sys
.stdin
.isatty() or not sys
.stdout
.isatty():
957 if os
.environ
.has_key('PAGER'):
958 if sys
.platform
== 'win32': # pipes completely broken in Windows
959 return lambda text
: tempfilepager(plain(text
), os
.environ
['PAGER'])
960 elif os
.environ
.get('TERM') in ['dumb', 'emacs']:
961 return lambda text
: pipepager(plain(text
), os
.environ
['PAGER'])
963 return lambda text
: pipepager(text
, os
.environ
['PAGER'])
964 if sys
.platform
== 'win32':
965 return lambda text
: tempfilepager(plain(text
), 'more <')
966 if hasattr(os
, 'system') and os
.system('less 2>/dev/null') == 0:
967 return lambda text
: pipepager(text
, 'less')
970 filename
= tempfile
.mktemp()
971 open(filename
, 'w').close()
973 if hasattr(os
, 'system') and os
.system('more %s' % filename
) == 0:
974 return lambda text
: pipepager(text
, 'more')
981 """Remove boldface formatting from text."""
982 return re
.sub('.\b', '', text
)
984 def pipepager(text
, cmd
):
985 """Page through text by feeding it to another program."""
986 pipe
= os
.popen(cmd
, 'w')
991 pass # Ignore broken pipes caused by quitting the pager program.
993 def tempfilepager(text
, cmd
):
994 """Page through text by invoking a program on a temporary file."""
996 filename
= tempfile
.mktemp()
997 file = open(filename
, 'w')
1001 os
.system(cmd
+ ' ' + filename
)
1006 """Page through text on a text terminal."""
1007 lines
= split(plain(text
), '\n')
1010 fd
= sys
.stdin
.fileno()
1011 old
= tty
.tcgetattr(fd
)
1013 getchar
= lambda: sys
.stdin
.read(1)
1014 except (ImportError, AttributeError):
1016 getchar
= lambda: sys
.stdin
.readline()[:-1][:1]
1019 r
= inc
= os
.environ
.get('LINES', 25) - 1
1020 sys
.stdout
.write(join(lines
[:inc
], '\n') + '\n')
1022 sys
.stdout
.write('-- more --')
1027 sys
.stdout
.write('\r \r')
1029 elif c
in ['\r', '\n']:
1030 sys
.stdout
.write('\r \r' + lines
[r
] + '\n')
1033 if c
in ['b', 'B', '\x1b']:
1036 sys
.stdout
.write('\n' + join(lines
[r
:r
+inc
], '\n') + '\n')
1041 tty
.tcsetattr(fd
, tty
.TCSAFLUSH
, old
)
1043 def plainpager(text
):
1044 """Simply print unformatted text. This is the ultimate fallback."""
1045 sys
.stdout
.write(plain(text
))
1047 def describe(thing
):
1048 """Produce a short description of the given thing."""
1049 if inspect
.ismodule(thing
):
1050 if thing
.__name
__ in sys
.builtin_module_names
:
1051 return 'built-in module ' + thing
.__name
__
1052 if hasattr(thing
, '__path__'):
1053 return 'package ' + thing
.__name
__
1055 return 'module ' + thing
.__name
__
1056 if inspect
.isbuiltin(thing
):
1057 return 'built-in function ' + thing
.__name
__
1058 if inspect
.isclass(thing
):
1059 return 'class ' + thing
.__name
__
1060 if inspect
.isfunction(thing
):
1061 return 'function ' + thing
.__name
__
1062 if inspect
.ismethod(thing
):
1063 return 'method ' + thing
.__name
__
1064 if type(thing
) is types
.InstanceType
:
1065 return 'instance of ' + thing
.__class
__.__name
__
1066 return type(thing
).__name
__
1068 def locate(path
, forceload
=0):
1069 """Locate an object by name or dotted path, importing as necessary."""
1070 parts
= split(path
, '.')
1072 while n
< len(parts
):
1073 nextmodule
= safeimport(join(parts
[:n
+1], '.'), forceload
)
1074 if nextmodule
: module
, n
= nextmodule
, n
+ 1
1078 for part
in parts
[n
:]:
1079 try: object = getattr(object, part
)
1080 except AttributeError: return None
1084 if hasattr(__builtin__
, path
):
1085 return getattr(__builtin__
, path
)
1087 # --------------------------------------- interactive interpreter interface
1092 def doc(thing
, title
='Python Library Documentation: %s', forceload
=0):
1093 """Display text documentation, given an object or a path to an object."""
1094 suffix
, name
= '', None
1095 if type(thing
) is type(''):
1097 object = locate(thing
, forceload
)
1098 except ErrorDuringImport
, value
:
1102 print 'no Python documentation found for %s' % repr(thing
)
1104 parts
= split(thing
, '.')
1105 if len(parts
) > 1: suffix
= ' in ' + join(parts
[:-1], '.')
1109 desc
= describe(thing
)
1110 module
= inspect
.getmodule(thing
)
1111 if not suffix
and module
and module
is not thing
:
1112 suffix
= ' in module ' + module
.__name
__
1113 pager(title
% (desc
+ suffix
) + '\n\n' + text
.document(thing
, name
))
1115 def writedoc(key
, forceload
=0):
1116 """Write HTML documentation to a file in the current directory."""
1118 object = locate(key
, forceload
)
1119 except ErrorDuringImport
, value
:
1123 page
= html
.page(describe(object),
1124 html
.document(object, object.__name
__))
1125 file = open(key
+ '.html', 'w')
1128 print 'wrote', key
+ '.html'
1130 print 'no Python documentation found for %s' % repr(key
)
1132 def writedocs(dir, pkgpath
='', done
=None):
1133 """Write out HTML documentation for all modules in a directory tree."""
1134 if done
is None: done
= {}
1135 for file in os
.listdir(dir):
1136 path
= os
.path
.join(dir, file)
1138 writedocs(path
, pkgpath
+ file + '.', done
)
1139 elif os
.path
.isfile(path
):
1140 modname
= inspect
.getmodulename(path
)
1142 modname
= pkgpath
+ modname
1143 if not done
.has_key(modname
):
1150 'assert': ('ref/assert', ''),
1151 'break': ('ref/break', 'while for'),
1152 'class': ('ref/class', 'CLASSES SPECIALMETHODS'),
1153 'continue': ('ref/continue', 'while for'),
1154 'def': ('ref/function', ''),
1155 'del': ('ref/del', 'BASICMETHODS'),
1157 'else': ('ref/if', 'while for'),
1159 'exec': ('ref/exec', ''),
1161 'for': ('ref/for', 'break continue while'),
1163 'global': ('ref/global', 'NAMESPACES'),
1164 'if': ('ref/if', 'TRUTHVALUE'),
1165 'import': ('ref/import', 'MODULES'),
1166 'in': ('ref/comparisons', 'SEQUENCEMETHODS2'),
1168 'lambda': ('ref/lambda', 'FUNCTIONS'),
1172 'print': ('ref/print', ''),
1173 'raise': ('ref/raise', 'EXCEPTIONS'),
1174 'return': ('ref/return', 'FUNCTIONS'),
1175 'try': ('ref/try', 'EXCEPTIONS'),
1176 'while': ('ref/while', 'break continue if TRUTHVALUE'),
1180 'TYPES': ('ref/types', 'STRINGS UNICODE NUMBERS SEQUENCES MAPPINGS FUNCTIONS CLASSES MODULES FILES inspect'),
1181 'STRINGS': ('ref/strings', 'str UNICODE SEQUENCES STRINGMETHODS FORMATTING TYPES'),
1182 'STRINGMETHODS': ('lib/string-methods', 'STRINGS FORMATTING'),
1183 'FORMATTING': ('lib/typesseq-strings', 'OPERATORS'),
1184 'UNICODE': ('ref/unicode', 'encodings unicode TYPES STRING'),
1185 'NUMBERS': ('ref/numbers', 'INTEGER FLOAT COMPLEX TYPES'),
1186 'INTEGER': ('ref/integers', 'int range'),
1187 'FLOAT': ('ref/floating', 'float math'),
1188 'COMPLEX': ('ref/imaginary', 'complex cmath'),
1189 'SEQUENCES': ('lib/typesseq', 'STRINGMETHODS FORMATTING xrange LISTS'),
1190 'MAPPINGS': 'DICTIONARIES',
1191 'FUNCTIONS': ('lib/typesfunctions', 'def TYPES'),
1192 'METHODS': ('lib/typesmethods', 'class def CLASSES TYPES'),
1193 'CODEOBJECTS': ('lib/bltin-code-objects', 'compile FUNCTIONS TYPES'),
1194 'TYPEOBJECTS': ('lib/bltin-type-objects', 'types TYPES'),
1195 'FRAMEOBJECTS': 'TYPES',
1196 'TRACEBACKS': 'TYPES',
1197 'NONE': ('lib/bltin-null-object', ''),
1198 'ELLIPSIS': ('lib/bltin-ellipsis-object', 'SLICINGS'),
1199 'FILES': ('lib/bltin-file-objects', ''),
1200 'SPECIALATTRIBUTES': ('lib/specialattrs', ''),
1201 'CLASSES': ('ref/types', 'class SPECIALMETHODS PRIVATENAMES'),
1202 'MODULES': ('lib/typesmodules', 'import'),
1203 'PACKAGES': 'import',
1204 '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'),
1205 'OPERATORS': 'EXPRESSIONS',
1206 'PRECEDENCE': 'EXPRESSIONS',
1207 'OBJECTS': ('ref/objects', 'TYPES'),
1208 'SPECIALMETHODS': ('ref/specialnames', 'BASICMETHODS ATTRIBUTEMETHODS CALLABLEMETHODS SEQUENCEMETHODS1 MAPPINGMETHODS SEQUENCEMETHODS2 NUMBERMETHODS CLASSES'),
1209 'BASICMETHODS': ('ref/customization', 'cmp hash repr str SPECIALMETHODS'),
1210 'ATTRIBUTEMETHODS': ('ref/attribute-access', 'ATTRIBUTES SPECIALMETHODS'),
1211 'CALLABLEMETHODS': ('ref/callable-types', 'CALLS SPECIALMETHODS'),
1212 'SEQUENCEMETHODS1': ('ref/sequence-types', 'SEQUENCES SEQUENCEMETHODS2 SPECIALMETHODS'),
1213 'SEQUENCEMETHODS2': ('ref/sequence-methods', 'SEQUENCES SEQUENCEMETHODS1 SPECIALMETHODS'),
1214 'MAPPINGMETHODS': ('ref/sequence-types', 'MAPPINGS SPECIALMETHODS'),
1215 'NUMBERMETHODS': ('ref/numeric-types', 'NUMBERS AUGMENTEDASSIGNMENT SPECIALMETHODS'),
1216 'EXECUTION': ('ref/execframes', ''),
1217 'NAMESPACES': ('ref/execframes', 'global ASSIGNMENT DELETION'),
1218 'SCOPING': 'NAMESPACES',
1219 'FRAMES': 'NAMESPACES',
1220 'EXCEPTIONS': ('ref/exceptions', 'try except finally raise'),
1221 'COERCIONS': 'CONVERSIONS',
1222 'CONVERSIONS': ('ref/conversions', ''),
1223 'IDENTIFIERS': ('ref/identifiers', 'keywords SPECIALIDENTIFIERS'),
1224 'SPECIALIDENTIFIERS': ('ref/id-classes', ''),
1225 'PRIVATENAMES': ('ref/atom-identifiers', ''),
1226 'LITERALS': ('ref/atom-literals', 'STRINGS BACKQUOTES NUMBERS TUPLELITERALS LISTLITERALS DICTIONARYLITERALS'),
1227 'TUPLES': 'SEQUENCES',
1228 'TUPLELITERALS': ('ref/exprlists', 'TUPLES LITERALS'),
1229 'LISTS': ('lib/typesseq-mutable', 'LISTLITERALS'),
1230 'LISTLITERALS': ('ref/lists', 'LISTS LITERALS'),
1231 'DICTIONARIES': ('lib/typesmapping', 'DICTIONARYLITERALS'),
1232 'DICTIONARYLITERALS': ('ref/dict', 'DICTIONARIES LITERALS'),
1233 'BACKQUOTES': ('ref/string-conversions', 'repr str STRINGS LITERALS'),
1234 'ATTRIBUTES': ('ref/attribute-references', 'getattr hasattr setattr ATTRIBUTEMETHODS'),
1235 'SUBSCRIPTS': ('ref/subscriptions', 'SEQUENCEMETHODS1'),
1236 'SLICINGS': ('ref/slicings', 'SEQUENCEMETHODS2'),
1237 'CALLS': ('ref/calls', 'EXPRESSIONS'),
1238 'POWER': ('ref/power', 'EXPRESSIONS'),
1239 'UNARY': ('ref/unary', 'EXPRESSIONS'),
1240 'BINARY': ('ref/binary', 'EXPRESSIONS'),
1241 'SHIFTING': ('ref/shifting', 'EXPRESSIONS'),
1242 'BITWISE': ('ref/bitwise', 'EXPRESSIONS'),
1243 'COMPARISON': ('ref/comparisons', 'EXPRESSIONS BASICMETHODS'),
1244 'BOOLEAN': ('ref/lambda', 'EXPRESSIONS TRUTHVALUE'),
1245 'ASSERTION': 'assert',
1246 'ASSIGNMENT': ('ref/assignment', 'AUGMENTEDASSIGNMENT'),
1247 'AUGMENTEDASSIGNMENT': ('ref/augassign', 'NUMBERMETHODS'),
1249 'PRINTING': 'print',
1250 'RETURNING': 'return',
1251 'IMPORTING': 'import',
1252 'CONDITIONAL': 'if',
1253 'LOOPING': ('ref/compound', 'for while break continue'),
1254 'TRUTHVALUE': ('lib/truth', 'if while and or not BASICMETHODS'),
1255 'DEBUGGING': ('lib/module-pdb', 'pdb'),
1258 def __init__(self
, input, output
):
1260 self
.output
= output
1262 execdir
= os
.path
.dirname(sys
.executable
)
1263 homedir
= os
.environ
.get('PYTHONHOME')
1264 for dir in [os
.environ
.get('PYTHONDOCS'),
1265 homedir
and os
.path
.join(homedir
, 'doc'),
1266 os
.path
.join(execdir
, 'doc'),
1267 '/usr/doc/python-docs-' + split(sys
.version
)[0],
1268 '/usr/doc/python-' + split(sys
.version
)[0],
1269 '/usr/doc/python-docs-' + sys
.version
[:3],
1270 '/usr/doc/python-' + sys
.version
[:3]]:
1271 if dir and os
.path
.isdir(os
.path
.join(dir, 'lib')):
1275 if inspect
.stack()[1][3] == '?':
1278 return '<pydoc.Helper instance>'
1280 def __call__(self
, request
=None):
1281 if request
is not None:
1286 self
.output
.write('''
1287 You're now leaving help and returning to the Python interpreter.
1288 If you want to ask for help on a particular object directly from the
1289 interpreter, you can type "help(object)". Executing "help('string')"
1290 has the same effect as typing a particular string at the help> prompt.
1294 self
.output
.write('\n')
1296 self
.output
.write('help> ')
1299 request
= self
.input.readline()
1300 if not request
: break
1301 except KeyboardInterrupt: break
1302 request
= strip(replace(request
, '"', '', "'", ''))
1303 if lower(request
) in ['q', 'quit']: break
1306 def help(self
, request
):
1307 if type(request
) is type(''):
1308 if request
== 'help': self
.intro()
1309 elif request
== 'keywords': self
.listkeywords()
1310 elif request
== 'topics': self
.listtopics()
1311 elif request
== 'modules': self
.listmodules()
1312 elif request
[:8] == 'modules ':
1313 self
.listmodules(split(request
)[1])
1314 elif self
.keywords
.has_key(request
): self
.showtopic(request
)
1315 elif self
.topics
.has_key(request
): self
.showtopic(request
)
1316 elif request
: doc(request
, 'Help on %s:')
1317 elif isinstance(request
, Helper
): self()
1318 else: doc(request
, 'Help on %s:')
1319 self
.output
.write('\n')
1322 self
.output
.write('''
1323 Welcome to Python %s! This is the online help utility.
1325 If this is your first time using Python, you should definitely check out
1326 the tutorial on the Internet at http://www.python.org/doc/tut/.
1328 Enter the name of any module, keyword, or topic to get help on writing
1329 Python programs and using Python modules. To quit this help utility and
1330 return to the interpreter, just type "quit".
1332 To get a list of available modules, keywords, or topics, type "modules",
1333 "keywords", or "topics". Each module also comes with a one-line summary
1334 of what it does; to list the modules whose summaries contain a given word
1335 such as "spam", type "modules spam".
1336 ''' % sys
.version
[:3])
1338 def list(self
, items
, columns
=4, width
=80):
1341 colw
= width
/ columns
1342 rows
= (len(items
) + columns
- 1) / columns
1343 for row
in range(rows
):
1344 for col
in range(columns
):
1345 i
= col
* rows
+ row
1347 self
.output
.write(items
[i
])
1348 if col
< columns
- 1:
1349 self
.output
.write(' ' + ' ' * (colw
-1 - len(items
[i
])))
1350 self
.output
.write('\n')
1352 def listkeywords(self
):
1353 self
.output
.write('''
1354 Here is a list of the Python keywords. Enter any keyword to get more help.
1357 self
.list(self
.keywords
.keys())
1359 def listtopics(self
):
1360 self
.output
.write('''
1361 Here is a list of available topics. Enter any topic name to get more help.
1364 self
.list(self
.topics
.keys())
1366 def showtopic(self
, topic
):
1368 self
.output
.write('''
1369 Sorry, topic and keyword documentation is not available because the Python
1370 HTML documentation files could not be found. If you have installed them,
1371 please set the environment variable PYTHONDOCS to indicate their location.
1374 target
= self
.topics
.get(topic
, self
.keywords
.get(topic
))
1376 self
.output
.write('no documentation found for %s\n' % repr(topic
))
1378 if type(target
) is type(''):
1379 return self
.showtopic(target
)
1381 filename
, xrefs
= target
1382 filename
= self
.docdir
+ '/' + filename
+ '.html'
1384 file = open(filename
)
1386 self
.output
.write('could not read docs from %s\n' % filename
)
1389 divpat
= re
.compile('<div[^>]*navigat.*?</div.*?>', re
.I | re
.S
)
1390 addrpat
= re
.compile('<address.*?>.*?</address.*?>', re
.I | re
.S
)
1391 document
= re
.sub(addrpat
, '', re
.sub(divpat
, '', file.read()))
1394 import htmllib
, formatter
, StringIO
1395 buffer = StringIO
.StringIO()
1396 parser
= htmllib
.HTMLParser(
1397 formatter
.AbstractFormatter(formatter
.DumbWriter(buffer)))
1398 parser
.start_table
= parser
.do_p
1399 parser
.end_table
= lambda parser
=parser
: parser
.do_p({})
1400 parser
.start_tr
= parser
.do_br
1401 parser
.start_td
= parser
.start_th
= lambda a
, b
=buffer: b
.write('\t')
1402 parser
.feed(document
)
1403 buffer = replace(buffer.getvalue(), '\xa0', ' ', '\n', '\n ')
1404 pager(' ' + strip(buffer) + '\n')
1406 buffer = StringIO
.StringIO()
1407 formatter
.DumbWriter(buffer).send_flowing_data(
1408 'Related help topics: ' + join(split(xrefs
), ', ') + '\n')
1409 self
.output
.write('\n%s\n' % buffer.getvalue())
1411 def listmodules(self
, key
=''):
1413 self
.output
.write('''
1414 Here is a list of matching modules. Enter any module name to get more help.
1419 self
.output
.write('''
1420 Please wait a moment while I gather a list of all available modules...
1424 def callback(path
, modname
, desc
, modules
=modules
):
1425 if modname
and modname
[-9:] == '.__init__':
1426 modname
= modname
[:-9] + ' (package)'
1427 if find(modname
, '.') < 0:
1428 modules
[modname
] = 1
1429 ModuleScanner().run(callback
)
1430 self
.list(modules
.keys())
1431 self
.output
.write('''
1432 Enter any module name to get more help. Or, type "modules spam" to search
1433 for modules whose descriptions contain the word "spam".
1436 help = Helper(sys
.stdin
, sys
.stdout
)
1439 """A generic tree iterator."""
1440 def __init__(self
, roots
, children
, descendp
):
1441 self
.roots
= roots
[:]
1443 self
.children
= children
1444 self
.descendp
= descendp
1450 root
= self
.roots
.pop(0)
1451 self
.state
= [(root
, self
.children(root
))]
1452 node
, children
= self
.state
[-1]
1456 child
= children
.pop(0)
1457 if self
.descendp(child
):
1458 self
.state
.append((child
, self
.children(child
)))
1461 class ModuleScanner(Scanner
):
1462 """An interruptible scanner that searches module synopses."""
1464 roots
= map(lambda dir: (dir, ''), pathdirs())
1465 Scanner
.__init
__(self
, roots
, self
.submodules
, self
.isnewpackage
)
1466 self
.inodes
= map(lambda (dir, pkg
): os
.stat(dir)[1], roots
)
1468 def submodules(self
, (dir, package
)):
1470 for file in os
.listdir(dir):
1471 path
= os
.path
.join(dir, file)
1473 children
.append((path
, package
+ (package
and '.') + file))
1475 children
.append((path
, package
))
1476 children
.sort() # so that spam.py comes before spam.pyc or spam.pyo
1479 def isnewpackage(self
, (dir, package
)):
1480 inode
= os
.path
.exists(dir) and os
.stat(dir)[1]
1481 if not (os
.path
.islink(dir) and inode
in self
.inodes
):
1482 self
.inodes
.append(inode
) # detect circular symbolic links
1483 return ispackage(dir)
1485 def run(self
, callback
, key
=None, completer
=None):
1486 if key
: key
= lower(key
)
1490 for modname
in sys
.builtin_module_names
:
1491 if modname
!= '__main__':
1494 callback(None, modname
, '')
1496 desc
= split(__import__(modname
).__doc
__ or '', '\n')[0]
1497 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1498 callback(None, modname
, desc
)
1500 while not self
.quit
:
1503 path
, package
= node
1504 modname
= inspect
.getmodulename(path
)
1505 if os
.path
.isfile(path
) and modname
:
1506 modname
= package
+ (package
and '.') + modname
1507 if not seen
.has_key(modname
):
1508 seen
[modname
] = 1 # if we see spam.py, skip spam.pyc
1510 callback(path
, modname
, '')
1512 desc
= synopsis(path
) or ''
1513 if find(lower(modname
+ ' - ' + desc
), key
) >= 0:
1514 callback(path
, modname
, desc
)
1515 if completer
: completer()
1518 """Print all the one-line module summaries that contain a substring."""
1519 def callback(path
, modname
, desc
):
1520 if modname
[-9:] == '.__init__':
1521 modname
= modname
[:-9] + ' (package)'
1522 print modname
, desc
and '- ' + desc
1523 try: import warnings
1524 except ImportError: pass
1525 else: warnings
.filterwarnings('ignore') # ignore problems during import
1526 ModuleScanner().run(callback
, key
)
1528 # --------------------------------------------------- web browser interface
1530 def serve(port
, callback
=None, completer
=None):
1531 import BaseHTTPServer
, mimetools
, select
1533 # Patch up mimetools.Message so it doesn't break if rfc822 is reloaded.
1534 class Message(mimetools
.Message
):
1535 def __init__(self
, fp
, seekable
=1):
1536 Message
= self
.__class
__
1537 Message
.__bases
__[0].__bases
__[0].__init
__(self
, fp
, seekable
)
1538 self
.encodingheader
= self
.getheader('content-transfer-encoding')
1539 self
.typeheader
= self
.getheader('content-type')
1543 class DocHandler(BaseHTTPServer
.BaseHTTPRequestHandler
):
1544 def send_document(self
, title
, contents
):
1546 self
.send_response(200)
1547 self
.send_header('Content-Type', 'text/html')
1549 self
.wfile
.write(html
.page(title
, contents
))
1550 except IOError: pass
1554 if path
[-5:] == '.html': path
= path
[:-5]
1555 if path
[:1] == '/': path
= path
[1:]
1556 if path
and path
!= '.':
1558 obj
= locate(path
, forceload
=1)
1559 except ErrorDuringImport
, value
:
1560 self
.send_document(path
, html
.escape(str(value
)))
1563 self
.send_document(describe(obj
), html
.document(obj
, path
))
1565 self
.send_document(path
,
1566 'no Python documentation found for %s' % repr(path
))
1568 heading
= html
.heading(
1569 '<big><big><strong>Python: Index of Modules</strong></big></big>',
1570 '#ffffff', '#7799ee')
1571 def bltinlink(name
):
1572 return '<a href="%s.html">%s</a>' % (name
, name
)
1573 names
= filter(lambda x
: x
!= '__main__',
1574 sys
.builtin_module_names
)
1575 contents
= html
.multicolumn(names
, bltinlink
)
1576 indices
= ['<p>' + html
.bigsection(
1577 'Built-in Modules', '#ffffff', '#ee77aa', contents
)]
1580 for dir in pathdirs():
1581 indices
.append(html
.index(dir, seen
))
1582 contents
= heading
+ join(indices
) + '''<p align=right>
1583 <small><small><font color="#909090" face="helvetica, arial"><strong>
1584 pydoc</strong> by Ka-Ping Yee <ping@lfw.org></font></small></small>'''
1585 self
.send_document('Index of Modules', contents
)
1587 def log_message(self
, *args
): pass
1589 class DocServer(BaseHTTPServer
.HTTPServer
):
1590 def __init__(self
, port
, callback
):
1591 host
= (sys
.platform
== 'mac') and '127.0.0.1' or 'localhost'
1592 self
.address
= ('', port
)
1593 self
.url
= 'http://%s:%d/' % (host
, port
)
1594 self
.callback
= callback
1595 self
.base
.__init
__(self
, self
.address
, self
.handler
)
1597 def serve_until_quit(self
):
1600 while not self
.quit
:
1601 rd
, wr
, ex
= select
.select([self
.socket
.fileno()], [], [], 1)
1602 if rd
: self
.handle_request()
1604 def server_activate(self
):
1605 self
.base
.server_activate(self
)
1606 if self
.callback
: self
.callback(self
)
1608 DocServer
.base
= BaseHTTPServer
.HTTPServer
1609 DocServer
.handler
= DocHandler
1610 DocHandler
.MessageClass
= Message
1613 DocServer(port
, callback
).serve_until_quit()
1614 except (KeyboardInterrupt, select
.error
):
1617 if completer
: completer()
1619 # ----------------------------------------------------- graphical interface
1622 """Graphical interface (starts web server and pops up a control window)."""
1624 def __init__(self
, window
, port
=7464):
1625 self
.window
= window
1630 self
.server_frm
= Tkinter
.Frame(window
)
1631 self
.title_lbl
= Tkinter
.Label(self
.server_frm
,
1632 text
='Starting server...\n ')
1633 self
.open_btn
= Tkinter
.Button(self
.server_frm
,
1634 text
='open browser', command
=self
.open, state
='disabled')
1635 self
.quit_btn
= Tkinter
.Button(self
.server_frm
,
1636 text
='quit serving', command
=self
.quit
, state
='disabled')
1638 self
.search_frm
= Tkinter
.Frame(window
)
1639 self
.search_lbl
= Tkinter
.Label(self
.search_frm
, text
='Search for')
1640 self
.search_ent
= Tkinter
.Entry(self
.search_frm
)
1641 self
.search_ent
.bind('<Return>', self
.search
)
1642 self
.stop_btn
= Tkinter
.Button(self
.search_frm
,
1643 text
='stop', pady
=0, command
=self
.stop
, state
='disabled')
1644 if sys
.platform
== 'win32':
1645 # Trying to hide and show this button crashes under Windows.
1646 self
.stop_btn
.pack(side
='right')
1648 self
.window
.title('pydoc')
1649 self
.window
.protocol('WM_DELETE_WINDOW', self
.quit
)
1650 self
.title_lbl
.pack(side
='top', fill
='x')
1651 self
.open_btn
.pack(side
='left', fill
='x', expand
=1)
1652 self
.quit_btn
.pack(side
='right', fill
='x', expand
=1)
1653 self
.server_frm
.pack(side
='top', fill
='x')
1655 self
.search_lbl
.pack(side
='left')
1656 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
1657 self
.search_frm
.pack(side
='top', fill
='x')
1658 self
.search_ent
.focus_set()
1660 font
= ('helvetica', sys
.platform
== 'win32' and 8 or 10)
1661 self
.result_lst
= Tkinter
.Listbox(window
, font
=font
, height
=6)
1662 self
.result_lst
.bind('<Button-1>', self
.select
)
1663 self
.result_lst
.bind('<Double-Button-1>', self
.goto
)
1664 self
.result_scr
= Tkinter
.Scrollbar(window
,
1665 orient
='vertical', command
=self
.result_lst
.yview
)
1666 self
.result_lst
.config(yscrollcommand
=self
.result_scr
.set)
1668 self
.result_frm
= Tkinter
.Frame(window
)
1669 self
.goto_btn
= Tkinter
.Button(self
.result_frm
,
1670 text
='go to selected', command
=self
.goto
)
1671 self
.hide_btn
= Tkinter
.Button(self
.result_frm
,
1672 text
='hide results', command
=self
.hide
)
1673 self
.goto_btn
.pack(side
='left', fill
='x', expand
=1)
1674 self
.hide_btn
.pack(side
='right', fill
='x', expand
=1)
1676 self
.window
.update()
1677 self
.minwidth
= self
.window
.winfo_width()
1678 self
.minheight
= self
.window
.winfo_height()
1679 self
.bigminheight
= (self
.server_frm
.winfo_reqheight() +
1680 self
.search_frm
.winfo_reqheight() +
1681 self
.result_lst
.winfo_reqheight() +
1682 self
.result_frm
.winfo_reqheight())
1683 self
.bigwidth
, self
.bigheight
= self
.minwidth
, self
.bigminheight
1685 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
1686 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
1690 target
=serve
, args
=(port
, self
.ready
, self
.quit
)).start()
1692 def ready(self
, server
):
1693 self
.server
= server
1694 self
.title_lbl
.config(
1695 text
='Python documentation server at\n' + server
.url
)
1696 self
.open_btn
.config(state
='normal')
1697 self
.quit_btn
.config(state
='normal')
1699 def open(self
, event
=None, url
=None):
1700 url
= url
or self
.server
.url
1703 webbrowser
.open(url
)
1704 except ImportError: # pre-webbrowser.py compatibility
1705 if sys
.platform
== 'win32':
1706 os
.system('start "%s"' % url
)
1707 elif sys
.platform
== 'mac':
1709 except ImportError: pass
1710 else: ic
.launchurl(url
)
1712 rc
= os
.system('netscape -remote "openURL(%s)" &' % url
)
1713 if rc
: os
.system('netscape "%s" &' % url
)
1715 def quit(self
, event
=None):
1717 self
.server
.quit
= 1
1720 def search(self
, event
=None):
1721 key
= self
.search_ent
.get()
1722 self
.stop_btn
.pack(side
='right')
1723 self
.stop_btn
.config(state
='normal')
1724 self
.search_lbl
.config(text
='Searching for "%s"...' % key
)
1725 self
.search_ent
.forget()
1726 self
.search_lbl
.pack(side
='left')
1727 self
.result_lst
.delete(0, 'end')
1728 self
.goto_btn
.config(state
='disabled')
1733 self
.scanner
.quit
= 1
1734 self
.scanner
= ModuleScanner()
1735 threading
.Thread(target
=self
.scanner
.run
,
1736 args
=(self
.update
, key
, self
.done
)).start()
1738 def update(self
, path
, modname
, desc
):
1739 if modname
[-9:] == '.__init__':
1740 modname
= modname
[:-9] + ' (package)'
1741 self
.result_lst
.insert('end',
1742 modname
+ ' - ' + (desc
or '(no description)'))
1744 def stop(self
, event
=None):
1746 self
.scanner
.quit
= 1
1751 self
.search_lbl
.config(text
='Search for')
1752 self
.search_lbl
.pack(side
='left')
1753 self
.search_ent
.pack(side
='right', fill
='x', expand
=1)
1754 if sys
.platform
!= 'win32': self
.stop_btn
.forget()
1755 self
.stop_btn
.config(state
='disabled')
1757 def select(self
, event
=None):
1758 self
.goto_btn
.config(state
='normal')
1760 def goto(self
, event
=None):
1761 selection
= self
.result_lst
.curselection()
1763 modname
= split(self
.result_lst
.get(selection
[0]))[0]
1764 self
.open(url
=self
.server
.url
+ modname
+ '.html')
1767 if not self
.expanded
: return
1768 self
.result_frm
.forget()
1769 self
.result_scr
.forget()
1770 self
.result_lst
.forget()
1771 self
.bigwidth
= self
.window
.winfo_width()
1772 self
.bigheight
= self
.window
.winfo_height()
1773 self
.window
.wm_geometry('%dx%d' % (self
.minwidth
, self
.minheight
))
1774 self
.window
.wm_minsize(self
.minwidth
, self
.minheight
)
1778 if self
.expanded
: return
1779 self
.result_frm
.pack(side
='bottom', fill
='x')
1780 self
.result_scr
.pack(side
='right', fill
='y')
1781 self
.result_lst
.pack(side
='top', fill
='both', expand
=1)
1782 self
.window
.wm_geometry('%dx%d' % (self
.bigwidth
, self
.bigheight
))
1783 self
.window
.wm_minsize(self
.minwidth
, self
.bigminheight
)
1786 def hide(self
, event
=None):
1792 gui
= GUI(Tkinter
.Tk())
1794 except KeyboardInterrupt:
1797 # -------------------------------------------------- command-line interface
1800 return type(x
) is types
.StringType
and find(x
, os
.sep
) >= 0
1803 """Command-line interface (looks at sys.argv to decide what to do)."""
1805 class BadUsage
: pass
1807 # Scripts don't get the current directory in their path by default.
1808 scriptdir
= os
.path
.dirname(sys
.argv
[0])
1809 if scriptdir
in sys
.path
:
1810 sys
.path
.remove(scriptdir
)
1811 sys
.path
.insert(0, '.')
1814 opts
, args
= getopt
.getopt(sys
.argv
[1:], 'gk:p:w')
1817 for opt
, val
in opts
:
1830 print 'pydoc server ready at %s' % server
.url
1832 print 'pydoc server stopped'
1833 serve(port
, ready
, stopped
)
1838 if not args
: raise BadUsage
1841 if ispath(arg
) and os
.path
.isfile(arg
):
1842 arg
= importfile(arg
)
1844 if ispath(arg
) and os
.path
.isdir(arg
):
1850 except ErrorDuringImport
, value
:
1853 except (getopt
.error
, BadUsage
):
1855 print """pydoc - the Python documentation tool
1858 Show text documentation on something. <name> may be the name of a
1859 function, module, or package, or a dotted reference to a class or
1860 function within a module or module in a package. If <name> contains
1861 a '%s', it is used as the path to a Python source file to document.
1864 Search for a keyword in the synopsis lines of all available modules.
1867 Start an HTTP server on the given port on the local machine.
1870 Pop up a graphical interface for finding and serving documentation.
1873 Write out the HTML documentation for a module to a file in the current
1874 directory. If <name> contains a '%s', it is treated as a filename; if
1875 it names a directory, documentation is written for all the contents.
1876 """ % (cmd
, os
.sep
, cmd
, cmd
, cmd
, cmd
, os
.sep
)
1878 if __name__
== '__main__': cli()