docs: def diff_objects(objects_a,objects_b,key,comparator = None,with_unchanged = False):
      """
      Returns a "diff" between two lists of objects.
  
      :param key: The key that identifies objects with identical location in each set,
                  such as files with the same path or code objects with the same URL.
      :param comparator: Comparison functions that decides if two objects are identical.
      """
  
      objects_by_key = {'a' :defaultdict(list),
                        'b' : defaultdict(list)}
  
      for name,objects in ('a',objects_a),('b',objects_b):
          d = objects_by_key[name]
          for obj in objects:
              d[key(obj)].append(obj)
  
      added_objects = [obj for key,objs in objects_by_key['b'].items()
                       if key not in objects_by_key['a'] for obj in objs]
  
      deleted_objects = [obj for key,objs in objects_by_key['a'].items()
                         if key not in objects_by_key['b'] for obj in objs]
  
      joint_keys = [key for key in objects_by_key['a']
                    if key in objects_by_key['b']]
  
      modified_objects = []
  
      #we go through the keys that exist in both object sets
      for key in joint_keys:
          objects_a = objects_by_key['a'][key]
          objects_b = objects_by_key['b'][key]
  
          if len(objects_a) > 1 or len(objects_b) > 1:
  
              #this is an ambiguous situation: we have more than one object for the same
              #key, so we have to decide which ones have been added or not
              #we try to remove identical objects from the set
  
              objects_a_copy = objects_a[:]
              objects_b_copy = objects_b[:]
  
              #for the next step, we need a comparator
              if comparator:
                  #we iterate through the list and try to find different objects...
                  for obj_a in objects_a:
                      for obj_b in objects_b_copy:
                          if comparator(obj_a,obj_b) == 0:
                              #these objects are identical, we remove them from both sets...
                              objects_a_copy.remove(obj_a)
                              objects_b_copy.remove(obj_b)
                              break
  
              #here we cannot distinguish objects...
              if len(objects_b_copy) > len(objects_a_copy):
                  #we arbitrarily mark the last objects in objects_b as added
                  added_objects.extend(objects_b_copy[len(objects_a_copy):])
              elif len(objects_a_copy) > len(objects_b_copy):
                  #we arbitrarily mark the last objects in objects_a as deleted
                  deleted_objects.extend(objects_a_copy[len(objects_b_copy):])
          else:
              if comparator and comparator(objects_a[0],objects_b[0]) != 0:
                  #these objects are different
                  modified_objects.append(objects_a[0])
  
      result = {
          'added' : added_objects,
          'deleted' : deleted_objects,
          'modified' : modified_objects,
      }
  
      if with_unchanged:
          unchanged_objects = [objects_b_by_key[key]
                               for key in joint_keys
                               if not objects_b_by_key[key] in modified_objects]
          result['unchanged'] = unchanged_objects
  
      return result