gh-121604: Make sure all deprecated items in importlib raise DeprecationWarning (#128007)

Co-authored-by: rashansmith <smith.rashan@gmail.com>
Co-authored-by: Stan Ulbrych <89152624+StanFromIreland@users.noreply.github.com>
Co-authored-by: Brett Cannon <brett@python.org>
This commit is contained in:
Tomas R. 2025-01-15 01:48:46 +01:00 committed by GitHub
parent b52de22ac3
commit bd3baa8b1a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 96 additions and 5 deletions

View file

@ -716,6 +716,12 @@ class WindowsRegistryFinder:
@classmethod
def find_spec(cls, fullname, path=None, target=None):
_warnings.warn('importlib.machinery.WindowsRegistryFinder is '
'deprecated; use site configuration instead. '
'Future versions of Python may not enable this '
'finder by default.',
DeprecationWarning, stacklevel=2)
filepath = cls._search_registry(fullname)
if filepath is None:
return None

View file

@ -70,6 +70,15 @@ class ResourceLoader(Loader):
"""
def __init__(self):
import warnings
warnings.warn('importlib.abc.ResourceLoader is deprecated in '
'favour of supporting resource loading through '
'importlib.resources.abc.ResourceReader.',
DeprecationWarning, stacklevel=2)
super().__init__()
@abc.abstractmethod
def get_data(self, path):
"""Abstract method which when implemented should return the bytes for
@ -199,6 +208,10 @@ class SourceLoader(_bootstrap_external.SourceLoader, ResourceLoader, ExecutionLo
def path_mtime(self, path):
"""Return the (int) modification time for the path (str)."""
import warnings
warnings.warn('SourceLoader.path_mtime is deprecated in favour of '
'SourceLoader.path_stats().',
DeprecationWarning, stacklevel=2)
if self.path_stats.__func__ is SourceLoader.path_stats:
raise OSError
return int(self.path_stats(path)['mtime'])

View file

@ -3,9 +3,11 @@
from ._bootstrap import ModuleSpec
from ._bootstrap import BuiltinImporter
from ._bootstrap import FrozenImporter
from ._bootstrap_external import (SOURCE_SUFFIXES, DEBUG_BYTECODE_SUFFIXES,
OPTIMIZED_BYTECODE_SUFFIXES, BYTECODE_SUFFIXES,
EXTENSION_SUFFIXES)
from ._bootstrap_external import (
SOURCE_SUFFIXES, BYTECODE_SUFFIXES, EXTENSION_SUFFIXES,
DEBUG_BYTECODE_SUFFIXES as _DEBUG_BYTECODE_SUFFIXES,
OPTIMIZED_BYTECODE_SUFFIXES as _OPTIMIZED_BYTECODE_SUFFIXES
)
from ._bootstrap_external import WindowsRegistryFinder
from ._bootstrap_external import PathFinder
from ._bootstrap_external import FileFinder
@ -27,3 +29,22 @@ __all__ = ['AppleFrameworkLoader', 'BYTECODE_SUFFIXES', 'BuiltinImporter',
'NamespaceLoader', 'OPTIMIZED_BYTECODE_SUFFIXES', 'PathFinder',
'SOURCE_SUFFIXES', 'SourceFileLoader', 'SourcelessFileLoader',
'WindowsRegistryFinder', 'all_suffixes']
def __getattr__(name):
import warnings
if name == 'DEBUG_BYTECODE_SUFFIXES':
warnings.warn('importlib.machinery.DEBUG_BYTECODE_SUFFIXES is '
'deprecated; use importlib.machinery.BYTECODE_SUFFIXES '
'instead.',
DeprecationWarning, stacklevel=2)
return _DEBUG_BYTECODE_SUFFIXES
elif name == 'OPTIMIZED_BYTECODE_SUFFIXES':
warnings.warn('importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES is '
'deprecated; use importlib.machinery.BYTECODE_SUFFIXES '
'instead.',
DeprecationWarning, stacklevel=2)
return _OPTIMIZED_BYTECODE_SUFFIXES
raise AttributeError(f'module {__name__!r} has no attribute {name!r}')

View file

@ -858,8 +858,7 @@ def getsourcefile(object):
Return None if no way can be identified to get the source.
"""
filename = getfile(object)
all_bytecode_suffixes = importlib.machinery.DEBUG_BYTECODE_SUFFIXES[:]
all_bytecode_suffixes += importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES[:]
all_bytecode_suffixes = importlib.machinery.BYTECODE_SUFFIXES[:]
if any(filename.endswith(s) for s in all_bytecode_suffixes):
filename = (os.path.splitext(filename)[0] +
importlib.machinery.SOURCE_SUFFIXES[0])

View file

@ -913,5 +913,37 @@ class SourceLoaderGetSourceTests:
SourceOnlyLoaderMock=SPLIT_SOL)
class SourceLoaderDeprecationWarningsTests(unittest.TestCase):
"""Tests SourceLoader deprecation warnings."""
def test_deprecated_path_mtime(self):
from importlib.abc import SourceLoader
class DummySourceLoader(SourceLoader):
def get_data(self, path):
return b''
def get_filename(self, fullname):
return 'foo.py'
def path_stats(self, path):
return {'mtime': 1}
loader = DummySourceLoader()
with self.assertWarns(DeprecationWarning):
loader.path_mtime('foo.py')
class ResourceLoaderDeprecationWarningsTests(unittest.TestCase):
"""Tests ResourceLoader deprecation warnings."""
def test_deprecated_resource_loader(self):
from importlib.abc import ResourceLoader
class DummyLoader(ResourceLoader):
def get_data(self, path):
return b''
with self.assertWarns(DeprecationWarning):
DummyLoader()
if __name__ == '__main__':
unittest.main()

View file

@ -492,5 +492,18 @@ class TestModuleAll(unittest.TestCase):
support.check__all__(self, util['Source'], extra=extra)
class TestDeprecations(unittest.TestCase):
def test_machinery_deprecated_attributes(self):
from importlib import machinery
attributes = (
'DEBUG_BYTECODE_SUFFIXES',
'OPTIMIZED_BYTECODE_SUFFIXES',
)
for attr in attributes:
with self.subTest(attr=attr):
with self.assertWarns(DeprecationWarning):
getattr(machinery, attr)
if __name__ == '__main__':
unittest.main()

View file

@ -104,6 +104,12 @@ class WindowsRegistryFinderTests:
spec = self.machinery.WindowsRegistryFinder.find_spec(self.test_module)
self.assertIsNone(spec)
def test_raises_deprecation_warning(self):
# WindowsRegistryFinder is not meant to be instantiated, so the
# deprecation warning is raised in the 'find_spec' method instead.
with self.assertWarns(DeprecationWarning):
self.machinery.WindowsRegistryFinder.find_spec('spam')
(Frozen_WindowsRegistryFinderTests,
Source_WindowsRegistryFinderTests
) = test_util.test_both(WindowsRegistryFinderTests, machinery=machinery)

View file

@ -0,0 +1 @@
Add missing Deprecation warnings for :attr:`importlib.machinery.DEBUG_BYTECODE_SUFFIXES`, :attr:`importlib.machinery.OPTIMIZED_BYTECODE_SUFFIXES`, :class:`importlib.machinery.WindowsRegistryFinder`, :class:`importlib.abc.ResourceLoader`, :meth:`importlib.abc.SourceLoader.path_mtime`.