Skip to content

Commit 67bfa7d

Browse files
committed
Thread-safety for linecache
1 parent 6020260 commit 67bfa7d

File tree

1 file changed

+39
-31
lines changed

1 file changed

+39
-31
lines changed

Lib/linecache.py

Lines changed: 39 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,9 @@ def getlines(filename, module_globals=None):
3333
"""Get the lines for a Python source file from the cache.
3434
Update the cache if it doesn't contain an entry for this file already."""
3535

36-
if filename in cache:
37-
entry = cache[filename]
38-
if len(entry) != 1:
39-
return cache[filename][2]
36+
entry = cache.get(filename, None)
37+
if entry is not None and len(entry) != 1:
38+
return entry[2]
4039

4140
try:
4241
return updatecache(filename, module_globals)
@@ -56,10 +55,9 @@ def _make_key(code):
5655

5756
def _getlines_from_code(code):
5857
code_id = _make_key(code)
59-
if code_id in _interactive_cache:
60-
entry = _interactive_cache[code_id]
61-
if len(entry) != 1:
62-
return _interactive_cache[code_id][2]
58+
entry = _interactive_cache.get(code_id, None)
59+
if entry is not None and len(entry) != 1:
60+
return entry[2]
6361
return []
6462

6563

@@ -84,12 +82,8 @@ def checkcache(filename=None):
8482
filenames = [filename]
8583

8684
for filename in filenames:
87-
try:
88-
entry = cache[filename]
89-
except KeyError:
90-
continue
91-
92-
if len(entry) == 1:
85+
entry = cache.get(filename, None)
86+
if entry is None or len(entry) == 1:
9387
# lazy cache entry, leave it lazy.
9488
continue
9589
size, mtime, lines, fullname = entry
@@ -125,9 +119,10 @@ def updatecache(filename, module_globals=None):
125119
# These import can fail if the interpreter is shutting down
126120
return []
127121

128-
if filename in cache:
129-
if len(cache[filename]) != 1:
130-
cache.pop(filename, None)
122+
# entry = cache.get(filename, None)
123+
# if entry is not None and len(entry) != 1:
124+
# cache.pop(filename, None)
125+
entry = cache.pop(filename, None)
131126
if _source_unavailable(filename):
132127
return []
133128

@@ -146,23 +141,27 @@ def updatecache(filename, module_globals=None):
146141

147142
# Realise a lazy loader based lookup if there is one
148143
# otherwise try to lookup right now.
149-
if lazycache(filename, module_globals):
144+
lazy_entry = entry if entry is not None and len(entry) == 1 else None
145+
if lazy_entry is None:
146+
lazy_entry = _make_lazycache_entry(filename, module_globals)
147+
if lazy_entry is not None:
150148
try:
151-
data = cache[filename][0]()
149+
data = lazy_entry[0]()
152150
except (ImportError, OSError):
153151
pass
154152
else:
155153
if data is None:
156154
# No luck, the PEP302 loader cannot find the source
157155
# for this module.
158156
return []
159-
cache[filename] = (
157+
entry = (
160158
len(data),
161159
None,
162160
[line + '\n' for line in data.splitlines()],
163161
fullname
164162
)
165-
return cache[filename][2]
163+
cache[filename] = entry
164+
return entry[2]
166165

167166
# Try looking through the module search path, which is only useful
168167
# when handling a relative filename.
@@ -211,13 +210,20 @@ def lazycache(filename, module_globals):
211210
get_source method must be found, the filename must be a cacheable
212211
filename, and the filename must not be already cached.
213212
"""
214-
if filename in cache:
215-
if len(cache[filename]) == 1:
216-
return True
217-
else:
218-
return False
213+
entry = cache.get(filename, None)
214+
if entry is not None:
215+
return len(entry) == 1
216+
217+
lazy_entry = _make_lazycache_entry(filename, module_globals)
218+
if lazy_entry is not None:
219+
cache[filename] = lazy_entry
220+
return True
221+
return False
222+
223+
224+
def _make_lazycache_entry(filename, module_globals):
219225
if not filename or (filename.startswith('<') and filename.endswith('>')):
220-
return False
226+
return None
221227
# Try for a __loader__, if available
222228
if module_globals and '__name__' in module_globals:
223229
spec = module_globals.get('__spec__')
@@ -230,9 +236,10 @@ def lazycache(filename, module_globals):
230236
if name and get_source:
231237
def get_lines(name=name, *args, **kwargs):
232238
return get_source(name, *args, **kwargs)
233-
cache[filename] = (get_lines,)
234-
return True
235-
return False
239+
return (get_lines,)
240+
return None
241+
242+
236243

237244
def _register_code(code, string, name):
238245
entry = (len(string),
@@ -245,4 +252,5 @@ def _register_code(code, string, name):
245252
for const in code.co_consts:
246253
if isinstance(const, type(code)):
247254
stack.append(const)
248-
_interactive_cache[_make_key(code)] = entry
255+
key = _make_key(code)
256+
_interactive_cache[key] = entry

0 commit comments

Comments
 (0)