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

Skip to content

Commit 12c6bda

Browse files
committed
Issue #15316: Let exceptions raised during imports triggered by the
fromlist of __import__ propagate. The problem previously was that if something listed in fromlist didn't exist then that's okay. The fix for that was too broad in terms of catching ImportError. The trick with the solution to this issue is that the proper refactoring of import thanks to importlib doesn't allow for a way to distinguish (portably) between an ImportError because finders couldn't find a loader, or a loader raised the exception. In Python 3.4 the hope is to introduce a new exception (e.g. ModuleNotFound) to make it clean to differentiate why ImportError was raised.
1 parent 7a54d16 commit 12c6bda

4 files changed

Lines changed: 254 additions & 193 deletions

File tree

Lib/importlib/_bootstrap.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1513,7 +1513,11 @@ def _find_and_load_unlocked(name, import_):
15131513
raise ImportError(msg, name=name)
15141514
loader = _find_module(name, path)
15151515
if loader is None:
1516-
raise ImportError(_ERR_MSG.format(name), name=name)
1516+
exc = ImportError(_ERR_MSG.format(name), name=name)
1517+
# TODO(brett): switch to a proper ModuleNotFound exception in Python
1518+
# 3.4.
1519+
exc._not_found = True
1520+
raise exc
15171521
elif name not in sys.modules:
15181522
# The parent import may have already imported this module.
15191523
loader.load_module(name)
@@ -1599,10 +1603,16 @@ def _handle_fromlist(module, fromlist, import_):
15991603
try:
16001604
_call_with_frames_removed(import_,
16011605
'{}.{}'.format(module.__name__, x))
1602-
except ImportError:
1606+
except ImportError as exc:
16031607
# Backwards-compatibility dictates we ignore failed
1604-
# imports triggered by fromlist.
1605-
pass
1608+
# imports triggered by fromlist for modules that don't
1609+
# exist.
1610+
# TODO(brett): In Python 3.4, have import raise
1611+
# ModuleNotFound and catch that.
1612+
if hasattr(exc, '_not_found') and exc._not_found:
1613+
pass
1614+
else:
1615+
raise
16061616
return module
16071617

16081618

Lib/test/test_importlib/import_/test_api.py

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,22 @@
1+
from .. import util as importlib_test_util
12
from . import util
3+
import imp
4+
import sys
25
import unittest
36

47

8+
class BadLoaderFinder:
9+
bad = 'fine.bogus'
10+
@classmethod
11+
def find_module(cls, fullname, path):
12+
if fullname == cls.bad:
13+
return cls
14+
@classmethod
15+
def load_module(cls, fullname):
16+
if fullname == cls.bad:
17+
raise ImportError('I cannot be loaded!')
18+
19+
520
class APITest(unittest.TestCase):
621

722
"""Test API-specific details for __import__ (e.g. raising the right
@@ -19,6 +34,29 @@ def test_negative_level(self):
1934
with self.assertRaises(ValueError):
2035
util.import_('os', globals(), level=-1)
2136

37+
def test_nonexistent_fromlist_entry(self):
38+
# If something in fromlist doesn't exist, that's okay.
39+
# issue15715
40+
mod = imp.new_module('fine')
41+
mod.__path__ = ['XXX']
42+
with importlib_test_util.import_state(meta_path=[BadLoaderFinder]):
43+
with importlib_test_util.uncache('fine'):
44+
sys.modules['fine'] = mod
45+
util.import_('fine', fromlist=['not here'])
46+
47+
def test_fromlist_load_error_propagates(self):
48+
# If something in fromlist triggers an exception not related to not
49+
# existing, let that exception propagate.
50+
# issue15316
51+
mod = imp.new_module('fine')
52+
mod.__path__ = ['XXX']
53+
with importlib_test_util.import_state(meta_path=[BadLoaderFinder]):
54+
with importlib_test_util.uncache('fine'):
55+
sys.modules['fine'] = mod
56+
with self.assertRaises(ImportError):
57+
util.import_('fine', fromlist=['bogus'])
58+
59+
2260

2361
def test_main():
2462
from test.support import run_unittest

Misc/NEWS

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,10 @@ What's New in Python 3.3.0 Release Candidate 1?
1010
Core and Builtins
1111
-----------------
1212

13+
- Issue #15316: When an item in the fromlist for __import__ doesn't exist,
14+
don't raise an error, but if an exception is raised as part of an import do
15+
let that propagate.
16+
1317
- Issue #15778: ensure that str(ImportError(msg)) returns a str
1418
even when msg isn't a str.
1519

0 commit comments

Comments
 (0)