https://github.com/python/cpython/commit/c3fe3c3b8560b9d54d49f7b02068ceee8cdb8cd6
commit: c3fe3c3b8560b9d54d49f7b02068ceee8cdb8cd6
branch: main
author: JoaoMarcos44 <[email protected]>
committer: rhettinger <[email protected]>
date: 2026-10-31T16:46:08-05:00
summary:
gh-160929: Preserve ChainMap lookup values in reverse unions (gh-160932)
files:
A Misc/NEWS.d/next/Library/2026-10-29-21-36-08.gh-issue-160929.mK8n2Q.rst
M Lib/collections/__init__.py
M Lib/test/test_collections.py
diff --git a/Lib/collections/__init__.py b/Lib/collections/__init__.py
index f23129d7e3275e7..2239787dd6b51aa 100644
--- a/Lib/collections/__init__.py
+++ b/Lib/collections/__init__.py
@@ -1163,8 +1163,7 @@ def __ror__(self, other):
if not isinstance(other, _collections_abc.Mapping):
return NotImplemented
m = dict(other)
- for child in reversed(self.maps):
- m.update(child)
+ m.update(self)
return self.__class__(m)
diff --git a/Lib/test/test_collections.py b/Lib/test/test_collections.py
index b1b2dd2ca5ca0db..8bd5cf478f44b03 100644
--- a/Lib/test/test_collections.py
+++ b/Lib/test/test_collections.py
@@ -309,6 +309,42 @@ def __ror__(self, other):
self.assertIs(type(tmp), SubclassRor)
self.assertIs(type(tmp.maps[0]), dict)
+ def test_reverse_union_with_counter(self):
+ left = {'shared': 99, 'left_only': 3}
+ front = Counter(front=2)
+ back = {'shadowed': 5, 'shared': 7, 'back': 9}
+ cm = ChainMap(front, back)
+
+ self.assertEqual(cm['shadowed'], 0)
+ result = left | cm
+ self.assertEqual(list(result.items()), [
+ ('shared', 0), ('left_only', 3), ('shadowed', 0),
+ ('back', 0), ('front', 2),
+ ])
+ self.assertEqual(left, {'shared': 99, 'left_only': 3})
+ self.assertEqual(dict(front), {'front': 2})
+ self.assertEqual(back, {'shadowed': 5, 'shared': 7, 'back': 9})
+
+ def test_reverse_union_with_defaultdict(self):
+ left = {'shared': 99, 'left_only': 3}
+ front = collections.defaultdict(lambda: -1, {'front': 2})
+ back = {'shadowed': 5, 'shared': 7}
+ cm = ChainMap(front, back)
+
+ fresh_front = collections.defaultdict(lambda: -1, {'front': 2})
+ fresh = ChainMap(fresh_front, {'shadowed': 5, 'shared': 7})
+ self.assertEqual(fresh['shadowed'], -1)
+ self.assertEqual(fresh['shared'], -1)
+ self.assertEqual(fresh_front, {'front': 2, 'shadowed': -1, 'shared':
-1})
+
+ result = left | cm
+ self.assertEqual(list(result.items()), [
+ ('shared', -1), ('left_only', 3), ('shadowed', -1), ('front', 2),
+ ])
+ self.assertEqual(left, {'shared': 99, 'left_only': 3})
+ self.assertEqual(front, {'front': 2, 'shadowed': -1, 'shared': -1})
+ self.assertEqual(back, {'shadowed': 5, 'shared': 7})
+
################################################################################
### Named Tuples
diff --git
a/Misc/NEWS.d/next/Library/2026-10-29-21-36-08.gh-issue-160929.mK8n2Q.rst
b/Misc/NEWS.d/next/Library/2026-10-29-21-36-08.gh-issue-160929.mK8n2Q.rst
new file mode 100644
index 000000000000000..09bd1e568e7e9bd
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-10-29-21-36-08.gh-issue-160929.mK8n2Q.rst
@@ -0,0 +1,3 @@
+Fix reverse union with :class:`~collections.ChainMap` to preserve its lookup
+semantics for defaulting mappings such as :class:`~collections.Counter` and
+:class:`~collections.defaultdict`.
_______________________________________________
Python-checkins mailing list -- [email protected]
To unsubscribe send an email to [email protected]
https://mail.python.org/mailman3//lists/python-checkins.python.org
Member address: [email protected]