bpo-32932: More revealing error message when non-str objects in __all__ (GH-5848)
This commit is contained in:
parent
5cbb84106e
commit
d8b291a742
|
@ -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.
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
Make error message more revealing when there are non-str objects in ``__all__``.
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue