summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNikita Sobolev <mail@sobolevn.me>2022-10-07 00:57:10 (GMT)
committerGitHub <noreply@github.com>2022-10-07 00:57:10 (GMT)
commit27025e158c70331d0a8fb42fe234a2a6770850d1 (patch)
tree7a65a7e92f1db72ce3d942f32af13dfe40ed2462
parent4875433682ffec2694647ac43f1b21f5ad73fd25 (diff)
downloadcpython-27025e158c70331d0a8fb42fe234a2a6770850d1.zip
cpython-27025e158c70331d0a8fb42fe234a2a6770850d1.tar.gz
cpython-27025e158c70331d0a8fb42fe234a2a6770850d1.tar.bz2
gh-97850: Remove deprecated functions from `importlib.utils` (#97898)
* gh-97850: Remove deprecated functions from `importlib.utils` * Rebase and remove `set_package` from diff
-rw-r--r--Doc/library/importlib.rst54
-rw-r--r--Lib/importlib/util.py87
-rw-r--r--Lib/test/test_importlib/test_abc.py8
-rw-r--r--Lib/test/test_importlib/test_spec.py48
-rw-r--r--Lib/test/test_importlib/test_util.py178
-rw-r--r--Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst2
6 files changed, 4 insertions, 373 deletions
diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst
index a7c067c..3fc1531 100644
--- a/Doc/library/importlib.rst
+++ b/Doc/library/importlib.rst
@@ -443,7 +443,7 @@ ABC hierarchy::
from the import. If the loader inserted a module and the load fails, it
must be removed by the loader from :data:`sys.modules`; modules already
in :data:`sys.modules` before the loader began execution should be left
- alone (see :func:`importlib.util.module_for_loader`).
+ alone.
The loader should set several attributes on the module
(note that some of these attributes can change when a module is
@@ -1326,58 +1326,6 @@ an :term:`importer`.
.. versionadded:: 3.5
-.. decorator:: module_for_loader
-
- A :term:`decorator` for :meth:`importlib.abc.Loader.load_module`
- to handle selecting the proper
- module object to load with. The decorated method is expected to have a call
- signature taking two positional arguments
- (e.g. ``load_module(self, module)``) for which the second argument
- will be the module **object** to be used by the loader.
- Note that the decorator will not work on static methods because of the
- assumption of two arguments.
-
- The decorated method will take in the **name** of the module to be loaded
- as expected for a :term:`loader`. If the module is not found in
- :data:`sys.modules` then a new one is constructed. Regardless of where the
- module came from, :attr:`__loader__` set to **self** and :attr:`__package__`
- is set based on what :meth:`importlib.abc.InspectLoader.is_package` returns
- (if available). These attributes are set unconditionally to support
- reloading.
-
- If an exception is raised by the decorated method and a module was added to
- :data:`sys.modules`, then the module will be removed to prevent a partially
- initialized module from being in left in :data:`sys.modules`. If the module
- was already in :data:`sys.modules` then it is left alone.
-
- .. versionchanged:: 3.3
- :attr:`__loader__` and :attr:`__package__` are automatically set
- (when possible).
-
- .. versionchanged:: 3.4
- Set :attr:`__name__`, :attr:`__loader__` :attr:`__package__`
- unconditionally to support reloading.
-
- .. deprecated:: 3.4
- The import machinery now directly performs all the functionality
- provided by this function.
-
-.. decorator:: set_loader
-
- A :term:`decorator` for :meth:`importlib.abc.Loader.load_module`
- to set the :attr:`__loader__`
- attribute on the returned module. If the attribute is already set the
- decorator does nothing. It is assumed that the first positional argument to
- the wrapped method (i.e. ``self``) is what :attr:`__loader__` should be set
- to.
-
- .. versionchanged:: 3.4
- Set ``__loader__`` if set to ``None``, as if the attribute does not
- exist.
-
- .. deprecated:: 3.4
- The import machinery takes care of this automatically.
-
.. function:: spec_from_loader(name, loader, *, origin=None, is_package=None)
A factory function for creating a :class:`~importlib.machinery.ModuleSpec`
diff --git a/Lib/importlib/util.py b/Lib/importlib/util.py
index 7f15b02..9e29c58 100644
--- a/Lib/importlib/util.py
+++ b/Lib/importlib/util.py
@@ -11,12 +11,9 @@ from ._bootstrap_external import decode_source
from ._bootstrap_external import source_from_cache
from ._bootstrap_external import spec_from_file_location
-from contextlib import contextmanager
import _imp
-import functools
import sys
import types
-import warnings
def source_hash(source_bytes):
@@ -115,90 +112,6 @@ def find_spec(name, package=None):
return spec
-@contextmanager
-def _module_to_load(name):
- is_reload = name in sys.modules
-
- module = sys.modules.get(name)
- if not is_reload:
- # This must be done before open() is called as the 'io' module
- # implicitly imports 'locale' and would otherwise trigger an
- # infinite loop.
- module = type(sys)(name)
- # This must be done before putting the module in sys.modules
- # (otherwise an optimization shortcut in import.c becomes wrong)
- module.__initializing__ = True
- sys.modules[name] = module
- try:
- yield module
- except Exception:
- if not is_reload:
- try:
- del sys.modules[name]
- except KeyError:
- pass
- finally:
- module.__initializing__ = False
-
-
-def set_loader(fxn):
- """Set __loader__ on the returned module.
-
- This function is deprecated.
-
- """
- @functools.wraps(fxn)
- def set_loader_wrapper(self, *args, **kwargs):
- warnings.warn('The import system now takes care of this automatically; '
- 'this decorator is slated for removal in Python 3.12',
- DeprecationWarning, stacklevel=2)
- module = fxn(self, *args, **kwargs)
- if getattr(module, '__loader__', None) is None:
- module.__loader__ = self
- return module
- return set_loader_wrapper
-
-
-def module_for_loader(fxn):
- """Decorator to handle selecting the proper module for loaders.
-
- The decorated function is passed the module to use instead of the module
- name. The module passed in to the function is either from sys.modules if
- it already exists or is a new module. If the module is new, then __name__
- is set the first argument to the method, __loader__ is set to self, and
- __package__ is set accordingly (if self.is_package() is defined) will be set
- before it is passed to the decorated function (if self.is_package() does
- not work for the module it will be set post-load).
-
- If an exception is raised and the decorator created the module it is
- subsequently removed from sys.modules.
-
- The decorator assumes that the decorated function takes the module name as
- the second argument.
-
- """
- warnings.warn('The import system now takes care of this automatically; '
- 'this decorator is slated for removal in Python 3.12',
- DeprecationWarning, stacklevel=2)
- @functools.wraps(fxn)
- def module_for_loader_wrapper(self, fullname, *args, **kwargs):
- with _module_to_load(fullname) as module:
- module.__loader__ = self
- try:
- is_package = self.is_package(fullname)
- except (ImportError, AttributeError):
- pass
- else:
- if is_package:
- module.__package__ = fullname
- else:
- module.__package__ = fullname.rpartition('.')[0]
- # If __package__ was not set above, __import__() will do it later.
- return fxn(self, module, *args, **kwargs)
-
- return module_for_loader_wrapper
-
-
class _LazyModule(types.ModuleType):
"""A subclass of the module type which triggers loading upon attribute access."""
diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py
index 8641b6c..3c9149c 100644
--- a/Lib/test/test_importlib/test_abc.py
+++ b/Lib/test/test_importlib/test_abc.py
@@ -771,13 +771,7 @@ class SourceLoaderTestHarness:
class SourceOnlyLoaderTests(SourceLoaderTestHarness):
-
- """Test importlib.abc.SourceLoader for source-only loading.
-
- Reload testing is subsumed by the tests for
- importlib.util.module_for_loader.
-
- """
+ """Test importlib.abc.SourceLoader for source-only loading."""
def test_get_source(self):
# Verify the source code is returned as a string.
diff --git a/Lib/test/test_importlib/test_spec.py b/Lib/test/test_importlib/test_spec.py
index f1ab16c..80aa360 100644
--- a/Lib/test/test_importlib/test_spec.py
+++ b/Lib/test/test_importlib/test_spec.py
@@ -47,21 +47,6 @@ class NewLoader(TestLoader):
module.eggs = self.EGGS
-class LegacyLoader(TestLoader):
-
- HAM = -1
-
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", DeprecationWarning)
-
- frozen_util = util['Frozen']
-
- @frozen_util.module_for_loader
- def load_module(self, module):
- module.ham = self.HAM
- return module
-
-
class ModuleSpecTests:
def setUp(self):
@@ -302,26 +287,6 @@ class ModuleSpecMethodsTests:
loaded = self.bootstrap._load(self.spec)
self.assertNotIn(self.spec.name, sys.modules)
- def test_load_legacy(self):
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", ImportWarning)
- self.spec.loader = LegacyLoader()
- with CleanImport(self.spec.name):
- loaded = self.bootstrap._load(self.spec)
-
- self.assertEqual(loaded.ham, -1)
-
- def test_load_legacy_attributes(self):
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", ImportWarning)
- self.spec.loader = LegacyLoader()
- with CleanImport(self.spec.name):
- loaded = self.bootstrap._load(self.spec)
-
- self.assertIs(loaded.__loader__, self.spec.loader)
- self.assertEqual(loaded.__package__, self.spec.parent)
- self.assertIs(loaded.__spec__, self.spec)
-
def test_load_legacy_attributes_immutable(self):
module = object()
with warnings.catch_warnings():
@@ -387,19 +352,6 @@ class ModuleSpecMethodsTests:
self.assertFalse(hasattr(loaded, '__file__'))
self.assertFalse(hasattr(loaded, '__cached__'))
- def test_reload_legacy(self):
- with warnings.catch_warnings():
- warnings.simplefilter("ignore", ImportWarning)
- self.spec.loader = LegacyLoader()
- with CleanImport(self.spec.name):
- loaded = self.bootstrap._load(self.spec)
- reloaded = self.bootstrap._exec(self.spec, loaded)
- installed = sys.modules[self.spec.name]
-
- self.assertEqual(loaded.ham, -1)
- self.assertIs(reloaded, loaded)
- self.assertIs(installed, loaded)
-
(Frozen_ModuleSpecMethodsTests,
Source_ModuleSpecMethodsTests
diff --git a/Lib/test/test_importlib/test_util.py b/Lib/test/test_importlib/test_util.py
index e70971e..08a615e 100644
--- a/Lib/test/test_importlib/test_util.py
+++ b/Lib/test/test_importlib/test_util.py
@@ -121,184 +121,6 @@ class ModuleFromSpecTests:
util=importlib_util)
-class ModuleForLoaderTests:
-
- """Tests for importlib.util.module_for_loader."""
-
- @classmethod
- def module_for_loader(cls, func):
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- return cls.util.module_for_loader(func)
-
- def test_warning(self):
- # Should raise a PendingDeprecationWarning when used.
- with warnings.catch_warnings():
- warnings.simplefilter('error', DeprecationWarning)
- with self.assertRaises(DeprecationWarning):
- func = self.util.module_for_loader(lambda x: x)
-
- def return_module(self, name):
- fxn = self.module_for_loader(lambda self, module: module)
- return fxn(self, name)
-
- def raise_exception(self, name):
- def to_wrap(self, module):
- raise ImportError
- fxn = self.module_for_loader(to_wrap)
- try:
- fxn(self, name)
- except ImportError:
- pass
-
- def test_new_module(self):
- # Test that when no module exists in sys.modules a new module is
- # created.
- module_name = 'a.b.c'
- with util.uncache(module_name):
- module = self.return_module(module_name)
- self.assertIn(module_name, sys.modules)
- self.assertIsInstance(module, types.ModuleType)
- self.assertEqual(module.__name__, module_name)
-
- def test_reload(self):
- # Test that a module is reused if already in sys.modules.
- class FakeLoader:
- def is_package(self, name):
- return True
- @self.module_for_loader
- def load_module(self, module):
- return module
- name = 'a.b.c'
- module = types.ModuleType('a.b.c')
- module.__loader__ = 42
- module.__package__ = 42
- with util.uncache(name):
- sys.modules[name] = module
- loader = FakeLoader()
- returned_module = loader.load_module(name)
- self.assertIs(returned_module, sys.modules[name])
- self.assertEqual(module.__loader__, loader)
- self.assertEqual(module.__package__, name)
-
- def test_new_module_failure(self):
- # Test that a module is removed from sys.modules if added but an
- # exception is raised.
- name = 'a.b.c'
- with util.uncache(name):
- self.raise_exception(name)
- self.assertNotIn(name, sys.modules)
-
- def test_reload_failure(self):
- # Test that a failure on reload leaves the module in-place.
- name = 'a.b.c'
- module = types.ModuleType(name)
- with util.uncache(name):
- sys.modules[name] = module
- self.raise_exception(name)
- self.assertIs(module, sys.modules[name])
-
- def test_decorator_attrs(self):
- def fxn(self, module): pass
- wrapped = self.module_for_loader(fxn)
- self.assertEqual(wrapped.__name__, fxn.__name__)
- self.assertEqual(wrapped.__qualname__, fxn.__qualname__)
-
- def test_false_module(self):
- # If for some odd reason a module is considered false, still return it
- # from sys.modules.
- class FalseModule(types.ModuleType):
- def __bool__(self): return False
-
- name = 'mod'
- module = FalseModule(name)
- with util.uncache(name):
- self.assertFalse(module)
- sys.modules[name] = module
- given = self.return_module(name)
- self.assertIs(given, module)
-
- def test_attributes_set(self):
- # __name__, __loader__, and __package__ should be set (when
- # is_package() is defined; undefined implicitly tested elsewhere).
- class FakeLoader:
- def __init__(self, is_package):
- self._pkg = is_package
- def is_package(self, name):
- return self._pkg
- @self.module_for_loader
- def load_module(self, module):
- return module
-
- name = 'pkg.mod'
- with util.uncache(name):
- loader = FakeLoader(False)
- module = loader.load_module(name)
- self.assertEqual(module.__name__, name)
- self.assertIs(module.__loader__, loader)
- self.assertEqual(module.__package__, 'pkg')
-
- name = 'pkg.sub'
- with util.uncache(name):
- loader = FakeLoader(True)
- module = loader.load_module(name)
- self.assertEqual(module.__name__, name)
- self.assertIs(module.__loader__, loader)
- self.assertEqual(module.__package__, name)
-
-
-(Frozen_ModuleForLoaderTests,
- Source_ModuleForLoaderTests
- ) = util.test_both(ModuleForLoaderTests, util=importlib_util)
-
-
-class SetLoaderTests:
-
- """Tests importlib.util.set_loader()."""
-
- @property
- def DummyLoader(self):
- # Set DummyLoader on the class lazily.
- class DummyLoader:
- @self.util.set_loader
- def load_module(self, module):
- return self.module
- self.__class__.DummyLoader = DummyLoader
- return DummyLoader
-
- def test_no_attribute(self):
- loader = self.DummyLoader()
- loader.module = types.ModuleType('blah')
- try:
- del loader.module.__loader__
- except AttributeError:
- pass
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- self.assertEqual(loader, loader.load_module('blah').__loader__)
-
- def test_attribute_is_None(self):
- loader = self.DummyLoader()
- loader.module = types.ModuleType('blah')
- loader.module.__loader__ = None
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- self.assertEqual(loader, loader.load_module('blah').__loader__)
-
- def test_not_reset(self):
- loader = self.DummyLoader()
- loader.module = types.ModuleType('blah')
- loader.module.__loader__ = 42
- with warnings.catch_warnings():
- warnings.simplefilter('ignore', DeprecationWarning)
- self.assertEqual(42, loader.load_module('blah').__loader__)
-
-
-(Frozen_SetLoaderTests,
- Source_SetLoaderTests
- ) = util.test_both(SetLoaderTests, util=importlib_util)
-
-
class ResolveNameTests:
"""Tests importlib.util.resolve_name()."""
diff --git a/Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst b/Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst
new file mode 100644
index 0000000..5e759bc
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-10-05-11-40-02.gh-issue-97850.NzdREm.rst
@@ -0,0 +1,2 @@
+Remove deprecated :func:`importlib.utils.set_loader` and
+:func:`importlib.utils.module_for_loader` from :mod:`importlib.utils`.