]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-94619: Remove long deprecated methods module_repr() and load_module() (#94624)
authorBarry Warsaw <barry@python.org>
Fri, 5 Aug 2022 00:24:26 +0000 (17:24 -0700)
committerGitHub <noreply@github.com>
Fri, 5 Aug 2022 00:24:26 +0000 (17:24 -0700)
* gh-94619: Remove long deprecated methods module_repr() and load_module()

Closes #94619

* Update Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst

Fix typo

Co-authored-by: Brett Cannon <brett@python.org>
Co-authored-by: Brett Cannon <brett@python.org>
12 files changed:
Doc/library/importlib.rst
Doc/reference/import.rst
Lib/importlib/_abc.py
Lib/importlib/_bootstrap.py
Lib/importlib/_bootstrap_external.py
Lib/test/test_importlib/frozen/test_loader.py
Lib/test/test_importlib/source/test_file_loader.py
Lib/test/test_importlib/test_abc.py
Lib/test/test_importlib/test_namespace_pkgs.py
Lib/test/test_importlib/test_spec.py
Lib/test/test_module.py
Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst [new file with mode: 0644]

index c29d69c143cfe6fadaed302fe970f35273bf2648..0fd765f5985f7c3c36647ea38209d0ee91d74502 100644 (file)
@@ -493,20 +493,6 @@ ABC hierarchy::
            other responsibilities of :meth:`load_module` when
            :meth:`exec_module` is implemented.
 
-    .. method:: module_repr(module)
-
-        A legacy method which when implemented calculates and returns the given
-        module's representation, as a string.  The module type's default
-        :meth:`__repr__` will use the result of this method as appropriate.
-
-        .. versionadded:: 3.3
-
-        .. versionchanged:: 3.4
-           Made optional instead of an abstractmethod.
-
-        .. deprecated:: 3.4
-           The import machinery now takes care of this automatically.
-
 
 .. class:: ResourceLoader
 
index 1e6b08f32a7aca5506188e54ce1e87dca899fdf0..507f2b3763cae4c881ca81c01aa5a58d4978b760 100644 (file)
@@ -676,22 +676,10 @@ Here are the exact rules used:
 
  * Otherwise, just use the module's ``__name__`` in the repr.
 
-.. versionchanged:: 3.4
-   Use of :meth:`loader.module_repr() <importlib.abc.Loader.module_repr>`
-   has been deprecated and the module spec is now used by the import
-   machinery to generate a module repr.
-
-   For backward compatibility with Python 3.3, the module repr will be
-   generated by calling the loader's
-   :meth:`~importlib.abc.Loader.module_repr` method, if defined, before
-   trying either approach described above.  However, the method is deprecated.
-
-.. versionchanged:: 3.10
-
-   Calling :meth:`~importlib.abc.Loader.module_repr` now occurs after trying to
-   use a module's ``__spec__`` attribute but before falling back on
-   ``__file__``. Use of :meth:`~importlib.abc.Loader.module_repr` is slated to
-   stop in Python 3.12.
+.. versionchanged:: 3.12
+   Use of :meth:`module_repr`, having been deprecated since Python 3.4, was
+   removed in Python 3.12 and is no longer called during the resolution of a
+   module's repr.
 
 .. _pyc-invalidation:
 
index f80348fc7ffd1d8d5283cbe67e2ce59240e7b482..083205638965215e8a9022b3c754147d0fc57f84 100644 (file)
@@ -38,17 +38,3 @@ class Loader(metaclass=abc.ABCMeta):
             raise ImportError
         # Warning implemented in _load_module_shim().
         return _bootstrap._load_module_shim(self, fullname)
-
-    def module_repr(self, module):
-        """Return a module's repr.
-
-        Used by the module type when the method does not raise
-        NotImplementedError.
-
-        This method is deprecated.
-
-        """
-        warnings.warn("importlib.abc.Loader.module_repr() is deprecated and "
-                      "slated for removal in Python 3.12", DeprecationWarning)
-        # The exception will cause ModuleType.__repr__ to ignore this method.
-        raise NotImplementedError
index afb95f4e1df8692164aed45a885124a4e66b9b3c..67989c500f21c0b527bac8e9fa72b9c9d2ddb50d 100644 (file)
@@ -296,11 +296,6 @@ def _module_repr(module):
     loader = getattr(module, '__loader__', None)
     if spec := getattr(module, "__spec__", None):
         return _module_repr_from_spec(spec)
-    elif hasattr(loader, 'module_repr'):
-        try:
-            return loader.module_repr(module)
-        except Exception:
-            pass
     # Fall through to a catch-all which always succeeds.
     try:
         name = module.__name__
@@ -582,7 +577,6 @@ def module_from_spec(spec):
 
 def _module_repr_from_spec(spec):
     """Return the repr to use for the module."""
-    # We mostly replicate _module_repr() using the spec attributes.
     name = '?' if spec.name is None else spec.name
     if spec.origin is None:
         if spec.loader is None:
index b6c6716e90773418f20dc74c8196ff710001258b..82d204257ed7a3b39eb639f61b014ae870cc1a87 100644 (file)
@@ -1339,22 +1339,11 @@ class _NamespacePath:
 
 # This class is actually exposed publicly in a namespace package's __loader__
 # attribute, so it should be available through a non-private name.
-# https://bugs.python.org/issue35673
+# https://github.com/python/cpython/issues/92054
 class NamespaceLoader:
     def __init__(self, name, path, path_finder):
         self._path = _NamespacePath(name, path, path_finder)
 
-    @staticmethod
-    def module_repr(module):
-        """Return repr for the module.
-
-        The method is deprecated.  The import machinery does the job itself.
-
-        """
-        _warnings.warn("NamespaceLoader.module_repr() is deprecated and "
-                       "slated for removal in Python 3.12", DeprecationWarning)
-        return '<module {!r} (namespace)>'.format(module.__name__)
-
     def is_package(self, fullname):
         return True
 
index f2df7e60bf8e38bdadd17c2bf85136beb6d53fe6..32f951cb1aca28682f8b1541aa0a44a6e0ace3c4 100644 (file)
@@ -103,14 +103,6 @@ class ExecModuleTests(abc.LoaderTests):
                              expected=value))
         self.assertEqual(output, 'Hello world!\n')
 
