mirror of
https://github.com/python/cpython.git
synced 2025-12-08 06:10:17 +00:00
gh-122255: Synchronize warnings in C and Python implementations of the warnings module (GH-122824)
In the linecache module and in the Python implementation of the warnings module, a DeprecationWarning is issued when m.__loader__ differs from m.__spec__.loader (like in the C implementation of the warnings module).
This commit is contained in:
parent
c10fa5be61
commit
8deaa9393e
4 changed files with 82 additions and 22 deletions
|
|
@ -224,21 +224,58 @@ def lazycache(filename, module_globals):
|
|||
def _make_lazycache_entry(filename, module_globals):
|
||||
if not filename or (filename.startswith('<') and filename.endswith('>')):
|
||||
return None
|
||||
# Try for a __loader__, if available
|
||||
if module_globals and '__name__' in module_globals:
|
||||
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:
|
||||
def get_lines(name=name, *args, **kwargs):
|
||||
return get_source(name, *args, **kwargs)
|
||||
return (get_lines,)
|
||||
return None
|
||||
if module_globals is not None and not isinstance(module_globals, dict):
|
||||
raise TypeError(f'module_globals must be a dict, not {type(module_globals).__qualname__}')
|
||||
if not module_globals or '__name__' not in module_globals:
|
||||
return None
|
||||
|
||||
spec = module_globals.get('__spec__')
|
||||
name = getattr(spec, 'name', None) or module_globals['__name__']
|
||||
if name is None:
|
||||
return None
|
||||
|
||||
loader = _bless_my_loader(module_globals)
|
||||
if loader is None:
|
||||
return None
|
||||
|
||||
get_source = getattr(loader, 'get_source', None)
|
||||
if get_source is None:
|
||||
return None
|
||||
|
||||
def get_lines(name=name, *args, **kwargs):
|
||||
return get_source(name, *args, **kwargs)
|
||||
return (get_lines,)
|
||||
|
||||
def _bless_my_loader(module_globals):
|
||||
# Similar to _bless_my_loader() in importlib._bootstrap_external,
|
||||
# but always emits warnings instead of errors.
|
||||
loader = module_globals.get('__loader__')
|
||||
if loader is None and '__spec__' not in module_globals:
|
||||
return None
|
||||
spec = module_globals.get('__spec__')
|
||||
|
||||
# The __main__ module has __spec__ = None.
|
||||
if spec is None and module_globals.get('__name__') == '__main__':
|
||||
return loader
|
||||
|
||||
spec_loader = getattr(spec, 'loader', None)
|
||||
if spec_loader is None:
|
||||
import warnings
|
||||
warnings.warn(
|
||||
'Module globals is missing a __spec__.loader',
|
||||
DeprecationWarning)
|
||||
return loader
|
||||
|
||||
assert spec_loader is not None
|
||||
if loader is not None and loader != spec_loader:
|
||||
import warnings
|
||||
warnings.warn(
|
||||
'Module globals; __loader__ != __spec__.loader',
|
||||
DeprecationWarning)
|
||||
return loader
|
||||
|
||||
return spec_loader
|
||||
|
||||
|
||||
def _register_code(code, string, name):
|
||||
|
|
|
|||
|
|
@ -259,22 +259,44 @@ def raise_memoryerror(*args, **kwargs):
|
|||
def test_loader(self):
|
||||
filename = 'scheme://path'
|
||||
|
||||
for loader in (None, object(), NoSourceLoader()):
|
||||
linecache.clearcache()
|
||||
module_globals = {'__name__': 'a.b.c', '__loader__': None}
|
||||
self.assertEqual(linecache.getlines(filename, module_globals), [])
|
||||
|
||||
for loader in object(), NoSourceLoader():
|
||||
linecache.clearcache()
|
||||
module_globals = {'__name__': 'a.b.c', '__loader__': loader}
|
||||
self.assertEqual(linecache.getlines(filename, module_globals), [])
|
||||
with self.assertWarns(DeprecationWarning) as w:
|
||||
self.assertEqual(linecache.getlines(filename, module_globals), [])
|
||||
self.assertEqual(str(w.warning),
|
||||
'Module globals is missing a __spec__.loader')
|
||||
|
||||
linecache.clearcache()
|
||||
module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader()}
|
||||
self.assertEqual(linecache.getlines(filename, module_globals),
|
||||
['source for a.b.c\n'])
|
||||
with self.assertWarns(DeprecationWarning) as w:
|
||||
self.assertEqual(linecache.getlines(filename, module_globals),
|
||||
['source for a.b.c\n'])
|
||||
self.assertEqual(str(w.warning),
|
||||
'Module globals is missing a __spec__.loader')
|
||||
|
||||
for spec in (None, object(), ModuleSpec('', FakeLoader())):
|
||||
for spec in None, object():
|
||||
linecache.clearcache()
|
||||
module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader(),
|
||||
'__spec__': spec}
|
||||
with self.assertWarns(DeprecationWarning) as w:
|
||||
self.assertEqual(linecache.getlines(filename, module_globals),
|
||||
['source for a.b.c\n'])
|
||||
self.assertEqual(str(w.warning),
|
||||
'Module globals is missing a __spec__.loader')
|
||||
|
||||
linecache.clearcache()
|
||||
module_globals = {'__name__': 'a.b.c', '__loader__': FakeLoader(),
|
||||
'__spec__': ModuleSpec('', FakeLoader())}
|
||||
with self.assertWarns(DeprecationWarning) as w:
|
||||
self.assertEqual(linecache.getlines(filename, module_globals),
|
||||
['source for a.b.c\n'])
|
||||
self.assertEqual(str(w.warning),
|
||||
'Module globals; __loader__ != __spec__.loader')
|
||||
|
||||
linecache.clearcache()
|
||||
spec = ModuleSpec('x.y.z', FakeLoader())
|
||||
|
|
|
|||
|
|
@ -727,7 +727,7 @@ def check_module_globals(self, module_globals):
|
|||
|
||||
def check_module_globals_error(self, module_globals, errmsg, errtype=ValueError):
|
||||
if self.module is py_warnings:
|
||||
self.check_module_globals(module_globals)
|
||||
self.check_module_globals_deprecated(module_globals, errmsg)
|
||||
return
|
||||
with self.module.catch_warnings(record=True) as w:
|
||||
self.module.filterwarnings('always')
|
||||
|
|
@ -738,9 +738,6 @@ def check_module_globals_error(self, module_globals, errmsg, errtype=ValueError)
|
|||
self.assertEqual(len(w), 0)
|
||||
|
||||
def check_module_globals_deprecated(self, module_globals, msg):
|
||||
if self.module is py_warnings:
|
||||
self.check_module_globals(module_globals)
|
||||
return
|
||||
with self.module.catch_warnings(record=True) as w:
|
||||
self.module.filterwarnings('always')
|
||||
self.module.warn_explicit(
|
||||
|
|
|
|||
|
|
@ -0,0 +1,4 @@
|
|||
In the :mod:`linecache` module and in the Python implementation of the
|
||||
:mod:`warnings` module, a ``DeprecationWarning`` is issued when
|
||||
``mod.__loader__`` differs from ``mod.__spec__.loader`` (like in the C
|
||||
implementation of the :mod:`!warnings` module).
|
||||
Loading…
Add table
Add a link
Reference in a new issue