Skip to main content

Recursive diff and patch for nested structures.

Project description

Nested-Diff.py

Recursive diff and patch for nested structures.

Tests Status Coverage Status Supported Python versions License

Main features

  • Machine-readable diff structure.
  • Human-friendly diff visualization, collapsible html diffs.
  • All operation tags are optional and may be disabled.
  • Extensibility.

See Live Demo!

Install

pip install nested_diff

For extra formats support (YAML, TOML) in cli tools, use

pip install nested_diff[cli]

Command line tools

$ cat a.json b.json
[0, [1],    3]
[0, [1, 2], 3]
$ nested_diff a.json b.json
  [1]
+   [1]
+     2
nested_diff a.json b.json --ofmt json > patch.json
nested_patch a.json patch.json

Library usage

>>> from nested_diff import diff, patch
>>>
>>> a = {'one': 1, 'two': 2, 'three': 3}
>>> b = {'one': 1, 'two': 42}
>>>
>>> diff(a, b)
{'D': {'three': {'R': 3}, 'two': {'N': 42, 'O': 2}, 'one': {'U': 1}}}
>>>
>>> diff(a, b, O=False, U=False)
{'D': {'three': {'R': 3}, 'two': {'N': 42}}}
>>>
>>>
>>> c = [0,1,2,3]
>>> d = [  1,2,4,5]
>>>
>>> c = patch(c, diff(c, d))
>>> assert c == d
>>>

Formatting diffs

>>> from nested_diff import diff, handlers
>>> from nested_diff.formatters import TextFormatter
>>>
>>> a = {'one': 1, 'two': 'some\ntext\ninside'}
>>> b = {'one': 0, 'two': 'some\ntext'}
>>>
>>> d = diff(a, b, U=False, extra_handlers=[handlers.TextHandler(context=3)])
>>> print(TextFormatter().format(d))
  {'one'}
-   1
+   0
  {'two'}
#   <str>
    @@ -1,3 +1,2 @@
    some
    text
-   inside
<BLANKLINE>
>>>

For more examples see Live Demo, HOWTO and tests.

Diff structure

Diff is a dict and may contain status keys:

  • A stands for 'added', it's value - added item.
  • D means 'different' and contains subdiff.
  • N is a new value for changed item.
  • O is a changed item's old value.
  • R key used for removed item.
  • U represent unchanged item.

and auxiliary keys:

  • C comment; optional, value - arbitrary string.
  • E extension ID (optional).
  • I index for sequence item, used only when prior item was omitted.

Diff metadata alternates with actual data; simple types specified as is, dicts, lists and tuples contain subdiffs for their items with native for such types addressing: indexes for lists and tuples, keys for dictionaries. Any status key, except D may be omitted during diff computation. E key is used with D when entity unable to contain diff by itself (set, frozenset for example); D contain a list of subdiffs in this case.

Annotated example

a:  {"one": [5,7]}
b:  {"one": [5], "two": 2}
opts: U=False  # omit unchanged items

diff:
{"D": {"one": {"D": [{"I": 1, "R": 7}]}, "two": {"A": 2}}}
| |   |  |    | |   || |   |   |   |       |    | |   |
| |   |  |    | |   || |   |   |   |       |    | |   +- with value 2
| |   |  |    | |   || |   |   |   |       |    | +- key 'two' was added
| |   |  |    | |   || |   |   |   |       |    +- subdiff for it
| |   |  |    | |   || |   |   |   |       +- another key from top-level
| |   |  |    | |   || |   |   |   +- what it was (item's value: 7)
| |   |  |    | |   || |   |   +- what happened to item (removed)
| |   |  |    | |   || |   +- list item's actual index
| |   |  |    | |   || +- prior item was omitted
| |   |  |    | |   |+- subdiff for list item
| |   |  |    | |   +- it's value - list
| |   |  |    | +- it is deeply changed
| |   |  |    +- subdiff for key 'one'
| |   |  +- it has key 'one'
| |   +- top-level thing is a dict
| +- changes somewhere deeply inside
+- diff is always a dict

License

Licensed under the terms of the Apache License, Version 2.0.

See Also

HOWTO

deepdiff, jsondiff, jsonpatch, json-delta

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

nested_diff-1.4.0.tar.gz (22.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

nested_diff-1.4.0-py3-none-any.whl (26.0 kB view details)

Uploaded Python 3

File details

Details for the file nested_diff-1.4.0.tar.gz.

File metadata

  • Download URL: nested_diff-1.4.0.tar.gz
  • Upload date:
  • Size: 22.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/4.0.2 CPython/3.11.8

File hashes

Hashes for nested_diff-1.4.0.tar.gz
Algorithm Hash digest
SHA256 ab01974b724751e3a1dd56f611bdc1b34c4bf761fb661cf65ea1a3653e4041b7
MD5 54a6f40fa66bfaaa4ba67b45bf46276c
BLAKE2b-256 9d4c5d83b43640e5b667cc11d8af54815dc152c3007684abf61b4bcba2a56a0b

See more details on using hashes here.

File details

Details for the file nested_diff-1.4.0-py3-none-any.whl.

File metadata

  • Download URL: nested_diff-1.4.0-py3-none-any.whl
  • Upload date:
  • Size: 26.0 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/4.0.2 CPython/3.11.8

File hashes

Hashes for nested_diff-1.4.0-py3-none-any.whl
Algorithm Hash digest
SHA256 9fede8371797964182cca3a1b6d2b36cb7fdfc92d0374dae5301b4675cf02864
MD5 e05d42e6159e4e22ae18e0e5cc13bcdf
BLAKE2b-256 f660b2959b52b4cb9c4dfb3a50cb06c44edbb3b6ce85623d092bd17828178368

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page