diff -r ec00f8570c55 Lib/test/test_imp.py --- a/Lib/test/test_imp.py Mon Nov 05 22:23:16 2012 +0200 +++ b/Lib/test/test_imp.py Tue Nov 06 16:52:39 2012 +0100 @@ -217,6 +217,19 @@ mod = imp.load_module(example, *x) self.assertEqual(mod.__name__, example) + def test_issue16421_multiple_modules_in_one_dll(self): + # Issue 16421: loading several modules from the same compiled file fails + m = '_testimportmultiple' + f = imp.find_module(m)[1] + mod0 = imp.load_dynamic(m, f) + mod1 = imp.load_dynamic('foo', f) + mod2 = imp.load_dynamic('bar', f) + self.assertEqual(mod0.__name__, m) + self.assertEqual(mod1.__name__, 'foo') + self.assertEqual(mod2.__name__, 'bar') + with self.assertRaises(ImportError): + imp.load_dynamic('nonexistent', f) + 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 -r ec00f8570c55 Modules/_testimportmultiple.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Modules/_testimportmultiple.c Tue Nov 06 16:52:39 2012 +0100 @@ -0,0 +1,60 @@ +#include + +/* This file defines 3 modules, only the first one is called the same as compiled file: + + * _testimportmodule + * foo + * bar + +*/ + +static struct PyModuleDef _testimportmultiple = { + PyModuleDef_HEAD_INIT, + "_testimportmultiple", + "_testimportmultiple doc", + -1, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC PyInit__testimportmultiple() +{ + return PyModule_Create(&_testimportmultiple); +} + +static struct PyModuleDef _foomodule = { + PyModuleDef_HEAD_INIT, + "foo", + "foo doc", + -1, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC PyInit_foo() +{ + return PyModule_Create(&_foomodule); +} + +static struct PyModuleDef _barmodule = { + PyModuleDef_HEAD_INIT, + "bar", + "bar doc", + -1, + NULL, + NULL, + NULL, + NULL, + NULL +}; + +PyMODINIT_FUNC PyInit_bar(){ + return PyModule_Create(&_barmodule); +} + diff -r ec00f8570c55 Python/import.c --- a/Python/import.c Mon Nov 05 22:23:16 2012 +0200 +++ b/Python/import.c Tue Nov 06 16:52:39 2012 +0100 @@ -449,12 +449,12 @@ /* Magic for extension modules (built-in as well as dynamically loaded). To prevent initializing an extension module more than - once, we keep a static dictionary 'extensions' keyed by module name - (for built-in modules) or by filename (for dynamically loaded - modules), containing these modules. A copy of the module's - dictionary is stored by calling _PyImport_FixupExtensionObject() - immediately after the module initialization function succeeds. A - copy can be retrieved from there by calling + once, we keep a static dictionary 'extensions' keyed by the tuple + (module name, module name) (for built-in modules) or by + (filename, module name) (for dynamically loaded modules), containing these + modules. A copy of the module's dictionary is stored by calling + _PyImport_FixupExtensionObject() immediately after the module initialization + function succeeds. A copy can be retrieved from there by calling _PyImport_FindExtensionObject(). Modules which do support multiple initialization set their m_size @@ -505,7 +505,7 @@ if (def->m_base.m_copy == NULL) return -1; } - PyDict_SetItem(extensions, filename, (PyObject*)def); + PyDict_SetItem(extensions, PyTuple_Pack(2,filename, name), (PyObject*)def); return 0; } @@ -529,7 +529,7 @@ PyModuleDef* def; if (extensions == NULL) return NULL; - def = (PyModuleDef*)PyDict_GetItem(extensions, filename); + def = (PyModuleDef*)PyDict_GetItem(extensions, PyTuple_Pack(2, filename, name)); if (def == NULL) return NULL; if (def->m_size == -1) { diff -r ec00f8570c55 setup.py --- a/setup.py Mon Nov 05 22:23:16 2012 +0200 +++ b/setup.py Tue Nov 06 16:52:39 2012 +0100 @@ -591,6 +591,8 @@ depends=['testcapi_long.h']) ) # Python PEP-3118 (buffer protocol) test module exts.append( Extension('_testbuffer', ['_testbuffer.c']) ) + # Test loading multiple modules from one compiled file (http://bugs.python.org/issue16421) + exts.append( Extension('_testimportmultiple', ['_testimportmultiple.c']) ) # profiler (_lsprof is for cProfile.py) exts.append( Extension('_lsprof', ['_lsprof.c', 'rotatingtree.c']) ) # static Unicode character database