-    def test_module_repr(self):
-        name = '__hello__'
-        module, output = self.exec_module(name)
-        with deprecated():
-            repr_str = self.machinery.FrozenImporter.module_repr(module)
-        self.assertEqual(repr_str,
-                         "<module '__hello__' (frozen)>")
-
     def test_module_repr_indirect(self):
         name = '__hello__'
         module, output = self.exec_module(name)
index 378dcbe08a80507cf90069f8c74c331739ab8ec5..f35adec1a8e800b1935b35a088821fe977449b2c 100644 (file)
@@ -51,7 +51,6 @@ class SimpleTest(abc.LoaderTests):
             def get_code(self, _): pass
             def get_source(self, _): pass
             def is_package(self, _): pass
-            def module_repr(self, _): pass
 
         path = 'some_path'
         name = 'some_name'
index d59b663a43ed06138e7322ba6ab834724be24bfc..88bf100efaad80ae4470d4968a041878018edd5c 100644 (file)
@@ -221,8 +221,6 @@ class LoaderDefaultsTests(ABCTestHarness):
         mod = types.ModuleType('blah')
         with warnings.catch_warnings():
             warnings.simplefilter("ignore", DeprecationWarning)
-            with self.assertRaises(NotImplementedError):
-                self.ins.module_repr(mod)
             original_repr = repr(mod)
             mod.__loader__ = self.ins
             # Should still return a proper repr.
index cd08498545e8025ded1ca3349128e0aefcbec0a1..f451f7547b35bb68d42f9c8dae98878b96ae7b6b 100644 (file)
@@ -79,13 +79,6 @@ class SingleNamespacePackage(NamespacePackageTest):
         with self.assertRaises(ImportError):
             import foo.two
 
-    def test_module_repr(self):
-        import foo.one
-        with warnings.catch_warnings():
-            warnings.simplefilter("ignore")
-            self.assertEqual(foo.__spec__.loader.module_repr(foo),
-                            "<module 'foo' (namespace)>")
-
 
 class DynamicPathNamespacePackage(NamespacePackageTest):
     paths = ['portion1']
index 21e2c02094f22e39cf9e7a90abec755f232e0749..f1ab16c7b2a9bebcf72c931e16b0c567449ebd53 100644 (file)
@@ -407,101 +407,6 @@ class ModuleSpecMethodsTests:
                          machinery=machinery)
 
 
