Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 15 commits into from
Jan 15, 2025
Merged
6 changes: 6 additions & 0 deletions Lib/importlib/_bootstrap_external.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,6 +716,12 @@ def _search_registry(cls, fullname):

@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
Expand Down
13 changes: 13 additions & 0 deletions Lib/importlib/abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -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.',
brettcannon marked this conversation as resolved.
Show resolved Hide resolved
DeprecationWarning, stacklevel=2)
super().__init__()


@abc.abstractmethod
def get_data(self, path):
"""Abstract method which when implemented should return the bytes for
Expand Down Expand Up @@ -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'])
Expand Down
27 changes: 24 additions & 3 deletions Lib/importlib/machinery.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -27,3 +29,22 @@ def all_suffixes():
'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}')
3 changes: 1 addition & 2 deletions Lib/inspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -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])
Expand Down
32 changes: 32 additions & 0 deletions Lib/test/test_importlib/test_abc.py
Original file line number Diff line number Diff line change
Expand Up @@ -913,5 +913,37 @@ def test_universal_newlines(self):
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()
13 changes: 13 additions & 0 deletions Lib/test/test_importlib/test_api.py
Original file line number Diff line number Diff line change
Expand Up @@ -492,5 +492,18 @@ def test_util(self):
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()
6 changes: 6 additions & 0 deletions Lib/test/test_importlib/test_windows.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,12 @@ def test_module_not_found(self):
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)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add missing Deprecation warnings for several :mod:`importlib` members.
brettcannon marked this conversation as resolved.
Show resolved Hide resolved
Loading