]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.14] gh-71896: Add a docs warning about trailing newlines ignored by `difflib.HtmlD...
authorMiss Islington (bot) <31488909+miss-islington@users.noreply.github.com>
Sat, 18 Jul 2026 14:11:27 +0000 (16:11 +0200)
committerGitHub <noreply@github.com>
Sat, 18 Jul 2026 14:11:27 +0000 (14:11 +0000)
(cherry picked from commit 755d97167f6f5d4361c790f8f18df76cae8f2ad2)

Co-authored-by: Lenormand Julien <lenormand.julien0@gmail.com>
Doc/library/difflib.rst
Lib/difflib.py
Lib/test/test_difflib.py

index 85357008b6e14f491051ec409c4e6b2ea604fde6..e53a47289bf5d4103ed891bcdf47527e20b7f724 100644 (file)
@@ -89,6 +89,11 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module.
    with inter-line and intra-line change highlights.  The table can be generated in
    either full or contextual difference mode.
 
+   .. warning::
+
+      The trailing newlines get stripped before the diff, so the result can be
+      incomplete. See :gh:`71896` for details.
+
    The constructor for this class is:
 
 
index ac1ba4a6e4ee9475ebe75dbf6c955a03dca5c518..aef2b6f0fd8a1bfcfee3c778d827e566f5ccd4c9 100644 (file)
@@ -1977,6 +1977,8 @@ class HtmlDiff(object):
 
         # change tabs to spaces before it gets more difficult after we insert
         # markup
+        # it also removes trailing newlines, causing some diffs to be missed
+        # see: gh-71896
         fromlines,tolines = self._tab_newline_replace(fromlines,tolines)
 
         # create diffs iterator which generates side by side from/to data
index 36be5c99c3f01b5f17b3ab06a5a8c33a240a2756..518b8c5278e4c4785a7d52b94ec68b387b1874a6 100644 (file)
@@ -282,6 +282,29 @@ class TestSFpatches(unittest.TestCase):
         self.assertIn('content="text/html; charset=us-ascii"', output)
         self.assertIn('&#305;mpl&#305;c&#305;t', output)
 
+    def test_strip_trailing_newlines_before_diff(self):
+        # characterization test for the current buggy behavior
+        # see: gh-71896
+        html_diff = difflib.HtmlDiff()
+        from_lines = [
+            "Line 1: no newline after",
+            "Line 2: one newline after\n",
+            "Line 3: several newlines after\n\n\n\n\n",
+        ]
+        to_lines = [
+            "Line 1: no newline after",
+            "Line 2: one newline after",  # actually no \n
+            "Line 3: several newlines after",  # actually no \n
+        ]
+        output = html_diff.make_table(from_lines, to_lines)
+        # we (currently) expect no line change, so all equal
+        self.assertNotIn('class="diff_add"', output)
+        self.assertNotIn('class="diff_chg"', output)
+        self.assertNotIn('class="diff_sub"', output)
+        self.assertEqual(output.count('>Line&nbsp;1:&nbsp;no&nbsp;newline&nbsp;after<'), 2)
+        self.assertEqual(output.count('>Line&nbsp;2:&nbsp;one&nbsp;newline&nbsp;after<'), 2)
+        self.assertEqual(output.count('>Line&nbsp;3:&nbsp;several&nbsp;newlines&nbsp;after<'), 2)
+
 class TestDiffer(unittest.TestCase):
     def test_close_matches_aligned(self):
         # Of the 4 closely matching pairs, we want 1 to match with 3,