]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-32932: More revealing error message when non-str objects in __all__ (GH-5848)
authorXiang Zhang <angwerzx@126.com>
Sat, 24 Mar 2018 10:39:36 +0000 (18:39 +0800)
committerGitHub <noreply@github.com>
Sat, 24 Mar 2018 10:39:36 +0000 (18:39 +0800)
Lib/test/test_import/__init__.py
Misc/NEWS.d/next/Core and Builtins/2018-02-24-21-51-42.bpo-32932.2cz31L.rst [new file with mode: 0644]
Python/ceval.c

index ceea79f6ad96ff7ff38255c81b90b43474012652..606b05784afcf4074f5eeb73dc8df371b1338d0f 100644 (file)
@@ -111,6 +111,27 @@ class ImportTests(unittest.TestCase):
         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 (file)
index 0000000..51e3d9b
--- /dev/null
@@ -0,0 +1 @@
+Make error message more revealing when there are non-str objects in ``__all__``.
index 14603d330083efdcf8d04b608079e126bd60eec9..d18a284e9f9d220f0de91a9f0b1ddd37003419d0 100644 (file)
@@ -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;