docs: def _compare_dict(new_dict, old_dict, change_list=None, root=None):
  
      '''
          a method for recursively listing changes made to a dictionary
  
      :param new_dict: dictionary with new key-value pairs
      :param old_dict: dictionary with old key-value pairs
      :param change_list: list of differences between old and new
      :patam root: string with record of path to the root of the main object
      :return: list of differences between old and new
      '''
  
      from copy import deepcopy
      
      new_keys = set(new_dict.keys())
      old_keys = set(old_dict.keys())
      missing_keys = old_keys - new_keys
      extra_keys = new_keys - old_keys
      same_keys = new_keys.intersection(old_keys)
      for key in missing_keys:
          new_path = deepcopy(root)
          new_path.append(key)
          change_list.append({'action': 'DELETE', 'value': None, 'path': new_path})
      for key in extra_keys:
          for k, v in new_dict.items():
              if key == k:
                  new_path = deepcopy(root)
                  new_path.append(key)
                  change_list.append({'action': 'ADD', 'value': v, 'path': new_path})
      for key in same_keys:
          new_path = deepcopy(root)
          new_path.append(key)
          if new_dict[key].__class__ != old_dict[key].__class__:
              change_list.append({'action': 'UPDATE', 'value': new_dict[key], 'path': new_path})
          elif isinstance(new_dict[key], dict):
              _compare_dict(new_dict[key], old_dict[key], change_list, new_path)
          elif isinstance(new_dict[key], list):
              _compare_list(new_dict[key], old_dict[key], change_list, new_path)
          elif isinstance(new_dict[key], set):
              _compare_set(new_dict[key], old_dict[key], change_list, new_path)
          elif new_dict[key] != old_dict[key]:
              change_list.append({'action': 'UPDATE', 'value': new_dict[key], 'path': new_path})
      return change_list