mirror of https://github.com/python/cpython.git
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).
This commit is contained in:
parent
202c99b2e0
commit
dec96e92ae
280
Lib/pydoc.py
280
Lib/pydoc.py
|
@ -53,36 +53,6 @@ class or function within a module or module in a package. If the
|
||||||
|
|
||||||
# --------------------------------------------------------- common routines
|
# --------------------------------------------------------- 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():
|
def pathdirs():
|
||||||
"""Convert sys.path into a list of absolute, existing, unique paths."""
|
"""Convert sys.path into a list of absolute, existing, unique paths."""
|
||||||
dirs = []
|
dirs = []
|
||||||
|
@ -116,12 +86,11 @@ def classname(object, modname):
|
||||||
name = object.__module__ + '.' + name
|
name = object.__module__ + '.' + name
|
||||||
return name
|
return name
|
||||||
|
|
||||||
def isconstant(object):
|
def isdata(object):
|
||||||
"""Check if an object is of a type that probably means it's a constant."""
|
"""Check if an object is of a type that probably means it's data."""
|
||||||
return type(object) in [
|
return not (inspect.ismodule(object) or inspect.isclass(object) or
|
||||||
types.FloatType, types.IntType, types.ListType, types.LongType,
|
inspect.isroutine(object) or inspect.isframe(object) or
|
||||||
types.StringType, types.TupleType, types.TypeType,
|
inspect.istraceback(object) or inspect.iscode(object))
|
||||||
hasattr(types, 'UnicodeType') and types.UnicodeType or 0]
|
|
||||||
|
|
||||||
def replace(text, *pairs):
|
def replace(text, *pairs):
|
||||||
"""Do a series of global replacements on a string."""
|
"""Do a series of global replacements on a string."""
|
||||||
|
@ -156,6 +125,46 @@ def allmethods(cl):
|
||||||
methods[key] = getattr(cl, key)
|
methods[key] = getattr(cl, key)
|
||||||
return methods
|
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):
|
class ErrorDuringImport(Exception):
|
||||||
"""Errors that occurred while trying to import something to document it."""
|
"""Errors that occurred while trying to import something to document it."""
|
||||||
def __init__(self, filename, (exc, value, tb)):
|
def __init__(self, filename, (exc, value, tb)):
|
||||||
|
@ -189,12 +198,49 @@ def importfile(path):
|
||||||
file.close()
|
file.close()
|
||||||
return module
|
return module
|
||||||
|
|
||||||
def ispackage(path):
|
def safeimport(path, forceload=0, cache={}):
|
||||||
"""Guess whether a path refers to a package directory."""
|
"""Import a module; handle errors; return None if the module isn't found.
|
||||||
if os.path.isdir(path):
|
|
||||||
for ext in ['.py', '.pyc', '.pyo']:
|
If the module *is* found but an exception occurs, it's wrapped in an
|
||||||
if os.path.isfile(os.path.join(path, '__init__' + ext)):
|
ErrorDuringImport exception and reraised. Unlike __import__, if a
|
||||||
return 1
|
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
|
# ---------------------------------------------------- formatter base class
|
||||||
|
|
||||||
|
@ -221,7 +267,8 @@ class HTMLRepr(Repr):
|
||||||
"""Class for safely making an HTML representation of a Python object."""
|
"""Class for safely making an HTML representation of a Python object."""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Repr.__init__(self)
|
Repr.__init__(self)
|
||||||
self.maxlist = self.maxtuple = self.maxdict = 10
|
self.maxlist = self.maxtuple = 20
|
||||||
|
self.maxdict = 10
|
||||||
self.maxstring = self.maxother = 100
|
self.maxstring = self.maxother = 100
|
||||||
|
|
||||||
def escape(self, text):
|
def escape(self, text):
|
||||||
|
@ -344,12 +391,11 @@ def namelink(self, name, *dicts):
|
||||||
|
|
||||||
def classlink(self, object, modname):
|
def classlink(self, object, modname):
|
||||||
"""Make a link for a class."""
|
"""Make a link for a class."""
|
||||||
name = classname(object, modname)
|
name, module = object.__name__, sys.modules.get(object.__module__)
|
||||||
if sys.modules.has_key(object.__module__) and \
|
if hasattr(module, name) and getattr(module, name) is object:
|
||||||
getattr(sys.modules[object.__module__], object.__name__) is object:
|
|
||||||
return '<a href="%s.html#%s">%s</a>' % (
|
return '<a href="%s.html#%s">%s</a>' % (
|
||||||
object.__module__, object.__name__, name)
|
module.__name__, name, classname(object, modname))
|
||||||
return name
|
return classname(object, modname)
|
||||||
|
|
||||||
def modulelink(self, object):
|
def modulelink(self, object):
|
||||||
"""Make a link for a module."""
|
"""Make a link for a module."""
|
||||||
|
@ -475,9 +521,10 @@ def docmodule(self, object, name=None, mod=None):
|
||||||
funcs.append((key, value))
|
funcs.append((key, value))
|
||||||
fdict[key] = '#-' + key
|
fdict[key] = '#-' + key
|
||||||
if inspect.isfunction(value): fdict[value] = fdict[key]
|
if inspect.isfunction(value): fdict[value] = fdict[key]
|
||||||
constants = []
|
data = []
|
||||||
for key, value in inspect.getmembers(object, isconstant):
|
for key, value in inspect.getmembers(object, isdata):
|
||||||
constants.append((key, value))
|
if key not in ['__builtins__', '__doc__']:
|
||||||
|
data.append((key, value))
|
||||||
|
|
||||||
doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
|
doc = self.markup(getdoc(object), self.preformat, fdict, cdict)
|
||||||
doc = doc and '<tt>%s</tt>' % doc
|
doc = doc and '<tt>%s</tt>' % doc
|
||||||
|
@ -518,12 +565,12 @@ def docmodule(self, object, name=None, mod=None):
|
||||||
contents.append(self.document(value, key, name, fdict, cdict))
|
contents.append(self.document(value, key, name, fdict, cdict))
|
||||||
result = result + self.bigsection(
|
result = result + self.bigsection(
|
||||||
'Functions', '#ffffff', '#eeaa77', join(contents))
|
'Functions', '#ffffff', '#eeaa77', join(contents))
|
||||||
if constants:
|
if data:
|
||||||
contents = []
|
contents = []
|
||||||
for key, value in constants:
|
for key, value in data:
|
||||||
contents.append(self.document(value, key))
|
contents.append(self.document(value, key))
|
||||||
result = result + self.bigsection(
|
result = result + self.bigsection(
|
||||||
'Constants', '#ffffff', '#55aa55', join(contents, '<br>'))
|
'Data', '#ffffff', '#55aa55', join(contents, '<br>\n'))
|
||||||
if hasattr(object, '__author__'):
|
if hasattr(object, '__author__'):
|
||||||
contents = self.markup(str(object.__author__), self.preformat)
|
contents = self.markup(str(object.__author__), self.preformat)
|
||||||
result = result + self.bigsection(
|
result = result + self.bigsection(
|
||||||
|
@ -665,7 +712,8 @@ class TextRepr(Repr):
|
||||||
"""Class for safely making a text representation of a Python object."""
|
"""Class for safely making a text representation of a Python object."""
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
Repr.__init__(self)
|
Repr.__init__(self)
|
||||||
self.maxlist = self.maxtuple = self.maxdict = 10
|
self.maxlist = self.maxtuple = 20
|
||||||
|
self.maxdict = 10
|
||||||
self.maxstring = self.maxother = 100
|
self.maxstring = self.maxother = 100
|
||||||
|
|
||||||
def repr1(self, x, level):
|
def repr1(self, x, level):
|
||||||
|
@ -754,9 +802,10 @@ def docmodule(self, object, name=None, mod=None):
|
||||||
for key, value in inspect.getmembers(object, inspect.isroutine):
|
for key, value in inspect.getmembers(object, inspect.isroutine):
|
||||||
if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
|
if inspect.isbuiltin(value) or inspect.getmodule(value) is object:
|
||||||
funcs.append((key, value))
|
funcs.append((key, value))
|
||||||
constants = []
|
data = []
|
||||||
for key, value in inspect.getmembers(object, isconstant):
|
for key, value in inspect.getmembers(object, isdata):
|
||||||
constants.append((key, value))
|
if key not in ['__builtins__', '__doc__']:
|
||||||
|
data.append((key, value))
|
||||||
|
|
||||||
if hasattr(object, '__path__'):
|
if hasattr(object, '__path__'):
|
||||||
modpkgs = []
|
modpkgs = []
|
||||||
|
@ -785,11 +834,11 @@ def docmodule(self, object, name=None, mod=None):
|
||||||
contents.append(self.document(value, key, name))
|
contents.append(self.document(value, key, name))
|
||||||
result = result + self.section('FUNCTIONS', join(contents, '\n'))
|
result = result + self.section('FUNCTIONS', join(contents, '\n'))
|
||||||
|
|
||||||
if constants:
|
if data:
|
||||||
contents = []
|
contents = []
|
||||||
for key, value in constants:
|
for key, value in data:
|
||||||
contents.append(self.docother(value, key, name, 70))
|
contents.append(self.docother(value, key, name, 70))
|
||||||
result = result + self.section('CONSTANTS', join(contents, '\n'))
|
result = result + self.section('DATA', join(contents, '\n'))
|
||||||
|
|
||||||
if hasattr(object, '__version__'):
|
if hasattr(object, '__version__'):
|
||||||
version = str(object.__version__)
|
version = str(object.__version__)
|
||||||
|
@ -903,13 +952,15 @@ def getpager():
|
||||||
return plainpager
|
return plainpager
|
||||||
if os.environ.has_key('PAGER'):
|
if os.environ.has_key('PAGER'):
|
||||||
if sys.platform == 'win32': # pipes completely broken in Windows
|
if sys.platform == 'win32': # pipes completely broken in Windows
|
||||||
return lambda a: tempfilepager(a, os.environ['PAGER'])
|
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:
|
else:
|
||||||
return lambda a: pipepager(a, os.environ['PAGER'])
|
return lambda text: pipepager(text, os.environ['PAGER'])
|
||||||
if sys.platform == 'win32':
|
if sys.platform == 'win32':
|
||||||
return lambda a: tempfilepager(a, 'more <')
|
return lambda text: tempfilepager(plain(text), 'more <')
|
||||||
if hasattr(os, 'system') and os.system('less 2>/dev/null') == 0:
|
if hasattr(os, 'system') and os.system('less 2>/dev/null') == 0:
|
||||||
return lambda a: pipepager(a, 'less')
|
return lambda text: pipepager(text, 'less')
|
||||||
|
|
||||||
import tempfile
|
import tempfile
|
||||||
filename = tempfile.mktemp()
|
filename = tempfile.mktemp()
|
||||||
|
@ -922,6 +973,10 @@ def getpager():
|
||||||
finally:
|
finally:
|
||||||
os.unlink(filename)
|
os.unlink(filename)
|
||||||
|
|
||||||
|
def plain(text):
|
||||||
|
"""Remove boldface formatting from text."""
|
||||||
|
return re.sub('.\b', '', text)
|
||||||
|
|
||||||
def pipepager(text, cmd):
|
def pipepager(text, cmd):
|
||||||
"""Page through text by feeding it to another program."""
|
"""Page through text by feeding it to another program."""
|
||||||
pipe = os.popen(cmd, 'w')
|
pipe = os.popen(cmd, 'w')
|
||||||
|
@ -943,10 +998,6 @@ def tempfilepager(text, cmd):
|
||||||
finally:
|
finally:
|
||||||
os.unlink(filename)
|
os.unlink(filename)
|
||||||
|
|
||||||
def plain(text):
|
|
||||||
"""Remove boldface formatting from text."""
|
|
||||||
return re.sub('.\b', '', text)
|
|
||||||
|
|
||||||
def ttypager(text):
|
def ttypager(text):
|
||||||
"""Page through text on a text terminal."""
|
"""Page through text on a text terminal."""
|
||||||
lines = split(plain(text), '\n')
|
lines = split(plain(text), '\n')
|
||||||
|
@ -1010,49 +1061,12 @@ def describe(thing):
|
||||||
return 'instance of ' + thing.__class__.__name__
|
return 'instance of ' + thing.__class__.__name__
|
||||||
return type(thing).__name__
|
return type(thing).__name__
|
||||||
|
|
||||||
def freshimport(path, cache={}):
|
def locate(path, forceload=0):
|
||||||
"""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."""
|
"""Locate an object by name or dotted path, importing as necessary."""
|
||||||
parts = split(path, '.')
|
parts = split(path, '.')
|
||||||
module, n = None, 0
|
module, n = None, 0
|
||||||
while n < len(parts):
|
while n < len(parts):
|
||||||
nextmodule = freshimport(join(parts[:n+1], '.'))
|
nextmodule = safeimport(join(parts[:n+1], '.'), forceload)
|
||||||
if nextmodule: module, n = nextmodule, n + 1
|
if nextmodule: module, n = nextmodule, n + 1
|
||||||
else: break
|
else: break
|
||||||
if module:
|
if module:
|
||||||
|
@ -1071,12 +1085,12 @@ def locate(path):
|
||||||
text = TextDoc()
|
text = TextDoc()
|
||||||
html = HTMLDoc()
|
html = HTMLDoc()
|
||||||
|
|
||||||
def doc(thing, title='Python Library Documentation: %s'):
|
def doc(thing, title='Python Library Documentation: %s', forceload=0):
|
||||||
"""Display text documentation, given an object or a path to an object."""
|
"""Display text documentation, given an object or a path to an object."""
|
||||||
suffix, name = '', None
|
suffix, name = '', None
|
||||||
if type(thing) is type(''):
|
if type(thing) is type(''):
|
||||||
try:
|
try:
|
||||||
object = locate(thing)
|
object = locate(thing, forceload)
|
||||||
except ErrorDuringImport, value:
|
except ErrorDuringImport, value:
|
||||||
print value
|
print value
|
||||||
return
|
return
|
||||||
|
@ -1094,10 +1108,10 @@ def doc(thing, title='Python Library Documentation: %s'):
|
||||||
suffix = ' in module ' + module.__name__
|
suffix = ' in module ' + module.__name__
|
||||||
pager(title % (desc + suffix) + '\n\n' + text.document(thing, name))
|
pager(title % (desc + suffix) + '\n\n' + text.document(thing, name))
|
||||||
|
|
||||||
def writedoc(key):
|
def writedoc(key, forceload=0):
|
||||||
"""Write HTML documentation to a file in the current directory."""
|
"""Write HTML documentation to a file in the current directory."""
|
||||||
try:
|
try:
|
||||||
object = locate(key)
|
object = locate(key, forceload)
|
||||||
except ErrorDuringImport, value:
|
except ErrorDuringImport, value:
|
||||||
print value
|
print value
|
||||||
else:
|
else:
|
||||||
|
@ -1111,12 +1125,13 @@ def writedoc(key):
|
||||||
else:
|
else:
|
||||||
print 'no Python documentation found for %s' % repr(key)
|
print 'no Python documentation found for %s' % repr(key)
|
||||||
|
|
||||||
def writedocs(dir, pkgpath='', done={}):
|
def writedocs(dir, pkgpath='', done=None):
|
||||||
"""Write out HTML documentation for all modules in a directory tree."""
|
"""Write out HTML documentation for all modules in a directory tree."""
|
||||||
|
if done is None: done = {}
|
||||||
for file in os.listdir(dir):
|
for file in os.listdir(dir):
|
||||||
path = os.path.join(dir, file)
|
path = os.path.join(dir, file)
|
||||||
if ispackage(path):
|
if ispackage(path):
|
||||||
writedocs(path, pkgpath + file + '.')
|
writedocs(path, pkgpath + file + '.', done)
|
||||||
elif os.path.isfile(path):
|
elif os.path.isfile(path):
|
||||||
modname = inspect.getmodulename(path)
|
modname = inspect.getmodulename(path)
|
||||||
if modname:
|
if modname:
|
||||||
|
@ -1251,26 +1266,12 @@ def __init__(self, input, output):
|
||||||
if dir and os.path.isdir(os.path.join(dir, 'lib')):
|
if dir and os.path.isdir(os.path.join(dir, 'lib')):
|
||||||
self.docdir = dir
|
self.docdir = dir
|
||||||
|
|
||||||
def __repr__(self):
|
|
||||||
self()
|
|
||||||
return ''
|
|
||||||
|
|
||||||
def __call__(self, request=None):
|
def __call__(self, request=None):
|
||||||
if request is not None:
|
if request is not None:
|
||||||
self.help(request)
|
self.help(request)
|
||||||
else:
|
else:
|
||||||
self.intro()
|
self.intro()
|
||||||
self.output.write('\n')
|
self.interact()
|
||||||
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('''
|
self.output.write('''
|
||||||
You're now leaving help and returning to the Python interpreter.
|
You're now leaving help and returning to the Python interpreter.
|
||||||
If you want to ask for help on a particular object directly from the
|
If you want to ask for help on a particular object directly from the
|
||||||
|
@ -1278,6 +1279,19 @@ def __call__(self, request=None):
|
||||||
has the same effect as typing a particular string at the help> prompt.
|
has the same effect as typing a particular string at the help> prompt.
|
||||||
''')
|
''')
|
||||||
|
|
||||||
|
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):
|
def help(self, request):
|
||||||
if type(request) is type(''):
|
if type(request) is type(''):
|
||||||
if request == 'help': self.intro()
|
if request == 'help': self.intro()
|
||||||
|
@ -1361,8 +1375,8 @@ def showtopic(self, topic):
|
||||||
self.output.write('could not read docs from %s\n' % filename)
|
self.output.write('could not read docs from %s\n' % filename)
|
||||||
return
|
return
|
||||||
|
|
||||||
divpat = re.compile('<div[^>]*navigat.*?</div[^>]*>', re.I | re.S)
|
divpat = re.compile('<div[^>]*navigat.*?</div.*?>', re.I | re.S)
|
||||||
addrpat = re.compile('<address[^>]*>.*?</address[^>]*>', re.I | re.S)
|
addrpat = re.compile('<address.*?>.*?</address.*?>', re.I | re.S)
|
||||||
document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
|
document = re.sub(addrpat, '', re.sub(divpat, '', file.read()))
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
|
@ -1460,7 +1474,7 @@ def run(self, callback, key=None, completer=None):
|
||||||
if key is None:
|
if key is None:
|
||||||
callback(None, modname, '')
|
callback(None, modname, '')
|
||||||
else:
|
else:
|
||||||
desc = split(freshimport(modname).__doc__ or '', '\n')[0]
|
desc = split(__import__(modname).__doc__ or '', '\n')[0]
|
||||||
if find(lower(modname + ' - ' + desc), key) >= 0:
|
if find(lower(modname + ' - ' + desc), key) >= 0:
|
||||||
callback(None, modname, desc)
|
callback(None, modname, desc)
|
||||||
|
|
||||||
|
@ -1522,7 +1536,7 @@ def do_GET(self):
|
||||||
if path[:1] == '/': path = path[1:]
|
if path[:1] == '/': path = path[1:]
|
||||||
if path and path != '.':
|
if path and path != '.':
|
||||||
try:
|
try:
|
||||||
obj = locate(path)
|
obj = locate(path, forceload=1)
|
||||||
except ErrorDuringImport, value:
|
except ErrorDuringImport, value:
|
||||||
self.send_document(path, html.escape(str(value)))
|
self.send_document(path, html.escape(str(value)))
|
||||||
return
|
return
|
||||||
|
|
Loading…
Reference in New Issue