@@ -157,7 +157,7 @@ def apply_patch(doc, patch, in_place=False, pointer_cls=JsonPointer):
157
157
return patch .apply (doc , in_place )
158
158
159
159
160
- def make_patch (src , dst , pointer_cls = JsonPointer ):
160
+ def make_patch (src , dst , generate_test_ops = False , pointer_cls = JsonPointer ):
161
161
"""Generates patch by comparing two document objects. Actually is
162
162
a proxy to :meth:`JsonPatch.from_diff` method.
163
163
@@ -170,6 +170,12 @@ def make_patch(src, dst, pointer_cls=JsonPointer):
170
170
:param pointer_cls: JSON pointer class to use.
171
171
:type pointer_cls: Type[JsonPointer]
172
172
173
+ :param generate_test_ops: While :const:`True` generate test operations
174
+ capturing previous values of `replace`/`remove`
175
+ operations. By default do not generate these
176
+ operations.
177
+ :type generate_test_ops: bool
178
+
173
179
>>> src = {'foo': 'bar', 'numbers': [1, 3, 4, 8]}
174
180
>>> dst = {'baz': 'qux', 'numbers': [1, 4, 7]}
175
181
>>> patch = make_patch(src, dst)
@@ -178,7 +184,7 @@ def make_patch(src, dst, pointer_cls=JsonPointer):
178
184
True
179
185
"""
180
186
181
- return JsonPatch .from_diff (src , dst , pointer_cls = pointer_cls )
187
+ return JsonPatch .from_diff (src , dst , generate_test_ops = generate_test_ops , pointer_cls = pointer_cls )
182
188
183
189
184
190
class PatchOperation (object ):
@@ -475,6 +481,11 @@ def apply(self, obj):
475
481
476
482
return obj
477
483
484
+ def _on_undo_add (self , path , key ):
485
+ return key
486
+
487
+ def _on_undo_remove (self , path , key ):
488
+ return key
478
489
479
490
class CopyOperation (PatchOperation ):
480
491
""" Copies an object property or an array element to a new location """
@@ -628,7 +639,7 @@ def from_string(cls, patch_str, loads=None, pointer_cls=JsonPointer):
628
639
629
640
@classmethod
630
641
def from_diff (
631
- cls , src , dst , optimization = True , dumps = None ,
642
+ cls , src , dst , generate_test_ops = False , dumps = None ,
632
643
pointer_cls = JsonPointer ,
633
644
):
634
645
"""Creates JsonPatch instance based on comparison of two document
@@ -641,6 +652,12 @@ def from_diff(
641
652
:param dst: Data source document object.
642
653
:type dst: dict
643
654
655
+ :param generate_test_ops: While :const:`True` generate test operations
656
+ capturing previous values of `replace`/`remove`
657
+ operations. By default do not generate these
658
+ operations.
659
+ :type generate_test_ops: bool
660
+
644
661
:param dumps: A function of one argument that produces a serialized
645
662
JSON string.
646
663
:type dumps: function
@@ -658,7 +675,7 @@ def from_diff(
658
675
True
659
676
"""
660
677
json_dumper = dumps or cls .json_dumper
661
- builder = DiffBuilder (src , dst , json_dumper , pointer_cls = pointer_cls )
678
+ builder = DiffBuilder (src , dst , json_dumper , generate_test_ops = generate_test_ops , pointer_cls = pointer_cls )
662
679
builder ._compare_values ('' , None , src , dst )
663
680
ops = list (builder .execute ())
664
681
return cls (ops , pointer_cls = pointer_cls )
@@ -711,9 +728,10 @@ def _get_operation(self, operation):
711
728
712
729
class DiffBuilder (object ):
713
730
714
- def __init__ (self , src_doc , dst_doc , dumps = json .dumps , pointer_cls = JsonPointer ):
731
+ def __init__ (self , src_doc , dst_doc , dumps = json .dumps , generate_test_ops = False , pointer_cls = JsonPointer ):
715
732
self .dumps = dumps
716
733
self .pointer_cls = pointer_cls
734
+ self .generate_test_ops = generate_test_ops
717
735
self .index_storage = [{}, {}]
718
736
self .index_storage2 = [[], []]
719
737
self .__root = root = []
@@ -819,6 +837,13 @@ def _item_added(self, path, key, item):
819
837
self .store_index (item , new_index , _ST_ADD )
820
838
821
839
def _item_removed (self , path , key , item ):
840
+ if self .generate_test_ops :
841
+ test_index = self .insert (TestOperation ({
842
+ 'op' : 'test' ,
843
+ 'path' : _path_join (path , key ),
844
+ 'value' : item ,
845
+ }, pointer_cls = self .pointer_cls ))
846
+
822
847
new_op = RemoveOperation ({
823
848
'op' : 'remove' ,
824
849
'path' : _path_join (path , key ),
@@ -847,11 +872,20 @@ def _item_removed(self, path, key, item):
847
872
848
873
else :
849
874
self .remove (new_index )
875
+ if self .generate_test_ops :
876
+ self .remove (test_index )
850
877
851
878
else :
852
879
self .store_index (item , new_index , _ST_REMOVE )
853
880
854
- def _item_replaced (self , path , key , item ):
881
+ def _item_replaced (self , path , key , item , old_item ):
882
+ if self .generate_test_ops :
883
+ self .insert (TestOperation ({
884
+ 'op' : 'test' ,
885
+ 'path' : _path_join (path , key ),
886
+ 'value' : old_item ,
887
+ }, pointer_cls = self .pointer_cls ))
888
+
855
889
self .insert (ReplaceOperation ({
856
890
'op' : 'replace' ,
857
891
'path' : _path_join (path , key ),
@@ -921,7 +955,7 @@ def _compare_values(self, path, key, src, dst):
921
955
return
922
956
923
957
else :
924
- self ._item_replaced (path , key , dst )
958
+ self ._item_replaced (path , key , dst , src )
925
959
926
960
927
961
def _path_join (path , key ):
0 commit comments