from copy import deepcopy def jay_diff_rev(_new, _old): delta = {} for k in _new.keys(): if k in _old: if isinstance(_new[k], dict): res = jay_diff_rev(_new[k], _old[k]) if len(res.keys()): delta[k] = res else: _old[k] = _new[k] delta[k] = _new[k] return delta def jay_diff_add(_old, _new): __old = deepcopy(_old) delta = jay_diff_rev(_new, __old) return delta def jay_diff_del(_old, _new): __new = deepcopy(_new) delta = jay_diff_rev(_old, __new) return delta def jay_diff_upd(temp_data, data, add_if_not_exist=False): new_data = {} for k in data.keys(): if k in temp_data: if isinstance(data[k], dict): res = jay_diff_upd(temp_data[k], data[k], add_if_not_exist) new_data[k] = res elif data[k] != temp_data[k]: new_data[k] = data[k] elif add_if_not_exist: new_data[k] = data[k] return new_data def jay_diff_upd_add(temp_data, data): return jay_diff_upd(temp_data, data, add_if_not_exist=True) def jay_diff_full(data, temp_data, combine_upd_add=False): diff = {} if combine_upd_add: res = jay_diff_upd_add(data, temp_data) if len(res.keys()): diff['update_add'] = res res = jay_diff_del(data, temp_data) if len(res.keys()): diff['delete'] = res else: res = jay_diff_upd(data, temp_data) if len(res.keys()): diff['update'] = res res = jay_diff_add(data, temp_data) if len(res.keys()): diff['add'] = res res = jay_diff_del(data, temp_data) if len(res.keys()): diff['delete'] = res return diff def jay_merge_update(d, u): for k, v in u.items(): if isinstance(v, dict): r = jay_merge_update(d.get(k, {}), v) d[k] = r else: d[k] = u[k] return d def jay_merge_plus(d, u): for k, v in u.items(): if isinstance(v, dict): if k in d: d[k].update(v) else: d[k] = v else: d[k] = u[k] return d def jay_merge_minus(d, u): for k, v in u.items(): if isinstance(v, dict): jay_merge_minus(d[k], u[k]) else: if k in d: del d[k] return d if __name__ == '__main__': diffed = jay_diff_add({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}) assert diffed == {'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}} diffed = jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) assert diffed == {} diffed = jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}) assert diffed == {} diffed = jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}) assert diffed == {'d':'icecream'} diffed = jay_diff_add({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) assert diffed == {'b':'fries'} diffed = jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, {'c': {'f': 'coffee'}}) assert diffed == {'c': {'f': 'coffee'}} diffed = jay_diff_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}) assert diffed == {} diffed = jay_diff_del({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) assert diffed == {'d':'icecream'} diffed = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) assert diffed == {} diffed = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}) assert diffed == {} diffed = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries'}) assert diffed == {'c':'pepsi'} diffed = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) assert diffed == {} diffed = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a': 'hamburger', 'b': 'fries'}) assert diffed == {'c': {'e': 'coke', 'f': 'coffee'}} diffed = jay_diff_del({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'coke'}}) assert diffed == {'a':'hamburger', 'b':'fries', 'c': {'f': 'coffee'}} diffed = jay_diff_del({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}) assert diffed == {} diffed = jay_diff_upd({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes'}) assert diffed == {'a':'hotdog', 'b':'potatoes'} diffed = jay_diff_upd({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi'}}) assert diffed == {'c': {'e': 'pepsi'}} diffed = jay_diff_upd({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'}) assert diffed == {'a':'hotdog'} diffed = jay_diff_upd({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}) assert diffed == {'c':'coke'} diffed = jay_diff_upd({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) assert diffed == {'c':'coke'} diffed = jay_diff_upd({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, {'c': {'f': 'coffee'}}) assert diffed == {'c': {}} diffed = jay_diff_upd({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}) assert diffed == {'c': {'e': 'pepsi'}} # Update/add diffed = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes', 'd': 'icecream'}) assert diffed == {'a':'hotdog', 'b':'potatoes', 'd': 'icecream'} diffed = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}, 'b':'potatoes'}) assert diffed == {'b':'potatoes', 'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}} diffed = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'}) assert diffed == {'a':'hotdog'} diffed = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}) assert diffed == {'c': {'e': 'pepsi'}} ##################### diffed = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes'}) assert diffed == {'a':'hotdog', 'b':'potatoes'} diffed = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi'}}) assert diffed == {'c': {'e': 'pepsi'}} diffed = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'}) assert diffed == {'a':'hotdog'} diffed = jay_diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}) assert diffed == {'c': 'coke', 'd': 'icecream'} diffed = jay_diff_upd_add({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}) assert diffed == {'b': 'fries', 'c': 'coke'} diffed = jay_diff_upd_add({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, {'c': {'f': 'coffee'}}) assert diffed == {'c': {'f': 'coffee'}} diffed = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}) assert diffed == {'c': {'e': 'pepsi'}} diffed = jay_diff_upd_add({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}}) assert diffed == {'c': {'e': 'pepsi', 'h': 'cake'}} # ToDo: jay_diff_full diffed = jay_diff_full({}, {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, combine_upd_add=False) assert diffed == {'add': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}} diffed = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add=False) assert diffed == {'update': {'c': 'coke'}} diffed = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, combine_upd_add=False) assert diffed == {'delete': {'d': 'icecream'}} diffed = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'd': 'icecream', 'c': 'coke'}, combine_upd_add=False) assert diffed == {'add': {'d': 'icecream'}, 'delete': {'b': 'fries'}, 'update': {'c': 'coke'}} diffed = jay_diff_full({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add=False) assert diffed == {'add': {'b': 'fries'}, 'delete': {'d': 'icecream'}, 'update': {'c': 'coke'}} diffed = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, {'c': {'f': 'coffee'}}, combine_upd_add=False) assert diffed == {'add': {'c': {'f': 'coffee'}}, 'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke'}}, 'update': {'c': {}}} diffed = jay_diff_full({'a': 'hamburger', 'c': 'pepsi', 'd': 'icecream'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add=False) assert diffed == {'add': {'b': 'fries'}, 'delete': {'d': 'icecream'}, 'update': {'c': 'coke'}} diffed = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add=False) assert diffed == {} diffed = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, {'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, combine_upd_add=False) assert diffed == {'update': {'c': 'pepsi'}} diffed = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries'}, combine_upd_add=False) assert diffed == {'delete': {'c': 'pepsi'}} diffed = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': 'pepsi'}, {'a': 'hamburger', 'b': 'fries', 'c': 'coke'}, combine_upd_add=False) assert diffed == {'update': {'c': 'coke'}} diffed = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a': 'hamburger', 'b': 'fries'}, combine_upd_add=False) assert diffed == {'delete': {'c': {'e': 'coke', 'f': 'coffee'}}} diffed = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, combine_upd_add=False) assert diffed == {'delete': {'c': {'e': 'coke'}}, 'update': {'c': {}}} diffed = jay_diff_full({'a': 'hamburger', 'b': 'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'coke'}}, combine_upd_add=False) assert diffed == {'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, 'update': {'c': {}}} diffed = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes'}, combine_upd_add=False) assert diffed == {'delete': {'c': {'e': 'coke', 'f': 'coffee'}}, 'update': {'a': 'hotdog', 'b': 'potatoes'}} diffed = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi'}}, combine_upd_add=False) assert diffed == {'delete': {'a': 'hamburger', 'b': 'fries', 'c': {'f': 'coffee'}}, 'update': {'c': {'e': 'pepsi'}}} diffed = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'}, combine_upd_add=False) assert diffed == {'delete': {'c': {'e': 'coke', 'f': 'coffee'}}, 'update': {'a': 'hotdog'}} diffed = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}, combine_upd_add=False) assert diffed == {'update': {'c': {'e': 'pepsi'}}} diffed = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'potatoes', 'd': 'icecream'}, combine_upd_add=False) assert diffed == {'add': {'d': 'icecream'}, 'delete': {'c': {'e': 'coke', 'f': 'coffee'}}, 'update': {'a': 'hotdog', 'b': 'potatoes'}} diffed = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'pepsi', 'g': 'tea', 'h': 'cake'}, 'b':'potatoes'}, combine_upd_add=False) assert diffed == {'add': {'c': {'g': 'tea', 'h': 'cake'}}, 'delete': {'a': 'hamburger', 'c': {'f': 'coffee'}}, 'update': {'b': 'potatoes', 'c': {'e': 'pepsi'}}} diffed = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hotdog', 'b':'fries'}, combine_upd_add=False) assert diffed == {'delete': {'c': {'e': 'coke', 'f': 'coffee'}}, 'update': {'a': 'hotdog'}} diffed = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee'}}, combine_upd_add=False) assert diffed == {'update': {'c': {'e': 'pepsi'}}} diffed = jay_diff_full({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'pepsi', 'f': 'coffee', 'h': 'cake'}}) assert diffed == {'add': {'c': {'h': 'cake'}}, 'update': {'c': {'e': 'pepsi'}}} # Merge merged = jay_merge_plus({}, {'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}) assert merged == {'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}} merged = jay_merge_plus({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'d':'icecream'}) assert merged == {'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}, 'd':'icecream'} merged = jay_merge_minus({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}, 'd':'icecream'}, {'d':'icecream'}) assert merged == {'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}} merged = jay_merge_minus({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'f': 'coffee'}}) assert merged == {'a':'hamburger', 'b':'fries', 'c': {'e': 'coke'}} merged = jay_merge_minus({'a':'hamburger', 'b':'fries', 'c': {'e': 'coke', 'f': 'coffee'}}, {'c': {'e': 'coke'}}) assert merged == {'a':'hamburger', 'b':'fries', 'c': {'f': 'coffee'}} merged = jay_merge_plus({'a':'hamburger', 'b':'fries', 'c': {'f': 'coffee'}}, {'d':'icecream'}) assert merged == {'a':'hamburger', 'b':'fries', 'c': {'f': 'coffee'}, 'd':'icecream'} merged = jay_merge_plus({'a':'hamburger', 'b':'fries', 'c': {'f': 'coffee'}, 'd':'icecream'}, {'d':'icecream'}) assert merged == {'a':'hamburger', 'b':'fries', 'c': {'f': 'coffee'}, 'd':'icecream'}