From 94987826e89e8a89c20f081e18be33fc840e6203 Mon Sep 17 00:00:00 2001 From: Garvit Khatri Date: Thu, 25 May 2017 03:49:50 +0530 Subject: [PATCH] bpo-29851: Have importlib.reload() raise ImportError if the module's spec is not found (GH-972) --- Doc/library/importlib.rst | 3 +++ Lib/importlib/__init__.py | 2 ++ Lib/test/test_importlib/test_api.py | 14 ++++++++++++-- Misc/ACKS | 1 + Misc/NEWS | 3 +++ 5 files changed, 21 insertions(+), 2 deletions(-) diff --git a/Doc/library/importlib.rst b/Doc/library/importlib.rst index 1fd56983d0a..1df613076da 100644 --- a/Doc/library/importlib.rst +++ b/Doc/library/importlib.rst @@ -203,6 +203,9 @@ Functions classes. .. versionadded:: 3.4 + .. versionchanged:: 3.7 + :exc:`ModuleNotFoundError` is raised when the module being reloaded lacks + a :class:`ModuleSpec`. :mod:`importlib.abc` -- Abstract base classes related to import diff --git a/Lib/importlib/__init__.py b/Lib/importlib/__init__.py index 86febffb6d2..cb37d246a70 100644 --- a/Lib/importlib/__init__.py +++ b/Lib/importlib/__init__.py @@ -164,6 +164,8 @@ def reload(module): pkgpath = None target = module spec = module.__spec__ = _bootstrap._find_spec(name, pkgpath, target) + if spec is None: + raise ModuleNotFoundError(f"spec not found for the module {name!r}", name=name) _bootstrap._exec(spec, module) # The module may have replaced itself in sys.modules! return sys.modules[name] diff --git a/Lib/test/test_importlib/test_api.py b/Lib/test/test_importlib/test_api.py index b0a94aaff5b..50dbfe1eda4 100644 --- a/Lib/test/test_importlib/test_api.py +++ b/Lib/test/test_importlib/test_api.py @@ -197,8 +197,6 @@ class FindLoaderPEP302Tests(FindLoaderTests): class ReloadTests: - """Test module reloading for builtin and extension modules.""" - def test_reload_modules(self): for mod in ('tokenize', 'time', 'marshal'): with self.subTest(module=mod): @@ -361,6 +359,18 @@ class ReloadTests: reloaded = self.init.reload(ham) self.assertIs(reloaded, ham) + def test_module_missing_spec(self): + #Test that reload() throws ModuleNotFounderror when reloading + # a module who's missing a spec. (bpo-29851) + name = 'spam' + with test_util.uncache(name): + module = sys.modules[name] = types.ModuleType(name) + # Sanity check by attempting an import. + module = self.init.import_module(name) + self.assertIsNone(module.__spec__) + with self.assertRaises(ModuleNotFoundError): + self.init.reload(module) + (Frozen_ReloadTests, Source_ReloadTests diff --git a/Misc/ACKS b/Misc/ACKS index b72c40c3330..bee9eb0e136 100644 --- a/Misc/ACKS +++ b/Misc/ACKS @@ -774,6 +774,7 @@ Robert Kern Jim Kerr Magnus Kessler Lawrence Kesteloot +Garvit Khatri Vivek Khera Dhiru Kholia Akshit Khurana diff --git a/Misc/NEWS b/Misc/NEWS index 69602384882..3efbb1789e1 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -604,6 +604,9 @@ Library - bpo-10379: locale.format_string now supports the 'monetary' keyword argument, and locale.format is deprecated. +- bpo-29851: importlib.reload() now raises ModuleNotFoundError if the + module lacks a spec. + - Issue #28556: Various updates to typing module: typing.Counter, typing.ChainMap, improved ABC caching, etc. Original PRs by Jelle Zijlstra, Ivan Levkivskyi, Manuel Krebber, and Ɓukasz Langa.