From cd40e07f658695981d30c740e61dcd4b9f1ee8b9 Mon Sep 17 00:00:00 2001 From: JoaoMarcos44 <87440198+JoaoMarcos44@users.noreply.github.com> Date: Thu, 29 Oct 2026 18:34:00 -0300 Subject: [PATCH 1/3] test: cover ChainMap reverse union lookups --- Lib/test/test_collections.py | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) 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 From 455a696e6741ca3ac08ff7acf06cd97ff684fe93 Mon Sep 17 00:00:00 2001 From: JoaoMarcos44 <87440198+JoaoMarcos44@users.noreply.github.com> Date: Thu, 29 Oct 2026 18:35:32 -0300 Subject: [PATCH 2/3] fix: preserve ChainMap values in reverse unions --- Lib/collections/__init__.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) 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) From aa591236ad337499fe80e90e6ad28178c81a8367 Mon Sep 17 00:00:00 2001 From: JoaoMarcos44 <87440198+JoaoMarcos44@users.noreply.github.com> Date: Thu, 29 Oct 2026 18:36:25 -0300 Subject: [PATCH 3/3] gh-160929: Document ChainMap reverse union fix --- .../Library/2026-10-29-21-36-08.gh-issue-160929.mK8n2Q.rst | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 Misc/NEWS.d/next/Library/2026-10-29-21-36-08.gh-issue-160929.mK8n2Q.rst 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`.