linecache.py 2.64 KB
Newer Older
1 2 3 4 5 6
"""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.
"""
Guido van Rossum's avatar
Guido van Rossum committed
7

8
import sys
Guido van Rossum's avatar
Guido van Rossum committed
9 10
import os

11 12
__all__ = ["getline","clearcache","checkcache"]

Guido van Rossum's avatar
Guido van Rossum committed
13
def getline(filename, lineno):
14 15 16 17 18
    lines = getlines(filename)
    if 1 <= lineno <= len(lines):
        return lines[lineno-1]
    else:
        return ''
Guido van Rossum's avatar
Guido van Rossum committed
19 20 21 22 23 24 25 26


# The cache

cache = {} # The cache


def clearcache():
27
    """Clear the cache entirely."""
Guido van Rossum's avatar
Guido van Rossum committed
28

29 30
    global cache
    cache = {}
Guido van Rossum's avatar
Guido van Rossum committed
31 32 33


def getlines(filename):
34 35
    """Get the lines for a file from the cache.
    Update the cache if it doesn't contain an entry for this file already."""
Guido van Rossum's avatar
Guido van Rossum committed
36

37
    if filename in cache:
38 39 40
        return cache[filename][2]
    else:
        return updatecache(filename)
Guido van Rossum's avatar
Guido van Rossum committed
41 42 43


def checkcache():
44 45
    """Discard cache entries that are out of date.
    (This is not checked upon each call!)"""
Guido van Rossum's avatar
Guido van Rossum committed
46

47 48 49 50 51 52 53
    for filename in cache.keys():
        size, mtime, lines, fullname = cache[filename]
        try:
            stat = os.stat(fullname)
        except os.error:
            del cache[filename]
            continue
54
        if size != stat.st_size or mtime != stat.st_mtime:
55
            del cache[filename]
Guido van Rossum's avatar
Guido van Rossum committed
56 57 58


def updatecache(filename):
59 60 61 62
    """Update a cache entry and return its list of lines.
    If something's wrong, print a message, discard the cache entry,
    and return an empty list."""

63
    if filename in cache:
64 65 66 67 68 69 70
        del cache[filename]
    if not filename or filename[0] + filename[-1] == '<>':
        return []
    fullname = filename
    try:
        stat = os.stat(fullname)
    except os.error, msg:
Tim Peters's avatar
Tim Peters committed
71
        # Try looking through the module search path.
72 73
        basename = os.path.split(filename)[1]
        for dirname in sys.path:
Tim Peters's avatar
Tim Peters committed
74 75
            # When using imputil, sys.path may contain things other than
            # strings; ignore them when it happens.
76
            try:
Tim Peters's avatar
Tim Peters committed
77 78 79
                fullname = os.path.join(dirname, basename)
            except (TypeError, AttributeError):
                # Not sufficiently string-like to do anything useful with.
80
                pass
Tim Peters's avatar
Tim Peters committed
81 82 83 84 85 86
            else:
                try:
                    stat = os.stat(fullname)
                    break
                except os.error:
                    pass
87 88 89 90 91
        else:
            # No luck
##          print '*** Cannot stat', filename, ':', msg
            return []
    try:
92
        fp = open(fullname, 'rU')
93 94 95 96 97
        lines = fp.readlines()
        fp.close()
    except IOError, msg:
##      print '*** Cannot open', fullname, ':', msg
        return []
98
    size, mtime = stat.st_size, stat.st_mtime
99 100
    cache[filename] = size, mtime, lines, fullname
    return lines