diff.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162
  1. import difflib
  2. from pytest_clarity.output import Colour, deleted_text, inserted_text, non_formatted
  3. def build_split_diff(lhs_repr, rhs_repr):
  4. lhs_out, rhs_out = "", ""
  5. matcher = difflib.SequenceMatcher(None, lhs_repr, rhs_repr)
  6. for op, i1, i2, j1, j2 in matcher.get_opcodes():
  7. lhs_substring_lines = lhs_repr[i1:i2].splitlines()
  8. rhs_substring_lines = rhs_repr[j1:j2].splitlines()
  9. for i, lhs_substring in enumerate(lhs_substring_lines):
  10. if op == "replace":
  11. lhs_out += inserted_text(lhs_substring)
  12. elif op == "delete":
  13. lhs_out += inserted_text(lhs_substring)
  14. elif op == "insert":
  15. lhs_out += Colour.stop + lhs_substring
  16. elif op == "equal":
  17. lhs_out += Colour.stop + lhs_substring
  18. if i != len(lhs_substring_lines) - 1:
  19. lhs_out += "\n"
  20. for j, rhs_substring in enumerate(rhs_substring_lines):
  21. if op == "replace":
  22. rhs_out += deleted_text(rhs_substring)
  23. elif op == "insert":
  24. rhs_out += deleted_text(rhs_substring)
  25. elif op == "equal":
  26. rhs_out += Colour.stop + rhs_substring
  27. if j != len(rhs_substring_lines) - 1:
  28. rhs_out += "\n"
  29. return lhs_out.splitlines(), rhs_out.splitlines()
  30. def build_unified_diff(lhs_repr, rhs_repr):
  31. differ = difflib.Differ()
  32. lines_lhs, lines_rhs = lhs_repr.splitlines(), rhs_repr.splitlines()
  33. diff = differ.compare(lines_lhs, lines_rhs)
  34. output = []
  35. for line in diff:
  36. # Differ instructs us how to transform left into right, but we want
  37. # our colours to indicate how to transform right into left
  38. if line.startswith("- "):
  39. output.append(inserted_text(" L " + line[2:]))
  40. elif line.startswith("+ "):
  41. output.append(deleted_text(" R " + line[2:]))
  42. elif line.startswith("? "):
  43. # We can use this to find the index of change in the
  44. # line above if required in the future
  45. pass
  46. else:
  47. output.append(non_formatted(line))
  48. return output