]> granicus.if.org Git - python/commitdiff
Issue #15767: Touch up ModuleNotFoundError usage by import.
authorBrett Cannon <brett@python.org>
Thu, 13 Jun 2013 03:29:18 +0000 (23:29 -0400)
committerBrett Cannon <brett@python.org>
Thu, 13 Jun 2013 03:29:18 +0000 (23:29 -0400)
Forgot to raise ModuleNotFoundError when None is found in sys.modules.
This led to introducing the C function PyErr_SetImportErrorSubclass()
to make setting ModuleNotFoundError easier.

Also updated the reference docs to mention ModuleNotFoundError
appropriately. Updated the docs for ModuleNotFoundError to mention the
None in sys.modules case.

Lastly, it was noticed that PyErr_SetImportError() was not setting an
exception when returning None in one case. That issue is now fixed.

Doc/c-api/exceptions.rst
Doc/library/exceptions.rst
Doc/reference/import.rst
Doc/whatsnew/3.4.rst
Include/pyerrors.h
Lib/importlib/_bootstrap.py
Misc/NEWS
Python/errors.c
Python/import.c
Python/importlib.h

index 1bdcdd3a3618e911f332f6e6d1791c80fabe260d..25e2a1c280991c89058c93319aed8cd4ab57b606 100644 (file)
@@ -292,6 +292,13 @@ in various ways.  There is a separate error indicator for each thread.
 
    .. versionadded:: 3.3
 
+.. c:function:: PyObject* PyErr_SetImportErrorSubclass(PyObject *msg, PyObject *name, PyObject *path)
+
+   Much like :c:func:`PyErr_SetImportError` but this function allows for
+   specifying a subclass of :exc:`ImportError` to raise.
+
+   .. versionadded:: 3.4
+
 
 .. c:function:: void PyErr_SyntaxLocationEx(char *filename, int lineno, int col_offset)
 
index 933667ce04dbae083519adac7677935206e9e8d0..377d98ae977a6809d41f0c002f1a30f31d84a94c 100644 (file)
@@ -185,7 +185,8 @@ The following exceptions are the exceptions that are usually raised.
    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.
+   or some other type of object. It is also raised when ``None`` is found in
+   :data:`sys.modules`.
 
    .. versionadded:: 3.4
 
