def _GetPlistDiff(self):
    new_plist = self.plist.GetXml().splitlines()
    if not self.original_plist:
      return [{'type': 'diff_add', 'line': line} for line in new_plist]

    original_plist = self.original_plist.splitlines()
    new_plist = self.plist.GetXml().splitlines()
    diff = difflib.Differ().compare(original_plist, new_plist)

    lines = []
    if diff:
      re_add = re.compile("^\s*\+")
      re_sub = re.compile("^\s*\-")
      for line in diff:
        if re_add.match(line):
          linetype = 'diff_add'
        elif re_sub.match(line):
          linetype = 'diff_sub'
        else:
          linetype = 'diff_none'
        lines.append({'type': linetype, 'line': line})

    omitting = False
    for i, line in enumerate(lines):
      if i > 1 and i < len(lines)-2:
        # A line is "omittable" if it's at least 2 lines away from the start,
        # end or an edited line.
        is_omit = all([l['type'] == 'diff_none' for l in lines[i-2:i+3]])
        if is_omit and not omitting:
          line['start_omitting'] = True
          omitting = True
      if omitting:
        not_omit = any([l['type'] != 'diff_none' for l in lines[i:i+3]])
        if i > len(lines)-3 or not_omit:
          line['end_omitting'] = True
          omitting = False

    return lines
Test reporting of extra columns, verbosity 3:
dataset/ETHPy150Open google/simian/src/simian/mac/models/base.py/AdminPackageLog._GetPlistDiff--crossover with--dataset/ETHPy150Open GeoscienceAustralia/agdc/tests/test_dbcompare.py/TestReporter.test_column_only_in_v3