Skip to content

Commit 75b6789

Browse files
[3.13] gh-71896: Add a docs warning about trailing newlines ignored by difflib.HtmlDiff (GH-153930) (GH-153968)
(cherry picked from commit 755d971) Co-authored-by: Lenormand Julien <lenormand.julien0@gmail.com>
1 parent 09f235e commit 75b6789

3 files changed

Lines changed: 29 additions & 0 deletions

File tree

Doc/library/difflib.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,11 @@ diffs. For comparing directories and files, see also, the :mod:`filecmp` module.
8989
with inter-line and intra-line change highlights. The table can be generated in
9090
either full or contextual difference mode.
9191

92+
.. warning::
93+
94+
The trailing newlines get stripped before the diff, so the result can be
95+
incomplete. See :gh:`71896` for details.
96+
9297
The constructor for this class is:
9398

9499

Lib/difflib.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1961,6 +1961,8 @@ def make_table(self,fromlines,tolines,fromdesc='',todesc='',context=False,
19611961

19621962
# change tabs to spaces before it gets more difficult after we insert
19631963
# markup
1964+
# it also removes trailing newlines, causing some diffs to be missed
1965+
# see: gh-71896
19641966
fromlines,tolines = self._tab_newline_replace(fromlines,tolines)
19651967

19661968
# create diffs iterator which generates side by side from/to data

Lib/test/test_difflib.py

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,6 +282,28 @@ def test_make_file_usascii_charset_with_nonascii_input(self):
282282
self.assertIn('content="text/html; charset=us-ascii"', output)
283283
self.assertIn('&#305;mpl&#305;c&#305;t', output)
284284

285+
def test_strip_trailing_newlines_before_diff(self):
286+
# characterization test for the current buggy behavior
287+
# see: gh-71896
288+
html_diff = difflib.HtmlDiff()
289+
from_lines = [
290+
"Line 1: no newline after",
291+
"Line 2: one newline after\n",
292+
"Line 3: several newlines after\n\n\n\n\n",
293+
]
294+
to_lines = [
295+
"Line 1: no newline after",
296+
"Line 2: one newline after", # actually no \n
297+
"Line 3: several newlines after", # actually no \n
298+
]
299+
output = html_diff.make_table(from_lines, to_lines)
300+
# we (currently) expect no line change, so all equal
301+
self.assertNotIn('class="diff_add"', output)
302+
self.assertNotIn('class="diff_chg"', output)
303+
self.assertNotIn('class="diff_sub"', output)
304+
self.assertEqual(output.count('>Line&nbsp;1:&nbsp;no&nbsp;newline&nbsp;after<'), 2)
305+
self.assertEqual(output.count('>Line&nbsp;2:&nbsp;one&nbsp;newline&nbsp;after<'), 2)
306+
self.assertEqual(output.count('>Line&nbsp;3:&nbsp;several&nbsp;newlines&nbsp;after<'), 2)
285307

286308
def test_one_insert(self):
287309
m = difflib.Differ().compare('b' * 2, 'a' + 'b' * 2)

0 commit comments

Comments
 (0)