mirror of
				https://github.com/python/cpython.git
				synced 2025-11-04 07:31:38 +00:00 
			
		
		
		
	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
					
				
					 1 changed files with 147 additions and 133 deletions
				
			
		
							
								
								
									
										270
									
								
								Lib/pydoc.py
									
										
									
									
									
								
							
							
						
						
									
										270
									
								
								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,15 +1266,20 @@ 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.interact()
 | 
				
			||||||
 | 
					            self.output.write('''
 | 
				
			||||||
 | 
					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
 | 
				
			||||||
 | 
					interpreter, you can type "help(object)".  Executing "help('string')"
 | 
				
			||||||
 | 
					has the same effect as typing a particular string at the help> prompt.
 | 
				
			||||||
 | 
					''')
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    def interact(self):
 | 
				
			||||||
        self.output.write('\n')
 | 
					        self.output.write('\n')
 | 
				
			||||||
        while 1:
 | 
					        while 1:
 | 
				
			||||||
            self.output.write('help> ')
 | 
					            self.output.write('help> ')
 | 
				
			||||||
| 
						 | 
					@ -1271,12 +1291,6 @@ def __call__(self, request=None):
 | 
				
			||||||
            request = strip(replace(request, '"', '', "'", ''))
 | 
					            request = strip(replace(request, '"', '', "'", ''))
 | 
				
			||||||
            if lower(request) in ['q', 'quit']: break
 | 
					            if lower(request) in ['q', 'quit']: break
 | 
				
			||||||
            self.help(request)
 | 
					            self.help(request)
 | 
				
			||||||
            self.output.write('''
 | 
					 | 
				
			||||||
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
 | 
					 | 
				
			||||||
interpreter, you can type "help(object)".  Executing "help('string')"
 | 
					 | 
				
			||||||
has the same effect as typing a particular string at the help> prompt.
 | 
					 | 
				
			||||||
''')
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def help(self, request):
 | 
					    def help(self, request):
 | 
				
			||||||
        if type(request) is type(''):
 | 
					        if type(request) is type(''):
 | 
				
			||||||
| 
						 | 
					@ -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…
	
	Add table
		Add a link
		
	
		Reference in a new issue