summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Lib/test/test_descr.py17
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst1
-rw-r--r--Objects/typeobject.c11
3 files changed, 28 insertions, 1 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index fd0af9b..beeab6c 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -4734,6 +4734,20 @@ class ClassPropertiesAndMethods(unittest.TestCase):
with self.assertRaises(AttributeError):
del X.__abstractmethods__
+ def test_gh55664(self):
+ # gh-55664: issue a warning when the
+ # __dict__ of a class contains non-string keys
+ with self.assertWarnsRegex(RuntimeWarning, 'MyClass'):
+ MyClass = type('MyClass', (), {1: 2})
+
+ class meta(type):
+ def __new__(mcls, name, bases, ns):
+ ns[1] = 2
+ return super().__new__(mcls, name, bases, ns)
+
+ with self.assertWarnsRegex(RuntimeWarning, 'MyClass'):
+ MyClass = meta('MyClass', (), {})
+
def test_proxy_call(self):
class FakeStr:
__class__ = str
@@ -5151,7 +5165,8 @@ class MiscTests(unittest.TestCase):
mykey = 'from Base2'
mykey2 = 'from Base2'
- X = type('X', (Base,), {MyKey(): 5})
+ with self.assertWarnsRegex(RuntimeWarning, 'X'):
+ X = type('X', (Base,), {MyKey(): 5})
# mykey is read from Base
self.assertEqual(X.mykey, 'from Base')
# mykey2 is read from Base2 because MyKey.__eq__ has set __bases__
diff --git a/Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst
new file mode 100644
index 0000000..438be98
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2023-06-06-19-09-00.gh-issue-55664.vYYl0V.rst
@@ -0,0 +1 @@
+Add warning when creating :class:`type` using a namespace dictionary with non-string keys. Patched by Daniel Urban and Furkan Onder.
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index 114cf21..a850473 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3828,6 +3828,17 @@ type_new_impl(type_new_ctx *ctx)
// Put the proper slots in place
fixup_slot_dispatchers(type);
+ if (!_PyDict_HasOnlyStringKeys(type->tp_dict)) {
+ if (PyErr_WarnFormat(
+ PyExc_RuntimeWarning,
+ 1,
+ "non-string key in the __dict__ of class %.200s",
+ type->tp_name) == -1)
+ {
+ goto error;
+ }
+ }
+
if (type_new_set_names(type) < 0) {
goto error;
}