Index: Lib/difflib.py =================================================================== --- Lib/difflib.py (revision 88766) +++ Lib/difflib.py (working copy) @@ -1198,14 +1198,26 @@ for tag, i1, i2, j1, j2 in group: if tag == 'equal': for line in a[i1:i2]: - yield ' ' + line + if not line.endswith(lineterm): + yield ' ' + line + lineterm + yield r'\ No newline at end of file' + lineterm + else: + yield ' ' + line continue if tag == 'replace' or tag == 'delete': for line in a[i1:i2]: - yield '-' + line + if not line.endswith(lineterm): + yield '-' + line + lineterm + yield r'\ No newline at end of file' + lineterm + else: + yield '-' + line if tag == 'replace' or tag == 'insert': for line in b[j1:j2]: - yield '+' + line + if not line.endswith(lineterm): + yield '+' + line + lineterm + yield r'\ No newline at end of file' + lineterm + else: + yield '+' + line # See http://www.unix.org/single_unix_specification/ def context_diff(a, b, fromfile='', tofile='', @@ -1272,7 +1284,11 @@ for tag, i1, i2, _, _ in group: if tag != 'insert': for line in a[i1:i2]: - yield prefixmap[tag] + line + if not line.endswith(lineterm): + yield prefixmap[tag] + line + lineterm + yield r'\ No newline at end of file' + lineterm + else: + yield prefixmap[tag] + line if group[-1][4] - group[0][3] >= 2: yield '--- %d,%d ----%s' % (group[0][3]+1, group[-1][4], lineterm) @@ -1283,7 +1299,11 @@ for tag, _, _, j1, j2 in group: if tag != 'delete': for line in b[j1:j2]: - yield prefixmap[tag] + line + if not line.endswith(lineterm): + yield prefixmap[tag] + line + lineterm + yield r'\ No newline at end of file' + lineterm + else: + yield prefixmap[tag] + line def ndiff(a, b, linejunk=None, charjunk=IS_CHARACTER_JUNK): r""" Index: Lib/test/test_difflib.py =================================================================== --- Lib/test/test_difflib.py (revision 88766) +++ Lib/test/test_difflib.py (working copy) @@ -237,12 +237,55 @@ self.assertEqual(list(cd)[0:2], ["*** Original", "--- Current"]) +class TestNoNewLineAtEnd(unittest.TestCase): + """ Test no newline at end of file, from issue2142 """ + def test_unified_diff(self): + lines = list(difflib.unified_diff( + "one\ntwo\nthree".splitlines(1), + "one\ntwo\ntrois".splitlines(1), + "Before", "After")) + expected = [ + '--- Before\n', + '+++ After\n', + '@@ -1,3 +1,3 @@\n', + ' one\n', + ' two\n', + '-three\n', + '\\ No newline at end of file\n', + '+trois\n', + '\\ No newline at end of file\n' + ] + self.assertEqual(lines, expected) + + def test_context_diff(self): + lines = list(difflib.context_diff( + "one\ntwo\nthree".splitlines(1), + "one\ntwo\ntrois".splitlines(1), + "Before", "After")) + expected = [ + '*** Before\n', + '--- After\n', + '***************\n', + '*** 1,3 ****\n', + ' one\n', + ' two\n', + '! three\n', + '\\ No newline at end of file\n', + '--- 1,3 ----\n', + ' one\n', + ' two\n', + '! trois\n', + '\\ No newline at end of file\n', + ] + self.assertEqual(lines, expected) + + def test_main(): difflib.HtmlDiff._default_prefix = 0 Doctests = doctest.DocTestSuite(difflib) run_unittest( TestWithAscii, TestAutojunk, TestSFpatches, TestSFbugs, - TestOutputFormat, Doctests) + TestOutputFormat, TestNoNewLineAtEnd, Doctests) if __name__ == '__main__': test_main()