index b587fc9c98fe3478910b21da811638cb92b2bb09..73f5ae58a8a848ce54d9a298f3c567003efc4fbf 100644 (file)
@@ -37,7 +37,7 @@ use the standard import system.
 
 When a module is first imported, Python searches for the module and if found,
 it creates a module object [#fnmo]_, initializing it.  If the named module
-cannot be found, an :exc:`ImportError` is raised.  Python implements various
+cannot be found, an :exc:`ModuleNotFoundError` is raised.  Python implements various
 strategies to search for the named module when the import machinery is
 invoked.  These strategies can be modified and extended by using various hooks
 described in the sections below.
@@ -168,7 +168,7 @@ arguments to the :keyword:`import` statement, or from the parameters to the
 This name will be used in various phases of the import search, and it may be
 the dotted path to a submodule, e.g. ``foo.bar.baz``.  In this case, Python
 first tries to import ``foo``, then ``foo.bar``, and finally ``foo.bar.baz``.
-If any of the intermediate imports fail, an :exc:`ImportError` is raised.
+If any of the intermediate imports fail, an :exc:`ModuleNotFoundError` is raised.
 
 
 The module cache
@@ -187,7 +187,7 @@ object.
 During import, the module name is looked up in :data:`sys.modules` and if
 present, the associated value is the module satisfying the import, and the
 process completes.  However, if the value is ``None``, then an
-:exc:`ImportError` is raised.  If the module name is missing, Python will
+:exc:`ModuleNotFoundError` is raised.  If the module name is missing, Python will
 continue searching for the module.
 
 :data:`sys.modules` is writable.  Deleting a key may not destroy the
@@ -195,7 +195,7 @@ associated module (as other modules may hold references to it),
 but it will invalidate the cache entry for the named module, causing
 Python to search anew for the named module upon its next
 import. The key can also be assigned to ``None``, forcing the next import
-of the module to result in an :exc:`ImportError`.
+of the module to result in an :exc:`ModuleNotFoundError`.
 
 Beware though, as if you keep a reference to the module object,
 invalidate its cache entry in :data:`sys.modules`, and then re-import the
@@ -284,7 +284,7 @@ handle the named module or not.
 If the meta path finder knows how to handle the named module, it returns a
 loader object.  If it cannot handle the named module, it returns ``None``.  If
 :data:`sys.meta_path` processing reaches the end of its list without returning
-a loader, then an :exc:`ImportError` is raised.  Any other exceptions raised
+a loader, then an :exc:`ModuleNotFoundError` is raised.  Any other exceptions raised
 are simply propagated up, aborting the import process.
 
 The :meth:`find_module()` method of meta path finders is called with two
@@ -647,7 +647,7 @@ import statements within that module.
 
 To selectively prevent import of some modules from a hook early on the
 meta path (rather than disabling the standard import system entirely),
-it is sufficient to raise :exc:`ImportError` directly from
+it is sufficient to raise :exc:`ModuleNotFoundError` directly from
 :meth:`find_module` instead of returning ``None``. The latter indicates
 that the meta path search should continue. while raising an exception
 terminates it immediately.
index 23ccae2999c204a825d7cfb41ebaa2319cbbf151..1054c687b6984b4f1f4459eada9f1624eaea8717 100644 (file)
@@ -269,3 +269,6 @@ that may require changes to your code.
 * Frozen packages no longer set ``__path__`` to a list containg the package name
   but an empty list instead. Determing if a module is a package should be done
   using ``hasattr(module, '__path__')``.
+
+* :c:func:`PyErr_SetImportError` now sets :exc:`TypeError` when its **msg**
+  argument is not set. Previously only ``NULL`` was returned.
index 2e66c0efb62d9d7e20484003e7558a742c5e4351..22a22cef2caaff899ac510cf60cf421496f77ff7 100644 (file)
@@ -268,6 +268,9 @@ PyAPI_FUNC(PyObject *) PyErr_SetExcFromWindowsErr(PyObject *, int);
 
 PyAPI_FUNC(PyObject *) PyErr_SetExcWithArgsKwargs(PyObject *, PyObject *,
     PyObject *);
+
+PyAPI_FUNC(PyObject *) PyErr_SetImportErrorSubclass(PyObject *, PyObject *,
+    PyObject *, PyObject *);
 PyAPI_FUNC(PyObject *) PyErr_SetImportError(PyObject *, PyObject *,
     PyObject *);
 
index cd41336aaba0d2be5e188b61988b4e3168ff34ba..9a82bd1ee5f0d7f1697a688f8c053bd735204d36 100644 (file)
@@ -1614,7 +1614,7 @@ def _gcd_import(name, package=None, level=0):
         _imp.release_lock()
         message = ("import of {} halted; "
                     "None in sys.modules".format(name))
-        raise ImportError(message, name=name)
+        raise ModuleNotFoundError(message, name=name)
     _lock_unlock_module(name)
     return module
 
index 50158a71b5f3c81556fcba13ccd690161b253cdc..194a2b8ecf94c2634c67609bcc8b65197b9bc030 100644 (file)
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -443,6 +443,10 @@ Tests
 C-API
 -----
 
+- Issue #15767: Added PyErr_SetImportErrorSubclass().
+
+- PyErr_SetImportError() now sets TypeError when its msg argument is set.
+
 - Issue #9369: The types of `char*` arguments of PyObject_CallFunction() and
   PyObject_CallMethod() now changed to `const char*`.  Based on patches by
   Jörg Müller and Lars Buitinck.
index 1f955b54f049e8bf29ed77f1dfc04e4a2798352b..89021aadd6b1a97f4a480b1d37c972e90c9b343c 100644 (file)
@@ -619,12 +619,25 @@ PyObject *PyErr_SetFromWindowsErrWithUnicodeFilename(
 #endif /* MS_WINDOWS */
 
 PyObject *
-PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path)
+PyErr_SetImportErrorSubclass(PyObject *exception, PyObject *msg,
+    PyObject *name, PyObject *path)
 {
+    int issubclass;
     PyObject *args, *kwargs, *error;
 
-    if (msg == NULL)
+    issubclass = PyObject_IsSubclass(exception, PyExc_ImportError);
+    if (issubclass < 0) {
+        return NULL;
+    }
+    else if (!issubclass) {
+        PyErr_SetString(PyExc_TypeError, "expected a subclass of ImportError");
+        return NULL;
+    }
+
+    if (msg == NULL) {
+        PyErr_SetString(PyExc_TypeError, "expected a message argument");
         return NULL;
+    }
 
     args = PyTuple_New(1);
     if (args == NULL)
@@ -649,7 +662,7 @@ PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path)
     PyDict_SetItemString(kwargs, "name", name);
     PyDict_SetItemString(kwargs, "path", path);
 
-    error = PyObject_Call(PyExc_ImportError, args, kwargs);
+    error = PyObject_Call(exception, args, kwargs);
     if (error != NULL) {
         PyErr_SetObject((PyObject *)Py_TYPE(error), error);
         Py_DECREF(error);
@@ -661,6 +674,12 @@ PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path)
     return NULL;
 }
 
+PyObject *
+PyErr_SetImportError(PyObject *msg, PyObject *name, PyObject *path)
+{
+    return PyErr_SetImportErrorSubclass(PyExc_ImportError, msg, name, path);
+}
+
 void
 _PyErr_BadInternalCall(const char *filename, int lineno)
 {
index 0bb46d2e1e419cea39feab452704b475aeddc568..fad54e66ce16abb12a7b9c114f9fe8e5db086563 100644 (file)
@@ -1436,7 +1436,8 @@ PyImport_ImportModuleLevelObject(PyObject *name, PyObject *given_globals,
         PyObject *msg = PyUnicode_FromFormat("import of %R halted; "
                                              "None in sys.modules", abs_name);
         if (msg != NULL) {
-            PyErr_SetImportError(msg, abs_name, NULL);
+            PyErr_SetImportErrorSubclass(PyExc_ModuleNotFoundError, msg,
+                    abs_name, NULL);
             Py_DECREF(msg);
         }
         mod = NULL;
index 406763103d00f5199bd34cb51d4fffcb358a964c..e2f60c905ddc494df4bdf72ecbd89795cdcf407a 100644 (file)
@@ -3239,8 +3239,8 @@ const unsigned char _Py_M__importlib[] = {
     0,114,64,1,0,0,114,59,1,0,0,114,96,0,0,0,
     114,56,1,0,0,114,7,0,0,0,114,145,0,0,0,114,
     69,1,0,0,244,11,0,0,0,95,103,99,100,95,105,109,
-    112,111,114,116,114,97,0,0,0,114,46,0,0,0,114,156,
-    0,0,0,114,98,0,0,0,40,5,0,0,0,114,66,0,
+    112,111,114,116,114,97,0,0,0,114,46,0,0,0,114,66,
+    1,0,0,114,98,0,0,0,40,5,0,0,0,114,66,0,
     0,0,114,57,1,0,0,114,58,1,0,0,114,160,0,0,
     0,114,139,0,0,0,114,4,0,0,0,114,4,0,0,0,
     114,5,0,0,0,114,70,1,0,0,61,6,0,0,115,26,