ignored_keys = ('hash', 'timestamp')

def filter_items(d):
    ''' Filter out keys when returning items() '''
    l = []
    # Ensure we return sorted tuples
    for k, v in sorted(d.items()):
        if k not in ignored_keys:
            l.append((k, v))
    return l

def is_update_required(original, proposed):
    ''' Compare two data-structures '''
    if type(original) != type(proposed):
        print "Datatypes don't match: {0} vs {1}".format(type(original), type(proposed))
        return True
    if isinstance(original, list) or isinstance(original, tuple):
        if len(original) != len(proposed):
            print "Lengths don't match: {0} vs {1}".format(len(original), len(proposed))
            return True
        for a, b in zip(original, proposed):
            if is_update_required(a, b):
                return True
    elif isinstance(original, dict):
        # Turn dictionaries into list of tuples, and re-evaluate
        if is_update_required(filter_items(original), filter_items(proposed)):
            return True
    else:  # Works for sets, integers, strings, ...
        if original != proposed:
            print "Values don't match: {0} vs {1}".format(original, proposed)
            return True
    return False