https://github.com/python/cpython/commit/ece712197d2d23bcc80937d122e7b9f07338350e
commit: ece712197d2d23bcc80937d122e7b9f07338350e
branch: main
author: Stefan Zetzsche <[email protected]>
committer: encukou <[email protected]>
date: 2026-03-11T13:21:22+01:00
summary:

gh-145546: unittest.util: fix `sorted_list_difference` tail deduplication 
(GH-145547)

* fix(unittest.util): Deduplicate tail elements in sorted_list_difference

sorted_list_difference failed to deduplicate remaining elements when one
list was exhausted, causing duplicate values in the result.

Deduplicate before extending.

Co-authored-by: blurb-it[bot] <43283697+blurb-it[bot]@users.noreply.github.com>

files:
A Misc/NEWS.d/next/Library/2026-03-05-14-13-10.gh-issue-145546.3tnlxx.rst
M Lib/test/test_unittest/test_util.py
M Lib/unittest/util.py

diff --git a/Lib/test/test_unittest/test_util.py 
b/Lib/test/test_unittest/test_util.py
index d590a333930278..09ce09b91b7ac2 100644
--- a/Lib/test/test_unittest/test_util.py
+++ b/Lib/test/test_unittest/test_util.py
@@ -26,6 +26,39 @@ def test_sorted_list_difference(self):
         self.assertEqual(sorted_list_difference([2], [1, 1]), ([2], [1]))
         self.assertEqual(sorted_list_difference([1, 2], [1, 1]), ([2], []))
 
+    def test_sorted_list_difference_tail_deduplication(self):
+        # Tail deduplication when one list is exhausted before the other.
+        # These exercise the except-IndexError path in sorted_list_difference.
+        self.assertEqual(sorted_list_difference([], [0, 0]), ([], [0]))
+        self.assertEqual(sorted_list_difference([0, 0], []), ([0], []))
+        self.assertEqual(sorted_list_difference([], [1, 1, 2, 2]), ([], [1, 
2]))
+        self.assertEqual(sorted_list_difference([1, 1, 2, 2], []), ([1, 2], 
[]))
+        # One list exhausts mid-way, leaving duplicated tail in the other.
+        self.assertEqual(sorted_list_difference([1], [1, 2, 2, 3, 3]), ([], 
[2, 3]))
+        self.assertEqual(sorted_list_difference([1, 2, 2, 3, 3], [1]), ([2, 
3], []))
+
+    def test_sorted_list_difference_strings(self):
+        self.assertEqual(
+            sorted_list_difference(['a', 'b'], ['b', 'c']),
+            (['a'], ['c']))
+        self.assertEqual(
+            sorted_list_difference([], ['a', 'a', 'b']),
+            ([], ['a', 'b']))
+        self.assertEqual(
+            sorted_list_difference(['a', 'a', 'b'], []),
+            (['a', 'b'], []))
+
+    def test_sorted_list_difference_unhashable(self):
+        self.assertEqual(
+            sorted_list_difference([[1], [2]], [[2], [3]]),
+            ([[1]], [[3]]))
+        self.assertEqual(
+            sorted_list_difference([], [[0], [0]]),
+            ([], [[0]]))
+        self.assertEqual(
+            sorted_list_difference([[0], [0]], []),
+            ([[0]], []))
+
     def test_unorderable_list_difference(self):
         self.assertEqual(unorderable_list_difference([], []), ([], []))
         self.assertEqual(unorderable_list_difference([1, 2], []), ([2, 1], []))
diff --git a/Lib/unittest/util.py b/Lib/unittest/util.py
index c7e6b941978cd5..0681163c979587 100644
--- a/Lib/unittest/util.py
+++ b/Lib/unittest/util.py
@@ -63,6 +63,14 @@ def safe_repr(obj, short=False):
 def strclass(cls):
     return "%s.%s" % (cls.__module__, cls.__qualname__)
 
+def _dedupe_sorted(lst):
+    """Remove consecutive duplicate elements from a sorted list."""
+    result = []
+    for item in lst:
+        if not result or result[-1] != item:
+            result.append(item)
+    return result
+
 def sorted_list_difference(expected, actual):
     """Finds elements in only one or the other of two, sorted input lists.
 
@@ -98,8 +106,8 @@ def sorted_list_difference(expected, actual):
                     while actual[j] == a:
                         j += 1
         except IndexError:
-            missing.extend(expected[i:])
-            unexpected.extend(actual[j:])
+            missing.extend(_dedupe_sorted(expected[i:]))
+            unexpected.extend(_dedupe_sorted(actual[j:]))
             break
     return missing, unexpected
 
diff --git 
a/Misc/NEWS.d/next/Library/2026-03-05-14-13-10.gh-issue-145546.3tnlxx.rst 
b/Misc/NEWS.d/next/Library/2026-03-05-14-13-10.gh-issue-145546.3tnlxx.rst
new file mode 100644
index 00000000000000..e9401bb08c6774
--- /dev/null
+++ b/Misc/NEWS.d/next/Library/2026-03-05-14-13-10.gh-issue-145546.3tnlxx.rst
@@ -0,0 +1,2 @@
+Fix ``unittest.util.sorted_list_difference()`` to deduplicate remaining
+elements when one input list is exhausted before the other.

_______________________________________________
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]

Reply via email to