Skip to content

Instantly share code, notes, and snippets.

@soxofaan
Last active June 22, 2023 03:52
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save soxofaan/e97112c4789ee74e1bf61532c998c0eb to your computer and use it in GitHub Desktop.
Save soxofaan/e97112c4789ee74e1bf61532c998c0eb to your computer and use it in GitHub Desktop.
Python implementation of side-by-side diff
# Code licensed MIT 2023 Stefaan Lippens
import difflib
import itertools
from typing import List, Tuple, Iterator
class Sdiffer:
def __init__(self, max_width:int = 80):
# Two columns with a gutter
self._col_width = (max_width - 3) // 2
assert self._col_width > 0
def _fit(self, s: str) -> str:
s = s.rstrip()[:self._col_width]
return f"{s: <{self._col_width}}"
def sdiff(self, a: List[str], b: List[str]) -> Iterator[str]:
diff_lines = difflib.Differ().compare(a, b)
diff_table: List[Tuple[str, List[str], List[str]]] = []
for diff_type, line_group in itertools.groupby(diff_lines, key=lambda ln: ln[:1]):
lines = [ln[2:] for ln in line_group]
if diff_type == " ":
diff_table.append((" ", lines, lines))
else:
if not diff_table or diff_table[-1][0] != "|":
diff_table.append(("|", [], []))
if diff_type == "-":
# Lines only in `a`
diff_table[-1][1].extend(lines)
elif diff_type == "+":
# Lines only in `b`
diff_table[-1][2].extend(lines)
for diff_type, cell_a, cell_b in diff_table:
for left, right in itertools.zip_longest(cell_a, cell_b, fillvalue=""):
yield f"{self._fit(left)} {diff_type} {self._fit(right)}"
def print_sdiff(self, a: List[str], b: List[str]) -> Iterator[str]:
print("\n".join(self.sdiff(a, b)))
@soxofaan
Copy link
Author

soxofaan commented Apr 6, 2023

usage example:

dump_a = json.dumps(..., indent=2).splitlines(keepends=True)
dump_b = json.dumps(..., indent=2).splitlines(keepends=True)

Sdiffer().print_sdiff(dump_a, dump_b)
 {                                          {                                      
   "exp": 1680773344,                         "exp": 1680773344,                   
   "iat": 1680773044,                         "iat": 1680773044,                   
   "jti": "40410c7c-8828-4755-a5b8-fa09b |    "jti": "564abdb3-6e34-4a7c-b00e-77d1e
   "iss": "http://localhost:8642/realms/      "iss": "http://localhost:8642/realms/
   "aud": "account",                          "aud": "account",                    
   "sub": "7e7feab3-afd4-4186-a00c-c546a |    "sub": "d2aa0547-daaa-478b-9cb9-1ba2b
   "typ": "Bearer",                           "typ": "Bearer",                     
   "azp": "public-client-VQ5r6dli",      |    "azp": "service-client-L8FFS94R",    
   "session_state": "0c09bcad-45de-47ff- |    "preferred_username": "service-accoun
   "preferred_username": "user-c39y4yag" |                                         
   "email_verified": false,                   "email_verified": false,             
   "acr": "1",                                "acr": "1",                          
   "realm_access": {                          "realm_access": {                    
     "roles": [                                 "roles": [                         
       "default-roles-i168realm",                 "default-roles-i168realm",       
...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment