[Python-checkins] gh-94619: Remove long deprecated methods module_repr() and load_module() (#94624)

warsaw webhook-mailer at python.org
Thu Aug 4 20:24:34 EDT 2022


https://github.com/python/cpython/commit/e1182bc3776ea7cfdd3f82d5ba4fdfee40ae57ee
commit: e1182bc3776ea7cfdd3f82d5ba4fdfee40ae57ee
branch: main
author: Barry Warsaw <barry at python.org>
committer: warsaw <barry at python.org>
date: 2022-08-04T17:24:26-07:00
summary:

gh-94619: Remove long deprecated methods module_repr() and load_module() (#94624)

* 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 at python.org>

Co-authored-by: Brett Cannon <brett at python.org>

files:
A Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst
M Doc/library/importlib.rst
M Doc/reference/import.rst
M Lib/importlib/_abc.py
M Lib/importlib/_bootstrap.py
M Lib/importlib/_bootstrap_external.py
M Lib/test/test_importlib/frozen/test_loader.py
M Lib/test/test_importlib/source/test_file_loader.py
M Lib/test/test_importlib/test_abc.py
M Lib/test/test_importlib/test_namespace_pkgs.py
M Lib/test/test_importlib/test_spec.py
M Lib/test/test_module.py

diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst
index c29d69c143cf..0fd765f5985f 100644
--- a/Doc/library/importlib.rst
+++ b/Doc/library/importlib.rst
@@ -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
 
diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst
index 1e6b08f32a7a..507f2b3763ca 100644
--- a/Doc/reference/import.rst
+++ b/Doc/reference/import.rst
@@ -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:
 
diff --git a/Lib/importlib/_abc.py b/Lib/importlib/_abc.py
index f80348fc7ffd..083205638965 100644
--- a/Lib/importlib/_abc.py
+++ b/Lib/importlib/_abc.py
@@ -38,17 +38,3 @@ def load_module(self, fullname):
             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
diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py
index afb95f4e1df8..67989c500f21 100644
--- a/Lib/importlib/_bootstrap.py
+++ b/Lib/importlib/_bootstrap.py
@@ -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:
diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py
index b6c6716e9077..82d204257ed7 100644
--- a/Lib/importlib/_bootstrap_external.py
+++ b/Lib/importlib/_bootstrap_external.py
@@ -1339,22 +1339,11 @@ def append(self, item):
 
 # 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
 
diff --git a/Lib/test/test_importlib/frozen/test_loader.py b/Lib/test/test_importlib/frozen/test_loader.py
index f2df7e60bf8e..32f951cb1aca 100644
--- a/Lib/test/test_importlib/frozen/test_loader.py
+++ b/Lib/test/test_importlib/frozen/test_loader.py
@@ -103,14 +103,6 @@ def test_lacking_parent(self):
                              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)
diff --git a/Lib/test/test_importlib/source/test_file_loader.py b/Lib/test/test_importlib/source/test_file_loader.py
index 378dcbe08a80..f35adec1a8e8 100644
--- a/Lib/test/test_importlib/source/test_file_loader.py
+++ b/Lib/test/test_importlib/source/test_file_loader.py
@@ -51,7 +51,6 @@ class Tester(self.abc.FileLoader):
             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'
diff --git a/Lib/test/test_importlib/test_abc.py b/Lib/test/test_importlib/test_abc.py
index d59b663a43ed..88bf100efaad 100644
--- a/Lib/test/test_importlib/test_abc.py
+++ b/Lib/test/test_importlib/test_abc.py
@@ -221,8 +221,6 @@ def test_module_repr(self):
         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.
diff --git a/Lib/test/test_importlib/test_namespace_pkgs.py b/Lib/test/test_importlib/test_namespace_pkgs.py
index cd08498545e8..f451f7547b35 100644
--- a/Lib/test/test_importlib/test_namespace_pkgs.py
+++ b/Lib/test/test_importlib/test_namespace_pkgs.py
@@ -79,13 +79,6 @@ def test_cant_import_other(self):
         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']
diff --git a/Lib/test/test_importlib/test_spec.py b/Lib/test/test_importlib/test_spec.py
index 21e2c02094f2..f1ab16c7b2a9 100644
--- a/Lib/test/test_importlib/test_spec.py
+++ b/Lib/test/test_importlib/test_spec.py
@@ -407,101 +407,6 @@ def test_reload_legacy(self):
                          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):
diff --git a/Lib/test/test_module.py b/Lib/test/test_module.py
index f72177dda370..6c83d76c8e3c 100644
--- a/Lib/test/test_module.py
+++ b/Lib/test/test_module.py
@@ -8,10 +8,10 @@
 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 @@ def test_module_repr_with_full_loader(self):
         # 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 @@ def test_module_repr_with_full_loader_and_filename(self):
         # 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
index 000000000000..a79050344246
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2022-07-06-14-57-33.gh-issue-94619.PRqKVX.rst
@@ -0,0 +1 @@
+Remove the long-deprecated `module_repr()` from `importlib`.



More information about the Python-checkins mailing list