Skip to content

Commit f7c05d7

Browse files
furkanonderdurban
andauthored
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>
1 parent 3bb6912 commit f7c05d7

File tree

3 files changed

+28
-1
lines changed

3 files changed

+28
-1
lines changed

Lib/test/test_descr.py

+16-1
Original file line numberDiff line numberDiff line change
@@ -4734,6 +4734,20 @@ class X(object):
47344734
with self.assertRaises(AttributeError):
47354735
del X.__abstractmethods__
47364736

4737+
def test_gh55664(self):
4738+
# gh-55664: issue a warning when the
4739+
# __dict__ of a class contains non-string keys
4740+
with self.assertWarnsRegex(RuntimeWarning, 'MyClass'):
4741+
MyClass = type('MyClass', (), {1: 2})
4742+
4743+
class meta(type):
4744+
def __new__(mcls, name, bases, ns):
4745+
ns[1] = 2
4746+
return super().__new__(mcls, name, bases, ns)
4747+
4748+
with self.assertWarnsRegex(RuntimeWarning, 'MyClass'):
4749+
MyClass = meta('MyClass', (), {})
4750+
47374751
def test_proxy_call(self):
47384752
class FakeStr:
47394753
__class__ = str
@@ -5151,7 +5165,8 @@ class Base2(object):
51515165
mykey = 'from Base2'
51525166
mykey2 = 'from Base2'
51535167

5154-
X = type('X', (Base,), {MyKey(): 5})
5168+
with self.assertWarnsRegex(RuntimeWarning, 'X'):
5169+
X = type('X', (Base,), {MyKey(): 5})
51555170
# mykey is read from Base
51565171
self.assertEqual(X.mykey, 'from Base')
51575172
# mykey2 is read from Base2 because MyKey.__eq__ has set __bases__
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add warning when creating :class:`type` using a namespace dictionary with non-string keys. Patched by Daniel Urban and Furkan Onder.

Objects/typeobject.c

+11
Original file line numberDiff line numberDiff line change
@@ -3828,6 +3828,17 @@ type_new_impl(type_new_ctx *ctx)
38283828
// Put the proper slots in place
38293829
fixup_slot_dispatchers(type);
38303830

3831+
if (!_PyDict_HasOnlyStringKeys(type->tp_dict)) {
3832+
if (PyErr_WarnFormat(
3833+
PyExc_RuntimeWarning,
3834+
1,
3835+
"non-string key in the __dict__ of class %.200s",
3836+
type->tp_name) == -1)
3837+
{
3838+
goto error;
3839+
}
3840+
}
3841+
38313842
if (type_new_set_names(type) < 0) {
38323843
goto error;
38333844
}

0 commit comments

Comments
 (0)