Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions Lib/test/test_dict.py
Original file line number Diff line number Diff line change
Expand Up @@ -1602,6 +1602,7 @@ def __hash__(self):
d.get(key2)

def test_clear_at_lookup(self):
# gh-140551 dict crash if clear is called at lookup stage
class X:
def __hash__(self):
return 1
Expand All @@ -1622,13 +1623,31 @@ def __eq__(self, other):
self.assertEqual(len(d), 1)

def test_split_table_update_with_str_subclass(self):
# gh-142218: inserting into a split table dictionary with a non str
# key that matches an existing key.
class MyStr(str): pass
class MyClass: pass
obj = MyClass()
obj.attr = 1
obj.__dict__[MyStr('attr')] = 2
self.assertEqual(obj.attr, 2)

def test_split_table_insert_with_str_subclass(self):
# gh-143189: inserting into split table dictionary with a non str
# key that matches an existing key in the shared table but not in
# the dict yet.

class MyStr(str): pass
class MyClass: pass

obj = MyClass()
obj.attr1 = 1

obj2 = MyClass()
d = obj2.__dict__
d[MyStr("attr1")] = 2
assert isinstance(list(d)[0], MyStr)
Copy link

Copilot AI Dec 30, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use unittest assertion method instead of bare assert statement. This ensures the test properly reports failures with helpful messages and follows unittest best practices. Replace with self.assertTrue(isinstance(list(d)[0], MyStr)).

Suggested change
assert isinstance(list(d)[0], MyStr)
self.assertTrue(isinstance(list(d)[0], MyStr))

Copilot uses AI. Check for mistakes.


class CAPITest(unittest.TestCase):

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
Fix crash when inserting a non-:class:`str` key into a split table
dictionary when the key matches an existing key in the split table
but has no corresponding value in the dict.
7 changes: 5 additions & 2 deletions Objects/dictobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1877,7 +1877,7 @@ static int
insertdict(PyDictObject *mp,
PyObject *key, Py_hash_t hash, PyObject *value)
{
PyObject *old_value;
PyObject *old_value = NULL;
Py_ssize_t ix;

ASSERT_DICT_LOCKED(mp);
Expand All @@ -1898,11 +1898,14 @@ insertdict(PyDictObject *mp,
goto Fail;
}

if (ix == DKIX_EMPTY) {
if (old_value == NULL) {
// insert_combined_dict() will convert from non DICT_KEYS_GENERAL table
// into DICT_KEYS_GENERAL table if key is not Unicode.
// We don't convert it before _Py_dict_lookup because non-Unicode key
// may change generic table into Unicode table.
//
// NOTE: ix may not be DKIX_EMPTY because split table may have key
// without value.
if (insert_combined_dict(mp, hash, key, value) < 0) {
goto Fail;
}
Expand Down
Loading