gh-86291: linecache: get module name from __spec__ if available (GH-2… · python/cpython@e976bab · GitHub
Skip to content

Commit e976bab

Browse files
authored
gh-86291: linecache: get module name from __spec__ if available (GH-22908)
This allows getting source code for the __main__ module when a custom loader is used.
1 parent 937d282 commit e976bab

3 files changed

Lines changed: 45 additions & 7 deletions

File tree

Lib/linecache.py

Lines changed: 5 additions & 7 deletions

Lib/test/test_linecache.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import os.path
66
import tempfile
77
import tokenize
8+
from importlib.machinery import ModuleSpec
89
from test import support
910
from test.support import os_helper
1011

@@ -97,6 +98,16 @@ class BadUnicode_WithDeclaration(GetLineTestsBadData, unittest.TestCase):
9798
file_byte_string = b'# coding=utf-8\n\x80abc'
9899

99100

101+
class FakeLoader:
102+
def get_source(self, fullname):
103+
return f'source for {fullname}'
104+
105+
106+
class NoSourceLoader:
107+
def get_source(self, fullname):
108+
return None
109+
110+
100111
class LineCacheTests(unittest.TestCase):
101112

102113
def test_getline(self):
@@ -238,6 +249,33 @@ def raise_memoryerror(*args, **kwargs):
238249
self.assertEqual(lines3, [])
239250
self.assertEqual(linecache.getlines(FILENAME), lines)
240251

252+
def test_loader(self):
253+
filename = 'scheme://path'
254+
255+
for loader in (None, object(), NoSourceLoader()):
256+
linecache.clearcache()
257+
module_globals = {'__name__': 'a.b.c', '__loader__': loader}
258+
self.assertEqual(linecache.getlines(filename, module_globals), [])
259+
260+
linecache.clearcache()
261+
module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader()}
262+
self.assertEqual(linecache.getlines(filename, module_globals),
263+
['source for a.b.c\n'])
264+
265+
for spec in (None, object(), ModuleSpec('', FakeLoader())):
266+
linecache.clearcache()
267+
module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader(),
268+
'__spec__': spec}
269+
self.assertEqual(linecache.getlines(filename, module_globals),
270+
['source for a.b.c\n'])
271+
272+
linecache.clearcache()
273+
spec = ModuleSpec('x.y.z', FakeLoader())
274+
module_globals = {'__name__': 'a.b.c', '__loader__': spec.loader,
275+
'__spec__': spec}
276+
self.assertEqual(linecache.getlines(filename, module_globals),
277+
['source for x.y.z\n'])
278+
241279

242280
class LineCacheInvalidationTests(unittest.TestCase):
243281
def setUp(self):
Lines changed: 2 additions & 0 deletions

0 commit comments

Comments
 (0)