mirror of
https://github.com/RustPython/RustPython.git
synced 2026-10-28 10:44:36 +08:00
Preserve recursively-set value in defaultdict.__missing__ (#7718)
CPython's defaultdict.__missing__ (Modules/_collectionsmodule.c::defdict_missing) calls default_factory() first; if the factory's recursion already populated self[key] while running, the existing value is preserved instead of being overwritten. RustPython ships a Python fallback at Lib/collections/_defaultdict.py (the C _collections.defaultdict is not available). That fallback unconditionally executed self[key] = val after the factory returned, overwriting any value the recursive call had already stored. Add a 'if key in self: return self[key]' guard before the assignment. dict.__contains__ does not invoke __missing__, so there's no recursion risk; in the common non-reentrant case the check is False and behavior is unchanged. Unmasks test_defaultdict.TestDefaultDict.test_factory_conflict_with_set_value.
This commit is contained in:
1 parent
82e8b200db
commit
330b18f2fe
2 files changed
+4
-1
No files matched your search
Vendored
+4
@@ -17,6 +17,10 @@ class defaultdict(dict):
|
||||
val = self.default_factory()
|
||||
else:
|
||||
raise KeyError(key)
|
||||
# CPython parity: a recursive __missing__ via factory() may have
|
||||
# already populated key; preserve that value instead of overwriting.
|
||||
if key in self:
|
||||
return self[key]
|
||||
self[key] = val
|
||||
return val
|
||||
|
||||
|
||||
Vendored
-1
@@ -186,7 +186,6 @@ class TestDefaultDict(unittest.TestCase):
|
||||
with self.assertRaises(TypeError):
|
||||
i |= None
|
||||
|
||||
@unittest.expectedFailure # TODO: RUSTPYTHON; AssertionError: 1 != 2
|
||||
def test_factory_conflict_with_set_value(self):
|
||||
key = "conflict_test"
|
||||
count = 0
|
||||
|
||||
Reference in new issue
Block a user