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.
- Updated Lib/collections from CPython v3.14.3
- Preserved RustPython's fallback implementation for defaultdict
- Added test for update_reentrant_add_clears_counter
- Minor formatting fixes in test file
Co-authored-by: CPython Developers <>
Clean implementation of changes in PR #3371 based on feedback.
Copies from [CPython tag `v3.9.7` and adds back custom RustPython changes where needed for:
- `Lib/collections/__init__.py`
- `Lib/test/test_collections.py`
Closes: #3371