-class ModuleReprTests:
-
-    @property
-    def bootstrap(self):
-        return self.init._bootstrap
-
-    def setUp(self):
-        self.module = type(os)('spam')
-        self.spec = self.machinery.ModuleSpec('spam', TestLoader())
-
-    def test_module___loader___module_repr(self):
-        class Loader:
-            def module_repr(self, module):
-                return '<delicious {}>'.format(module.__name__)
-        self.module.__loader__ = Loader()
-        modrepr = self.bootstrap._module_repr(self.module)
-
-        self.assertEqual(modrepr, '<delicious spam>')
-
-    def test_module___loader___module_repr_bad(self):
-        class Loader(TestLoader):
-            def module_repr(self, module):
-                raise Exception
-        self.module.__loader__ = Loader()
-        modrepr = self.bootstrap._module_repr(self.module)
-
-        self.assertEqual(modrepr,
-                         '<module {!r} (<TestLoader object>)>'.format('spam'))
-
-    def test_module___spec__(self):
-        origin = 'in a hole, in the ground'
-        self.spec.origin = origin
-        self.module.__spec__ = self.spec
-        modrepr = self.bootstrap._module_repr(self.module)
-
-        self.assertEqual(modrepr, '<module {!r} ({})>'.format('spam', origin))
-
-    def test_module___spec___location(self):
-        location = 'in_a_galaxy_far_far_away.py'
-        self.spec.origin = location
-        self.spec._set_fileattr = True
-        self.module.__spec__ = self.spec
-        modrepr = self.bootstrap._module_repr(self.module)
-
-        self.assertEqual(modrepr,
-                         '<module {!r} from {!r}>'.format('spam', location))
-
-    def test_module___spec___no_origin(self):
-        self.spec.loader = TestLoader()
-        self.module.__spec__ = self.spec
-        modrepr = self.bootstrap._module_repr(self.module)
-
-        self.assertEqual(modrepr,
-                         '<module {!r} (<TestLoader object>)>'.format('spam'))
-
-    def test_module___spec___no_origin_no_loader(self):
-        self.spec.loader = None
-        self.module.__spec__ = self.spec
-        modrepr = self.bootstrap._module_repr(self.module)
-
-        self.assertEqual(modrepr, '<module {!r}>'.format('spam'))
-
-    def test_module_no_name(self):
-        del self.module.__name__
-        modrepr = self.bootstrap._module_repr(self.module)
-
-        self.assertEqual(modrepr, '<module {!r}>'.format('?'))
-
-    def test_module_with_file(self):
-        filename = 'e/i/e/i/o/spam.py'
-        self.module.__file__ = filename
-        modrepr = self.bootstrap._module_repr(self.module)
-
-        self.assertEqual(modrepr,
-                         '<module {!r} from {!r}>'.format('spam', filename))
-
-    def test_module_no_file(self):
-        self.module.__loader__ = TestLoader()
-        modrepr = self.bootstrap._module_repr(self.module)
-
-        self.assertEqual(modrepr,
-                         '<module {!r} (<TestLoader object>)>'.format('spam'))
-
-    def test_module_no_file_no_loader(self):
-        modrepr = self.bootstrap._module_repr(self.module)
-
-        self.assertEqual(modrepr, '<module {!r}>'.format('spam'))
-
-
-(Frozen_ModuleReprTests,
- Source_ModuleReprTests
- ) = test_util.test_both(ModuleReprTests, init=init, util=util,
-                         machinery=machinery)
-
-
 class FactoryTests:
 
     def setUp(self):
index f72177dda3702aa0aa6df33982088a3eb433c9ba..6c83d76c8e3c686ce48569a6e4412ce236b20ab6 100644 (file)
@@ -8,10 +8,10 @@ from test.support.script_helper import assert_python_ok
 import sys
 ModuleType = type(sys)
 
+
 class FullLoader:
-    @classmethod
-    def module_repr(cls, m):
-        return "<module '{}' (crafted)>".format(m.__name__)
+    pass
+
 
 class BareLoader:
     pass
@@ -236,7 +236,7 @@ a = A(destroyed)"""
         # Yes, a class not an instance.
         m.__loader__ = FullLoader
         self.assertEqual(
-            repr(m), "<module 'foo' (crafted)>")
+            repr(m), "<module 'foo' (<class 'test.test_module.FullLoader'>)>")
 
     def test_module_repr_with_bare_loader_and_filename(self):
         # Because the loader has no module_repr(), use the file name.
@@ -252,7 +252,7 @@ a = A(destroyed)"""
         # Yes, a class not an instance.
         m.__loader__ = FullLoader
         m.__file__ = '/tmp/foo.py'
-        self.assertEqual(repr(m), "<module 'foo' (crafted)>")
+        self.assertEqual(repr(m), "<module 'foo' from '/tmp/foo.py'>")
 
     def test_module_repr_builtin(self):
         self.assertEqual(repr(sys), "<module 'sys' (built-in)>")
diff --git a/Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst b/Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst
new file mode 100644 (file)
index 0000000..a790503
--- /dev/null
@@ -0,0 +1 @@
+Remove the long-deprecated `module_repr()` from `importlib`.