Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e1182bc

Browse files
warsawbrettcannon
andauthoredAug 5, 2022
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@python.org> Co-authored-by: Brett Cannon <brett@python.org>
1 parent 44f1f63 commit e1182bc

12 files changed

+11
-180
lines changed
 

‎Doc/library/importlib.rst

-14
Original file line numberDiff line numberDiff line change
@@ -493,20 +493,6 @@ ABC hierarchy::
493493
other responsibilities of :meth:`load_module` when
494494
:meth:`exec_module` is implemented.
495495

496-
.. method:: module_repr(module)
497-
498-
A legacy method which when implemented calculates and returns the given
499-
module's representation, as a string. The module type's default
500-
:meth:`__repr__` will use the result of this method as appropriate.
501-
502-
.. versionadded:: 3.3
503-
504-
.. versionchanged:: 3.4
505-
Made optional instead of an abstractmethod.
506-
507-
.. deprecated:: 3.4
508-
The import machinery now takes care of this automatically.
509-
510496

511497
.. class:: ResourceLoader
512498

‎Doc/reference/import.rst

+4-16
Original file line numberDiff line numberDiff line change
@@ -676,22 +676,10 @@ Here are the exact rules used:
676676

677677
* Otherwise, just use the module's ``__name__`` in the repr.
678678

679-
.. versionchanged:: 3.4
680-
Use of :meth:`loader.module_repr() <importlib.abc.Loader.module_repr>`
681-
has been deprecated and the module spec is now used by the import
682-
machinery to generate a module repr.
683-
684-
For backward compatibility with Python 3.3, the module repr will be
685-
generated by calling the loader's
686-
:meth:`~importlib.abc.Loader.module_repr` method, if defined, before
687-
trying either approach described above. However, the method is deprecated.
688-
689-
.. versionchanged:: 3.10
690-
691-
Calling :meth:`~importlib.abc.Loader.module_repr` now occurs after trying to
692-
use a module's ``__spec__`` attribute but before falling back on
693-
``__file__``. Use of :meth:`~importlib.abc.Loader.module_repr` is slated to
694-
stop in Python 3.12.
679+
.. versionchanged:: 3.12
680+
Use of :meth:`module_repr`, having been deprecated since Python 3.4, was
681+
removed in Python 3.12 and is no longer called during the resolution of a
682+
module's repr.
695683

696684
.. _pyc-invalidation:
697685

‎Lib/importlib/_abc.py

-14
Original file line numberDiff line numberDiff line change
@@ -38,17 +38,3 @@ def load_module(self, fullname):
3838
raise ImportError
3939
# Warning implemented in _load_module_shim().
4040
return _bootstrap._load_module_shim(self, fullname)
41-
42-
def module_repr(self, module):
43-
"""Return a module's repr.
44-
45-
Used by the module type when the method does not raise
46-
NotImplementedError.
47-
48-
This method is deprecated.
49-
50-
"""
51-
warnings.warn("importlib.abc.Loader.module_repr() is deprecated and "
52-
"slated for removal in Python 3.12", DeprecationWarning)
53-
# The exception will cause ModuleType.__repr__ to ignore this method.
54-
raise NotImplementedError

‎Lib/importlib/_bootstrap.py

-6
Original file line numberDiff line numberDiff line change
@@ -296,11 +296,6 @@ def _module_repr(module):
296296
loader = getattr(module, '__loader__', None)
297297
if spec := getattr(module, "__spec__", None):
298298
return _module_repr_from_spec(spec)
299-
elif hasattr(loader, 'module_repr'):
300-
try:
301-
return loader.module_repr(module)
302-
except Exception:
303-
pass
304299
# Fall through to a catch-all which always succeeds.
305300
try:
306301
name = module.__name__
@@ -582,7 +577,6 @@ def module_from_spec(spec):
582577

583578
def _module_repr_from_spec(spec):
584579
"""Return the repr to use for the module."""
585-
# We mostly replicate _module_repr() using the spec attributes.
586580
name = '?' if spec.name is None else spec.name
587581
if spec.origin is None:
588582
if spec.loader is None:

‎Lib/importlib/_bootstrap_external.py

+1-12
Original file line numberDiff line numberDiff line change
@@ -1339,22 +1339,11 @@ def append(self, item):
13391339

