JSON Merge Patch
This library provides functions to merge JSON documents in accordance with RFC 7386, the JSON Merge Patch standard. It offers a simpler alternative to JSON Patch for updating JSON resources, especially for object-based modifications. The current version is 0.3.0, with a focus on implementing the standard without external dependencies beyond the standard library.
Warnings
- gotcha JSON Merge Patch (RFC 7386) does not support granular modification of array elements. To change an array, you must provide the complete new array in the patch, replacing the entire original array. Individual elements cannot be added, removed, or modified directly within the array without sending the whole new array.
- gotcha Setting a key's value to `null` in the patch document signifies deletion of that key from the target document. It is not possible to use a JSON Merge Patch to *set* a key's value *to* `null` (unless the key did not exist, in which case it would be added and then immediately deleted).
- gotcha The `json-merge-patch` library operates on Python dictionary objects. It does not handle JSON string loading (`json.loads`) or dumping (`json.dumps`); this responsibility lies with the user.
- breaking Version 0.3.0 and later require Python 3.9 or higher. Earlier versions (e.g., 0.2.0 from 2017) supported older Python 3 versions (and potentially Python 2.7).
- gotcha If preserving key order is critical for merge operations (e.g., when using the `position` argument), inputs to the `merge` function must be `collections.OrderedDict` instances. Passing standard dictionaries will not guarantee order and may result in an error if order-dependent arguments are used.
Install
-
pip install json-merge-patch
Imports
- json_merge_patch
import json_merge_patch
- merge
import json_merge_patch json_merge_patch.merge(document, patch)
- create_patch
import json_merge_patch json_merge_patch.create_patch(original, target)
Quickstart
import json
import json_merge_patch
document = {"a": 1, "b": 2, "c": {"d": 4}}
patch = {"a": 2, "c": {"e": 5}, "f": None}
# Applying a merge patch
# 'f': None in patch implies deletion of 'f' if it existed, otherwise ignored
# 'c': {'e': 5} replaces the entire 'c' object
result = json_merge_patch.merge(document, patch)
print(f"Merged result: {json.dumps(result, indent=2)}")
# Expected output: {'a': 2, 'b': 2, 'c': {'e': 5}}
original = {"name": "Alice", "details": {"age": 30, "city": "NY"}, "tags": ["A", "B"]}
target = {"name": "Bob", "details": {"age": 31}, "email": "bob@example.com", "tags": ["C"]}
# Creating a merge patch
# 'name': 'Bob' replaces 'Alice'
# 'details': {'age': 31} replaces the entire 'details' object (city is removed)
# 'email': 'bob@example.com' is added
# 'tags': ['C'] replaces the entire 'tags' array
patch_doc = json_merge_patch.create_patch(original, target)
print(f"Generated patch: {json.dumps(patch_doc, indent=2)}")
# Expected output: {'name': 'Bob', 'details': {'age': 31}, 'email': 'bob@example.com', 'tags': ['C']}