blob: 884cbf493a494da752d15c6a7b52d575fa7649a2 [file] [log] [blame]
Victor Stinner376658f2015-03-18 14:16:50 +01001"""Cache lines from Python source files.
Guido van Rossum54f22ed2000-02-04 15:10:34 +00002
3This is intended to read lines from modules imported -- hence if a filename
4is not found, it will look down the module search path for a file by
5that name.
6"""
Guido van Rossum921c8241992-01-10 14:54:42 +00007
Guido van Rossumc341c621992-03-27 15:12:43 +00008import sys
Guido van Rossum921c8241992-01-10 14:54:42 +00009import os
Benjamin Peterson9b8d24b2009-03-24 22:30:15 +000010import tokenize
Guido van Rossum921c8241992-01-10 14:54:42 +000011
Jeremy Hylton97b2e842003-06-29 16:59:43 +000012__all__ = ["getline", "clearcache", "checkcache"]
Skip Montanaro17ab1232001-01-24 06:27:27 +000013
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000014def getline(filename, lineno, module_globals=None):
15 lines = getlines(filename, module_globals)
Guido van Rossum54f22ed2000-02-04 15:10:34 +000016 if 1 <= lineno <= len(lines):
17 return lines[lineno-1]
18 else:
19 return ''
Guido van Rossum921c8241992-01-10 14:54:42 +000020
21
22# The cache
23
24cache = {} # The cache
25
26
Guido van Rossum921c8241992-01-10 14:54:42 +000027def clearcache():
Guido van Rossum54f22ed2000-02-04 15:10:34 +000028 """Clear the cache entirely."""
Guido van Rossum921c8241992-01-10 14:54:42 +000029
Guido van Rossum54f22ed2000-02-04 15:10:34 +000030 global cache
31 cache = {}
Guido van Rossum921c8241992-01-10 14:54:42 +000032
Guido van Rossum921c8241992-01-10 14:54:42 +000033
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000034def getlines(filename, module_globals=None):
Victor Stinner376658f2015-03-18 14:16:50 +010035 """Get the lines for a Python source file from the cache.
Guido van Rossum54f22ed2000-02-04 15:10:34 +000036 Update the cache if it doesn't contain an entry for this file already."""
Guido van Rossum921c8241992-01-10 14:54:42 +000037
Raymond Hettinger54f02222002-06-01 14:18:47 +000038 if filename in cache:
Guido van Rossum54f22ed2000-02-04 15:10:34 +000039 return cache[filename][2]
Serhiy Storchakac512adc2015-04-01 16:54:05 +030040
41 try:
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000042 return updatecache(filename, module_globals)
Serhiy Storchakac512adc2015-04-01 16:54:05 +030043 except MemoryError:
44 clearcache()
45 return []
Guido van Rossum921c8241992-01-10 14:54:42 +000046
Guido van Rossum921c8241992-01-10 14:54:42 +000047
Hye-Shik Chang182ac852004-10-26 09:16:42 +000048def checkcache(filename=None):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000049 """Discard cache entries that are out of date.
50 (This is not checked upon each call!)"""
Guido van Rossum921c8241992-01-10 14:54:42 +000051
Hye-Shik Chang182ac852004-10-26 09:16:42 +000052 if filename is None:
Guido van Rossumf5433482007-02-26 22:21:25 +000053 filenames = list(cache.keys())
Hye-Shik Chang182ac852004-10-26 09:16:42 +000054 else:
55 if filename in cache:
56 filenames = [filename]
57 else:
58 return
59
60 for filename in filenames:
Guido van Rossum54f22ed2000-02-04 15:10:34 +000061 size, mtime, lines, fullname = cache[filename]
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000062 if mtime is None:
63 continue # no-op for files loaded via a __loader__
Guido van Rossum54f22ed2000-02-04 15:10:34 +000064 try:
65 stat = os.stat(fullname)
Andrew Svetlovad28c7f2012-12-18 22:02:39 +020066 except OSError:
Guido van Rossum54f22ed2000-02-04 15:10:34 +000067 del cache[filename]
68 continue
Raymond Hettinger32200ae2002-06-01 19:51:15 +000069 if size != stat.st_size or mtime != stat.st_mtime:
Guido van Rossum54f22ed2000-02-04 15:10:34 +000070 del cache[filename]
Guido van Rossum921c8241992-01-10 14:54:42 +000071
Guido van Rossum921c8241992-01-10 14:54:42 +000072
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000073def updatecache(filename, module_globals=None):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000074 """Update a cache entry and return its list of lines.
75 If something's wrong, print a message, discard the cache entry,
76 and return an empty list."""
77
Raymond Hettinger54f02222002-06-01 14:18:47 +000078 if filename in cache:
Guido van Rossum54f22ed2000-02-04 15:10:34 +000079 del cache[filename]
Benjamin Petersonaada7b82010-05-21 21:45:06 +000080 if not filename or (filename.startswith('<') and filename.endswith('>')):
Guido van Rossum54f22ed2000-02-04 15:10:34 +000081 return []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000082
Guido van Rossum54f22ed2000-02-04 15:10:34 +000083 fullname = filename
84 try:
85 stat = os.stat(fullname)
Benjamin Petersonaada7b82010-05-21 21:45:06 +000086 except OSError:
Georg Brandl991f9202009-05-05 08:31:54 +000087 basename = filename
Thomas Wouters49fd7fa2006-04-21 10:40:58 +000088
89 # Try for a __loader__, if available
90 if module_globals and '__loader__' in module_globals:
91 name = module_globals.get('__name__')
92 loader = module_globals['__loader__']
93 get_source = getattr(loader, 'get_source', None)
94
95 if name and get_source:
Nick Coghlanf088e5e2008-12-14 11:50:48 +000096 try:
97 data = get_source(name)
Andrew Svetlovf7a17b42012-12-25 16:47:37 +020098 except (ImportError, OSError):
Nick Coghlanf088e5e2008-12-14 11:50:48 +000099 pass
100 else:
101 if data is None:
102 # No luck, the PEP302 loader cannot find the source
103 # for this module.
104 return []
105 cache[filename] = (
106 len(data), None,
107 [line+'\n' for line in data.splitlines()], fullname
108 )
109 return cache[filename][2]
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000110
Georg Brandl991f9202009-05-05 08:31:54 +0000111 # Try looking through the module search path, which is only useful
112 # when handling a relative filename.
113 if os.path.isabs(filename):
114 return []
Thomas Wouters49fd7fa2006-04-21 10:40:58 +0000115
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000116 for dirname in sys.path:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000117 try:
Tim Peters12f21ae2001-05-29 04:27:01 +0000118 fullname = os.path.join(dirname, basename)
119 except (TypeError, AttributeError):
120 # Not sufficiently string-like to do anything useful with.
Benjamin Petersonaada7b82010-05-21 21:45:06 +0000121 continue
122 try:
123 stat = os.stat(fullname)
124 break
Andrew Svetlovad28c7f2012-12-18 22:02:39 +0200125 except OSError:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000126 pass
127 else:
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000128 return []
Benjamin Petersonaada7b82010-05-21 21:45:06 +0000129 try:
Victor Stinner58c07522010-11-09 01:08:59 +0000130 with tokenize.open(fullname) as fp:
Benjamin Petersonaada7b82010-05-21 21:45:06 +0000131 lines = fp.readlines()
Andrew Svetlovf7a17b42012-12-25 16:47:37 +0200132 except OSError:
Victor Stinner41a64a52010-09-29 01:30:45 +0000133 return []
Benjamin Petersonaada7b82010-05-21 21:45:06 +0000134 if lines and not lines[-1].endswith('\n'):
135 lines[-1] += '\n'
Raymond Hettinger32200ae2002-06-01 19:51:15 +0000136 size, mtime = stat.st_size, stat.st_mtime
Guido van Rossum54f22ed2000-02-04 15:10:34 +0000137 cache[filename] = size, mtime, lines, fullname
138 return lines