diff --git a/Lib/imp.py b/Lib/imp.py index 80b04c83ed0..da9c84ee39d 100644 --- a/Lib/imp.py +++ b/Lib/imp.py @@ -153,13 +153,15 @@ def load_module(name, file, filename, details): warnings.simplefilter('ignore') if mode and (not mode.startswith(('r', 'U')) or '+' in mode): raise ValueError('invalid file open mode {!r}'.format(mode)) - elif file is None and type_ in {PY_SOURCE, PY_COMPILED}: + elif file is None and type_ in {PY_SOURCE, PY_COMPILED, C_EXTENSION}: msg = 'file object required for import (type code {})'.format(type_) raise ValueError(msg) elif type_ == PY_SOURCE: return load_source(name, filename, file) elif type_ == PY_COMPILED: return load_compiled(name, filename, file) + elif type_ == C_EXTENSION: + return load_dynamic(name, filename, file) elif type_ == PKG_DIRECTORY: return load_package(name, filename) elif type_ == C_BUILTIN: @@ -167,7 +169,7 @@ def load_module(name, file, filename, details): elif type_ == PY_FROZEN: return init_frozen(name) else: - msg = "Don't know how to import {} (type code {}".format(name, type_) + msg = "Don't know how to import {} (type code {})".format(name, type_) raise ImportError(msg, name=name) diff --git a/Lib/test/test_imp.py b/Lib/test/test_imp.py index a660278c9c7..20e5608e81b 100644 --- a/Lib/test/test_imp.py +++ b/Lib/test/test_imp.py @@ -186,6 +186,35 @@ class ImportTests(unittest.TestCase): self.assertRaises(SyntaxError, imp.find_module, "badsyntax_pep3120", [path]) + def test_load_from_source(self): + # Verify that the imp module can correctly load and find .py files + # XXX (ncoghlan): It would be nice to use support.CleanImport + # here, but that breaks because the os module registers some + # handlers in copy_reg on import. Since CleanImport doesn't + # revert that registration, the module is left in a broken + # state after reversion. Reinitialising the module contents + # and just reverting os.environ to its previous state is an OK + # workaround + orig_path = os.path + orig_getenv = os.getenv + with support.EnvironmentVarGuard(): + x = imp.find_module("os") + self.addCleanup(x[0].close) + new_os = imp.load_module("os", *x) + self.assertIs(os, new_os) + self.assertIs(orig_path, new_os.path) + self.assertIsNot(orig_getenv, new_os.getenv) + + @support.cpython_only + def test_issue15828_load_extensions(self): + # Issue 15828 picked up that the adapter between the old imp API + # and importlib couldn't handle C extensions + example = "_heapq" + x = imp.find_module(example) + self.addCleanup(x[0].close) + mod = imp.load_module(example, *x) + self.assertEqual(mod.__name__, example) + def test_load_dynamic_ImportError_path(self): # Issue #1559549 added `name` and `path` attributes to ImportError # in order to provide better detail. Issue #10854 implemented those diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py index 60447dc26bc..19863b936af 100644 --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -149,25 +149,6 @@ class ImportTests(unittest.TestCase): self.assertEqual(oct(stat.S_IMODE(stat_info.st_mode)), oct(mode)) - def test_imp_module(self): - # Verify that the imp module can correctly load and find .py files - # XXX (ncoghlan): It would be nice to use support.CleanImport - # here, but that breaks because the os module registers some - # handlers in copy_reg on import. Since CleanImport doesn't - # revert that registration, the module is left in a broken - # state after reversion. Reinitialising the module contents - # and just reverting os.environ to its previous state is an OK - # workaround - orig_path = os.path - orig_getenv = os.getenv - with EnvironmentVarGuard(): - x = imp.find_module("os") - self.addCleanup(x[0].close) - new_os = imp.load_module("os", *x) - self.assertIs(os, new_os) - self.assertIs(orig_path, new_os.path) - self.assertIsNot(orig_getenv, new_os.getenv) - def test_bug7732(self): source = TESTFN + '.py' os.mkdir(source) diff --git a/Misc/NEWS b/Misc/NEWS index 12766944440..e59173d177a 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -54,6 +54,8 @@ Core and Builtins Library ------- +- Issue #15828: Restore support for C extensions in imp.load_module() + - Issue #10650: Deprecate the watchexp parameter of the Decimal.quantize() method.