From d39b42d2ad2aa980d29b2f846bf44a1ce0c71347 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 2 Dec 2025 15:39:44 -0800 Subject: [PATCH 1/7] GH-97850: Remove all uses and definitions of `load_module()` from importlib --- Doc/library/importlib.rst | 96 ++------ Doc/reference/import.rst | 27 +-- Lib/importlib/_abc.py | 18 -- Lib/importlib/_bootstrap.py | 100 +-------- Lib/importlib/_bootstrap_external.py | 29 --- Lib/importlib/abc.py | 1 - Lib/test/test_import/__init__.py | 12 +- Lib/test/test_importlib/abc.py | 16 -- .../test_importlib/builtin/test_loader.py | 64 ------ .../test_importlib/extension/test_loader.py | 114 ---------- Lib/test/test_importlib/import_/test_api.py | 46 ---- .../test_importlib/source/test_file_loader.py | 209 +----------------- Lib/test/test_importlib/source/test_finder.py | 8 +- .../source/test_source_encoding.py | 26 --- Lib/test/test_importlib/test_abc.py | 117 ---------- Lib/test/test_importlib/test_spec.py | 14 -- ...5-12-02-15-39-16.gh-issue-97850.H6QKwl.rst | 3 + 17 files changed, 44 insertions(+), 856 deletions(-) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-12-02-15-39-16.gh-issue-97850.H6QKwl.rst diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 3f0a54ac535cd6..5e3c1aa1641f48 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -320,6 +320,9 @@ ABC hierarchy:: .. versionchanged:: 3.7 Introduced the optional :meth:`get_resource_reader` method. + .. versionchanged:: 3.15 + Removed the ``load_module()`` method. + .. method:: create_module(spec) A method that returns the module object to use when @@ -344,46 +347,6 @@ ABC hierarchy:: .. versionchanged:: 3.6 :meth:`create_module` must also be defined. - .. method:: load_module(fullname) - - A legacy method for loading a module. If the module cannot be - loaded, :exc:`ImportError` is raised, otherwise the loaded module is - returned. - - If the requested module already exists in :data:`sys.modules`, that - module should be used and reloaded. - Otherwise the loader should create a new module and insert it into - :data:`sys.modules` before any loading begins, to prevent recursion - from the import. If the loader inserted a module and the load fails, it - must be removed by the loader from :data:`sys.modules`; modules already - in :data:`sys.modules` before the loader began execution should be left - alone. - - The loader should set several attributes on the module - (note that some of these attributes can change when a module is - reloaded): - - - :attr:`module.__name__` - - :attr:`module.__file__` - - :attr:`module.__cached__` *(deprecated)* - - :attr:`module.__path__` - - :attr:`module.__package__` *(deprecated)* - - :attr:`module.__loader__` *(deprecated)* - - When :meth:`exec_module` is available then backwards-compatible - functionality is provided. - - .. versionchanged:: 3.4 - Raise :exc:`ImportError` when called instead of - :exc:`NotImplementedError`. Functionality provided when - :meth:`exec_module` is available. - - .. deprecated-removed:: 3.4 3.15 - The recommended API for loading a module is :meth:`exec_module` - (and :meth:`create_module`). Loaders should implement it instead of - :meth:`load_module`. The import machinery takes care of all the - other responsibilities of :meth:`load_module` when - :meth:`exec_module` is implemented. .. class:: ResourceLoader @@ -484,19 +447,14 @@ ABC hierarchy:: Added the *fullname* parameter. + + .. method:: exec_module(module) Implementation of :meth:`Loader.exec_module`. .. versionadded:: 3.4 - .. method:: load_module(fullname) - - Implementation of :meth:`Loader.load_module`. - - .. deprecated-removed:: 3.4 3.15 - use :meth:`exec_module` instead. - .. class:: ExecutionLoader @@ -530,6 +488,9 @@ ABC hierarchy:: .. versionadded:: 3.3 + .. versionchanged:: 3.15 + Removed the ``load_module()`` method. + .. attribute:: name The name of the module the loader can handle. @@ -538,13 +499,6 @@ ABC hierarchy:: Path to the file of the module. - .. method:: load_module(fullname) - - Calls super's ``load_module()``. - - .. deprecated-removed:: 3.4 3.15 - Use :meth:`Loader.exec_module` instead. - .. method:: get_filename(fullname) :abstractmethod: @@ -576,6 +530,9 @@ ABC hierarchy:: optimization to speed up loading by removing the parsing step of Python's compiler, and so no bytecode-specific API is exposed. + .. versionchanged:: 3.15 + Removed the ``load_module()`` method. + .. method:: path_stats(path) Optional abstract method which returns a :class:`dict` containing @@ -629,13 +586,6 @@ ABC hierarchy:: .. versionadded:: 3.4 - .. method:: load_module(fullname) - - Concrete implementation of :meth:`Loader.load_module`. - - .. deprecated-removed:: 3.4 3.15 - Use :meth:`exec_module` instead. - .. method:: get_source(fullname) Concrete implementation of :meth:`InspectLoader.get_source`. @@ -1059,6 +1009,9 @@ find and load modules. .. versionadded:: 3.3 + .. versionchanged:: 3.15 + Removed the ``load_module()`` method. + .. attribute:: name The name of the module that this loader will handle. @@ -1079,15 +1032,6 @@ find and load modules. Concrete implementation of :meth:`importlib.abc.SourceLoader.set_data`. - .. method:: load_module(name=None) - - Concrete implementation of :meth:`importlib.abc.Loader.load_module` where - specifying the name of the module to load is optional. - - .. deprecated-removed:: 3.6 3.15 - - Use :meth:`importlib.abc.Loader.exec_module` instead. - .. class:: SourcelessFileLoader(fullname, path) @@ -1101,6 +1045,9 @@ find and load modules. .. versionadded:: 3.3 + .. versionchanged:: 3.15 + Removed the ``load_module()`` method. + .. attribute:: name The name of the module the loader will handle. @@ -1122,15 +1069,6 @@ find and load modules. Returns ``None`` as bytecode files have no source when this loader is used. - .. method:: load_module(name=None) - - Concrete implementation of :meth:`importlib.abc.Loader.load_module` where - specifying the name of the module to load is optional. - - .. deprecated-removed:: 3.6 3.15 - - Use :meth:`importlib.abc.Loader.exec_module` instead. - .. class:: ExtensionFileLoader(fullname, path) diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index d772d1f5345fcd..e3ff758e6d67bc 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -362,18 +362,16 @@ of what happens during the loading portion of import:: if spec.origin is None and spec.submodule_search_locations is not None: # namespace package sys.modules[spec.name] = module - elif not hasattr(spec.loader, 'exec_module'): - module = spec.loader.load_module(spec.name) - else: - sys.modules[spec.name] = module + + sys.modules[spec.name] = module + try: + spec.loader.exec_module(module) + except BaseException: try: - spec.loader.exec_module(module) - except BaseException: - try: - del sys.modules[spec.name] - except KeyError: - pass - raise + del sys.modules[spec.name] + except KeyError: + pass + raise return sys.modules[spec.name] Note the following details: @@ -408,7 +406,10 @@ Note the following details: .. versionchanged:: 3.4 The import system has taken over the boilerplate responsibilities of loaders. These were previously performed by the - :meth:`importlib.abc.Loader.load_module` method. + ``importlib.abc.Loader.load_module`` method. + +.. versionchanged:: 3.15 + The ``load_module`` method is no longer used. Loaders ------- @@ -443,7 +444,7 @@ import machinery will create the new module itself. The :meth:`~importlib.abc.Loader.create_module` method of loaders. .. versionchanged:: 3.4 - The :meth:`~importlib.abc.Loader.load_module` method was replaced by + The ``importlib.abc.Loader.load_module`` method was replaced by :meth:`~importlib.abc.Loader.exec_module` and the import machinery assumed all the boilerplate responsibilities of loading. diff --git a/Lib/importlib/_abc.py b/Lib/importlib/_abc.py index 693b466112638f..2598036dac4918 100644 --- a/Lib/importlib/_abc.py +++ b/Lib/importlib/_abc.py @@ -19,21 +19,3 @@ def create_module(self, spec): # We don't define exec_module() here since that would break # hasattr checks we do to support backward compatibility. - - def load_module(self, fullname): - """Return the loaded module. - - The module must be added to sys.modules and have import-related - attributes set properly. The fullname is a str. - - ImportError is raised on failure. - - This method is deprecated in favor of loader.exec_module(). If - exec_module() exists then it is used to provide a backwards-compatible - functionality for this method. - - """ - if not hasattr(self, 'exec_module'): - raise ImportError - # Warning implemented in _load_module_shim(). - return _bootstrap._load_module_shim(self, fullname) diff --git a/Lib/importlib/_bootstrap.py b/Lib/importlib/_bootstrap.py index 43c66765dd9779..8cee9fda935050 100644 --- a/Lib/importlib/_bootstrap.py +++ b/Lib/importlib/_bootstrap.py @@ -521,24 +521,6 @@ def _requires_frozen_wrapper(self, fullname): return _requires_frozen_wrapper -# Typically used by loader classes as a method replacement. -def _load_module_shim(self, fullname): - """Load the specified module into sys.modules and return it. - - This method is deprecated. Use loader.exec_module() instead. - - """ - msg = ("the load_module() method is deprecated and slated for removal in " - "Python 3.15; use exec_module() instead") - _warnings.warn(msg, DeprecationWarning) - spec = spec_from_loader(fullname, self) - if fullname in sys.modules: - module = sys.modules[fullname] - _exec(spec, module) - return sys.modules[fullname] - else: - return _load(spec) - # Module specifications ####################################################### def _module_repr(module): @@ -763,8 +745,7 @@ def _init_module_attrs(spec, module, *, override=False): # should also be None for consistency. While a bit of a hack, # this is the best place to ensure this consistency. # - # See # https://docs.python.org/3/library/importlib.html#importlib.abc.Loader.load_module - # and bpo-32305 + # See bpo-32305 module.__file__ = None try: module.__loader__ = loader @@ -844,7 +825,7 @@ def _module_repr_from_spec(spec): return f'' -# Used by importlib.reload() and _load_module_shim(). +# Used by importlib.reload(). def _exec(spec, module): """Execute the spec's specified module in an existing module's namespace.""" name = spec.name @@ -860,13 +841,7 @@ def _exec(spec, module): _init_module_attrs(spec, module, override=True) else: _init_module_attrs(spec, module, override=True) - if not hasattr(spec.loader, 'exec_module'): - msg = (f"{_object_name(spec.loader)}.exec_module() not found; " - "falling back to load_module()") - _warnings.warn(msg, ImportWarning) - spec.loader.load_module(name) - else: - spec.loader.exec_module(module) + spec.loader.exec_module(module) finally: # Update the order of insertion into sys.modules for module # clean-up at shutdown. @@ -874,53 +849,8 @@ def _exec(spec, module): sys.modules[spec.name] = module return module - -def _load_backward_compatible(spec): - # It is assumed that all callers have been warned about using load_module() - # appropriately before calling this function. - try: - spec.loader.load_module(spec.name) - except: - if spec.name in sys.modules: - module = sys.modules.pop(spec.name) - sys.modules[spec.name] = module - raise - # The module must be in sys.modules at this point! - # Move it to the end of sys.modules. - module = sys.modules.pop(spec.name) - sys.modules[spec.name] = module - if getattr(module, '__loader__', None) is None: - try: - module.__loader__ = spec.loader - except AttributeError: - pass - if getattr(module, '__package__', None) is None: - try: - # Since module.__path__ may not line up with - # spec.submodule_search_paths, we can't necessarily rely - # on spec.parent here. - module.__package__ = module.__name__ - if not hasattr(module, '__path__'): - module.__package__ = spec.name.rpartition('.')[0] - except AttributeError: - pass - if getattr(module, '__spec__', None) is None: - try: - module.__spec__ = spec - except AttributeError: - pass - return module - def _load_unlocked(spec): # A helper for direct use by the import system. - if spec.loader is not None: - # Not a namespace package. - if not hasattr(spec.loader, 'exec_module'): - msg = (f"{_object_name(spec.loader)}.exec_module() not found; " - "falling back to load_module()") - _warnings.warn(msg, ImportWarning) - return _load_backward_compatible(spec) - module = module_from_spec(spec) # This must be done before putting the module in sys.modules @@ -954,8 +884,7 @@ def _load_unlocked(spec): return module -# A method used during testing of _load_unlocked() and by -# _load_module_shim(). +# A method used during testing of _load_unlocked(). def _load(spec): """Return a new module object, loaded by the spec's loader. @@ -1020,8 +949,6 @@ def is_package(cls, fullname): """Return False as built-in modules are never packages.""" return False - load_module = classmethod(_load_module_shim) - class FrozenImporter: @@ -1178,25 +1105,6 @@ def exec_module(module): code = _call_with_frames_removed(_imp.get_frozen_object, name) exec(code, module.__dict__) - @classmethod - def load_module(cls, fullname): - """Load a frozen module. - - This method is deprecated. Use exec_module() instead. - - """ - # Warning about deprecation implemented in _load_module_shim(). - module = _load_module_shim(cls, fullname) - info = _imp.find_frozen(fullname) - assert info is not None - _, ispkg, origname = info - module.__origname__ = origname - vars(module).pop('__file__', None) - if ispkg: - module.__path__ = [] - cls._fix_up_module(module) - return module - @classmethod @_requires_frozen def get_code(cls, fullname): diff --git a/Lib/importlib/_bootstrap_external.py b/Lib/importlib/_bootstrap_external.py index 2f9307cba4f086..332dc1c5a4fc8f 100644 --- a/Lib/importlib/_bootstrap_external.py +++ b/Lib/importlib/_bootstrap_external.py @@ -757,11 +757,6 @@ def exec_module(self, module): 'get_code() returns None') _bootstrap._call_with_frames_removed(exec, code, module.__dict__) - def load_module(self, fullname): - """This method is deprecated.""" - # Warning implemented in _load_module_shim(). - return _bootstrap._load_module_shim(self, fullname) - class SourceLoader(_LoaderBasics): @@ -927,18 +922,6 @@ def __eq__(self, other): def __hash__(self): return hash(self.name) ^ hash(self.path) - @_check_name - def load_module(self, fullname): - """Load a module from a file. - - This method is deprecated. Use exec_module() instead. - - """ - # The only reason for this method is for the name check. - # Issue #14857: Avoid the zero-argument form of super so the implementation - # of that form can be updated without breaking the frozen module. - return super(FileLoader, self).load_module(fullname) - @_check_name def get_filename(self, fullname): """Return the path to the source file as found by the finder.""" @@ -1190,18 +1173,6 @@ def create_module(self, spec): def exec_module(self, module): pass - def load_module(self, fullname): - """Load a namespace module. - - This method is deprecated. Use exec_module() instead. - - """ - # The import system never calls this method. - _bootstrap._verbose_message('namespace module loaded with path {!r}', - self._path) - # Warning implemented in _load_module_shim(). - return _bootstrap._load_module_shim(self, fullname) - def get_resource_reader(self, module): from importlib.readers import NamespaceReader return NamespaceReader(self._path) diff --git a/Lib/importlib/abc.py b/Lib/importlib/abc.py index 5c13432b5bda8c..87922f32d1111b 100644 --- a/Lib/importlib/abc.py +++ b/Lib/importlib/abc.py @@ -128,7 +128,6 @@ def source_to_code(data, path='', fullname=None): return compile(data, path, 'exec', dont_inherit=True, module=fullname) exec_module = _bootstrap_external._LoaderBasics.exec_module - load_module = _bootstrap_external._LoaderBasics.load_module _register(InspectLoader, machinery.BuiltinImporter, machinery.FrozenImporter, machinery.NamespaceLoader) diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py index 271361ae816449..ba112a97a61c49 100644 --- a/Lib/test/test_import/__init__.py +++ b/Lib/test/test_import/__init__.py @@ -2039,10 +2039,6 @@ def test_import_bug(self): # away from the traceback. self.create_module("foo", "") importlib = sys.modules['_frozen_importlib_external'] - if 'load_module' in vars(importlib.SourceLoader): - old_exec_module = importlib.SourceLoader.exec_module - else: - old_exec_module = None try: def exec_module(*args): 1/0 @@ -2055,10 +2051,7 @@ def exec_module(*args): self.fail("ZeroDivisionError should have been raised") self.assert_traceback(tb, [__file__, '', 'exec') - with self.mock_get_code() as mocked_get_code: - mocked_get_code.return_value = code - loader = self.InspectLoaderSubclass() - module = self.load(loader) - self.assertEqual(module, sys.modules[self.module_name]) - - -(Frozen_ILLoadModuleTests, - Source_ILLoadModuleTests - ) = test_util.test_both(InspectLoaderLoadModuleTests, - InspectLoaderSubclass=SPLIT_IL, - init=init, - util=util) - - ##### ExecutionLoader concrete methods ######################################### class ExecutionLoaderGetCodeTests: @@ -729,34 +640,6 @@ def test_source_to_code(self): code = self.loader.source_to_code(self.loader.source, self.path) self.verify_code(code) - def test_load_module(self): - # Loading a module should set __name__, __loader__, __package__, - # __path__ (for packages), __file__, and __cached__. - # The module should also be put into sys.modules. - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - with test_util.uncache(self.name): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = self.loader.load_module(self.name) - self.verify_module(module) - self.assertEqual(module.__path__, [os.path.dirname(self.path)]) - self.assertIn(self.name, sys.modules) - - def test_package_settings(self): - # __package__ needs to be set, while __path__ is set on if the module - # is a package. - # Testing the values for a package are covered by test_load_module. - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - self.setUp(is_package=False) - with test_util.uncache(self.name): - with warnings.catch_warnings(): - warnings.simplefilter('ignore', DeprecationWarning) - module = self.loader.load_module(self.name) - self.verify_module(module) - self.assertNotHasAttr(module, '__path__') - def test_get_source_encoding(self): # Source is considered encoded in UTF-8 by default unless otherwise # specified by an encoding line. diff --git a/Lib/test/test_importlib/test_spec.py b/Lib/test/test_importlib/test_spec.py index aebeabaf83f75d..fef0fda101e46d 100644 --- a/Lib/test/test_importlib/test_spec.py +++ b/Lib/test/test_importlib/test_spec.py @@ -287,20 +287,6 @@ def exec_module(self, module): loaded = self.bootstrap._load(self.spec) self.assertNotIn(self.spec.name, sys.modules) - def test_load_legacy_attributes_immutable(self): - module = object() - with warnings.catch_warnings(): - warnings.simplefilter("ignore", ImportWarning) - class ImmutableLoader(TestLoader): - def load_module(self, name): - sys.modules[name] = module - return module - self.spec.loader = ImmutableLoader() - with CleanImport(self.spec.name): - loaded = self.bootstrap._load(self.spec) - - self.assertIs(sys.modules[self.spec.name], module) - # reload() def test_reload(self): diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-02-15-39-16.gh-issue-97850.H6QKwl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-02-15-39-16.gh-issue-97850.H6QKwl.rst new file mode 100644 index 00000000000000..fbfe686b8df1f1 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-02-15-39-16.gh-issue-97850.H6QKwl.rst @@ -0,0 +1,3 @@ +Remove all ``*.load_module()`` usage and definitions from the import system +and importlib. The method has been deprecated in favor of +:meth:`importlib.abc.Loader.exec_module` since Python 3.4. From d70a7fb87c09284d75527455acf5fcc71694096b Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 2 Dec 2025 15:45:46 -0800 Subject: [PATCH 2/7] Make the docs build happy --- .../2025-12-02-15-39-16.gh-issue-97850.H6QKwl.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-02-15-39-16.gh-issue-97850.H6QKwl.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-02-15-39-16.gh-issue-97850.H6QKwl.rst index fbfe686b8df1f1..f26d79d0c03bc8 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-12-02-15-39-16.gh-issue-97850.H6QKwl.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-02-15-39-16.gh-issue-97850.H6QKwl.rst @@ -1,3 +1,3 @@ Remove all ``*.load_module()`` usage and definitions from the import system and importlib. The method has been deprecated in favor of -:meth:`importlib.abc.Loader.exec_module` since Python 3.4. +``importlib.abc.Loader.exec_module()`` since Python 3.4. From e256f38bb6439804946ffa5d3aa7165d21f194f7 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 2 Dec 2025 15:58:07 -0800 Subject: [PATCH 3/7] Remove references to `load_module()` from What's New --- Doc/whatsnew/3.10.rst | 4 ++-- Doc/whatsnew/3.4.rst | 8 ++++---- Doc/whatsnew/3.6.rst | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/Doc/whatsnew/3.10.rst b/Doc/whatsnew/3.10.rst index d8251185fa7f4b..4b092b13959530 100644 --- a/Doc/whatsnew/3.10.rst +++ b/Doc/whatsnew/3.10.rst @@ -1622,7 +1622,7 @@ Deprecated compatibility. Specifically, :meth:`!find_loader`/:meth:`!find_module` (superseded by :meth:`~importlib.abc.MetaPathFinder.find_spec`), - :meth:`~importlib.abc.Loader.load_module` + ``importlib.abc.Loader.load_module`` (superseded by :meth:`~importlib.abc.Loader.exec_module`), :meth:`!module_repr` (which the import system takes care of for you), the ``__package__`` attribute @@ -1652,7 +1652,7 @@ Deprecated preference for :meth:`~zipimport.zipimporter.exec_module`. (Contributed by Brett Cannon in :issue:`26131`.) -* The use of :meth:`~importlib.abc.Loader.load_module` by the import +* The use of ``importlib.abc.Loader.load_module`` by the import system now triggers an :exc:`ImportWarning` as :meth:`~importlib.abc.Loader.exec_module` is preferred. (Contributed by Brett Cannon in :issue:`26131`.) diff --git a/Doc/whatsnew/3.4.rst b/Doc/whatsnew/3.4.rst index 9f4068116e3726..a390211ddb5021 100644 --- a/Doc/whatsnew/3.4.rst +++ b/Doc/whatsnew/3.4.rst @@ -2086,10 +2086,10 @@ Deprecations in the Python API :meth:`!importlib.abc.PathEntryFinder.find_loader` and :meth:`!find_module` are replaced by :meth:`importlib.abc.PathEntryFinder.find_spec`; all of the :samp:`{xxx}Loader` ABC - ``load_module`` methods (:meth:`!importlib.abc.Loader.load_module`, - :meth:`!importlib.abc.InspectLoader.load_module`, - :meth:`!importlib.abc.FileLoader.load_module`, - :meth:`!importlib.abc.SourceLoader.load_module`) should no longer be + ``load_module`` methods (``importlib.abc.Loader.load_module``, + ``importlib.abc.InspectLoader.load_module``, + ``importlib.abc.FileLoader.load_module``, + ``importlib.abc.SourceLoader.load_module``) should no longer be implemented, instead loaders should implement an ``exec_module`` method (:meth:`importlib.abc.Loader.exec_module`, diff --git a/Doc/whatsnew/3.6.rst b/Doc/whatsnew/3.6.rst index b1e3269239d629..9eafc09dbee5f4 100644 --- a/Doc/whatsnew/3.6.rst +++ b/Doc/whatsnew/3.6.rst @@ -2006,10 +2006,10 @@ deprecated. importlib ~~~~~~~~~ -The :meth:`importlib.machinery.SourceFileLoader.load_module` and -:meth:`importlib.machinery.SourcelessFileLoader.load_module` methods +The ``importlib.machinery.SourceFileLoader.load_module`` and +``importlib.machinery.SourcelessFileLoader.load_module`` methods are now deprecated. They were the only remaining implementations of -:meth:`importlib.abc.Loader.load_module` in :mod:`importlib` that had not +``importlib.abc.Loader.load_module`` in :mod:`importlib` that had not been deprecated in previous versions of Python in favour of :meth:`importlib.abc.Loader.exec_module`. From 845c8686549ee4528c3bc8088fe135490ca4ce67 Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 2 Dec 2025 16:03:46 -0800 Subject: [PATCH 4/7] Try to make the docs build happy --- Misc/NEWS.d/3.14.0a6.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Misc/NEWS.d/3.14.0a6.rst b/Misc/NEWS.d/3.14.0a6.rst index 9064402bcf71f6..cf250df5526091 100644 --- a/Misc/NEWS.d/3.14.0a6.rst +++ b/Misc/NEWS.d/3.14.0a6.rst @@ -621,7 +621,7 @@ Andrew Svetlov. .. nonce: jQ0CvW .. section: Library -Update the deprecation warning of :meth:`importlib.abc.Loader.load_module`. +Update the deprecation warning of ``importlib.abc.Loader.load_module``. .. From b7def8f61302d486a69d15c873a767f47b8e9b2d Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 9 Dec 2025 11:22:21 -0800 Subject: [PATCH 5/7] Update Doc/library/importlib.rst --- Doc/library/importlib.rst | 2 -- 1 file changed, 2 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 5e3c1aa1641f48..70da730f749837 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -447,8 +447,6 @@ ABC hierarchy:: Added the *fullname* parameter. - - .. method:: exec_module(module) Implementation of :meth:`Loader.exec_module`. From 2d571cce3a125dabc5240954ee21221363866e8f Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 9 Dec 2025 11:24:51 -0800 Subject: [PATCH 6/7] Update Doc/library/importlib.rst --- Doc/library/importlib.rst | 1 - 1 file changed, 1 deletion(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 70da730f749837..34130f9be67e7e 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -348,7 +348,6 @@ ABC hierarchy:: :meth:`create_module` must also be defined. - .. class:: ResourceLoader *Superseded by TraversableResources* From 0dd7fd8f34261008ad8154023a6497f6fb6c39fe Mon Sep 17 00:00:00 2001 From: Brett Cannon Date: Tue, 9 Dec 2025 11:32:11 -0800 Subject: [PATCH 7/7] Simplify import handling by removing namespace package logic Remove handling for namespace packages in import. --- Doc/reference/import.rst | 3 --- 1 file changed, 3 deletions(-) diff --git a/Doc/reference/import.rst b/Doc/reference/import.rst index e3ff758e6d67bc..f50d02a0ef03b9 100644 --- a/Doc/reference/import.rst +++ b/Doc/reference/import.rst @@ -359,9 +359,6 @@ of what happens during the loading portion of import:: if spec.loader is None: # unsupported raise ImportError - if spec.origin is None and spec.submodule_search_locations is not None: - # namespace package - sys.modules[spec.name] = module sys.modules[spec.name] = module try: