bpo-32932: More revealing error message when non-str objects in __all__ (GH-5848)

This commit is contained in:
Xiang Zhang 2018-03-24 18:39:36 +08:00 committed by GitHub
parent 5cbb84106e
commit d8b291a742
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 49 additions and 1 deletions

View File

@ -111,6 +111,27 @@ class ImportTests(unittest.TestCase):
self.assertIn(cm.exception.name, {'posixpath', 'ntpath'}) self.assertIn(cm.exception.name, {'posixpath', 'ntpath'})
self.assertIsNotNone(cm.exception) self.assertIsNotNone(cm.exception)
def test_from_import_star_invalid_type(self):
import re
with _ready_to_import() as (name, path):
with open(path, 'w') as f:
f.write("__all__ = [b'invalid_type']")
globals = {}
with self.assertRaisesRegex(
TypeError, f"{re.escape(name)}\.__all__ must be str"
):
exec(f"from {name} import *", globals)
self.assertNotIn(b"invalid_type", globals)
with _ready_to_import() as (name, path):
with open(path, 'w') as f:
f.write("globals()[b'invalid_type'] = object()")
globals = {}
with self.assertRaisesRegex(
TypeError, f"{re.escape(name)}\.__dict__ must be str"
):
exec(f"from {name} import *", globals)
self.assertNotIn(b"invalid_type", globals)
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
# this far, we know for sure that "random" exists. # this far, we know for sure that "random" exists.

View File

@ -0,0 +1 @@
Make error message more revealing when there are non-str objects in ``__all__``.

View File

@ -4837,6 +4837,7 @@ import_all_from(PyObject *locals, PyObject *v)
{ {
_Py_IDENTIFIER(__all__); _Py_IDENTIFIER(__all__);
_Py_IDENTIFIER(__dict__); _Py_IDENTIFIER(__dict__);
_Py_IDENTIFIER(__name__);
PyObject *all, *dict, *name, *value; PyObject *all, *dict, *name, *value;
int skip_leading_underscores = 0; int skip_leading_underscores = 0;
int pos, err; int pos, err;
@ -4869,7 +4870,32 @@ import_all_from(PyObject *locals, PyObject *v)
PyErr_Clear(); PyErr_Clear();
break; break;
} }
if (skip_leading_underscores && PyUnicode_Check(name)) { if (!PyUnicode_Check(name)) {
PyObject *modname = _PyObject_GetAttrId(v, &PyId___name__);
if (modname == NULL) {
Py_DECREF(name);
err = -1;
break;
}
if (!PyUnicode_Check(modname)) {
PyErr_Format(PyExc_TypeError,
"module __name__ must be a string, not %.100s",
Py_TYPE(modname)->tp_name);
}
else {
PyErr_Format(PyExc_TypeError,
"%s in %U.%s must be str, not %.100s",
skip_leading_underscores ? "Key" : "Item",
modname,
skip_leading_underscores ? "__dict__" : "__all__",
Py_TYPE(name)->tp_name);
}
Py_DECREF(modname);
Py_DECREF(name);
err = -1;
break;
}
if (skip_leading_underscores) {
if (PyUnicode_READY(name) == -1) { if (PyUnicode_READY(name) == -1) {
Py_DECREF(name); Py_DECREF(name);
err = -1; err = -1;