~ubuntu-branches/ubuntu/trusty/python3.4/trusty-proposed

« back to all changes in this revision

Viewing changes to Lib/linecache.py

  • Committer: Package Import Robot
  • Author(s): Matthias Klose
  • Date: 2013-11-25 09:44:27 UTC
  • Revision ID: package-import@ubuntu.com-20131125094427-lzxj8ap5w01lmo7f
Tags: upstream-3.4~b1
ImportĀ upstreamĀ versionĀ 3.4~b1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
"""Cache lines from files.
 
2
 
 
3
This is intended to read lines from modules imported -- hence if a filename
 
4
is not found, it will look down the module search path for a file by
 
5
that name.
 
6
"""
 
7
 
 
8
import sys
 
9
import os
 
10
import tokenize
 
11
 
 
12
__all__ = ["getline", "clearcache", "checkcache"]
 
13
 
 
14
def getline(filename, lineno, module_globals=None):
 
15
    lines = getlines(filename, module_globals)
 
16
    if 1 <= lineno <= len(lines):
 
17
        return lines[lineno-1]
 
18
    else:
 
19
        return ''
 
20
 
 
21
 
 
22
# The cache
 
23
 
 
24
cache = {} # The cache
 
25
 
 
26
 
 
27
def clearcache():
 
28
    """Clear the cache entirely."""
 
29
 
 
30
    global cache
 
31
    cache = {}
 
32
 
 
33
 
 
34
def getlines(filename, module_globals=None):
 
35
    """Get the lines for a file from the cache.
 
36
    Update the cache if it doesn't contain an entry for this file already."""
 
37
 
 
38
    if filename in cache:
 
39
        return cache[filename][2]
 
40
    else:
 
41
        return updatecache(filename, module_globals)
 
42
 
 
43
 
 
44
def checkcache(filename=None):
 
45
    """Discard cache entries that are out of date.
 
46
    (This is not checked upon each call!)"""
 
47
 
 
48
    if filename is None:
 
49
        filenames = list(cache.keys())
 
50
    else:
 
51
        if filename in cache:
 
52
            filenames = [filename]
 
53
        else:
 
54
            return
 
55
 
 
56
    for filename in filenames:
 
57
        size, mtime, lines, fullname = cache[filename]
 
58
        if mtime is None:
 
59
            continue   # no-op for files loaded via a __loader__
 
60
        try:
 
61
            stat = os.stat(fullname)
 
62
        except OSError:
 
63
            del cache[filename]
 
64
            continue
 
65
        if size != stat.st_size or mtime != stat.st_mtime:
 
66
            del cache[filename]
 
67
 
 
68
 
 
69
def updatecache(filename, module_globals=None):
 
70
    """Update a cache entry and return its list of lines.
 
71
    If something's wrong, print a message, discard the cache entry,
 
72
    and return an empty list."""
 
73
 
 
74
    if filename in cache:
 
75
        del cache[filename]
 
76
    if not filename or (filename.startswith('<') and filename.endswith('>')):
 
77
        return []
 
78
 
 
79
    fullname = filename
 
80
    try:
 
81
        stat = os.stat(fullname)
 
82
    except OSError:
 
83
        basename = filename
 
84
 
 
85
        # Try for a __loader__, if available
 
86
        if module_globals and '__loader__' in module_globals:
 
87
            name = module_globals.get('__name__')
 
88
            loader = module_globals['__loader__']
 
89
            get_source = getattr(loader, 'get_source', None)
 
90
 
 
91
            if name and get_source:
 
92
                try:
 
93
                    data = get_source(name)
 
94
                except (ImportError, OSError):
 
95
                    pass
 
96
                else:
 
97
                    if data is None:
 
98
                        # No luck, the PEP302 loader cannot find the source
 
99
                        # for this module.
 
100
                        return []
 
101
                    cache[filename] = (
 
102
                        len(data), None,
 
103
                        [line+'\n' for line in data.splitlines()], fullname
 
104
                    )
 
105
                    return cache[filename][2]
 
106
 
 
107
        # Try looking through the module search path, which is only useful
 
108
        # when handling a relative filename.
 
109
        if os.path.isabs(filename):
 
110
            return []
 
111
 
 
112
        for dirname in sys.path:
 
113
            try:
 
114
                fullname = os.path.join(dirname, basename)
 
115
            except (TypeError, AttributeError):
 
116
                # Not sufficiently string-like to do anything useful with.
 
117
                continue
 
118
            try:
 
119
                stat = os.stat(fullname)
 
120
                break
 
121
            except OSError:
 
122
                pass
 
123
        else:
 
124
            return []
 
125
    try:
 
126
        with tokenize.open(fullname) as fp:
 
127
            lines = fp.readlines()
 
128
    except OSError:
 
129
        return []
 
130
    if lines and not lines[-1].endswith('\n'):
 
131
        lines[-1] += '\n'
 
132
    size, mtime = stat.st_size, stat.st_mtime
 
133
    cache[filename] = size, mtime, lines, fullname
 
134
    return lines