diff --git a/Lib/test/test_import.py b/Lib/test/test_import.py --- a/Lib/test/test_import.py +++ b/Lib/test/test_import.py @@ -410,16 +410,25 @@ class ImportTests(unittest.TestCase): "sys.modules['sa'] = sys.modules[__name__];" "import sa") sys.path.insert(0, dir_name) # a segfault means the test failed! import sa finally: rmtree(dir_name) + def test_fromlist_error_messages(self): + # Test for issue #21720: fromlist unicode error messages + with self.assertRaises(TypeError) as cm: + __import__('encodings', fromlist=[u'aliases']) + self.assertIn("must be str, not unicode", str(cm.exception)) + with self.assertRaises(TypeError) as cm: + __import__('encodings', fromlist=[1]) + self.assertIn("must be str, not int", str(cm.exception)) + class PycRewritingTests(unittest.TestCase): # Test that the `co_filename` attribute on code objects always points # to the right file, even when various things happen (e.g. both the .py # and the .pyc file are renamed). module_name = "unlikely_module_name" module_source = """ diff --git a/Python/import.c b/Python/import.c --- a/Python/import.c +++ b/Python/import.c @@ -2586,18 +2586,19 @@ ensure_fromlist(PyObject *mod, PyObject if (item == NULL) { if (PyErr_ExceptionMatches(PyExc_IndexError)) { PyErr_Clear(); return 1; } return 0; } if (!PyString_Check(item)) { - PyErr_SetString(PyExc_TypeError, - "Item in ``from list'' not a string"); + PyErr_Format(PyExc_TypeError, + "Item in ``from list'' must be str, not %200s", + Py_TYPE(item)->tp_name); Py_DECREF(item); return 0; } if (PyString_AS_STRING(item)[0] == '*') { PyObject *all; Py_DECREF(item); /* See if the package defines __all__ */ if (recursive)