ยปCore Development>Code coverage>Lib/linecache.py

Python code coverage for Lib/linecache.py

#countcontent
1n/a"""Cache lines from Python source files.
2n/a
3n/aThis is intended to read lines from modules imported -- hence if a filename
4n/ais not found, it will look down the module search path for a file by
5n/athat name.
6n/a"""
7n/a
8n/aimport functools
9n/aimport sys
10n/aimport os
11n/aimport tokenize
12n/a
13n/a__all__ = ["getline", "clearcache", "checkcache"]
14n/a
15n/adef getline(filename, lineno, module_globals=None):
16n/a lines = getlines(filename, module_globals)
17n/a if 1 <= lineno <= len(lines):
18n/a return lines[lineno-1]
19n/a else:
20n/a return ''
21n/a
22n/a
23n/a# The cache
24n/a
25n/a# The cache. Maps filenames to either a thunk which will provide source code,
26n/a# or a tuple (size, mtime, lines, fullname) once loaded.
27n/acache = {}
28n/a
29n/a
30n/adef clearcache():
31n/a """Clear the cache entirely."""
32n/a
33n/a global cache
34n/a cache = {}
35n/a
36n/a
37n/adef getlines(filename, module_globals=None):
38n/a """Get the lines for a Python source file from the cache.
39n/a Update the cache if it doesn't contain an entry for this file already."""
40n/a
41n/a if filename in cache:
42n/a entry = cache[filename]
43n/a if len(entry) != 1:
44n/a return cache[filename][2]
45n/a
46n/a try:
47n/a return updatecache(filename, module_globals)
48n/a except MemoryError:
49n/a clearcache()
50n/a return []
51n/a
52n/a
53n/adef checkcache(filename=None):
54n/a """Discard cache entries that are out of date.
55n/a (This is not checked upon each call!)"""
56n/a
57n/a if filename is None:
58n/a filenames = list(cache.keys())
59n/a else:
60n/a if filename in cache:
61n/a filenames = [filename]
62n/a else:
63n/a return
64n/a
65n/a for filename in filenames:
66n/a entry = cache[filename]
67n/a if len(entry) == 1:
68n/a # lazy cache entry, leave it lazy.
69n/a continue
70n/a size, mtime, lines, fullname = entry
71n/a if mtime is None:
72n/a continue # no-op for files loaded via a __loader__
73n/a try:
74n/a stat = os.stat(fullname)
75n/a except OSError:
76n/a del cache[filename]
77n/a continue
78n/a if size != stat.st_size or mtime != stat.st_mtime:
79n/a del cache[filename]
80n/a
81n/a
82n/adef updatecache(filename, module_globals=None):
83n/a """Update a cache entry and return its list of lines.
84n/a If something's wrong, print a message, discard the cache entry,
85n/a and return an empty list."""
86n/a
87n/a if filename in cache:
88n/a if len(cache[filename]) != 1:
89n/a del cache[filename]
90n/a if not filename or (filename.startswith('<') and filename.endswith('>')):
91n/a return []
92n/a
93n/a fullname = filename
94n/a try:
95n/a stat = os.stat(fullname)
96n/a except OSError:
97n/a basename = filename
98n/a
99n/a # Realise a lazy loader based lookup if there is one
100n/a # otherwise try to lookup right now.
101n/a if lazycache(filename, module_globals):
102n/a try:
103n/a data = cache[filename][0]()
104n/a except (ImportError, OSError):
105n/a pass
106n/a else:
107n/a if data is None:
108n/a # No luck, the PEP302 loader cannot find the source
109n/a # for this module.
110n/a return []
111n/a cache[filename] = (
112n/a len(data), None,
113n/a [line+'\n' for line in data.splitlines()], fullname
114n/a )
115n/a return cache[filename][2]
116n/a
117n/a # Try looking through the module search path, which is only useful
118n/a # when handling a relative filename.
119n/a if os.path.isabs(filename):
120n/a return []
121n/a
122n/a for dirname in sys.path:
123n/a try:
124n/a fullname = os.path.join(dirname, basename)
125n/a except (TypeError, AttributeError):
126n/a # Not sufficiently string-like to do anything useful with.
127n/a continue
128n/a try:
129n/a stat = os.stat(fullname)
130n/a break
131n/a except OSError:
132n/a pass
133n/a else:
134n/a return []
135n/a try:
136n/a with tokenize.open(fullname) as fp:
137n/a lines = fp.readlines()
138n/a except OSError:
139n/a return []
140n/a if lines and not lines[-1].endswith('\n'):
141n/a lines[-1] += '\n'
142n/a size, mtime = stat.st_size, stat.st_mtime
143n/a cache[filename] = size, mtime, lines, fullname
144n/a return lines
145n/a
146n/a
147n/adef lazycache(filename, module_globals):
148n/a """Seed the cache for filename with module_globals.
149n/a
150n/a The module loader will be asked for the source only when getlines is
151n/a called, not immediately.
152n/a
153n/a If there is an entry in the cache already, it is not altered.
154n/a
155n/a :return: True if a lazy load is registered in the cache,
156n/a otherwise False. To register such a load a module loader with a
157n/a get_source method must be found, the filename must be a cachable
158n/a filename, and the filename must not be already cached.
159n/a """
160n/a if filename in cache:
161n/a if len(cache[filename]) == 1:
162n/a return True
163n/a else:
164n/a return False
165n/a if not filename or (filename.startswith('<') and filename.endswith('>')):
166n/a return False
167n/a # Try for a __loader__, if available
168n/a if module_globals and '__loader__' in module_globals:
169n/a name = module_globals.get('__name__')
170n/a loader = module_globals['__loader__']
171n/a get_source = getattr(loader, 'get_source', None)
172n/a
173n/a if name and get_source:
174n/a get_lines = functools.partial(get_source, name)
175n/a cache[filename] = (get_lines,)
176n/a return True
177n/a return False