ProvenPin Install

RFC 6902 JSON patches with jsonpatch + RFC 6901 pointers with jsonpointer: working versions (tested 2026-10-17)

Create, apply and hand-roll the inverse of RFC 6902 JSON patches with jsonpatch, and resolve or set RFC 6901 pointers (including ~0 and ~1 escapes) with jsonpointer.

passed6 passed · 0 failed2026-10-17 00:54 UTC
Status
passed
Last passed
2026-10-17 00:54 UTC
Tests
6 / 6
Language
Python
Runtime
Python 3.13.16
pinned versions3
jsonpatch@1.35.0jsonpointer@3.2.1pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt
.venv/bin/python -m pytest -q
test environment
Python 3.13.16
linux 6.17.0-1022-azure
x64
runner: github-actions 38988196687

The code

Exactly the files that passed. Your agent can pull them with get_recipe("jsonpatch-jsonpointer-apply") (install), or see them on GitHub.

requirements.txt
jsonpatch==1.35.0
jsonpointer==3.2.1
pytest==9.1.1
patching.py
"""Create, apply and invert RFC 6902 patches over RFC 6901 pointers."""
import copy

import jsonpatch
import jsonpointer


def make_patch(before, after):
    """Create the patch that turns before into after."""
    return jsonpatch.make_patch(before, after)


def apply(document, patch, in_place=False):
    """Apply a patch; jsonpatch returns a copy unless in_place is set."""
    return jsonpatch.JsonPatch(patch).apply(document, in_place=in_place)


def invert(document, patch):
    """Build the inverse patch; RFC 6902 does not define one.

    Replay the patch over a scratch copy to capture the values it
    overwrites, then emit inverse operations in reverse order.
    """
    scratch = copy.deepcopy(document)
    inverse = []
    for op in patch:
        kind, path = op["op"], op["path"]
        if kind == "add":
            inverse.append({"op": "remove", "path": path})
        elif kind in ("remove", "replace"):
            previous = jsonpointer.resolve_pointer(scratch, path)
            inverse.append(
                {
                    "op": "add" if kind == "remove" else "replace",
                    "path": path,
                    "value": previous,
                }
            )
        else:
            raise jsonpatch.JsonPatchException(f"cannot invert {kind!r}")
        scratch = jsonpatch.apply_patch(scratch, [op])
    inverse.reverse()
    return inverse


def read(document, pointer):
    """Resolve an RFC 6901 pointer, decoding ~1 (slash) and ~0 (tilde)."""
    return jsonpointer.resolve_pointer(document, pointer)


def write(document, pointer, value, in_place=True):
    """Set a pointer target; '-' appends. jsonpointer 3.x defaults to in place."""
    return jsonpointer.set_pointer(document, pointer, value, inplace=in_place)
tests/test_patching.py
import jsonpatch
import pytest

from patching import apply, invert, make_patch, read, write


def test_make_patch_and_apply_return_copy():
    before = {"name": "old", "tags": ["a"]}
    after = {"name": "new", "tags": ["a", "b"]}
    patch = make_patch(before, after)
    assert apply(before, patch) == after
    assert before == {"name": "old", "tags": ["a"]}


def test_apply_in_place_mutates_original():
    document = {"name": "old"}
    patch = [{"op": "replace", "path": "/name", "value": "new"}]
    result = apply(document, patch, in_place=True)
    assert result is document
    assert document == {"name": "new"}


def test_invert_round_trips_and_keeps_removed_values():
    before = {"flag": True, "meta": {"tags": ["x", "y"], "note": "keep"}}
    patch = [
        {"op": "replace", "path": "/flag", "value": False},
        {"op": "add", "path": "/meta/tags/1", "value": "z"},
        {"op": "remove", "path": "/meta/note"},
    ]
    after = apply(before, patch)
    inverse = invert(before, patch)
    assert {"op": "add", "path": "/meta/note", "value": "keep"} in inverse
    assert apply(after, inverse) == before


def test_pointer_escapes_and_set_pointer_default_is_in_place():
    document = {"a/b": {"m~n": 1}, "xs": [1, 2]}
    assert read(document, "/a~1b/m~0n") == 1
    write(document, "/xs/-", 3)
    assert document["xs"] == [1, 2, 3]


def test_set_pointer_can_copy():
    document = {"xs": [1, 2]}
    updated = write(document, "/xs/-", 3, in_place=False)
    assert document == {"xs": [1, 2]}
    assert updated == {"xs": [1, 2, 3]}


def test_test_op_failure_and_missing_path_conflict():
    with pytest.raises(jsonpatch.JsonPatchTestFailed):
        apply({"count": 1}, [{"op": "test", "path": "/count", "value": 2}])
    with pytest.raises(jsonpatch.JsonPatchConflict):
        apply({}, [{"op": "replace", "path": "/missing", "value": 1}])
pytest.ini
[pytest]
pythonpath = .

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.