mirror of
https://github.com/python/cpython.git
synced 2025-07-24 03:35:53 +00:00
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>
This commit is contained in:
parent
44f1f63ad5
commit
e1182bc377
12 changed files with 11 additions and 180 deletions
|
@ -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
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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'
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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']
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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)>")
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Remove the long-deprecated `module_repr()` from `importlib`.
|
Loading…
Add table
Add a link
Reference in a new issue