From f03d3028e0e9ce1a9d4d108d8ecf210a917cd5f8 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 12 Apr 2011 15:19:33 -0700 Subject: Issue 11747: Fix output format for context diffs. --- Lib/difflib.py | 30 +++++++++++++++++++++++++----- Lib/test/test_difflib.py | 29 +++++++++++++++++++++++++++-- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/Lib/difflib.py b/Lib/difflib.py index c5005a1..e6cc6ee 100644 --- a/Lib/difflib.py +++ b/Lib/difflib.py @@ -1144,7 +1144,11 @@ def IS_CHARACTER_JUNK(ch, ws=" \t"): return ch in ws -def _format_range(start, stop): +######################################################################## +### Unified Diff +######################################################################## + +def _format_range_unified(start, stop): 'Convert range to the "ed" format' # Per the diff spec at http://www.unix.org/single_unix_specification/ beginning = start + 1 # lines start numbering with one @@ -1206,8 +1210,8 @@ def unified_diff(a, b, fromfile='', tofile='', fromfiledate='', yield '+++ {}{}{}'.format(tofile, todate, lineterm) first, last = group[0], group[-1] - file1_range = _format_range(first[1], last[2]) - file2_range = _format_range(first[3], last[4]) + file1_range = _format_range_unified(first[1], last[2]) + file2_range = _format_range_unified(first[3], last[4]) yield '@@ -{} +{} @@{}'.format(file1_range, file2_range, lineterm) for tag, i1, i2, j1, j2 in group: @@ -1222,6 +1226,22 @@ def unified_diff(a, b, fromfile='', tofile='', fromfiledate='', for line in b[j1:j2]: yield '+' + line + +######################################################################## +### Context Diff +######################################################################## + +def _format_range_context(start, stop): + 'Convert range to the "ed" format' + # Per the diff spec at http://www.unix.org/single_unix_specification/ + beginning = start + 1 # lines start numbering with one + length = stop - start + if not length: + beginning -= 1 # empty ranges begin at line just before the range + if length <= 1: + return '{}'.format(beginning) + return '{},{}'.format(beginning, beginning + length - 1) + # See http://www.unix.org/single_unix_specification/ def context_diff(a, b, fromfile='', tofile='', fromfiledate='', tofiledate='', n=3, lineterm='\n'): @@ -1280,7 +1300,7 @@ def context_diff(a, b, fromfile='', tofile='', first, last = group[0], group[-1] yield '***************' + lineterm - file1_range = _format_range(first[1], last[2]) + file1_range = _format_range_context(first[1], last[2]) yield '*** {} ****{}'.format(file1_range, lineterm) if any(tag in {'replace', 'delete'} for tag, _, _, _, _ in group): @@ -1289,7 +1309,7 @@ def context_diff(a, b, fromfile='', tofile='', for line in a[i1:i2]: yield prefix[tag] + line - file2_range = _format_range(first[3], last[4]) + file2_range = _format_range_context(first[3], last[4]) yield '--- {} ----{}'.format(file2_range, lineterm) if any(tag in {'replace', 'insert'} for tag, _, _, _, _ in group): diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py index b08be53..325449a 100644 --- a/Lib/test/test_difflib.py +++ b/Lib/test/test_difflib.py @@ -236,7 +236,7 @@ class TestOutputFormat(unittest.TestCase): cd = difflib.context_diff(*args, lineterm='') self.assertEqual(list(cd)[0:2], ["*** Original", "--- Current"]) - def test_range_format(self): + def test_range_format_unified(self): # Per the diff spec at http://www.unix.org/single_unix_specification/ spec = '''\ Each field shall be of the form: @@ -246,13 +246,38 @@ class TestOutputFormat(unittest.TestCase): If a range is empty, its beginning line number shall be the number of the line just before the range, or 0 if the empty range starts the file. ''' - fmt = difflib._format_range + fmt = difflib._format_range_unified self.assertEqual(fmt(3,3), '3,0') self.assertEqual(fmt(3,4), '4') self.assertEqual(fmt(3,5), '4,2') self.assertEqual(fmt(3,6), '4,3') self.assertEqual(fmt(0,0), '0,0') + def test_range_format_context(self): + # Per the diff spec at http://www.unix.org/single_unix_specification/ + spec = '''\ + The range of lines in file1 shall be written in the following format + if the range contains two or more lines: + "*** %d,%d ****\n", , + and the following format otherwise: + "*** %d ****\n", + The ending line number of an empty range shall be the number of the preceding line, + or 0 if the range is at the start of the file. + + Next, the range of lines in file2 shall be written in the following format + if the range contains two or more lines: + "--- %d,%d ----\n", , + and the following format otherwise: + "--- %d ----\n", + ''' + fmt = difflib._format_range_context + self.assertEqual(fmt(3,3), '3') + self.assertEqual(fmt(3,4), '4') + self.assertEqual(fmt(3,5), '4,5') + self.assertEqual(fmt(3,6), '4,6') + self.assertEqual(fmt(0,0), '0') + + def test_main(): difflib.HtmlDiff._default_prefix = 0 Doctests = doctest.DocTestSuite(difflib) -- cgit v0.12