GeezerVison is showing github.com — `PyDict_Merge` and `PyDict_Update` have conflicting docs: both require `.keys` to exist · Issue #160669 · python/cpython
PyDict_Merge and PyDict_Update have conflicting docs: both require .keys to exist #160669
DescriptionWhile working on msgspec we noticed that PyDict_Merge does not follow the documented way of merging objects: msgspec/msgspec#1309 (comment)
The docs (https://docs.python.org/3/c-api/dict.html#c.PyDict_Update) of PyDict_Update say:
This is the same as PyDict_Merge(a, b, 1) in C, and is similar to a.update(b) in Python except that PyDict_Update() doesn’t fall back to the iterating over a sequence of key value pairs if the second argument has no “keys” attribute.
So, this confuses me:
Iterate over mapping object b adding key-value pairs to dictionary a. b may be a dictionary, or any object supporting PyMapping_Keys() and PyObject_GetItem().
PyDict_Update() doesn’t fall back to the iterating over a sequence of key value pairs if the second argument has no “keys” attribute.
So, I have 2 questions:
- Is this a
PyDict_Update doc issue?
- Should
PyDict_Merge require .keys attribute? Or can it work with an iterable of key-value pairs?
Repro
I can re-create this problem in CAPI tests:
diff --git Lib/test/test_capi/test_dict.py Lib/test/test_capi/test_dict.py
index 4cf404e9f56..6323a3ea28f 100644
--- Lib/test/test_capi/test_dict.py
+++ Lib/test/test_capi/test_dict.py
@@ -460,6 +460,11 @@ def test_dict_update(self):
def test_dict_merge(self):
# Test PyDict_Merge()
merge = _testlimitedcapi.dict_merge
+
+ dct = {'a': 1, 'b': 2}
+ merge(dct, [('b', 3), ('c', 4)], 0)
+ self.assertEqual(dct, {'a': 1, 'b': 2, 'c': 4})
+
for cls1 in DICT_TYPES:
for cls2 in ANYDICT_TYPES + MAPPING_TYPES:
dct = cls1({'a': 1, 'b': 2})
» ./python.exe -m test test_capi.test_dict
Using random seed: 1975933612
0:00:00 load avg: 1.91 mem: 27.6 MiB Run 1 test sequentially in a single process
0:00:00 load avg: 1.91 mem: 27.6 MiB [1/1] test_capi.test_dict
test test_capi.test_dict failed -- Traceback (most recent call last):
File "/Users/sobolev/Desktop/cpython/Lib/test/test_capi/test_dict.py", line 465, in test_dict_merge
merge(dct, [('b', 3), ('c', 4)], 0)
~~~~~^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'list' object has no attribute 'keys'
Linked PRs
Reacted by Janek Nouvertné, Shamil and bug Activitycommit-msuyog commented on Oct 26, 2026 Hi @sobolevn! Is this issue still free? I'd like to work on it.
It looks like a docs clarification in Doc/c-api/dict.rst. PyDict_Merge needs a keys() method and does not accept a sequence of pairs, so the docs should point to PyDict_MergeFromSeq2 for that case.
Could you confirm that direction? Thanks! sobolevn commented on Oct 26, 2026 encukou commented on Nov 4, 2026 As the docs say, PyDict_Update “is the same as PyDict_Merge(a, b, 1) in C”. IMO, the sentence (or ideally the paragraph) should end there.
Compared to a.update(b) in Python, neither PyDict_Merge nor PyDict_Update falls back to iterating key/value pairs.
MetadataMetadataStatusShow more project fields
DevelopmentNo branches or pull requestsIssue actions
|