13401340
# This class is actually exposed publicly in a namespace package's __loader__
13411341
# attribute, so it should be available through a non-private name.
1342-
# https://bugs.python.org/issue35673
1342+
# https://github.com/python/cpython/issues/92054
13431343
class NamespaceLoader:
13441344
def __init__(self, name, path, path_finder):
13451345
self._path = _NamespacePath(name, path, path_finder)
13461346

1347-
@staticmethod
1348-
def module_repr(module):
1349-
"""Return repr for the module.
1350-
1351-
The method is deprecated. The import machinery does the job itself.
1352-
1353-
"""
1354-
_warnings.warn("NamespaceLoader.module_repr() is deprecated and "
1355-
"slated for removal in Python 3.12", DeprecationWarning)
1356-
return '<module {!r} (namespace)>'.format(module.__name__)
1357-
13581347
def is_package(self, fullname):
13591348
return True
13601349

‎Lib/test/test_importlib/frozen/test_loader.py

-8
Original file line numberDiff line numberDiff line change
@@ -103,14 +103,6 @@ def test_lacking_parent(self):
103103
expected=value))
104104
self.assertEqual(output, 'Hello world!\n')
105105

106-
def test_module_repr(self):
107-
name = '__hello__'
108-
module, output = self.exec_module(name)
109-
with deprecated():
110-
repr_str = self.machinery.FrozenImporter.module_repr(module)
111-
self.assertEqual(repr_str,
112-
"<module '__hello__' (frozen)>")
113-
114106
def test_module_repr_indirect(self):
115107
name = '__hello__'
116108
module, output = self.exec_module(name)

‎Lib/test/test_importlib/source/test_file_loader.py

-1
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,6 @@ class Tester(self.abc.FileLoader):
5151
def get_code(self, _): pass
5252
def get_source(self, _): pass
5353
def is_package(self, _): pass
54-
def module_repr(self, _): pass
5554

5655
path = 'some_path'
5756
name = 'some_name'

‎Lib/test/test_importlib/test_abc.py

-2
Original file line numberDiff line numberDiff line change
@@ -221,8 +221,6 @@ def test_module_repr(self):
221221
mod = types.ModuleType('blah')
222222
with warnings.catch_warnings():
223223
warnings.simplefilter("ignore", DeprecationWarning)
224-
with self.assertRaises(NotImplementedError):
225-
self.ins.module_repr(mod)
226224
original_repr = repr(mod)
227225
mod.__loader__ = self.ins
228226
# Should still return a proper repr.

‎Lib/test/test_importlib/test_namespace_pkgs.py

-7
Original file line numberDiff line numberDiff line change
@@ -79,13 +79,6 @@ def test_cant_import_other(self):
7979
with self.assertRaises(ImportError):
8080
import foo.two
8181

82-
def test_module_repr(self):
83-
import foo.one
84-
with warnings.catch_warnings():
85-
warnings.simplefilter("ignore")
86-
self.assertEqual(foo.__spec__.loader.module_repr(foo),
87-
"<module 'foo' (namespace)>")
88-
8982

9083
class DynamicPathNamespacePackage(NamespacePackageTest):
9184
paths = ['portion1']

‎Lib/test/test_importlib/test_spec.py

-95
Original file line numberDiff line numberDiff line change
@@ -407,101 +407,6 @@ def test_reload_legacy(self):
407407
machinery=machinery)
408408

409409

