mirror of
https://github.com/python/cpython.git
synced 2025-08-03 00:23:06 +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
|
other responsibilities of :meth:`load_module` when
|
||||||
:meth:`exec_module` is implemented.
|
: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
|
.. class:: ResourceLoader
|
||||||
|
|
||||||
|
|
|
@ -676,22 +676,10 @@ Here are the exact rules used:
|
||||||
|
|
||||||
* Otherwise, just use the module's ``__name__`` in the repr.
|
* Otherwise, just use the module's ``__name__`` in the repr.
|
||||||
|
|
||||||
.. versionchanged:: 3.4
|
.. versionchanged:: 3.12
|
||||||
Use of :meth:`loader.module_repr() <importlib.abc.Loader.module_repr>`
|
Use of :meth:`module_repr`, having been deprecated since Python 3.4, was
|
||||||
has been deprecated and the module spec is now used by the import
|
removed in Python 3.12 and is no longer called during the resolution of a
|
||||||
machinery to generate a module repr.
|
module's 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.
|
|
||||||
|
|
||||||
.. _pyc-invalidation:
|
.. _pyc-invalidation:
|
||||||
|
|
||||||
|
|
|
@ -38,17 +38,3 @@ class Loader(metaclass=abc.ABCMeta):
|
||||||
raise ImportError
|
raise ImportError
|
||||||
# Warning implemented in _load_module_shim().
|
# Warning implemented in _load_module_shim().
|
||||||
return _bootstrap._load_module_shim(self, fullname)
|
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)
|
loader = getattr(module, '__loader__', None)
|
||||||
if spec := getattr(module, "__spec__", None):
|
if spec := getattr(module, "__spec__", None):
|
||||||
return _module_repr_from_spec(spec)
|
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.
|
# Fall through to a catch-all which always succeeds.
|
||||||
try:
|
try:
|
||||||
name = module.__name__
|
name = module.__name__
|
||||||
|
@ -582,7 +577,6 @@ def module_from_spec(spec):
|
||||||
|
|
||||||
def _module_repr_from_spec(spec):
|
def _module_repr_from_spec(spec):
|
||||||
"""Return the repr to use for the module."""
|
"""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
|
name = '?' if spec.name is None else spec.name
|
||||||
if spec.origin is None:
|
if spec.origin is None:
|
||||||
if spec.loader 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__
|
# This class is actually exposed publicly in a namespace package's __loader__
|
||||||
# attribute, so it should be available through a non-private name.
|
# 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:
|
class NamespaceLoader:
|
||||||
def __init__(self, name, path, path_finder):
|
def __init__(self, name, path, path_finder):
|
||||||
self._path = _NamespacePath(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):
|
def is_package(self, fullname):
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
|
@ -103,14 +103,6 @@ class ExecModuleTests(abc.LoaderTests):
|
||||||
expected=value))
|
expected=value))
|
||||||
self.assertEqual(output, 'Hello world!\n')
|
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):
|
def test_module_repr_indirect(self):
|
||||||
name = '__hello__'
|
name = '__hello__'
|
||||||
module, output = self.exec_module(name)
|
module, output = self.exec_module(name)
|
||||||
|
|
|
@ -51,7 +51,6 @@ class SimpleTest(abc.LoaderTests):
|
||||||
def get_code(self, _): pass
|
def get_code(self, _): pass
|
||||||
def get_source(self, _): pass
|
def get_source(self, _): pass
|
||||||
def is_package(self, _): pass
|
def is_package(self, _): pass
|
||||||
def module_repr(self, _): pass
|
|
||||||
|
|
||||||
path = 'some_path'
|
path = 'some_path'
|
||||||
name = 'some_name'
|
name = 'some_name'
|
||||||
|
|
|
@ -221,8 +221,6 @@ class LoaderDefaultsTests(ABCTestHarness):
|
||||||
mod = types.ModuleType('blah')
|
mod = types.ModuleType('blah')
|
||||||
with warnings.catch_warnings():
|
with warnings.catch_warnings():
|
||||||
warnings.simplefilter("ignore", DeprecationWarning)
|
warnings.simplefilter("ignore", DeprecationWarning)
|
||||||
with self.assertRaises(NotImplementedError):
|
|
||||||
self.ins.module_repr(mod)
|
|
||||||
original_repr = repr(mod)
|
original_repr = repr(mod)
|
||||||
mod.__loader__ = self.ins
|
mod.__loader__ = self.ins
|
||||||
# Should still return a proper repr.
|
# Should still return a proper repr.
|
||||||
|
|
|
@ -79,13 +79,6 @@ class SingleNamespacePackage(NamespacePackageTest):
|
||||||
with self.assertRaises(ImportError):
|
with self.assertRaises(ImportError):
|
||||||
import foo.two
|
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):
|
class DynamicPathNamespacePackage(NamespacePackageTest):
|
||||||
paths = ['portion1']
|
paths = ['portion1']
|
||||||
|
|
|
@ -407,101 +407,6 @@ class ModuleSpecMethodsTests:
|
||||||
machinery=machinery)
|
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:
|
class FactoryTests:
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -8,10 +8,10 @@ from test.support.script_helper import assert_python_ok
|
||||||
import sys
|
import sys
|
||||||
ModuleType = type(sys)
|
ModuleType = type(sys)
|
||||||
|
|
||||||
|
|
||||||
class FullLoader:
|
class FullLoader:
|
||||||
@classmethod
|
pass
|
||||||
def module_repr(cls, m):
|
|
||||||
return "<module '{}' (crafted)>".format(m.__name__)
|
|
||||||
|
|
||||||
class BareLoader:
|
class BareLoader:
|
||||||
pass
|
pass
|
||||||
|
@ -236,7 +236,7 @@ a = A(destroyed)"""
|
||||||
# Yes, a class not an instance.
|
# Yes, a class not an instance.
|
||||||
m.__loader__ = FullLoader
|
m.__loader__ = FullLoader
|
||||||
self.assertEqual(
|
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):
|
def test_module_repr_with_bare_loader_and_filename(self):
|
||||||
# Because the loader has no module_repr(), use the file name.
|
# Because the loader has no module_repr(), use the file name.
|
||||||
|
@ -252,7 +252,7 @@ a = A(destroyed)"""
|
||||||
# Yes, a class not an instance.
|
# Yes, a class not an instance.
|
||||||
m.__loader__ = FullLoader
|
m.__loader__ = FullLoader
|
||||||
m.__file__ = '/tmp/foo.py'
|
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):
|
def test_module_repr_builtin(self):
|
||||||
self.assertEqual(repr(sys), "<module 'sys' (built-in)>")
|
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