diff --git a/dictdiffer/__init__.py b/dictdiffer/__init__.py index fcd528a..859e374 100644 --- a/dictdiffer/__init__.py +++ b/dictdiffer/__init__.py @@ -275,7 +275,7 @@ def check(key): return _diff_recursive(first, second, node) -def patch(diff_result, destination, in_place=False): +def patch(diff_result, destination, in_place=False, action_flags="arc"): """Patch the diff result to the destination dictionary. :param diff_result: Changes returned by ``diff``. @@ -285,6 +285,10 @@ def patch(diff_result, destination, in_place=False): Setting ``in_place=True`` means that patch will apply the changes directly to and return the destination structure. + :param action_flags: By default ('arc'), apply all actions: "add", "remove", + "change". Setting ``actions_flag='a'`` means that + pactch will apply only "add" items in the ``diff_result + ``. Similarly, 'ac' only apply "add" and "change". """ if not in_place: destination = deepcopy(destination) @@ -325,7 +329,8 @@ def remove(node, changes): } for action, node, changes in diff_result: - patchers[action](node, changes) + if action[0] in action_flags: + patchers[action](node, changes) return destination diff --git a/dictdiffer/version.py b/dictdiffer/version.py index 3149802..6e420de 100644 --- a/dictdiffer/version.py +++ b/dictdiffer/version.py @@ -1,6 +1,6 @@ -# -*- coding: utf-8 -*- -# Do not change the format of this next line. Doing so risks breaking -# setup.py and docs/conf.py -"""Version information for dictdiffer package.""" - -__version__ = '0.9.0' +# -*- coding: utf-8 -*- +# Do not change the format of this next line. Doing so risks breaking +# setup.py and docs/conf.py +"""Version information for dictdiffer package.""" + +__version__ = '0.9.0' diff --git a/docs/index.rst b/docs/index.rst index b8d011e..cc4ed0e 100644 --- a/docs/index.rst +++ b/docs/index.rst @@ -76,6 +76,13 @@ Now we can apply the diff result with :func:`.patch` method: assert patched == second +use `action_flags` parameter to select desired actions: +'a' for 'add','r' for 'remove', 'c' for 'change' or any other +combinations. + +.. code-block:: python + + patched = patch(result, first, action_flags='a') Also we can swap the diff result with :func:`.swap` method: diff --git a/tests/test_utils.py b/tests/test_utils.py index 591a7eb..de15e83 100644 --- a/tests/test_utils.py +++ b/tests/test_utils.py @@ -8,6 +8,7 @@ import unittest +from dictdiffer import diff, patch from dictdiffer.utils import (PathLimit, WildcardDict, create_dotted_node, dot_lookup, get_path, is_super_path, nested_hash) @@ -144,3 +145,46 @@ def test_nested_hash(self): nested_hash((1, 2, 3)) nested_hash(set([1, 2, 3])) nested_hash({'foo': 'bar'}) + + def test_limit_actions_patch(self): + x = {"a": True, "b": {"b1": True, "b2": False}, "c": {"c1": True}} + y = {"a": False, "b": {"b1": True}, "c": {"c1": False, "c2": False}} + z_a = { + "a": True, + "b": {"b1": True, "b2": False}, + "c": {"c1": True, "c2": False}, + } # add only + z_r = {"a": True, "b": {"b1": True}, "c": {"c1": True}} # remove only + z_c = { + "a": False, + "b": {"b1": True, "b2": False}, + "c": {"c1": False}, + } # change only + z_ar = { + "a": True, + "b": {"b1": True}, + "c": {"c1": True, "c2": False}, + } # add and remove + z_ac = { + "a": False, + "b": {"b1": True, "b2": False}, + "c": {"c1": False, "c2": False}, + } # add and change + z_rc = { + "a": False, + "b": {"b1": True}, + "c": {"c1": False}} # remove and change + z_arc = y # all actions. Default + test_dict = { + "a": z_a, + "r": z_r, + "c": z_c, + "ar": z_ar, + "ac": z_ac, + "rc": z_rc, + "arc": z_arc, + } + for k in test_dict: + result = diff(x, y) + patched = patch(result, x, action_flags=k) + self.assertEqual(patched, test_dict[k])