From 8dc84d19b4293a8bd20b47133cac3f544c2e060b Mon Sep 17 00:00:00 2001 From: Amin Jamal Date: Tue, 7 Oct 2025 18:21:28 +0200 Subject: [PATCH] chore: improve naming and enhance comments --- src/diff/delta.py | 2 +- src/diff/diff.py | 45 +++++++++++++++++++++++++-------------------- src/diff/patch.py | 3 ++- tests/test_diff.py | 19 ++++++++++++++----- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/src/diff/delta.py b/src/diff/delta.py index e2402bd..32cf079 100644 --- a/src/diff/delta.py +++ b/src/diff/delta.py @@ -4,7 +4,7 @@ @dataclasses.dataclass class Delta: - op: typing.Literal["deleted", "modified", "added"] + operation: typing.Literal["deleted", "modified", "added"] path: str new_value: typing.Any | None old_value: typing.Any | None diff --git a/src/diff/diff.py b/src/diff/diff.py index 7fda207..81def81 100644 --- a/src/diff/diff.py +++ b/src/diff/diff.py @@ -1,41 +1,46 @@ +import typing + from diff import json_path from diff.delta import Delta -def diff(new: dict, old: dict) -> list[Delta]: +def diff(new: dict[str, typing.Any], old: dict[str, typing.Any]) -> list[Delta]: new_path_map = json_path.path_value_map( new, include_root=True, leaves_only=True, include_containers=False ) old_path_map = json_path.path_value_map( old, include_root=True, leaves_only=False, include_containers=False ) - ops: list[Delta] = [] + operations: list[Delta] = [] - # deleted deleted = old_path_map.keys() - new_path_map.keys() - for item in deleted: - ops.append( # noqa: PERF401 - Delta(path=item, op="deleted", old_value=old_path_map[item], new_value=None) + for key in deleted: + operations.append( # noqa: PERF401 + Delta( + path=key, + operation="deleted", + old_value=old_path_map[key], + new_value=None, + ) ) - # added added = new_path_map.keys() - old_path_map.keys() - for item in added: - ops.append( # noqa: PERF401 - Delta(path=item, op="added", old_value=None, new_value=new_path_map[item]) + for key in added: + operations.append( # noqa: PERF401 + Delta( + path=key, operation="added", old_value=None, new_value=new_path_map[key] + ) ) - # modified shared_keys = new_path_map.keys() & old_path_map.keys() - for item in shared_keys: - if old_path_map[item] != new_path_map[item]: - ops.append( # noqa: PERF401 + for key in shared_keys: + if old_path_map[key] != new_path_map[key]: + operations.append( # noqa: PERF401 Delta( - path=item, - op="modified", - old_value=old_path_map[item], - new_value=new_path_map[item], + path=key, + operation="modified", + old_value=old_path_map[key], + new_value=new_path_map[key], ) ) - # exlude root diff - return ops + return operations diff --git a/src/diff/patch.py b/src/diff/patch.py index bc31a00..64e452e 100644 --- a/src/diff/patch.py +++ b/src/diff/patch.py @@ -356,9 +356,10 @@ def pop_by_json_path( def patch(base: dict[str, typing.Any], deltas: list[Delta]) -> dict[str, typing.Any]: output = copy.deepcopy(base) for op in deltas: - if op.op == "deleted": + if op.operation == "deleted": pop_by_json_path(output, op.path, prune_empty=True, remove_from_list=True) continue + # we use set for both modify and add actions set_by_json_path( output, op.path, diff --git a/tests/test_diff.py b/tests/test_diff.py index 3020d6a..d3a5512 100644 --- a/tests/test_diff.py +++ b/tests/test_diff.py @@ -37,7 +37,14 @@ def _mk_expected_operation(**kwargs): ( {"name": "Amin"}, {"name": "Amin2"}, - [Delta(op="modified", path="$.name", old_value="Amin", new_value="Amin2")], + [ + Delta( + operation="modified", + path="$.name", + old_value="Amin", + new_value="Amin2", + ) + ], ) ], ) @@ -76,7 +83,9 @@ def test_added_key_expected_op_and_patch_roundtrip(): # At least one 'added' operation to $.age (value semantics may differ: new_value vs value) assert any( - o.op == "added" and o.path == "$.age" and _op_get(o, "new_value", "value") == 30 + o.operation == "added" + and o.path == "$.age" + and _op_get(o, "new_value", "value") == 30 for o in ops ) @@ -91,7 +100,7 @@ def test_deleted_key_expected_op_and_patch_roundtrip(): # At least one 'deleted' operation from $.name (old_value/value semantics) assert any( - o.op == "deleted" + o.operation == "deleted" and o.path == "$.name" and _op_get(o, "old_value", "value") == "Amin" for o in ops @@ -151,7 +160,7 @@ def test_none_handling_as_value_vs_absence(): old2 = {"y": None} new2: dict[str, typing.Any] = {} ops2 = diff(new=new2, old=old2) - assert any(o.op == "deleted" and o.path == "$.y" for o in ops2) + assert any(o.operation == "deleted" and o.path == "$.y" for o in ops2) assert patch(base=old2, deltas=ops2) == new2 @@ -176,7 +185,7 @@ def test_multiple_changes_in_one_structure(): "$.user.role": "added", "$.settings.theme": "modified", } - seen = {o.path: o.op for o in ops if o.path in expect_paths} + seen = {o.path: o.operation for o in ops if o.path in expect_paths} for p, expected_op in expect_paths.items(): assert seen.get(p) == expected_op, ( f"Expected {expected_op} at {p}, got {seen.get(p)}"