[Python-checkins] CVS: python/dist/src/Lib pydoc.py,1.30,1.31
Ka-Ping Yee
ping@users.sourceforge.net
Fri, 13 Apr 2001 02:55:51 -0700
Update of /cvsroot/python/python/dist/src/Lib
In directory usw-pr-cvs1:/tmp/cvs-serv18520
Modified Files:
pydoc.py
Log Message:
Make force-loading optional; don't force-load in interactive mode.
Make synopsis() load modules as '__temp__' so they don't clobber anything.
Change "constants" section to "data" section.
Don't show __builtins__ or __doc__ in "data" section.
For Bob Weiner: don't boldface text in Emacs shells or dumb terminals.
Remove Helper.__repr__ (it really belongs in site.py, and should be guarded by a check for len(inspect.stack) <= 2).
Index: pydoc.py
===================================================================
RCS file: /cvsroot/python/python/dist/src/Lib/pydoc.py,v
retrieving revision 1.30
retrieving revision 1.31
diff -C2 -r1.30 -r1.31
*** pydoc.py 2001/04/12 20:39:14 1.30
--- pydoc.py 2001/04/13 09:55:49 1.31
***************
*** 54,87 ****
# --------------------------------------------------------- common routines
- def synopsis(filename, cache={}):
- """Get the one-line summary out of a module file."""
- mtime = os.stat(filename)[stat.ST_MTIME]
- lastupdate, result = cache.get(filename, (0, None))
- if lastupdate < mtime:
- info = inspect.getmoduleinfo(filename)
- file = open(filename)
- if info and 'b' in info[2]: # binary modules have to be imported
- try: module = imp.load_module(info[0], file, filename, info[1:])
- except: return None
- result = split(module.__doc__ or '', '\n')[0]
- else: # text modules can be directly examined
- line = file.readline()
- while line[:1] == '#' or not strip(line):
- line = file.readline()
- if not line: break
- line = strip(line)
- if line[:4] == 'r"""': line = line[1:]
- if line[:3] == '"""':
- line = line[3:]
- if line[-1:] == '\\': line = line[:-1]
- while not strip(line):
- line = file.readline()
- if not line: break
- result = strip(split(line, '"""')[0])
- else: result = None
- file.close()
- cache[filename] = (mtime, result)
- return result
-
def pathdirs():
"""Convert sys.path into a list of absolute, existing, unique paths."""
--- 54,57 ----
***************
*** 117,126 ****
return name
! def isconstant(object):
! """Check if an object is of a type that probably means it's a constant."""
! return type(object) in [
! types.FloatType, types.IntType, types.ListType, types.LongType,
! types.StringType, types.TupleType, types.TypeType,
! hasattr(types, 'UnicodeType') and types.UnicodeType or 0]
def replace(text, *pairs):
--- 87,95 ----
return name
! def isdata(object):
! """Check if an object is of a type that probably means it's data."""
! return not (inspect.ismodule(object) or inspect.isclass(object) or
! inspect.isroutine(object) or inspect.isframe(object) or
! inspect.istraceback(object) or inspect.iscode(object))
def replace(text, *pairs):
***************
*** 157,160 ****
--- 126,169 ----
return methods
+ # ----------------------------------------------------- module manipulation
+
+ def ispackage(path):
+ """Guess whether a path refers to a package directory."""
+ if os.path.isdir(path):
+ for ext in ['.py', '.pyc', '.pyo']:
+ if os.path.isfile(os.path.join(path, '__init__' + ext)):
+ return 1
+
+ def synopsis(filename, cache={}):
+ """Get the one-line summary out of a module file."""
+ mtime = os.stat(filename)[stat.ST_MTIME]
+ lastupdate, result = cache.get(filename, (0, None))
+ if lastupdate < mtime:
+ info = inspect.getmoduleinfo(filename)
+ file = open(filename)
+ if info and 'b' in info[2]: # binary modules have to be imported
+ try: module = imp.load_module('__temp__', file, filename, info[1:])
+ except: return None
+ result = split(module.__doc__ or '', '\n')[0]
+ del sys.modules['__temp__']
+ else: # text modules can be directly examined
+ line = file.readline()
+ while line[:1] == '#' or not strip(line):
+ line = file.readline()
+ if not line: break
+ line = strip(line)
+ if line[:4] == 'r"""': line = line[1:]
+ if line[:3] == '"""':
+ line = line[3:]
+ if line[-1:] == '\\': line = line[:-1]
+ while not strip(line):
+ line = file.readline()
+ if not line: break
+ result = strip(split(line, '"""')[0])
+ else: result = None
+ file.close()
+ cache[filename] = (mtime, result)
+ return result
+
class ErrorDuringImport(Exception):
"""Errors that occurred while trying to import something to document it."""
***************
*** 190,200 ****
return module
! def ispackage(path):
! """Guess whether a path refers to a package directory."""
! if os.path.isdir(path):
! for ext in ['.py', '.pyc', '.pyo']:
! if os.path.isfile(os.path.join(path, '__init__' + ext)):
! return 1
# ---------------------------------------------------- formatter base class
--- 199,246 ----
return module
! def safeimport(path, forceload=0, cache={}):
! """Import a module; handle errors; return None if the module isn't found.
+ If the module *is* found but an exception occurs, it's wrapped in an
+ ErrorDuringImport exception and reraised. Unlike __import__, if a
+ package path is specified, the module at the end of the path is returned,
+ not the package at the beginning. If the optional 'forceload' argument
+ is 1, we reload the module from disk (unless it's a dynamic extension)."""
+ if forceload and sys.modules.has_key(path):
+ # This is the only way to be sure. Checking the mtime of the file
+ # isn't good enough (e.g. what if the module contains a class that
+ # inherits from another module that has changed?).
+ if path not in sys.builtin_module_names:
+ # Python never loads a dynamic extension a second time from the
+ # same path, even if the file is changed or missing. Deleting
+ # the entry in sys.modules doesn't help for dynamic extensions,
+ # so we're not even going to try to keep them up to date.
+ info = inspect.getmoduleinfo(sys.modules[path].__file__)
+ if info[3] != imp.C_EXTENSION:
+ cache[path] = sys.modules[path] # prevent module from clearing
+ del sys.modules[path]
+ try:
+ module = __import__(path)
+ except:
+ # Did the error occur before or after the module was found?
+ (exc, value, tb) = info = sys.exc_info()
+ if sys.modules.has_key(path):
+ # An error occured while executing the imported module.
+ raise ErrorDuringImport(sys.modules[path].__file__, info)
+ elif exc is SyntaxError:
+ # A SyntaxError occurred before we could execute the module.
+ raise ErrorDuringImport(value.filename, info)
+ elif exc is ImportError and \
+ split(lower(str(value)))[:2] == ['no', 'module']:
+ # The module was not found.
+ return None
+ else:
+ # Some other error occurred during the importing process.
+ raise ErrorDuringImport(path, sys.exc_info())
+ for part in split(path, '.')[1:]:
+ try: module = getattr(module, part)
+ except AttributeError: return None
+ return module
+
# ---------------------------------------------------- formatter base class
***************
*** 222,226 ****
def __init__(self):
Repr.__init__(self)
! self.maxlist = self.maxtuple = self.maxdict = 10
self.maxstring = self.maxother = 100
--- 268,273 ----
def __init__(self):
Repr.__init__(self)
! self.maxlist = self.maxtuple = 20
! self.maxdict = 10
self.maxstring = self.maxother = 100
***************
*** 345,354 ****
def classlink(self, object, modname):
"""Make a link for a class."""
! name = classname(object, modname)
! if sys.modules.has_key(object.__module__) and \
! getattr(sys.modules[object.__module__], object.__name__) is object:
return '<a href="%s.html#%s">%s</a>' % (
! object.__module__, object.__name__, name)
! return name
def modulelink(self, object):
--- 392,400 ----
def classlink(self, object, modname):
"""Make a link for a class."""
! name, module = object.__name__, sys.modules.get(object.__module__)
! if hasattr(module, name) and getattr(module, name) is object:
return '<a href="%s.html#%s">%s</a>' % (
! module.__name__, name, classname(object, modname))
! return classname(object, modname)
def modulelink(self, object):
***************
*** 476,482 ****
fdict[key] = '#-' + key
if inspect.isfunction(value): fdict[value] = fdict[key]
! constants = []
! for key, value in inspect.getmembers(object, isconstant):
! constants.append((key, value))
doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
--- 522,529 ----
fdict[key] = '#-' + key
if inspect.isfunction(value): fdict[value] = fdict[key]
! data = []
! for key, value in inspect.getmembers(object, isdata):
! if key not in ['__builtins__', '__doc__']:
! data.append((key, value))
doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
***************
*** 519,528 ****
result = result + self.bigsection(
'Functions', '#ffffff', '#eeaa77', join(contents))
! if constants:
contents = []
! for key, value in constants:
contents.append(self.document(value, key))
result = result + self.bigsection(
! 'Constants', '#ffffff', '#55aa55', join(contents, '<br>'))
if hasattr(object, '__author__'):
contents = self.markup(str(object.__author__), self.preformat)
--- 566,575 ----
result = result + self.bigsection(
'Functions', '#ffffff', '#eeaa77', join(contents))
! if data:
contents = []
! for key, value in data:
contents.append(self.document(value, key))
result = result + self.bigsection(
! 'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
if hasattr(object, '__author__'):
contents = self.markup(str(object.__author__), self.preformat)
***************
*** 666,670 ****
def __init__(self):
Repr.__init__(self)
! self.maxlist = self.maxtuple = self.maxdict = 10
self.maxstring = self.maxother = 100
--- 713,718 ----
def __init__(self):
Repr.__init__(self)
! self.maxlist = self.maxtuple = 20
! self.maxdict = 10
self.maxstring = self.maxother = 100
***************
*** 755,761 ****
if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
funcs.append((key, value))
! constants = []
! for key, value in inspect.getmembers(object, isconstant):
! constants.append((key, value))
if hasattr(object, '__path__'):
--- 803,810 ----
if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
funcs.append((key, value))
! data = []
! for key, value in inspect.getmembers(object, isdata):
! if key not in ['__builtins__', '__doc__']:
! data.append((key, value))
if hasattr(object, '__path__'):
***************
*** 786,794 ****
result = result + self.section('FUNCTIONS', join(contents, '\n'))
! if constants:
contents = []
! for key, value in constants:
contents.append(self.docother(value, key, name, 70))
! result = result + self.section('CONSTANTS', join(contents, '\n'))
if hasattr(object, '__version__'):
--- 835,843 ----
result = result + self.section('FUNCTIONS', join(contents, '\n'))
! if data:
contents = []
! for key, value in data:
contents.append(self.docother(value, key, name, 70))
! result = result + self.section('DATA', join(contents, '\n'))
if hasattr(object, '__version__'):
***************
*** 904,914 ****
if os.environ.has_key('PAGER'):
if sys.platform == 'win32': # pipes completely broken in Windows
! return lambda a: tempfilepager(a, os.environ['PAGER'])
else:
! return lambda a: pipepager(a, os.environ['PAGER'])
if sys.platform == 'win32':
! return lambda a: tempfilepager(a, 'more <')
if hasattr(os, 'system') and os.system('less 2>/dev/null') == 0:
! return lambda a: pipepager(a, 'less')
import tempfile
--- 953,965 ----
if os.environ.has_key('PAGER'):
if sys.platform == 'win32': # pipes completely broken in Windows
! return lambda text: tempfilepager(plain(text), os.environ['PAGER'])
! elif os.environ.get('TERM') in ['dumb', 'emacs']:
! return lambda text: pipepager(plain(text), os.environ['PAGER'])
else:
! return lambda text: pipepager(text, os.environ['PAGER'])
if sys.platform == 'win32':
! return lambda text: tempfilepager(plain(text), 'more <')
if hasattr(os, 'system') and os.system('less 2>/dev/null') == 0:
! return lambda text: pipepager(text, 'less')
import tempfile
***************
*** 923,926 ****
--- 974,981 ----
os.unlink(filename)
+ def plain(text):
+ """Remove boldface formatting from text."""
+ return re.sub('.\b', '', text)
+
def pipepager(text, cmd):
"""Page through text by feeding it to another program."""
***************
*** 944,951 ****
os.unlink(filename)
- def plain(text):
- """Remove boldface formatting from text."""
- return re.sub('.\b', '', text)
-
def ttypager(text):
"""Page through text on a text terminal."""
--- 999,1002 ----
***************
*** 1010,1057 ****
return 'instance of ' + thing.__class__.__name__
return type(thing).__name__
-
- def freshimport(path, cache={}):
- """Import a module freshly from disk, making sure it's up to date."""
- if sys.modules.has_key(path):
- # This is the only way to be sure. Checking the mtime of the file
- # isn't good enough (e.g. what if the module contains a class that
- # inherits from another module that has changed?).
- if path not in sys.builtin_module_names:
- # Python never loads a dynamic extension a second time from the
- # same path, even if the file is changed or missing. Deleting
- # the entry in sys.modules doesn't help for dynamic extensions,
- # so we're not even going to try to keep them up to date.
- info = inspect.getmoduleinfo(sys.modules[path].__file__)
- if info[3] != imp.C_EXTENSION:
- del sys.modules[path]
- try:
- module = __import__(path)
- except:
- # Did the error occur before or after the module was found?
- (exc, value, tb) = info = sys.exc_info()
- if sys.modules.has_key(path):
- # An error occured while executing the imported module.
- raise ErrorDuringImport(sys.modules[path].__file__, info)
- elif exc is SyntaxError:
- # A SyntaxError occurred before we could execute the module.
- raise ErrorDuringImport(value.filename, info)
- elif exc is ImportError and \
- split(lower(str(value)))[:2] == ['no', 'module']:
- # The module was not found.
- return None
- else:
- # Some other error occurred during the importing process.
- raise ErrorDuringImport(path, sys.exc_info())
- for part in split(path, '.')[1:]:
- try: module = getattr(module, part)
- except AttributeError: return None
- return module
! def locate(path):
"""Locate an object by name or dotted path, importing as necessary."""
parts = split(path, '.')
module, n = None, 0
while n < len(parts):
! nextmodule = freshimport(join(parts[:n+1], '.'))
if nextmodule: module, n = nextmodule, n + 1
else: break
--- 1061,1071 ----
return 'instance of ' + thing.__class__.__name__
return type(thing).__name__
! def locate(path, forceload=0):
"""Locate an object by name or dotted path, importing as necessary."""
parts = split(path, '.')
module, n = None, 0
while n < len(parts):
! nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
if nextmodule: module, n = nextmodule, n + 1
else: break
***************
*** 1072,1081 ****
html = HTMLDoc()
! def doc(thing, title='Python Library Documentation: %s'):
"""Display text documentation, given an object or a path to an object."""
suffix, name = '', None
if type(thing) is type(''):
try:
! object = locate(thing)
except ErrorDuringImport, value:
print value
--- 1086,1095 ----
html = HTMLDoc()
! def doc(thing, title='Python Library Documentation: %s', forceload=0):
"""Display text documentation, given an object or a path to an object."""
suffix, name = '', None
if type(thing) is type(''):
try:
! object = locate(thing, forceload)
except ErrorDuringImport, value:
print value
***************
*** 1095,1102 ****
pager(title % (desc + suffix) + '\n\n' + text.document(thing, name))
! def writedoc(key):
"""Write HTML documentation to a file in the current directory."""
try:
! object = locate(key)
except ErrorDuringImport, value:
print value
--- 1109,1116 ----
pager(title % (desc + suffix) + '\n\n' + text.document(thing, name))
! def writedoc(key, forceload=0):
"""Write HTML documentation to a file in the current directory."""
try:
! object = locate(key, forceload)
except ErrorDuringImport, value:
print value
***************
*** 1112,1121 ****
print 'no Python documentation found for %s' % repr(key)
! def writedocs(dir, pkgpath='', done={}):
"""Write out HTML documentation for all modules in a directory tree."""
for file in os.listdir(dir):
path = os.path.join(dir, file)
if ispackage(path):
! writedocs(path, pkgpath + file + '.')
elif os.path.isfile(path):
modname = inspect.getmodulename(path)
--- 1126,1136 ----
print 'no Python documentation found for %s' % repr(key)
! def writedocs(dir, pkgpath='', done=None):
"""Write out HTML documentation for all modules in a directory tree."""
+ if done is None: done = {}
for file in os.listdir(dir):
path = os.path.join(dir, file)
if ispackage(path):
! writedocs(path, pkgpath + file + '.', done)
elif os.path.isfile(path):
modname = inspect.getmodulename(path)
***************
*** 1252,1259 ****
self.docdir = dir
- def __repr__(self):
- self()
- return ''
-
def __call__(self, request=None):
if request is not None:
--- 1267,1270 ----
***************
*** 1261,1275 ****
else:
self.intro()
! self.output.write('\n')
! while 1:
! self.output.write('help> ')
! self.output.flush()
! try:
! request = self.input.readline()
! if not request: break
! except KeyboardInterrupt: break
! request = strip(replace(request, '"', '', "'", ''))
! if lower(request) in ['q', 'quit']: break
! self.help(request)
self.output.write('''
You're now leaving help and returning to the Python interpreter.
--- 1272,1276 ----
else:
self.intro()
! self.interact()
self.output.write('''
You're now leaving help and returning to the Python interpreter.
***************
*** 1279,1282 ****
--- 1280,1296 ----
''')
+ def interact(self):
+ self.output.write('\n')
+ while 1:
+ self.output.write('help> ')
+ self.output.flush()
+ try:
+ request = self.input.readline()
+ if not request: break
+ except KeyboardInterrupt: break
+ request = strip(replace(request, '"', '', "'", ''))
+ if lower(request) in ['q', 'quit']: break
+ self.help(request)
+
def help(self, request):
if type(request) is type(''):
***************
*** 1362,1367 ****
return
! divpat = re.compile('<div[^>]*navigat.*?</div[^>]*>', re.I | re.S)
! addrpat = re.compile('<address[^>]*>.*?</address[^>]*>', re.I | re.S)
document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
file.close()
--- 1376,1381 ----
return
! divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
! addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
file.close()
***************
*** 1461,1465 ****
callback(None, modname, '')
else:
! desc = split(freshimport(modname).__doc__ or '', '\n')[0]
if find(lower(modname + ' - ' + desc), key) >= 0:
callback(None, modname, desc)
--- 1475,1479 ----
callback(None, modname, '')
else:
! desc = split(__import__(modname).__doc__ or '', '\n')[0]
if find(lower(modname + ' - ' + desc), key) >= 0:
callback(None, modname, desc)
***************
*** 1523,1527 ****
if path and path != '.':
try:
! obj = locate(path)
except ErrorDuringImport, value:
self.send_document(path, html.escape(str(value)))
--- 1537,1541 ----
if path and path != '.':
try:
! obj = locate(path, forceload=1)
except ErrorDuringImport, value:
self.send_document(path, html.escape(str(value)))