https://github.com/python/cpython/commit/75b6789946076c65f0b5a4194f293ed019f81ff9 commit: 75b6789946076c65f0b5a4194f293ed019f81ff9 branch: 3.13 author: Peter Bierma <[email protected]> committer: ZeroIntensity <[email protected]> date: 2026-07-18T14:10:12Z summary:
[3.13] gh-71896: Add a docs warning about trailing newlines ignored by `difflib.HtmlDiff` (GH-153930) (GH-153968) (cherry picked from commit 755d97167f6f5d4361c790f8f18df76cae8f2ad2) Co-authored-by: Lenormand Julien <[email protected]> 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 85357008b6e14f..e53a47289bf5d4 100644 --- a/Doc/library/difflib.rst +++ b/Doc/library/difflib.rst @@ -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: diff --git a/Lib/difflib.py b/Lib/difflib.py index db550ceff2e075..cc8f2064a19d8e 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1961,6 +1961,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 943d7a659b1e1b..6c7d6c5199905b 100644 --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -282,6 +282,28 @@ def test_make_file_usascii_charset_with_nonascii_input(self): self.assertIn('content="text/html; 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) def test_one_insert(self): m = difflib.Differ().compare('b' * 2, 'a' + 'b' * 2) _______________________________________________ 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]
