https://github.com/python/cpython/commit/755d97167f6f5d4361c790f8f18df76cae8f2ad2
commit: 755d97167f6f5d4361c790f8f18df76cae8f2ad2
branch: main
author: Lenormand Julien <[email protected]>
committer: ZeroIntensity <[email protected]>
date: 2026-07-18T13:40:11Z
summary:
gh-71896: Add a docs warning about trailing newlines ignored by
`difflib.HtmlDiff` (GH-153930)
files:
M Doc/library/difflib.rst
M Lib/difflib.py
M Lib/test/test_difflib.py
diff --git a/Doc/library/difflib.rst b/Doc/library/difflib.rst
index 25edb40e35a630..3ed4768b6a1413 100644
--- a/Doc/library/difflib.rst
+++ b/Doc/library/difflib.rst
@@ -85,6 +85,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:
diff --git a/Lib/difflib.py b/Lib/difflib.py
index ae8b284b4d3647..95ba8fd782c6c3 100644
--- a/Lib/difflib.py
+++ b/Lib/difflib.py
@@ -2016,6 +2016,8 @@ def
make_table(self,fromlines,tolines,fromdesc='',todesc='',context=False,
# 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
diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py
index 46c9b2c1d8c9fc..4f99b7c91c654e 100644
--- a/Lib/test/test_difflib.py
+++ b/Lib/test/test_difflib.py
@@ -284,6 +284,29 @@ def
test_make_file_usascii_charset_with_nonascii_input(self):
self.assertIn('charset="us-ascii"', output)
self.assertIn('ımplıcı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 1: no newline after<'),
2)
+
self.assertEqual(output.count('>Line 2: one newline after<'),
2)
+
self.assertEqual(output.count('>Line 3: several newlines 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,
_______________________________________________
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]