[Python-checkins] cpython (merge 3.2 -> default): Issue #11747: Fix range formatting in context and unified diffs.

raymond.hettinger python-checkins at python.org
Mon Apr 11 22:11:12 CEST 2011


http://hg.python.org/cpython/rev/1e5e3bb3e1f1
changeset:   69251:1e5e3bb3e1f1
parent:      69249:c9e9142d82d6
parent:      69250:a2ee967de44f
user:        Raymond Hettinger <python at rcn.com>
date:        Mon Apr 11 12:42:59 2011 -0700
summary:
  Issue #11747: Fix range formatting in context and unified diffs.

files:
  Lib/difflib.py           |  34 ++++++++++++++++++---------
  Lib/test/test_difflib.py |  16 +++++++++++++
  Misc/NEWS                |   3 ++
  3 files changed, 42 insertions(+), 11 deletions(-)


diff --git a/Lib/difflib.py b/Lib/difflib.py
--- a/Lib/difflib.py
+++ b/Lib/difflib.py
@@ -1144,6 +1144,17 @@
     return ch in ws
 
 
+def _format_range(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 length == 1:
+        return '{}'.format(beginning)
+    if not length:
+        beginning -= 1        # empty ranges begin at line just before the range
+    return '{},{}'.format(beginning, length)
+
 def unified_diff(a, b, fromfile='', tofile='', fromfiledate='',
                  tofiledate='', n=3, lineterm='\n'):
     r"""
@@ -1193,9 +1204,12 @@
             todate = '\t{}'.format(tofiledate) if tofiledate else ''
             yield '--- {}{}{}'.format(fromfile, fromdate, lineterm)
             yield '+++ {}{}{}'.format(tofile, todate, lineterm)
+
         first, last = group[0], group[-1]
-        i1, i2, j1, j2 = first[1], last[2], first[3], last[4]
-        yield '@@ -{},{} +{},{} @@{}'.format(i1+1, i2-i1, j1+1, j2-j1, lineterm)
+        file1_range = _format_range(first[1], last[2])
+        file2_range = _format_range(first[3], last[4])
+        yield '@@ -{} +{} @@{}'.format(file1_range, file2_range, lineterm)
+
         for tag, i1, i2, j1, j2 in group:
             if tag == 'equal':
                 for line in a[i1:i2]:
@@ -1264,22 +1278,20 @@
             yield '--- {}{}{}'.format(tofile, todate, lineterm)
 
         first, last = group[0], group[-1]
-        yield '***************{}'.format(lineterm)
+        yield '***************' + lineterm
 
-        if last[2] - first[1] > 1:
-            yield '*** {},{} ****{}'.format(first[1]+1, last[2], lineterm)
-        else:
-            yield '*** {} ****{}'.format(last[2], lineterm)
+        file1_range = _format_range(first[1], last[2])
+        yield '*** {} ****{}'.format(file1_range, lineterm)
+
         if any(tag in {'replace', 'delete'} for tag, _, _, _, _ in group):
             for tag, i1, i2, _, _ in group:
                 if tag != 'insert':
                     for line in a[i1:i2]:
                         yield prefix[tag] + line
 
-        if last[4] - first[3] > 1:
-            yield '--- {},{} ----{}'.format(first[3]+1, last[4], lineterm)
-        else:
-            yield '--- {} ----{}'.format(last[4], lineterm)
+        file2_range = _format_range(first[3], last[4])
+        yield '--- {} ----{}'.format(file2_range, lineterm)
+
         if any(tag in {'replace', 'insert'} for tag, _, _, _, _ in group):
             for tag, _, _, j1, j2 in group:
                 if tag != 'delete':
diff --git a/Lib/test/test_difflib.py b/Lib/test/test_difflib.py
--- a/Lib/test/test_difflib.py
+++ b/Lib/test/test_difflib.py
@@ -236,6 +236,22 @@
         cd = difflib.context_diff(*args, lineterm='')
         self.assertEqual(list(cd)[0:2], ["*** Original", "--- Current"])
 
+    def test_range_format(self):
+        # Per the diff spec at http://www.unix.org/single_unix_specification/
+        spec = '''\
+           Each <range> field shall be of the form:
+             %1d", <beginning line number>  if the range contains exactly one line,
+           and:
+            "%1d,%1d", <beginning line number>, <number of lines> otherwise.
+           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
+        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_main():
     difflib.HtmlDiff._default_prefix = 0
diff --git a/Misc/NEWS b/Misc/NEWS
--- a/Misc/NEWS
+++ b/Misc/NEWS
@@ -109,6 +109,9 @@
 
 - Issue #11814: Fix likely typo in multiprocessing.Pool._terminate().
 
+- Issue #11747: Fix range formatting in difflib.context_diff() and
+  difflib.unified_diff().
+
 - Issue #8428: Fix a race condition in multiprocessing.Pool when terminating
   worker processes: new processes would be spawned while the pool is being
   shut down.  Patch by Charles-François Natali.

-- 
Repository URL: http://hg.python.org/cpython


More information about the Python-checkins mailing list