execute all data handlers on the specified data according to data type

    Args:
        data_type (str): data type handle
        data (dict or list): data

    Kwargs:
        data_id (str): can be used to differentiate between different data
            sets of the same data type. If not specified will default to
            the data type
        caller (object): if specified, holds the object or function that
            is trying to handle data

    Returns:
        dict or list - data after handlers have been executed on it

def handle(data_type, data, data_id=None, caller=None):
    """
    execute all data handlers on the specified data according to data type

    Args:
        data_type (str): data type handle
        data (dict or list): data

    Kwargs:
        data_id (str): can be used to differentiate between different data
            sets of the same data type. If not specified will default to
            the data type
        caller (object): if specified, holds the object or function that
            is trying to handle data

    Returns:
        dict or list - data after handlers have been executed on it
    """

    if not data_id:
        data_id = data_type

    # instantiate handlers for data type if they havent been yet
    if data_id not in _handlers:
        _handlers[data_id] = dict(
            [(h.handle, h) for h in handlers.instantiate_for_data_type(data_type, data_id=data_id)])

    for handler in list(_handlers[data_id].values()):
        try:
            data = handler(data, caller=caller)
        except Exception as inst:
            vodka.log.error("Data handler '%s' failed with error" % handler)
            vodka.log.error(traceback.format_exc())

    return data