Commit d576daa8 authored by Brett Cannon's avatar Brett Cannon

Issue #15767: back out 8a0ed9f63c6e, finishing the removal of

ModuleNotFoundError.
parent d0057e40
...@@ -686,8 +686,6 @@ the variables: ...@@ -686,8 +686,6 @@ the variables:
+-----------------------------------------+---------------------------------+----------+ +-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_ImportError` | :exc:`ImportError` | | | :c:data:`PyExc_ImportError` | :exc:`ImportError` | |
+-----------------------------------------+---------------------------------+----------+ +-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_ModuleNotFoundError` | :exc:`ModuleNotFoundError` | |
+-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_IndexError` | :exc:`IndexError` | | | :c:data:`PyExc_IndexError` | :exc:`IndexError` | |
+-----------------------------------------+---------------------------------+----------+ +-----------------------------------------+---------------------------------+----------+
| :c:data:`PyExc_InterruptedError` | :exc:`InterruptedError` | | | :c:data:`PyExc_InterruptedError` | :exc:`InterruptedError` | |
......
...@@ -169,8 +169,8 @@ The following exceptions are the exceptions that are usually raised. ...@@ -169,8 +169,8 @@ The following exceptions are the exceptions that are usually raised.
.. exception:: ImportError .. exception:: ImportError
Raised when the :keyword:`import` statement has troubles trying to load a Raised when an :keyword:`import` statement fails to find the module definition
module. or when a ``from ... import`` fails to find a name that is to be imported.
The :attr:`name` and :attr:`path` attributes can be set using keyword-only The :attr:`name` and :attr:`path` attributes can be set using keyword-only
arguments to the constructor. When set they represent the name of the module arguments to the constructor. When set they represent the name of the module
...@@ -180,15 +180,6 @@ The following exceptions are the exceptions that are usually raised. ...@@ -180,15 +180,6 @@ The following exceptions are the exceptions that are usually raised.
.. versionchanged:: 3.3 .. versionchanged:: 3.3
Added the :attr:`name` and :attr:`path` attributes. Added the :attr:`name` and :attr:`path` attributes.
.. exception:: ModuleNotFoundError
A subclass of :exc:`ImportError` which is raised by :keyword:`import` when a
module could not be located. This includes ``from ... import`` statements as
the specific attribute being requested cannot be known a priori to be a module
or some other type of object.
.. versionadded:: 3.4
.. exception:: IndexError .. exception:: IndexError
......
...@@ -137,9 +137,6 @@ Some smaller changes made to the core Python language are: ...@@ -137,9 +137,6 @@ Some smaller changes made to the core Python language are:
* Unicode database updated to UCD version 6.2. * Unicode database updated to UCD version 6.2.
* Import now raises the new exception :exc:`ModuleNotFoundError` (subclass of
:exc:`ImportError`) when it cannot find something.
* :func:`min` and :func:`max` now accept a *default* argument that can be used * :func:`min` and :func:`max` now accept a *default* argument that can be used
to specify the value they return if the iterable they are evaluating has no to specify the value they return if the iterable they are evaluating has no
elements. Contributed by Julian Berman in :issue:`18111`. elements. Contributed by Julian Berman in :issue:`18111`.
......
...@@ -152,7 +152,6 @@ PyAPI_DATA(PyObject *) PyExc_EOFError; ...@@ -152,7 +152,6 @@ PyAPI_DATA(PyObject *) PyExc_EOFError;
PyAPI_DATA(PyObject *) PyExc_FloatingPointError; PyAPI_DATA(PyObject *) PyExc_FloatingPointError;
PyAPI_DATA(PyObject *) PyExc_OSError; PyAPI_DATA(PyObject *) PyExc_OSError;
PyAPI_DATA(PyObject *) PyExc_ImportError; PyAPI_DATA(PyObject *) PyExc_ImportError;
PyAPI_DATA(PyObject *) PyExc_ModuleNotFoundError;
PyAPI_DATA(PyObject *) PyExc_IndexError; PyAPI_DATA(PyObject *) PyExc_IndexError;
PyAPI_DATA(PyObject *) PyExc_KeyError; PyAPI_DATA(PyObject *) PyExc_KeyError;
PyAPI_DATA(PyObject *) PyExc_KeyboardInterrupt; PyAPI_DATA(PyObject *) PyExc_KeyboardInterrupt;
......
...@@ -1556,7 +1556,11 @@ def _find_and_load_unlocked(name, import_): ...@@ -1556,7 +1556,11 @@ def _find_and_load_unlocked(name, import_):
raise ImportError(msg, name=name) raise ImportError(msg, name=name)
loader = _find_module(name, path) loader = _find_module(name, path)
if loader is None: if loader is None:
raise ModuleNotFoundError(_ERR_MSG.format(name), name=name) exc = ImportError(_ERR_MSG.format(name), name=name)
# TODO(brett): switch to a proper ModuleNotFound exception in Python
# 3.4.
exc._not_found = True
raise exc
elif name not in sys.modules: elif name not in sys.modules:
# The parent import may have already imported this module. # The parent import may have already imported this module.
loader.load_module(name) loader.load_module(name)
...@@ -1642,12 +1646,15 @@ def _handle_fromlist(module, fromlist, import_): ...@@ -1642,12 +1646,15 @@ def _handle_fromlist(module, fromlist, import_):
from_name = '{}.{}'.format(module.__name__, x) from_name = '{}.{}'.format(module.__name__, x)
try: try:
_call_with_frames_removed(import_, from_name) _call_with_frames_removed(import_, from_name)
except ModuleNotFoundError as exc: except ImportError as exc:
# Backwards-compatibility dictates we ignore failed # Backwards-compatibility dictates we ignore failed
# imports triggered by fromlist for modules that don't # imports triggered by fromlist for modules that don't
# exist. # exist.
if exc.name == from_name: # TODO(brett): In Python 3.4, have import raise
continue # ModuleNotFound and catch that.
if getattr(exc, '_not_found', False):
if exc.name == from_name:
continue
raise raise
return module return module
......
...@@ -316,7 +316,7 @@ def safeimport(path, forceload=0, cache={}): ...@@ -316,7 +316,7 @@ def safeimport(path, forceload=0, cache={}):
elif exc is SyntaxError: elif exc is SyntaxError:
# A SyntaxError occurred before we could execute the module. # A SyntaxError occurred before we could execute the module.
raise ErrorDuringImport(value.filename, info) raise ErrorDuringImport(value.filename, info)
elif issubclass(exc, ImportError) and value.name == path: elif exc is ImportError and value.name == path:
# No such module in the path. # No such module in the path.
return None return None
else: else:
......
...@@ -13,7 +13,6 @@ BaseException ...@@ -13,7 +13,6 @@ BaseException
+-- BufferError +-- BufferError
+-- EOFError +-- EOFError
+-- ImportError +-- ImportError
+-- ModuleNotFoundError
+-- LookupError +-- LookupError
| +-- IndexError | +-- IndexError
| +-- KeyError | +-- KeyError
......
...@@ -953,5 +953,8 @@ class ImportErrorTests(unittest.TestCase): ...@@ -953,5 +953,8 @@ class ImportErrorTests(unittest.TestCase):
self.assertEqual(str(arg), str(exc)) self.assertEqual(str(arg), str(exc))
def test_main():
run_unittest(ExceptionTests, ImportErrorTests)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() unittest.main()
...@@ -68,15 +68,7 @@ class ImportTests(unittest.TestCase): ...@@ -68,15 +68,7 @@ class ImportTests(unittest.TestCase):
def tearDown(self): def tearDown(self):
unload(TESTFN) unload(TESTFN)
def test_import_raises_ModuleNotFoundError(self): setUp = tearDown
with self.assertRaises(ModuleNotFoundError):
import something_that_should_not_exist_anywhere
def test_from_import_raises_ModuleNotFoundError(self):
with self.assertRaises(ModuleNotFoundError):
from something_that_should_not_exist_anywhere import blah
with self.assertRaises(ModuleNotFoundError):
from importlib import something_that_should_not_exist_anywhere
def test_case_sensitivity(self): def test_case_sensitivity(self):
# Brief digression to test that import is case-sensitive: if we got # Brief digression to test that import is case-sensitive: if we got
...@@ -495,7 +487,7 @@ func_filename = func.__code__.co_filename ...@@ -495,7 +487,7 @@ func_filename = func.__code__.co_filename
header = f.read(12) header = f.read(12)
code = marshal.load(f) code = marshal.load(f)
constants = list(code.co_consts) constants = list(code.co_consts)
foreign_code = importlib.import_module.__code__ foreign_code = test_main.__code__
pos = constants.index(1) pos = constants.index(1)
constants[pos] = foreign_code constants[pos] = foreign_code
code = type(code)(code.co_argcount, code.co_kwonlyargcount, code = type(code)(code.co_argcount, code.co_kwonlyargcount,
...@@ -1021,5 +1013,16 @@ class ImportTracebackTests(unittest.TestCase): ...@@ -1021,5 +1013,16 @@ class ImportTracebackTests(unittest.TestCase):
importlib.SourceLoader.load_module = old_load_module importlib.SourceLoader.load_module = old_load_module
def test_main(verbose=None):
run_unittest(ImportTests, PycacheTests, FilePermissionTests,
PycRewritingTests, PathsTests, RelativeImportTests,
OverridingImportBuiltinTests,
ImportlibBootstrapTests,
TestSymbolicallyLinkedPackage,
ImportTracebackTests)
if __name__ == '__main__': if __name__ == '__main__':
unittest.main() # Test needs to be a package, so we can do relative imports.
from test.test_import import test_main
test_main()
...@@ -22,10 +22,6 @@ class APITest(unittest.TestCase): ...@@ -22,10 +22,6 @@ class APITest(unittest.TestCase):
"""Test API-specific details for __import__ (e.g. raising the right """Test API-specific details for __import__ (e.g. raising the right
exception when passing in an int for the module name).""" exception when passing in an int for the module name)."""
def test_raises_ModuleNotFoundError(self):
with self.assertRaises(ModuleNotFoundError):
util.import_('some module that does not exist')
def test_name_requires_rparition(self): def test_name_requires_rparition(self):
# Raise TypeError if a non-string is passed in for the module name. # Raise TypeError if a non-string is passed in for the module name.
with self.assertRaises(TypeError): with self.assertRaises(TypeError):
......
...@@ -68,16 +68,16 @@ class HandlingFromlist(unittest.TestCase): ...@@ -68,16 +68,16 @@ class HandlingFromlist(unittest.TestCase):
self.assertTrue(hasattr(module, 'module')) self.assertTrue(hasattr(module, 'module'))
self.assertEqual(module.module.__name__, 'pkg.module') self.assertEqual(module.module.__name__, 'pkg.module')
def test_module_from_package_triggers_ModuleNotFoundError(self): def test_module_from_package_triggers_ImportError(self):
# If a submodule causes an ModuleNotFoundError because it tries to import # If a submodule causes an ImportError because it tries to import
# a module which doesn't exist, that should let the ModuleNotFoundError # a module which doesn't exist, that should let the ImportError
# propagate. # propagate.
def module_code(): def module_code():
import i_do_not_exist import i_do_not_exist
with util.mock_modules('pkg.__init__', 'pkg.mod', with util.mock_modules('pkg.__init__', 'pkg.mod',
module_code={'pkg.mod': module_code}) as importer: module_code={'pkg.mod': module_code}) as importer:
with util.import_state(meta_path=[importer]): with util.import_state(meta_path=[importer]):
with self.assertRaises(ModuleNotFoundError) as exc: with self.assertRaises(ImportError) as exc:
import_util.import_('pkg', fromlist=['mod']) import_util.import_('pkg', fromlist=['mod'])
self.assertEqual('i_do_not_exist', exc.exception.name) self.assertEqual('i_do_not_exist', exc.exception.name)
......
...@@ -206,7 +206,7 @@ expected_html_data_docstrings = tuple(s.replace(' ', ' ') ...@@ -206,7 +206,7 @@ expected_html_data_docstrings = tuple(s.replace(' ', ' ')
missing_pattern = "no Python documentation found for '%s'" missing_pattern = "no Python documentation found for '%s'"
# output pattern for module with bad imports # output pattern for module with bad imports
badimport_pattern = "problem in %s - ModuleNotFoundError: No module named %r" badimport_pattern = "problem in %s - ImportError: No module named %r"
def run_pydoc(module_name, *args, **env): def run_pydoc(module_name, *args, **env):
""" """
......
...@@ -131,7 +131,7 @@ class HelperFunctionsTests(unittest.TestCase): ...@@ -131,7 +131,7 @@ class HelperFunctionsTests(unittest.TestCase):
re.escape(os.path.join(pth_dir, pth_fn))) re.escape(os.path.join(pth_dir, pth_fn)))
# XXX: ditto previous XXX comment. # XXX: ditto previous XXX comment.
self.assertRegex(err_out.getvalue(), 'Traceback') self.assertRegex(err_out.getvalue(), 'Traceback')
self.assertRegex(err_out.getvalue(), 'ModuleNotFoundError') self.assertRegex(err_out.getvalue(), 'ImportError')
@unittest.skipIf(sys.platform == "win32", "Windows does not raise an " @unittest.skipIf(sys.platform == "win32", "Windows does not raise an "
"error for file paths containing null characters") "error for file paths containing null characters")
......
...@@ -25,9 +25,6 @@ Core and Builtins ...@@ -25,9 +25,6 @@ Core and Builtins
- Issue #18137: Detect integer overflow on precision in float.__format__() - Issue #18137: Detect integer overflow on precision in float.__format__()
and complex.__format__(). and complex.__format__().
- Issue #15767: Introduce ModuleNotFoundError which is raised when a module
could not be found.
- Issue #18183: Fix various unicode operations on strings with large unicode - Issue #18183: Fix various unicode operations on strings with large unicode
codepoints. codepoints.
......
...@@ -709,13 +709,6 @@ ComplexExtendsException(PyExc_Exception, ImportError, ...@@ -709,13 +709,6 @@ ComplexExtendsException(PyExc_Exception, ImportError,
"Import can't find module, or can't find name in " "Import can't find module, or can't find name in "
"module."); "module.");
/*
* ModuleNotFoundError extends ImportError
*/
MiddlingExtendsException(PyExc_ImportError, ModuleNotFoundError, ImportError,
"Module not found.");
/* /*
* OSError extends Exception * OSError extends Exception
*/ */
...@@ -2402,7 +2395,6 @@ _PyExc_Init(PyObject *bltinmod) ...@@ -2402,7 +2395,6 @@ _PyExc_Init(PyObject *bltinmod)
PRE_INIT(SystemExit) PRE_INIT(SystemExit)
PRE_INIT(KeyboardInterrupt) PRE_INIT(KeyboardInterrupt)
PRE_INIT(ImportError) PRE_INIT(ImportError)
PRE_INIT(ModuleNotFoundError)
PRE_INIT(OSError) PRE_INIT(OSError)
PRE_INIT(EOFError) PRE_INIT(EOFError)
PRE_INIT(RuntimeError) PRE_INIT(RuntimeError)
...@@ -2473,7 +2465,6 @@ _PyExc_Init(PyObject *bltinmod) ...@@ -2473,7 +2465,6 @@ _PyExc_Init(PyObject *bltinmod)
POST_INIT(SystemExit) POST_INIT(SystemExit)
POST_INIT(KeyboardInterrupt) POST_INIT(KeyboardInterrupt)
POST_INIT(ImportError) POST_INIT(ImportError)
POST_INIT(ModuleNotFoundError)
POST_INIT(OSError) POST_INIT(OSError)
INIT_ALIAS(EnvironmentError, OSError) INIT_ALIAS(EnvironmentError, OSError)
INIT_ALIAS(IOError, OSError) INIT_ALIAS(IOError, OSError)
......
...@@ -4588,7 +4588,7 @@ import_from(PyObject *v, PyObject *name) ...@@ -4588,7 +4588,7 @@ import_from(PyObject *v, PyObject *name)
x = PyObject_GetAttr(v, name); x = PyObject_GetAttr(v, name);
if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) { if (x == NULL && PyErr_ExceptionMatches(PyExc_AttributeError)) {
PyErr_Format(PyExc_ModuleNotFoundError, "cannot import name %S", name); PyErr_Format(PyExc_ImportError, "cannot import name %S", name);
} }
return x; return x;
} }
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment