Skip to content

Commit c943265

Browse files
Issue #15767: Add ModuleNotFoundError.
1 parent 86a7668 commit c943265

File tree

8 files changed

+42
-2
lines changed

8 files changed

+42
-2
lines changed

Doc/c-api/exceptions.rst

+2
Original file line numberDiff line numberDiff line change
@@ -782,6 +782,8 @@ the variables:
782782
+-----------------------------------------+---------------------------------+----------+
783783
| :c:data:`PyExc_ImportError` | :exc:`ImportError` | |
784784
+-----------------------------------------+---------------------------------+----------+
785+
| :c:data:`PyExc_ModuleNotFoundError` | :exc:`ModuleNotFoundError` | |
786+
+-----------------------------------------+---------------------------------+----------+
785787
| :c:data:`PyExc_IndexError` | :exc:`IndexError` | |
786788
+-----------------------------------------+---------------------------------+----------+
787789
| :c:data:`PyExc_InterruptedError` | :exc:`InterruptedError` | |

Doc/library/exceptions.rst

+11-2
Original file line numberDiff line numberDiff line change
@@ -170,8 +170,9 @@ The following exceptions are the exceptions that are usually raised.
170170

171171
.. exception:: ImportError
172172

173-
Raised when an :keyword:`import` statement fails to find the module definition
174-
or when a ``from ... import`` fails to find a name that is to be imported.
173+
Raised when the :keyword:`import` statement has troubles trying to
174+
load a module. Also raised when the "from list" in ``from ... import``
175+
has a name that cannot be found.
175176

176177
The :attr:`name` and :attr:`path` attributes can be set using keyword-only
177178
arguments to the constructor. When set they represent the name of the module
@@ -181,6 +182,14 @@ The following exceptions are the exceptions that are usually raised.
181182
.. versionchanged:: 3.3
182183
Added the :attr:`name` and :attr:`path` attributes.
183184

185+
.. exception:: ModuleNotFoundError
186+
187+
A subclass of :exc:`ImportError` which is raised by :keyword:`import`
188+
when a module could not be located. It is also raised when ``None``
189+
is found in :data:`sys.modules`.
190+
191+
.. versionadded:: 3.6
192+
184193

185194
.. exception:: IndexError
186195

Include/pyerrors.h

+1
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,7 @@ PyAPI_DATA(PyObject *) PyExc_EOFError;
160160
PyAPI_DATA(PyObject *) PyExc_FloatingPointError;
161161
PyAPI_DATA(PyObject *) PyExc_OSError;
162162
PyAPI_DATA(PyObject *) PyExc_ImportError;
163+
PyAPI_DATA(PyObject *) PyExc_ModuleNotFoundError;
163164
PyAPI_DATA(PyObject *) PyExc_IndexError;
164165
PyAPI_DATA(PyObject *) PyExc_KeyError;
165166
PyAPI_DATA(PyObject *) PyExc_KeyboardInterrupt;

Lib/_compat_pickle.py

+7
Original file line numberDiff line numberDiff line change
@@ -242,3 +242,10 @@
242242

243243
for excname in PYTHON3_OSERROR_EXCEPTIONS:
244244
REVERSE_NAME_MAPPING[('builtins', excname)] = ('exceptions', 'OSError')
245+
246+
PYTHON3_IMPORTERROR_EXCEPTIONS = (
247+
'ModuleNotFoundError',
248+
)
249+
250+
for excname in PYTHON3_IMPORTERROR_EXCEPTIONS:
251+
REVERSE_NAME_MAPPING[('builtins', excname)] = ('exceptions', 'ImportError')

Lib/test/exception_hierarchy.txt

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ BaseException
1414
+-- BufferError
1515
+-- EOFError
1616
+-- ImportError
17+
+-- ModuleNotFoundError
1718
+-- LookupError
1819
| +-- IndexError
1920
| +-- KeyError

Lib/test/test_pickle.py

+8
Original file line numberDiff line numberDiff line change
@@ -335,6 +335,9 @@ def test_name_mapping(self):
335335
if (module2, name2) == ('exceptions', 'OSError'):
336336
attr = getattribute(module3, name3)
337337
self.assertTrue(issubclass(attr, OSError))
338+
elif (module2, name2) == ('exceptions', 'ImportError'):
339+
attr = getattribute(module3, name3)
340+
self.assertTrue(issubclass(attr, ImportError))
338341
else:
339342
module, name = mapping(module2, name2)
340343
if module3[:1] != '_':
@@ -401,6 +404,11 @@ def test_exceptions(self):
401404
if exc is not OSError and issubclass(exc, OSError):
402405
self.assertEqual(reverse_mapping('builtins', name),
403406
('exceptions', 'OSError'))
407+
elif exc is not ImportError and issubclass(exc, ImportError):
408+
self.assertEqual(reverse_mapping('builtins', name),
409+
('exceptions', 'ImportError'))
410+
self.assertEqual(mapping('exceptions', name),
411+
('exceptions', name))
404412
else:
405413
self.assertEqual(reverse_mapping('builtins', name),
406414
('exceptions', name))

Misc/NEWS

+3
Original file line numberDiff line numberDiff line change
@@ -8043,6 +8043,9 @@ Core and Builtins
80438043
- Issue #18137: Detect integer overflow on precision in float.__format__()
80448044
and complex.__format__().
80458045

8046+
- Issue #15767: Introduce ModuleNotFoundError which is raised when a module
8047+
could not be found.
8048+
80468049
- Issue #18183: Fix various unicode operations on strings with large unicode
80478050
codepoints.
80488051

Objects/exceptions.c

+9
Original file line numberDiff line numberDiff line change
@@ -705,6 +705,13 @@ ComplexExtendsException(PyExc_Exception, ImportError,
705705
"Import can't find module, or can't find name in "
706706
"module.");
707707

708+
/*
709+
* ModuleNotFoundError extends ImportError
710+
*/
711+
712+
MiddlingExtendsException(PyExc_ImportError, ModuleNotFoundError, ImportError,
713+
"Module not found.");
714+
708715
/*
709716
* OSError extends Exception
710717
*/
@@ -2469,6 +2476,7 @@ _PyExc_Init(PyObject *bltinmod)
24692476
PRE_INIT(SystemExit)
24702477
PRE_INIT(KeyboardInterrupt)
24712478
PRE_INIT(ImportError)
2479+
PRE_INIT(ModuleNotFoundError)
24722480
PRE_INIT(OSError)
24732481
PRE_INIT(EOFError)
24742482
PRE_INIT(RuntimeError)
@@ -2541,6 +2549,7 @@ _PyExc_Init(PyObject *bltinmod)
25412549
POST_INIT(SystemExit)
25422550
POST_INIT(KeyboardInterrupt)
25432551
POST_INIT(ImportError)
2552+
POST_INIT(ModuleNotFoundError)
25442553
POST_INIT(OSError)
25452554
INIT_ALIAS(EnvironmentError, OSError)
25462555
INIT_ALIAS(IOError, OSError)

0 commit comments

Comments
 (0)