The JSON-delta API

This document is intended to describe the behaviour of the main entry points for every implementation of JSON-delta. For now, it effectively documents the top-level namespace of the Python implementation, as that is the most fully-developed implementation in the suite.

Core functions

json_delta.diff(left_struc, right_struc, minimal=True, verbose=True, key=None)

Compose a sequence of diff stanzas sufficient to convert the structure left_struc into the structure right_struc. (The goal is to add ‘necessary and’ to ‘sufficient’ above!).

Flags:

verbose: if this is set True (the default), a line of compression statistics will be printed to stderr.

minimal: if True, the function will try harder to find the diff that encodes as the shortest possible JSON string, at the expense of using more of both memory and processor time (as alternatives are computed and compared).

The parameter key is present because this function is mutually recursive with needle_diff() and keyset_diff(). If set to a list, it will be prefixed to every keypath in the output.

json_delta.patch(struc, diff, in_place=True)

Apply the sequence of diff stanzas diff to the structure struc.

By default, this function modifies struc in place; set in_place to False to return a patched copy of struc instead:

>>> will_change = [16]
>>> wont_change = [16]
>>> patch(will_change, [[[0]]])
[]
>>> will_change
[]
>>> patch(wont_change, [[[0]]], False)
[]
>>> wont_change
[16]
json_delta.udiff(left, right, patch=None, indent=0, entry=True)

Render the difference between the structures left and right as a string in a fashion inspired by diff -u.

Generating a udiff is strictly slower than generating a normal diff, since the udiff is computed on the basis of a normal diff between left and right. If such a diff has already been computed (e.g. by calling diff()), pass it as the patch parameter.

json_delta.upatch(struc, udiff, reverse=False)

Apply a patch of the form output by json_delta.udiff() to the structure struc.

load_and_*

For convenience when handling input that is already JSON-serialized, implementations should offer entry points named load_and_{FUNC}, which deserialize their input and then apply {FUNC} to it.

json_delta.load_and_diff(left=None, right=None, both=None, minimal=True, verbose=True)

Apply diff() to strings or files representing JSON-serialized structures.

Specify either left and right, or both, like so:

>>> (load_and_diff('{"foo":"bar"}', '{"foo":"baz"}', verbose=False)
...  == [[["foo"],"baz"]])
True
>>> (load_and_diff(both='[{"foo":"bar"},{"foo":"baz"}]', verbose=False)
...  == [[["foo"],"baz"]])
True

left, right and both may be either strings (instances of basestring in 2.7) or file-like objects.

minimal and verbose are passed through to diff(), which see.

A call to this function with string arguments is strictly equivalent to calling diff(json.loads(left), json.loads(right), minimal=minimal, verbose=verbose) or diff(*json.loads(both), minimal=minimal, verbose=verbose), as appropriate.

json_delta.load_and_patch(struc=None, stanzas=None, both=None, in_place=True)

Apply patch() to strings or files representing JSON-serialized structures.

Specify either struc and stanzas, or both, like so:

>>> (load_and_patch('{"foo":"bar"}', '[[["foo"],"baz"]]') ==
...  {"foo": "baz"})
True
>>> (load_and_patch(both='[{"foo":"bar"},[[["foo"],"baz"]]]') ==
...  {"foo": "baz"})
True

struc, stanzas and both may be either strings (instances of basestring in 2.7) or file-like objects.

in_place is passed through to patch(), which see.

A call to this function with string arguments is strictly equivalent to calling patch(json.loads(struc), json.loads(stanzas), in_place=in_place) or patch(*json.loads(both), in_place=in_place), as appropriate.

json_delta.load_and_udiff(left=None, right=None, both=None, stanzas=None, indent=0)

Apply udiff() to strings representing JSON-serialized structures.

Specify either left and right, or both, like so:

>>> udiff = """ {
...  "foo":
... -  "bar"
... +  "baz"
...  }"""
>>> test = load_and_udiff('{"foo":"bar"}', '{"foo":"baz"}')
>>> '\n'.join(test) == udiff
True
>>> test = load_and_udiff(both='[{"foo":"bar"},{"foo":"baz"}]')
>>> '\n'.join(test) == udiff
True

left, right and both may be either strings (instances of basestring in 2.7) or file-like objects.

stanzas and indent are passed through to udiff(), which see.

A call to this function with string arguments is strictly equivalent to calling udiff(json.loads(left), json.loads(right), stanzas=stanzas, indent=indent) or udiff(*json.loads(both), stanzas=stanzas, indent=indent), as appropriate.

json_delta.load_and_upatch(struc=None, json_udiff=None, both=None, reverse=False, in_place=True)

Apply upatch() to strings representing JSON-serialized structures.

Specify either struc and json_udiff, or both, like so:

>>> struc = '{"foo":"bar"}'
>>> json_udiff = r'" {\n  \"foo\":\n-  \"bar\"\n+  \"baz\"\n }"'
>>> both = r'[{"foo":"baz"}," '\
... r'{\n  \"foo\":\n-  \"bar\"\n+  \"baz\"\n }"]'
>>> load_and_upatch(struc, json_udiff) == {"foo": "baz"}
True
>>> load_and_upatch(both=both, reverse=True) == {"foo": "bar"}
True

struc, json_udiff and both may be either strings (instances of basestring in 2.7) or file-like objects. Note that json_udiff is so named because it must be a JSON-serialized representation of the udiff string, not the udiff string itself.

reverse is passed through to upatch(), which see.

A call to this function with string arguments is strictly equivalent to calling upatch(json.loads(struc), json.loads(json_udiff), reverse=reverse, in_place=in_place) or upatch(*json.loads(both), reverse=reverse, in_place=in_place), as appropriate.