Skip to content

Instantly share code, notes, and snippets.

@cedricvidal
Last active May 22, 2025 17:49
Show Gist options
  • Save cedricvidal/c4211d0552d2673929fb6555b45f6fb6 to your computer and use it in GitHub Desktop.
Save cedricvidal/c4211d0552d2673929fb6555b45f6fb6 to your computer and use it in GitHub Desktop.
Python CLI to create a JSON diff using the patchdiff package
#!/usr/bin/env python
import rich_click as click
import json
from pathlib import Path
from dotenv import load_dotenv
from sys import stdout
from patchdiff import diff as patch_diff
load_dotenv()
def load_jsonl(jsonl_file):
return [json.loads(line) for line in jsonl_file]
def key(model):
return f"{model['model']['name']}-{model['location']}"
def index(models):
return dict(map(lambda model: (key(model), model), models))
def make_patch(previous, next):
ops, _ = patch_diff(previous, next)
# Convert Path objects to strings so that they can be JSON dumped
for op in ops:
op["path"] = str(op["path"])
return ops if len(ops) > 0 else None
def diff(previous, next):
a = set(previous.keys())
b = set(next.keys())
common = a & b
removed = a - b
added = b - a
common_models = [(key, make_patch(previous[key], next[key]), previous[key]) for key in common]
return {
'updates': dict([(key, {"previous": prev, "changes": diff}) for (key, diff, prev) in common_models if diff]),
'removed': {key: previous[key] for key in removed},
'added': {key: next[key] for key in added}
}
@click.command()
@click.option('--previous-file', '-p', help='Previous file', type=click.File('r'))
@click.option('--next-file', '-n', help='Next file', type=click.File('r'))
@click.option('--diff-file', '-d', help='Diff file', type=click.File('w'), default=stdout)
def report(previous_file, next_file, diff_file):
click.echo(f"Creating diff report between {previous_file.name} and {next_file.name}")
previous = index(load_jsonl(previous_file))
next = index(load_jsonl(next_file))
d = diff(previous, next)
json.dump(d, diff_file, indent=2)
if __name__ == '__main__':
report()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment