Skip to content

Commit 7bbf5d6

Browse files
Support getting source file for frozen modules
1 parent ef06508 commit 7bbf5d6

File tree

2 files changed

+32
-2
lines changed

2 files changed

+32
-2
lines changed

Lib/linecache.py

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,16 @@ def _getlines_from_code(code):
6363
return []
6464

6565

66+
def _source_unavailable(filename):
67+
"""Return True if the source code is unavailable for such file name"""
68+
return (
69+
not filename
70+
or (filename.startswith('<')
71+
and filename.endswith('>')
72+
and not filename.startswith('<frozen '))
73+
)
74+
75+
6676
def checkcache(filename=None):
6777
"""Discard cache entries that are out of date.
6878
(This is not checked upon each call!)"""
@@ -118,10 +128,17 @@ def updatecache(filename, module_globals=None):
118128
if filename in cache:
119129
if len(cache[filename]) != 1:
120130
cache.pop(filename, None)
121-
if not filename or (filename.startswith('<') and filename.endswith('>')):
131+
if _source_unavailable(filename):
122132
return []
123133

124-
fullname = filename
134+
if filename.startswith('<frozen ') and module_globals is not None:
135+
# This is a frozen module, so we need to use the filename
136+
# from the module globals.
137+
fullname = module_globals.get('__file__', None)
138+
if fullname is None:
139+
return []
140+
else:
141+
fullname = filename
125142
try:
126143
stat = os.stat(fullname)
127144
except OSError:

Lib/test/test_linecache.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,19 @@ def test_loader(self):
281281
self.assertEqual(linecache.getlines(filename, module_globals),
282282
['source for x.y.z\n'])
283283

284+
def test_frozen(self):
285+
filename = '<frozen fakemodule>'
286+
module_globals = {'__file__': FILENAME}
287+
empty = linecache.getlines(filename)
288+
self.assertEqual(empty, [])
289+
lines = linecache.getlines(filename, module_globals)
290+
self.assertGreater(len(lines), 0)
291+
lines_cached = linecache.getlines(filename)
292+
self.assertEqual(lines, lines_cached)
293+
linecache.clearcache()
294+
empty = linecache.getlines(filename)
295+
self.assertEqual(empty, [])
296+
284297
def test_invalid_names(self):
285298
for name, desc in [
286299
('\x00', 'NUL bytes filename'),

0 commit comments

Comments
 (0)