nested-diff


Namenested-diff JSON
Version 1.4.0 PyPI version JSON
download
home_page
SummaryRecursive diff and patch for nested structures.
upload_time2024-02-18 00:06:38
maintainer
docs_urlNone
author
requires_python>=3.7
license
keywords diff nested-diff recursive-diff nested-data data-structures
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # Nested-Diff.py

Recursive diff and patch for nested structures.

[![Tests Status](https://github.com/mr-mixas/Nested-Diff.py/actions/workflows/tests.yml/badge.svg)](https://github.com/mr-mixas/Nested-Diff.py/actions?query=branch%3Amaster)
[![Coverage Status](https://coveralls.io/repos/github/mr-mixas/Nested-Diff.py/badge.svg)](https://coveralls.io/github/mr-mixas/Nested-Diff.py)
[![Supported Python versions](https://img.shields.io/pypi/pyversions/nested_diff.svg)](https://pypi.org/project/nested_diff/)
[![License](https://img.shields.io/pypi/l/nested_diff.svg)](https://pypi.org/project/nested_diff/)

## 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!](https://nesteddiff.pythonanywhere.com/)**

## Install

`pip install nested_diff`

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

`pip install nested_diff[cli]`

## Command line tools

```sh
$ cat a.json b.json
[0, [1],    3]
[0, [1, 2], 3]
```

```sh
$ nested_diff a.json b.json
  [1]
+   [1]
+     2
```

```sh
nested_diff a.json b.json --ofmt json > patch.json
nested_patch a.json patch.json
```

## Library usage

```py
>>> 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

```py
>>> 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](https://nesteddiff.pythonanywhere.com/),
[HOWTO](https://github.com/mr-mixas/Nested-Diff.py/blob/master/HOWTO.md) and
[tests](https://github.com/mr-mixas/Nested-Diff.py/tree/master/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

```text
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](http://www.apache.org/licenses/LICENSE-2.0).

## See Also

[HOWTO](https://github.com/mr-mixas/Nested-Diff.py/blob/master/HOWTO.md)

[deepdiff](https://pypi.org/project/deepdiff/),
[jsondiff](https://pypi.org/project/jsondiff/),
[jsonpatch](https://pypi.org/project/jsonpatch/),
[json-delta](https://pypi.org/project/json-delta/)


            

Raw data

            {
    "_id": null,
    "home_page": "",
    "name": "nested-diff",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.7",
    "maintainer_email": "",
    "keywords": "diff,nested-diff,recursive-diff,nested-data,data-structures",
    "author": "",
    "author_email": "Michael Samoglyadov <mixas.sr@gmail.com>",
    "download_url": "https://files.pythonhosted.org/packages/9d/4c/5d83b43640e5b667cc11d8af54815dc152c3007684abf61b4bcba2a56a0b/nested_diff-1.4.0.tar.gz",
    "platform": null,
    "description": "# Nested-Diff.py\n\nRecursive diff and patch for nested structures.\n\n[![Tests Status](https://github.com/mr-mixas/Nested-Diff.py/actions/workflows/tests.yml/badge.svg)](https://github.com/mr-mixas/Nested-Diff.py/actions?query=branch%3Amaster)\n[![Coverage Status](https://coveralls.io/repos/github/mr-mixas/Nested-Diff.py/badge.svg)](https://coveralls.io/github/mr-mixas/Nested-Diff.py)\n[![Supported Python versions](https://img.shields.io/pypi/pyversions/nested_diff.svg)](https://pypi.org/project/nested_diff/)\n[![License](https://img.shields.io/pypi/l/nested_diff.svg)](https://pypi.org/project/nested_diff/)\n\n## Main features\n\n* Machine-readable diff structure.\n* Human-friendly diff visualization, collapsible html diffs.\n* All operation tags are optional and may be disabled.\n* Extensibility.\n\n**[See Live Demo!](https://nesteddiff.pythonanywhere.com/)**\n\n## Install\n\n`pip install nested_diff`\n\nFor extra formats support (YAML, TOML) in cli tools, use\n\n`pip install nested_diff[cli]`\n\n## Command line tools\n\n```sh\n$ cat a.json b.json\n[0, [1],    3]\n[0, [1, 2], 3]\n```\n\n```sh\n$ nested_diff a.json b.json\n  [1]\n+   [1]\n+     2\n```\n\n```sh\nnested_diff a.json b.json --ofmt json > patch.json\nnested_patch a.json patch.json\n```\n\n## Library usage\n\n```py\n>>> from nested_diff import diff, patch\n>>>\n>>> a = {'one': 1, 'two': 2, 'three': 3}\n>>> b = {'one': 1, 'two': 42}\n>>>\n>>> diff(a, b)\n{'D': {'three': {'R': 3}, 'two': {'N': 42, 'O': 2}, 'one': {'U': 1}}}\n>>>\n>>> diff(a, b, O=False, U=False)\n{'D': {'three': {'R': 3}, 'two': {'N': 42}}}\n>>>\n>>>\n>>> c = [0,1,2,3]\n>>> d = [  1,2,4,5]\n>>>\n>>> c = patch(c, diff(c, d))\n>>> assert c == d\n>>>\n```\n\n### Formatting diffs\n\n```py\n>>> from nested_diff import diff, handlers\n>>> from nested_diff.formatters import TextFormatter\n>>>\n>>> a = {'one': 1, 'two': 'some\\ntext\\ninside'}\n>>> b = {'one': 0, 'two': 'some\\ntext'}\n>>>\n>>> d = diff(a, b, U=False, extra_handlers=[handlers.TextHandler(context=3)])\n>>> print(TextFormatter().format(d))\n  {'one'}\n-   1\n+   0\n  {'two'}\n#   <str>\n    @@ -1,3 +1,2 @@\n    some\n    text\n-   inside\n<BLANKLINE>\n>>>\n```\n\nFor more examples see [Live Demo](https://nesteddiff.pythonanywhere.com/),\n[HOWTO](https://github.com/mr-mixas/Nested-Diff.py/blob/master/HOWTO.md) and\n[tests](https://github.com/mr-mixas/Nested-Diff.py/tree/master/tests).\n\n## Diff structure\n\nDiff is a dict and may contain status keys:\n\n* `A` stands for 'added', it's value - added item.\n* `D` means 'different' and contains subdiff.\n* `N` is a new value for changed item.\n* `O` is a changed item's old value.\n* `R` key used for removed item.\n* `U` represent unchanged item.\n\nand auxiliary keys:\n\n* `C` comment; optional, value - arbitrary string.\n* `E` extension ID (optional).\n* `I` index for sequence item, used only when prior item was omitted.\n\nDiff metadata alternates with actual data; simple types specified as is, dicts,\nlists and tuples contain subdiffs for their items with native for such types\naddressing: indexes for lists and tuples, keys for dictionaries. Any status\nkey, except `D` may be omitted during diff computation. `E` key is used with\n`D` when entity unable to contain diff by itself (set, frozenset for example);\n`D` contain a list of subdiffs in this case.\n\n### Annotated example\n\n```text\na:  {\"one\": [5,7]}\nb:  {\"one\": [5], \"two\": 2}\nopts: U=False  # omit unchanged items\n\ndiff:\n{\"D\": {\"one\": {\"D\": [{\"I\": 1, \"R\": 7}]}, \"two\": {\"A\": 2}}}\n| |   |  |    | |   || |   |   |   |       |    | |   |\n| |   |  |    | |   || |   |   |   |       |    | |   +- with value 2\n| |   |  |    | |   || |   |   |   |       |    | +- key 'two' was added\n| |   |  |    | |   || |   |   |   |       |    +- subdiff for it\n| |   |  |    | |   || |   |   |   |       +- another key from top-level\n| |   |  |    | |   || |   |   |   +- what it was (item's value: 7)\n| |   |  |    | |   || |   |   +- what happened to item (removed)\n| |   |  |    | |   || |   +- list item's actual index\n| |   |  |    | |   || +- prior item was omitted\n| |   |  |    | |   |+- subdiff for list item\n| |   |  |    | |   +- it's value - list\n| |   |  |    | +- it is deeply changed\n| |   |  |    +- subdiff for key 'one'\n| |   |  +- it has key 'one'\n| |   +- top-level thing is a dict\n| +- changes somewhere deeply inside\n+- diff is always a dict\n```\n\n## License\n\nLicensed under the terms of the [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0).\n\n## See Also\n\n[HOWTO](https://github.com/mr-mixas/Nested-Diff.py/blob/master/HOWTO.md)\n\n[deepdiff](https://pypi.org/project/deepdiff/),\n[jsondiff](https://pypi.org/project/jsondiff/),\n[jsonpatch](https://pypi.org/project/jsonpatch/),\n[json-delta](https://pypi.org/project/json-delta/)\n\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "Recursive diff and patch for nested structures.",
    "version": "1.4.0",
    "project_urls": {
        "Homepage": "https://github.com/mr-mixas/Nested-Diff.py",
        "Repository": "https://github.com/mr-mixas/Nested-Diff.py.git"
    },
    "split_keywords": [
        "diff",
        "nested-diff",
        "recursive-diff",
        "nested-data",
        "data-structures"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "f660b2959b52b4cb9c4dfb3a50cb06c44edbb3b6ce85623d092bd17828178368",
                "md5": "e05d42e6159e4e22ae18e0e5cc13bcdf",
                "sha256": "9fede8371797964182cca3a1b6d2b36cb7fdfc92d0374dae5301b4675cf02864"
            },
            "downloads": -1,
            "filename": "nested_diff-1.4.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "e05d42e6159e4e22ae18e0e5cc13bcdf",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.7",
            "size": 25966,
            "upload_time": "2024-02-18T00:06:36",
            "upload_time_iso_8601": "2024-02-18T00:06:36.880536Z",
            "url": "https://files.pythonhosted.org/packages/f6/60/b2959b52b4cb9c4dfb3a50cb06c44edbb3b6ce85623d092bd17828178368/nested_diff-1.4.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "9d4c5d83b43640e5b667cc11d8af54815dc152c3007684abf61b4bcba2a56a0b",
                "md5": "54a6f40fa66bfaaa4ba67b45bf46276c",
                "sha256": "ab01974b724751e3a1dd56f611bdc1b34c4bf761fb661cf65ea1a3653e4041b7"
            },
            "downloads": -1,
            "filename": "nested_diff-1.4.0.tar.gz",
            "has_sig": false,
            "md5_digest": "54a6f40fa66bfaaa4ba67b45bf46276c",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.7",
            "size": 22078,
            "upload_time": "2024-02-18T00:06:38",
            "upload_time_iso_8601": "2024-02-18T00:06:38.132659Z",
            "url": "https://files.pythonhosted.org/packages/9d/4c/5d83b43640e5b667cc11d8af54815dc152c3007684abf61b4bcba2a56a0b/nested_diff-1.4.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-02-18 00:06:38",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "mr-mixas",
    "github_project": "Nested-Diff.py",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "tox": true,
    "lcname": "nested-diff"
}
        
Elapsed time: 0.21638s