Guide
JSON Patch in Python
How to apply and generate RFC 6902 JSON Patches in Python with the jsonpatch library - with working code you can copy straight into a project.
Installing the library
The de-facto standard library is python-jsonpatch. It implements every RFC 6902 operation - add, remove, replace, move, copy and test:
pip install jsonpatch
Applying a JSON Patch
jsonpatch.apply_patch takes a document and a patch (both plain Python dicts and lists) and returns the patched document:
import jsonpatch
doc = {
"name": "demo",
"version": 1,
"tags": ["a", "b"],
}
patch = [
{"op": "replace", "path": "/version", "value": 2},
{"op": "add", "path": "/tags/-", "value": "c"},
{"op": "remove", "path": "/name"},
]
result = jsonpatch.apply_patch(doc, patch)
print(result)
# {'version': 2, 'tags': ['a', 'b', 'c']}Note the special path /tags/-: the dash appends to the end of an array. Paths follow JSON Pointer (RFC 6901), so ~ and / inside keys are escaped as ~0 and ~1.
Generating a patch from two documents
jsonpatch.make_patch diffs two documents and returns the operations that turn the first into the second - the same thing the JSON Patch Generator does in your browser:
import jsonpatch
before = {"a": 1, "b": {"c": 2}}
after = {"a": 1, "b": {"c": 3, "d": 4}}
patch = jsonpatch.make_patch(before, after)
print(list(patch))
# [{'op': 'add', 'path': '/b/d', 'value': 4},
# {'op': 'replace', 'path': '/b/c', 'value': 3}]Validating with the test operation
The test operation stops evaluation if a value does not match. Use it as a precondition guard so patches only apply to the state you expect:
patch = [
{"op": "test", "path": "/version", "value": 1},
{"op": "replace", "path": "/version", "value": 2},
]
jsonpatch.apply_patch(doc, patch) # raises JsonPatchConflict if /version is not 1Handling errors
Two exception types cover most failures. Catch them explicitly and log the failing operation - evaluation stops at a failed operation; rollback of earlier mutations depends on the implementation:
import jsonpatch
try:
result = jsonpatch.apply_patch(doc, patch)
except jsonpatch.JsonPatchConflict as e:
# test operation failed, or replace/remove on a missing value
print("conflict:", e)
except jsonpatch.JsonPointerException as e:
# path does not exist (wrong key, index out of range)
print("bad pointer:", e)Common pitfalls
- Evaluation stops on error. RFC 6902 does not guarantee rollback of earlier operations; catch failures and verify library behavior before assuming transaction-like semantics.
- Numbers are not strings. A test on
{"value": 1}fails against{"value": "1"}. Type mismatches are the most common source of JsonPatchConflict. - Array indices shift. Removing index 0 makes index 1 become index 0. Order remove operations from the highest index down, or use value-based test guards.
- apply_patch does not mutate by default. It returns a new document; assign the result.
Try it in the browser first
Before writing Python, prototype the patch visually. Paste your two documents into the JSON Patch Generator to get the exact RFC 6902 operations, or use the JSON Diff tool to see every changed line. Then drop the generated patch into apply_patch.
New to the format? Read the JSON Patch documentation or browse real-world examples.