From 44debb1fb855c6faab628ae49eb4c7a55f0d51df Mon Sep 17 00:00:00 2001 From: felix h Date: Fri, 28 Aug 2026 12:03:21 +0200 Subject: [PATCH] Speed up difflib._mdiff() for lopsided replacements --- Lib/difflib.py | 8 ++++---- Lib/test/test_difflib.py | 20 ++++++++++++++++++++ 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py index 95ba8fd782c6c3c..360f88e6a23b930 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -31,7 +31,7 @@ 'unified_diff', 'diff_bytes', 'HtmlDiff', 'Match'] from heapq import nlargest as _nlargest -from collections import namedtuple as _namedtuple +from collections import deque as _deque, namedtuple as _namedtuple from types import GenericAlias lazy from _colorize import can_colorize, get_theme @@ -1558,7 +1558,7 @@ def _line_pair_iterator(): is defined) does not need to be of module scope. """ line_iterator = _line_iterator() - fromlines,tolines=[],[] + fromlines, tolines = _deque(), _deque() while True: # Collecting lines of text until we have a from/to pair while (len(fromlines)==0 or len(tolines)==0): @@ -1571,8 +1571,8 @@ def _line_pair_iterator(): if to_line is not None: tolines.append((to_line,found_diff)) # Once we have a pair, remove them from the collection and yield it - from_line, fromDiff = fromlines.pop(0) - to_line, to_diff = tolines.pop(0) + from_line, fromDiff = fromlines.popleft() + to_line, to_diff = tolines.popleft() yield (from_line,to_line,fromDiff or to_diff) # Handle case where user does not want context differencing, just yield diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py index 4f99b7c91c654e4..8e936aa2443f3d8 100644 --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -118,6 +118,26 @@ def test_mdiff_catch_stop_iteration(self): [((1, '\x00-2\x01'), (1, '\x00+3\x01'), True)], ) + def test_mdiff_lopsided_replace(self): + self.assertEqual( + list(difflib._mdiff(["a\n"] * 4, ["b\n"])), + [ + ((1, '\x00-a\n\x01'), (1, '\x00+b\n\x01'), True), + ((2, '\x00-a\n\x01'), ('', '\n'), True), + ((3, '\x00-a\n\x01'), ('', '\n'), True), + ((4, '\x00-a\n\x01'), ('', '\n'), True), + ], + ) + self.assertEqual( + list(difflib._mdiff(["a\n"], ["b\n"] * 4)), + [ + ((1, '\x00-a\n\x01'), (1, '\x00+b\n\x01'), True), + (('', '\n'), (2, '\x00+b\n\x01'), True), + (('', '\n'), (3, '\x00+b\n\x01'), True), + (('', '\n'), (4, '\x00+b\n\x01'), True), + ], + ) + patch914575_from1 = """ 1. Beautiful is beTTer than ugly.