@@ -171,6 +171,14 @@ def make_patch(src, dst):
171171 >>> new == dst
172172 True
173173 """
174+
175+ # TODO: fix patch optimiztion and remove the following check
176+ # fix when patch with optimization is incorrect
177+ patch = JsonPatch .from_diff (src , dst )
178+ new = patch .apply (src )
179+ if new != dst :
180+ return JsonPatch .from_diff (src , dst , False )
181+
174182 return JsonPatch .from_diff (src , dst )
175183
176184
@@ -268,7 +276,7 @@ def from_string(cls, patch_str):
268276 return cls (patch )
269277
270278 @classmethod
271- def from_diff (cls , src , dst ):
279+ def from_diff (cls , src , dst , optimization = True ):
272280 """Creates JsonPatch instance based on comparing of two document
273281 objects. Json patch would be created for `src` argument against `dst`
274282 one.
@@ -320,7 +328,7 @@ def compare_dicts(path, src, dst):
320328 'value' : dst [key ]}
321329
322330 def compare_lists (path , src , dst ):
323- return _compare_lists (path , src , dst )
331+ return _compare_lists (path , src , dst , optimization = optimization )
324332
325333 return cls (list (compare_values ([], src , dst )))
326334
@@ -561,9 +569,12 @@ def apply(self, obj):
561569 return obj
562570
563571
564- def _compare_lists (path , src , dst ):
572+ def _compare_lists (path , src , dst , optimization = True ):
565573 """Compares two lists objects and return JSON patch about."""
566- return _optimize (_compare (path , src , dst , * _split_by_common_seq (src , dst )))
574+ patch = list (_compare (path , src , dst , * _split_by_common_seq (src , dst )))
575+ if optimization :
576+ return list (_optimize (patch ))
577+ return patch
567578
568579
569580def _longest_common_subseq (src , dst ):
@@ -770,7 +781,16 @@ def _optimize_using_replace(prev, cur):
770781 if cur ['op' ] == 'add' :
771782 # make recursive patch
772783 patch = make_patch (prev ['value' ], cur ['value' ])
773- if len (patch .patch ) == 1 and patch .patch [0 ]['op' ] != 'remove' :
784+ # check case when dict "remove" is less than "add" and has a same key
785+ if isinstance (prev ['value' ], dict ) and isinstance (cur ['value' ], dict ) and len (prev ['value' ].keys ()) == 1 :
786+ prev_set = set (prev ['value' ].keys ())
787+ cur_set = set (cur ['value' ].keys ())
788+ if prev_set & cur_set == prev_set :
789+ patch = make_patch (cur ['value' ], prev ['value' ])
790+
791+ if len (patch .patch ) == 1 and \
792+ patch .patch [0 ]['op' ] != 'remove' and \
793+ patch .patch [0 ]['path' ] and patch .patch [0 ]['path' ].split ('/' )[1 ] in prev ['value' ]:
774794 prev ['path' ] = prev ['path' ] + patch .patch [0 ]['path' ]
775795 prev ['value' ] = patch .patch [0 ]['value' ]
776796 else :
0 commit comments