mirror of https://github.com/python/cpython
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.
This commit is contained in:
parent
937d282150
commit
e976baba99
|
@ -166,13 +166,11 @@ def lazycache(filename, module_globals):
|
|||
return False
|
||||
# Try for a __loader__, if available
|
||||
if module_globals and '__name__' in module_globals:
|
||||
name = module_globals['__name__']
|
||||
if (loader := module_globals.get('__loader__')) is None:
|
||||
if spec := module_globals.get('__spec__'):
|
||||
try:
|
||||
loader = spec.loader
|
||||
except AttributeError:
|
||||
pass
|
||||
spec = module_globals.get('__spec__')
|
||||
name = getattr(spec, 'name', None) or module_globals['__name__']
|
||||
loader = getattr(spec, 'loader', None)
|
||||
if loader is None:
|
||||
loader = module_globals.get('__loader__')
|
||||
get_source = getattr(loader, 'get_source', None)
|
||||
|
||||
if name and get_source:
|
||||
|
|
|
@ -5,6 +5,7 @@ import unittest
|
|||
import os.path
|
||||
import tempfile
|
||||
import tokenize
|
||||
from importlib.machinery import ModuleSpec
|
||||
from test import support
|
||||
from test.support import os_helper
|
||||
|
||||
|
@ -97,6 +98,16 @@ class BadUnicode_WithDeclaration(GetLineTestsBadData, unittest.TestCase):
|
|||
file_byte_string = b'# coding=utf-8\n\x80abc'
|
||||
|
||||
|
||||
class FakeLoader:
|
||||
def get_source(self, fullname):
|
||||
return f'source for {fullname}'
|
||||
|
||||
|
||||
class NoSourceLoader:
|
||||
def get_source(self, fullname):
|
||||
return None
|
||||
|
||||
|
||||
class LineCacheTests(unittest.TestCase):
|
||||
|
||||
def test_getline(self):
|
||||
|
@ -238,6 +249,33 @@ class LineCacheTests(unittest.TestCase):
|
|||
self.assertEqual(lines3, [])
|
||||
self.assertEqual(linecache.getlines(FILENAME), lines)
|
||||
|
||||
def test_loader(self):
|
||||
filename = 'scheme://path'
|
||||
|
||||
for loader in (None, object(), NoSourceLoader()):
|
||||
linecache.clearcache()
|
||||
module_globals = {'__name__': 'a.b.c', '__loader__': loader}
|
||||
self.assertEqual(linecache.getlines(filename, module_globals), [])
|
||||
|
||||
linecache.clearcache()
|
||||
module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader()}
|
||||
self.assertEqual(linecache.getlines(filename, module_globals),
|
||||
['source for a.b.c\n'])
|
||||
|
||||
for spec in (None, object(), ModuleSpec('', FakeLoader())):
|
||||
linecache.clearcache()
|
||||
module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader(),
|
||||
'__spec__': spec}
|
||||
self.assertEqual(linecache.getlines(filename, module_globals),
|
||||
['source for a.b.c\n'])
|
||||
|
||||
linecache.clearcache()
|
||||
spec = ModuleSpec('x.y.z', FakeLoader())
|
||||
module_globals = {'__name__': 'a.b.c', '__loader__': spec.loader,
|
||||
'__spec__': spec}
|
||||
self.assertEqual(linecache.getlines(filename, module_globals),
|
||||
['source for x.y.z\n'])
|
||||
|
||||
|
||||
class LineCacheInvalidationTests(unittest.TestCase):
|
||||
def setUp(self):
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
linecache: get module name from ``__spec__`` if available. This allows getting
|
||||
source code for the ``__main__`` module when a custom loader is used.
|
Loading…
Reference in New Issue