410-
class ModuleReprTests:
411-
412-
@property
413-
def bootstrap(self):
414-
return self.init._bootstrap
415-
416-
def setUp(self):
417-
self.module = type(os)('spam')
418-
self.spec = self.machinery.ModuleSpec('spam', TestLoader())
419-
420-
def test_module___loader___module_repr(self):
421-
class Loader:
422-
def module_repr(self, module):
423-
return '<delicious {}>'.format(module.__name__)
424-
self.module.__loader__ = Loader()
425-
modrepr = self.bootstrap._module_repr(self.module)
426-
427-
self.assertEqual(modrepr, '<delicious spam>')
428-
429-
def test_module___loader___module_repr_bad(self):
430-
class Loader(TestLoader):
431-
def module_repr(self, module):
432-
raise Exception
433-
self.module.__loader__ = Loader()
434-
modrepr = self.bootstrap._module_repr(self.module)
435-
436-
self.assertEqual(modrepr,
437-
'<module {!r} (<TestLoader object>)>'.format('spam'))
438-
439-
def test_module___spec__(self):
440-
origin = 'in a hole, in the ground'
441-
self.spec.origin = origin
442-
self.module.__spec__ = self.spec
443-
modrepr = self.bootstrap._module_repr(self.module)
444-
445-
self.assertEqual(modrepr, '<module {!r} ({})>'.format('spam', origin))
446-
447-
def test_module___spec___location(self):
448-
location = 'in_a_galaxy_far_far_away.py'
449-
self.spec.origin = location
450-
self.spec._set_fileattr = True
451-
self.module.__spec__ = self.spec
452-
modrepr = self.bootstrap._module_repr(self.module)
453-
454-
self.assertEqual(modrepr,
455-
'<module {!r} from {!r}>'.format('spam', location))
456-
457-
def test_module___spec___no_origin(self):
458-
self.spec.loader = TestLoader()
459-
self.module.__spec__ = self.spec
460-
modrepr = self.bootstrap._module_repr(self.module)
461-
462-
self.assertEqual(modrepr,
463-
'<module {!r} (<TestLoader object>)>'.format('spam'))
464-
465-
def test_module___spec___no_origin_no_loader(self):
466-
self.spec.loader = None
467-
self.module.__spec__ = self.spec
468-
modrepr = self.bootstrap._module_repr(self.module)
469-
470-
self.assertEqual(modrepr, '<module {!r}>'.format('spam'))
471-
472-
def test_module_no_name(self):
473-
del self.module.__name__
474-
modrepr = self.bootstrap._module_repr(self.module)
475-
476-
self.assertEqual(modrepr, '<module {!r}>'.format('?'))
477-
478-
def test_module_with_file(self):
479-
filename = 'e/i/e/i/o/spam.py'
480-
self.module.__file__ = filename
481-
modrepr = self.bootstrap._module_repr(self.module)
482-
483-
self.assertEqual(modrepr,
484-
'<module {!r} from {!r}>'.format('spam', filename))
485-
486-
def test_module_no_file(self):
487-
self.module.__loader__ = TestLoader()
488-
modrepr = self.bootstrap._module_repr(self.module)
489-
490-
self.assertEqual(modrepr,
491-
'<module {!r} (<TestLoader object>)>'.format('spam'))
492-
493-
def test_module_no_file_no_loader(self):
494-
modrepr = self.bootstrap._module_repr(self.module)
495-
496-
self.assertEqual(modrepr, '<module {!r}>'.format('spam'))
497-
498-
499-
(Frozen_ModuleReprTests,
500-
Source_ModuleReprTests
501-
) = test_util.test_both(ModuleReprTests, init=init, util=util,
502-
machinery=machinery)
503-
504-
505410
class FactoryTests:
506411

507412
def setUp(self):

‎Lib/test/test_module.py

+5-5
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,10 @@
88
import sys
99
ModuleType = type(sys)
1010

11+
1112
class FullLoader:
12-
@classmethod
13-
def module_repr(cls, m):
14-
return "<module '{}' (crafted)>".format(m.__name__)
13+
pass
14+
1515

1616
class BareLoader:
1717
pass
@@ -236,7 +236,7 @@ def test_module_repr_with_full_loader(self):
236236
# Yes, a class not an instance.
237237
m.__loader__ = FullLoader
238238
self.assertEqual(
239-
repr(m), "<module 'foo' (crafted)>")
239+
repr(m), "<module 'foo' (<class 'test.test_module.FullLoader'>)>")
240240

241241
def test_module_repr_with_bare_loader_and_filename(self):
242242
# 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):
252252
# Yes, a class not an instance.
253253
m.__loader__ = FullLoader
254254
m.__file__ = '/tmp/foo.py'
255-
self.assertEqual(repr(m), "<module 'foo' (crafted)>")
255+
self.assertEqual(repr(m), "<module 'foo' from '/tmp/foo.py'>")
256256

257257
def test_module_repr_builtin(self):
258258
self.assertEqual(repr(sys), "<module 'sys' (built-in)>")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Remove the long-deprecated `module_repr()` from `importlib`.

0 commit comments

Comments
 (0)
Please sign in to comment.