Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Lib/test/test_import/__init__.py
Original file line number Diff line number Diff line change
@@ -80,6 +80,25 @@ def test_from_import_missing_attr_raises_ImportError(self):
with self.assertRaises(ImportError):
from importlib import something_that_should_not_exist_anywhere

def test_from_import_missing_attr_has_name_and_path(self):
with self.assertRaises(ImportError) as cm:
from os import i_dont_exist
self.assertEqual(cm.exception.name, 'os')
self.assertEqual(cm.exception.path, os.__file__)

def test_from_import_missing_attr_has_name(self):
with self.assertRaises(ImportError) as cm:
# _warning has no path as it's a built-in module.
from _warning import i_dont_exist
self.assertEqual(cm.exception.name, '_warning')
self.assertIsNone(cm.exception.path)

def test_from_import_missing_attr_path_is_canonical(self):
with self.assertRaises(ImportError) as cm:
from os.path import i_dont_exist
self.assertIn(cm.exception.name, {'posixpath', 'ntpath'})
self.assertIsNotNone(cm.exception)

def test_case_sensitivity(self):
# Brief digression to test that import is case-sensitive: if we got
# this far, we know for sure that "random" exists.
2 changes: 2 additions & 0 deletions Misc/NEWS
Original file line number Diff line number Diff line change
@@ -12,6 +12,8 @@ Core and Builtins

- bpo-29438: Fixed use-after-free problem in key sharing dict.

- bpo-29546: Set the 'path' and 'name' attribute on ImportError for ``from ... import ...``.

- Issue #29319: Prevent RunMainFromImporter overwriting sys.path[0].

- Issue #29337: Fixed possible BytesWarning when compare the code objects.
12 changes: 10 additions & 2 deletions Python/ceval.c
Original file line number Diff line number Diff line change
@@ -4995,7 +4995,7 @@ import_from(PyObject *v, PyObject *name)
{
PyObject *x;
_Py_IDENTIFIER(__name__);
PyObject *fullmodname, *pkgname;
PyObject *fullmodname, *pkgname, *pkgpath;

x = PyObject_GetAttr(v, name);
if (x != NULL || !PyErr_ExceptionMatches(PyExc_AttributeError))
@@ -5021,7 +5021,15 @@ import_from(PyObject *v, PyObject *name)
Py_INCREF(x);
return x;
error:
PyErr_Format(PyExc_ImportError, "cannot import name %R", name);
pkgpath = PyModule_GetFilenameObject(v);

if (pkgpath == NULL || !PyUnicode_Check(pkgpath)) {
PyErr_Clear();
PyErr_SetImportError(PyUnicode_FromFormat("cannot import name %R", name), pkgname, NULL);
} else {
PyErr_SetImportError(PyUnicode_FromFormat("cannot import name %R", name), pkgname, pkgpath);
}

return NULL;
}