changeset: 97725:087464c9f982 branch: 3.5 parent: 97676:438dde69871d user: Nick Coghlan date: Sat Sep 05 21:05:05 2015 +1000 files: Lib/imp.py Lib/test/imp_dummy.py Lib/test/test_imp.py Misc/NEWS Modules/_testmultiphase.c description: Close #24748: Restore imp.load_dynamic compatibility To resolve a compatibility problem found with py2exe and pywin32, imp.load_dynamic() once again ignores previously loaded modules to support Python modules replacing themselves with extension modules. Patch by Petr Viktorin. diff -r 438dde69871d -r 087464c9f982 Lib/imp.py --- a/Lib/imp.py Fri Sep 04 12:15:54 2015 -0700 +++ b/Lib/imp.py Sat Sep 05 21:05:05 2015 +1000 @@ -334,6 +334,12 @@ """ import importlib.machinery loader = importlib.machinery.ExtensionFileLoader(name, path) - return loader.load_module() + + # Issue #24748: Skip the sys.modules check in _load_module_shim; + # always load new extension + spec = importlib.machinery.ModuleSpec( + name=name, loader=loader, origin=path) + return _load(spec) + else: load_dynamic = None diff -r 438dde69871d -r 087464c9f982 Lib/test/imp_dummy.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Lib/test/imp_dummy.py Sat Sep 05 21:05:05 2015 +1000 @@ -0,0 +1,3 @@ +# Fodder for test of issue24748 in test_imp + +dummy_name = True diff -r 438dde69871d -r 087464c9f982 Lib/test/test_imp.py --- a/Lib/test/test_imp.py Fri Sep 04 12:15:54 2015 -0700 +++ b/Lib/test/test_imp.py Sat Sep 05 21:05:05 2015 +1000 @@ -3,6 +3,7 @@ except ImportError: _thread = None import importlib +import importlib.util import os import os.path import shutil @@ -275,6 +276,29 @@ self.skipTest("found module doesn't appear to be a C extension") imp.load_module(name, None, *found[1:]) + @requires_load_dynamic + def test_issue24748_load_module_skips_sys_modules_check(self): + name = 'test.imp_dummy' + try: + del sys.modules[name] + except KeyError: + pass + try: + module = importlib.import_module(name) + spec = importlib.util.find_spec('_testmultiphase') + module = imp.load_dynamic(name, spec.origin) + self.assertEqual(module.__name__, name) + self.assertEqual(module.__spec__.name, name) + self.assertEqual(module.__spec__.origin, spec.origin) + self.assertRaises(AttributeError, getattr, module, 'dummy_name') + self.assertEqual(module.int_const, 1969) + self.assertIs(sys.modules[name], module) + finally: + try: + del sys.modules[name] + except KeyError: + pass + @unittest.skipIf(sys.dont_write_bytecode, "test meaningful only when writing bytecode") def test_bug7732(self): diff -r 438dde69871d -r 087464c9f982 Misc/NEWS --- a/Misc/NEWS Fri Sep 04 12:15:54 2015 -0700 +++ b/Misc/NEWS Sat Sep 05 21:05:05 2015 +1000 @@ -15,6 +15,11 @@ Library ------- +- Issue #24748: To resolve a compatibility problem found with py2exe and + pywin32, imp.load_dynamic() once again ignores previously loaded modules + to support Python modules replacing themselves with extension modules. + Patch by Petr Viktorin. + - Issue #24635: Fixed a bug in typing.py where isinstance([], typing.Iterable) would return True once, then False on subsequent calls. diff -r 438dde69871d -r 087464c9f982 Modules/_testmultiphase.c --- a/Modules/_testmultiphase.c Fri Sep 04 12:15:54 2015 -0700 +++ b/Modules/_testmultiphase.c Sat Sep 05 21:05:05 2015 +1000 @@ -582,3 +582,13 @@ { return PyModuleDef_Init(&def_exec_unreported_exception); } + +/*** Helper for imp test ***/ + +static PyModuleDef imp_dummy_def = TEST_MODULE_DEF("imp_dummy", main_slots, testexport_methods); + +PyMODINIT_FUNC +PyInit_imp_dummy(PyObject *spec) +{ + return PyModuleDef_Init(&imp_dummy_def); +}