mirror of
https://github.com/python/cpython.git
synced 2025-08-04 08:59:19 +00:00
gh-86298: Ensure that __loader__ and __spec__.loader agree in warnings.warn_explicit() (GH-97803)
In `_warnings.c`, in the C equivalent of `warnings.warn_explicit()`, if the module globals are given (and not None), the warning will attempt to get the source line for the issued warning. To do this, it needs the module's loader. Previously, it would only look up `__loader__` in the module globals. In https://github.com/python/cpython/issues/86298 we want to defer to the `__spec__.loader` if available. The first step on this journey is to check that `loader == __spec__.loader` and issue another warning if it is not. This commit does that. Since this is a PoC, only manual testing for now. ```python # /tmp/foo.py import warnings import bar warnings.warn_explicit( 'warning!', RuntimeWarning, 'bar.py', 2, module='bar knee', module_globals=bar.__dict__, ) ``` ```python # /tmp/bar.py import sys import os import pathlib # __loader__ = pathlib.Path() ``` Then running this: `./python.exe -Wdefault /tmp/foo.py` Produces: ``` bar.py:2: RuntimeWarning: warning! import os ``` Uncomment the `__loader__ = ` line in `bar.py` and try it again: ``` sys:1: ImportWarning: Module bar; __loader__ != __spec__.loader (<_frozen_importlib_external.SourceFileLoader object at 0x109f7dfa0> != PosixPath('.')) bar.py:2: RuntimeWarning: warning! import os ``` Automerge-Triggered-By: GH:warsaw
This commit is contained in:
parent
27369ef56f
commit
13d4489142
5 changed files with 182 additions and 3 deletions
|
@ -2,7 +2,9 @@
|
|||
|
||||
from importlib import _bootstrap_external, machinery
|
||||
import os.path
|
||||
from types import ModuleType, SimpleNamespace
|
||||
import unittest
|
||||
import warnings
|
||||
|
||||
from .. import util
|
||||
|
||||
|
@ -67,5 +69,116 @@ class FixUpModuleTests:
|
|||
|
||||
FrozenFixUpModuleTests, SourceFixUpModuleTests = util.test_both(FixUpModuleTests)
|
||||
|
||||
|
||||
class TestBlessMyLoader(unittest.TestCase):
|
||||
# GH#86298 is part of the migration away from module attributes and toward
|
||||
# __spec__ attributes. There are several cases to test here. This will
|
||||
# have to change in Python 3.14 when we actually remove/ignore __loader__
|
||||
# in favor of requiring __spec__.loader.
|
||||
|
||||
def test_gh86298_no_loader_and_no_spec(self):
|
||||
bar = ModuleType('bar')
|
||||
del bar.__loader__
|
||||
del bar.__spec__
|
||||
# 2022-10-06(warsaw): For backward compatibility with the
|
||||
# implementation in _warnings.c, this can't raise an
|
||||
# AttributeError. See _bless_my_loader() in _bootstrap_external.py
|
||||
# If working with a module:
|
||||
## self.assertRaises(
|
||||
## AttributeError, _bootstrap_external._bless_my_loader,
|
||||
## bar.__dict__)
|
||||
self.assertIsNone(_bootstrap_external._bless_my_loader(bar.__dict__))
|
||||
|
||||
def test_gh86298_loader_is_none_and_no_spec(self):
|
||||
bar = ModuleType('bar')
|
||||
bar.__loader__ = None
|
||||
del bar.__spec__
|
||||
# 2022-10-06(warsaw): For backward compatibility with the
|
||||
# implementation in _warnings.c, this can't raise an
|
||||
# AttributeError. See _bless_my_loader() in _bootstrap_external.py
|
||||
# If working with a module:
|
||||
## self.assertRaises(
|
||||
## AttributeError, _bootstrap_external._bless_my_loader,
|
||||
## bar.__dict__)
|
||||
self.assertIsNone(_bootstrap_external._bless_my_loader(bar.__dict__))
|
||||
|
||||
def test_gh86298_no_loader_and_spec_is_none(self):
|
||||
bar = ModuleType('bar')
|
||||
del bar.__loader__
|
||||
bar.__spec__ = None
|
||||
self.assertRaises(
|
||||
ValueError,
|
||||
_bootstrap_external._bless_my_loader, bar.__dict__)
|
||||
|
||||
def test_gh86298_loader_is_none_and_spec_is_none(self):
|
||||
bar = ModuleType('bar')
|
||||
bar.__loader__ = None
|
||||
bar.__spec__ = None
|
||||
self.assertRaises(
|
||||
ValueError,
|
||||
_bootstrap_external._bless_my_loader, bar.__dict__)
|
||||
|
||||
def test_gh86298_loader_is_none_and_spec_loader_is_none(self):
|
||||
bar = ModuleType('bar')
|
||||
bar.__loader__ = None
|
||||
bar.__spec__ = SimpleNamespace(loader=None)
|
||||
self.assertRaises(
|
||||
ValueError,
|
||||
_bootstrap_external._bless_my_loader, bar.__dict__)
|
||||
|
||||
def test_gh86298_no_spec(self):
|
||||
bar = ModuleType('bar')
|
||||
bar.__loader__ = object()
|
||||
del bar.__spec__
|
||||
with warnings.catch_warnings():
|
||||
self.assertWarns(
|
||||
DeprecationWarning,
|
||||
_bootstrap_external._bless_my_loader, bar.__dict__)
|
||||
|
||||
def test_gh86298_spec_is_none(self):
|
||||
bar = ModuleType('bar')
|
||||
bar.__loader__ = object()
|
||||
bar.__spec__ = None
|
||||
with warnings.catch_warnings():
|
||||
self.assertWarns(
|
||||
DeprecationWarning,
|
||||
_bootstrap_external._bless_my_loader, bar.__dict__)
|
||||
|
||||
def test_gh86298_no_spec_loader(self):
|
||||
bar = ModuleType('bar')
|
||||
bar.__loader__ = object()
|
||||
bar.__spec__ = SimpleNamespace()
|
||||
with warnings.catch_warnings():
|
||||
self.assertWarns(
|
||||
DeprecationWarning,
|
||||
_bootstrap_external._bless_my_loader, bar.__dict__)
|
||||
|
||||
def test_gh86298_loader_and_spec_loader_disagree(self):
|
||||
bar = ModuleType('bar')
|
||||
bar.__loader__ = object()
|
||||
bar.__spec__ = SimpleNamespace(loader=object())
|
||||
with warnings.catch_warnings():
|
||||
self.assertWarns(
|
||||
DeprecationWarning,
|
||||
_bootstrap_external._bless_my_loader, bar.__dict__)
|
||||
|
||||
def test_gh86298_no_loader_and_no_spec_loader(self):
|
||||
bar = ModuleType('bar')
|
||||
del bar.__loader__
|
||||
bar.__spec__ = SimpleNamespace()
|
||||
self.assertRaises(
|
||||
AttributeError,
|
||||
_bootstrap_external._bless_my_loader, bar.__dict__)
|
||||
|
||||
def test_gh86298_no_loader_with_spec_loader_okay(self):
|
||||
bar = ModuleType('bar')
|
||||
del bar.__loader__
|
||||
loader = object()
|
||||
bar.__spec__ = SimpleNamespace(loader=loader)
|
||||
self.assertEqual(
|
||||
_bootstrap_external._bless_my_loader(bar.__dict__),
|
||||
loader)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue