Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 6efa50a

Browse files
committed
Issue #14583: Fix importlib bug when a package's __init__.py would first import one of its modules then raise an error.
1 parent 943cab2 commit 6efa50a

6 files changed

Lines changed: 374 additions & 308 deletions

File tree

Lib/importlib/_bootstrap.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1082,7 +1082,7 @@ def __import__(name, globals={}, locals={}, fromlist=[], level=0):
10821082
# Return up to the first dot in 'name'. This is complicated by the fact
10831083
# that 'name' may be relative.
10841084
if level == 0:
1085-
return sys.modules[name.partition('.')[0]]
1085+
return _gcd_import(name.partition('.')[0])
10861086
elif not name:
10871087
return module
10881088
else:

Lib/importlib/test/import_/test_packages.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,62 @@ def test_bad_parent(self):
2323
import_util.import_('pkg.module')
2424
self.assertEqual(cm.exception.name, 'pkg')
2525

26+
def test_raising_parent_after_importing_child(self):
27+
def __init__():
28+
import pkg.module
29+
1/0
30+
mock = util.mock_modules('pkg.__init__', 'pkg.module',
31+
module_code={'pkg': __init__})
32+
with mock:
33+
with util.import_state(meta_path=[mock]):
34+
with self.assertRaises(ZeroDivisionError):
35+
import_util.import_('pkg')
36+
self.assertFalse('pkg' in sys.modules)
37+
self.assertTrue('pkg.module' in sys.modules)
38+
with self.assertRaises(ZeroDivisionError):
39+
import_util.import_('pkg.module')
40+
self.assertFalse('pkg' in sys.modules)
41+
self.assertTrue('pkg.module' in sys.modules)
42+
43+
def test_raising_parent_after_relative_importing_child(self):
44+
def __init__():
45+
from . import module
46+
1/0
47+
mock = util.mock_modules('pkg.__init__', 'pkg.module',
48+
module_code={'pkg': __init__})
49+
with mock:
50+
with util.import_state(meta_path=[mock]):
51+
with self.assertRaises((ZeroDivisionError, ImportError)):
52+
# This raises ImportError on the "from . import module"
53+
# line, not sure why.
54+
import_util.import_('pkg')
55+
self.assertFalse('pkg' in sys.modules)
56+
with self.assertRaises((ZeroDivisionError, ImportError)):
57+
import_util.import_('pkg.module')
58+
self.assertFalse('pkg' in sys.modules)
59+
# XXX False
60+
#self.assertTrue('pkg.module' in sys.modules)
61+
62+
def test_raising_parent_after_double_relative_importing_child(self):
63+
def __init__():
64+
from ..subpkg import module
65+
1/0
66+
mock = util.mock_modules('pkg.__init__', 'pkg.subpkg.__init__',
67+
'pkg.subpkg.module',
68+
module_code={'pkg.subpkg': __init__})
69+
with mock:
70+
with util.import_state(meta_path=[mock]):
71+
with self.assertRaises((ZeroDivisionError, ImportError)):
72+
# This raises ImportError on the "from ..subpkg import module"
73+
# line, not sure why.
74+
import_util.import_('pkg.subpkg')
75+
self.assertFalse('pkg.subpkg' in sys.modules)
76+
with self.assertRaises((ZeroDivisionError, ImportError)):
77+
import_util.import_('pkg.subpkg.module')
78+
self.assertFalse('pkg.subpkg' in sys.modules)
79+
# XXX False
80+
#self.assertTrue('pkg.subpkg.module' in sys.modules)
81+
2682
def test_module_not_package(self):
2783
# Try to import a submodule from a non-package should raise ImportError.
2884
assert not hasattr(sys, '__path__')

Lib/importlib/test/util.py

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,11 @@ def load_module(self, fullname):
124124
else:
125125
sys.modules[fullname] = self.modules[fullname]
126126
if fullname in self.module_code:
127-
self.module_code[fullname]()
127+
try:
128+
self.module_code[fullname]()
129+
except Exception:
130+
del sys.modules[fullname]
131+
raise
128132
return self.modules[fullname]
129133

130134
def __enter__(self):

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@ Core and Builtins
2020
Library
2121
-------
2222

23+
- Issue #14583: Fix importlib bug when a package's __init__.py would first
24+
import one of its modules then raise an error.
25+
2326
- Issue #14741: Fix missing support for Ellipsis ('...') in parser module.
2427

2528
- Issue #14697: Fix missing support for set displays and set comprehensions in

Python/import.c

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1633,19 +1633,20 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
16331633
goto error_with_unlock;
16341634
}
16351635

1636+
if (PyUnicode_GET_LENGTH(PyTuple_GET_ITEM(partition, 1)) == 0) {
1637+
/* No dot in module name, simple exit */
1638+
Py_DECREF(partition);
1639+
final_mod = mod;
1640+
Py_INCREF(mod);
1641+
goto exit_with_unlock;
1642+
}
1643+
16361644
front = PyTuple_GET_ITEM(partition, 0);
16371645
Py_INCREF(front);
16381646
Py_DECREF(partition);
16391647

16401648
if (level == 0) {
1641-
final_mod = PyDict_GetItem(interp->modules, front);
1642-
if (final_mod == NULL) {
1643-
PyErr_Format(PyExc_KeyError,
1644-
"%R not in sys.modules as expected", front);
1645-
}
1646-
else {
1647-
Py_INCREF(final_mod);
1648-
}
1649+
final_mod = PyObject_CallFunctionObjArgs(builtins_import, front, NULL);
16491650
Py_DECREF(front);
16501651
}
16511652
else {
@@ -1682,6 +1683,8 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
16821683
fromlist, builtins_import,
16831684
NULL);
16841685
}
1686+
1687+
exit_with_unlock:
16851688
error_with_unlock:
16861689
#ifdef WITH_THREAD
16871690
if (_PyImport_ReleaseLock() < 0) {

0 commit comments

Comments
 (0)