[Python-checkins] bpo-32932: More revealing error message when non-str objects in __all__ (GH-5848)
Xiang Zhang
webhook-mailer at python.org
Sat Mar 24 06:39:44 EDT 2018
https://github.com/python/cpython/commit/d8b291a74284307610946f1b5801aa95d7f1e052
commit: d8b291a74284307610946f1b5801aa95d7f1e052
branch: master
author: Xiang Zhang <angwerzx at 126.com>
committer: GitHub <noreply at github.com>
date: 2018-03-24T18:39:36+08:00
summary:
bpo-32932: More revealing error message when non-str objects in __all__ (GH-5848)
files:
A Misc/NEWS.d/next/Core and Builtins/2018-02-24-21-51-42.bpo-32932.2cz31L.rst
M Lib/test/test_import/__init__.py
M Python/ceval.c
diff --git a/Lib/test/test_import/__init__.py b/Lib/test/test_import/__init__.py
index ceea79f6ad96..606b05784afc 100644
--- a/Lib/test/test_import/__init__.py
+++ b/Lib/test/test_import/__init__.py
@@ -111,6 +111,27 @@ def test_from_import_missing_attr_path_is_canonical(self):
self.assertIn(cm.exception.name, {'posixpath', 'ntpath'})
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):
# Brief digression to test that import is case-sensitive: if we got
# this far, we know for sure that "random" exists.
diff --git a/Misc/NEWS.d/next/Core and Builtins/2018-02-24-21-51-42.bpo-32932.2cz31L.rst b/Misc/NEWS.d/next/Core and Builtins/2018-02-24-21-51-42.bpo-32932.2cz31L.rst
new file mode 100644
index 000000000000..51e3d9b613d5
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2018-02-24-21-51-42.bpo-32932.2cz31L.rst
@@ -0,0 +1 @@
+Make error message more revealing when there are non-str objects in ``__all__``.
diff --git a/Python/ceval.c b/Python/ceval.c
index 14603d330083..d18a284e9f9d 100644
--- a/Python/ceval.c
+++ b/Python/ceval.c
@@ -4837,6 +4837,7 @@ import_all_from(PyObject *locals, PyObject *v)
{
_Py_IDENTIFIER(__all__);
_Py_IDENTIFIER(__dict__);
+ _Py_IDENTIFIER(__name__);
PyObject *all, *dict, *name, *value;
int skip_leading_underscores = 0;
int pos, err;
@@ -4869,7 +4870,32 @@ import_all_from(PyObject *locals, PyObject *v)
PyErr_Clear();
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) {
Py_DECREF(name);
err = -1;
More information about the Python-checkins
mailing list