diff options
Diffstat (limited to 'Lib/linecache.py')
-rw-r--r-- | Lib/linecache.py | 106 |
1 files changed, 34 insertions, 72 deletions
diff --git a/Lib/linecache.py b/Lib/linecache.py index 3afcce1..4b97be3 100644 --- a/Lib/linecache.py +++ b/Lib/linecache.py @@ -1,14 +1,12 @@ -"""Cache lines from Python source files. +"""Cache lines from files. This is intended to read lines from modules imported -- hence if a filename is not found, it will look down the module search path for a file by that name. """ -import functools import sys import os -import tokenize __all__ = ["getline", "clearcache", "checkcache"] @@ -22,9 +20,7 @@ def getline(filename, lineno, module_globals=None): # The cache -# The cache. Maps filenames to either a thunk which will provide source code, -# or a tuple (size, mtime, lines, fullname) once loaded. -cache = {} +cache = {} # The cache def clearcache(): @@ -35,13 +31,11 @@ def clearcache(): def getlines(filename, module_globals=None): - """Get the lines for a Python source file from the cache. + """Get the lines for a file from the cache. Update the cache if it doesn't contain an entry for this file already.""" if filename in cache: - entry = cache[filename] - if len(entry) != 1: - return cache[filename][2] + return cache[filename][2] try: return updatecache(filename, module_globals) @@ -55,7 +49,7 @@ def checkcache(filename=None): (This is not checked upon each call!)""" if filename is None: - filenames = list(cache.keys()) + filenames = cache.keys() else: if filename in cache: filenames = [filename] @@ -63,16 +57,12 @@ def checkcache(filename=None): return for filename in filenames: - entry = cache[filename] - if len(entry) == 1: - # lazy cache entry, leave it lazy. - continue - size, mtime, lines, fullname = entry + size, mtime, lines, fullname = cache[filename] if mtime is None: continue # no-op for files loaded via a __loader__ try: stat = os.stat(fullname) - except OSError: + except os.error: del cache[filename] continue if size != stat.st_size or mtime != stat.st_mtime: @@ -85,8 +75,7 @@ def updatecache(filename, module_globals=None): and return an empty list.""" if filename in cache: - if len(cache[filename]) != 1: - del cache[filename] + del cache[filename] if not filename or (filename.startswith('<') and filename.endswith('>')): return [] @@ -96,23 +85,27 @@ def updatecache(filename, module_globals=None): except OSError: basename = filename - # Realise a lazy loader based lookup if there is one - # otherwise try to lookup right now. - if lazycache(filename, module_globals): - try: - data = cache[filename][0]() - except (ImportError, OSError): - pass - else: - if data is None: - # No luck, the PEP302 loader cannot find the source - # for this module. - return [] - cache[filename] = ( - len(data), None, - [line+'\n' for line in data.splitlines()], fullname - ) - return cache[filename][2] + # Try for a __loader__, if available + if module_globals and '__loader__' in module_globals: + name = module_globals.get('__name__') + loader = module_globals['__loader__'] + get_source = getattr(loader, 'get_source', None) + + if name and get_source: + try: + data = get_source(name) + except (ImportError, IOError): + pass + else: + if data is None: + # No luck, the PEP302 loader cannot find the source + # for this module. + return [] + cache[filename] = ( + len(data), None, + [line+'\n' for line in data.splitlines()], fullname + ) + return cache[filename][2] # Try looking through the module search path, which is only useful # when handling a relative filename. @@ -120,6 +113,8 @@ def updatecache(filename, module_globals=None): return [] for dirname in sys.path: + # When using imputil, sys.path may contain things other than + # strings; ignore them when it happens. try: fullname = os.path.join(dirname, basename) except (TypeError, AttributeError): @@ -128,50 +123,17 @@ def updatecache(filename, module_globals=None): try: stat = os.stat(fullname) break - except OSError: + except os.error: pass else: return [] try: - with tokenize.open(fullname) as fp: + with open(fullname, 'rU') as fp: lines = fp.readlines() - except OSError: + except IOError: return [] if lines and not lines[-1].endswith('\n'): lines[-1] += '\n' size, mtime = stat.st_size, stat.st_mtime cache[filename] = size, mtime, lines, fullname return lines - - -def lazycache(filename, module_globals): - """Seed the cache for filename with module_globals. - - The module loader will be asked for the source only when getlines is - called, not immediately. - - If there is an entry in the cache already, it is not altered. - - :return: True if a lazy load is registered in the cache, - otherwise False. To register such a load a module loader with a - get_source method must be found, the filename must be a cachable - filename, and the filename must not be already cached. - """ - if filename in cache: - if len(cache[filename]) == 1: - return True - else: - return False - if not filename or (filename.startswith('<') and filename.endswith('>')): - return False - # Try for a __loader__, if available - if module_globals and '__loader__' in module_globals: - name = module_globals.get('__name__') - loader = module_globals['__loader__'] - get_source = getattr(loader, 'get_source', None) - - if name and get_source: - get_lines = functools.partial(get_source, name) - cache[filename] = (get_lines,) - return True - return False |