gh-55664: Add warning when creating a type using a namespace dictionary with non-string keys. (GH-105338)

Co-authored-by: Daniel Urban <durban@users.noreply.github.com>
This commit is contained in:
Furkan Onder 2024-01-29 02:05:29 +03:00 committed by GitHub
parent 3bb6912d88
commit f7c05d7ad3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 28 additions and 1 deletions

View File

@ -4734,6 +4734,20 @@ class ClassPropertiesAndMethods(unittest.TestCase):
with self.assertRaises(AttributeError): with self.assertRaises(AttributeError):
del X.__abstractmethods__ 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): def test_proxy_call(self):
class FakeStr: class FakeStr:
__class__ = str __class__ = str
@ -5151,7 +5165,8 @@ class MiscTests(unittest.TestCase):
mykey = 'from Base2' mykey = 'from Base2'
mykey2 = '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 # mykey is read from Base
self.assertEqual(X.mykey, 'from Base') self.assertEqual(X.mykey, 'from Base')
# mykey2 is read from Base2 because MyKey.__eq__ has set __bases__ # mykey2 is read from Base2 because MyKey.__eq__ has set __bases__

View File

@ -0,0 +1 @@
Add warning when creating :class:`type` using a namespace dictionary with non-string keys. Patched by Daniel Urban and Furkan Onder.

View File

@ -3828,6 +3828,17 @@ type_new_impl(type_new_ctx *ctx)
// Put the proper slots in place // Put the proper slots in place
fixup_slot_dispatchers(type); 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) { if (type_new_set_names(type) < 0) {
goto error; goto error;
} }