

def safe_get_list(data, key):
    """Read attribute from a dictionary, which is expected to be a list. If it is not - return empty list

    :type data: dict
    :type key: str | unicode
    :rtype: list | tuple
    """
    if key not in data:
        return []
    else:
        if type(data[key]) is list or type(data[key]) is tuple:
            return data[key]
        else:
            return []


def safe_get_list_all(data, key):
    """Recursively walk through the given data and retrieve list, which is the union
    of all list attributes of nested dicts by the given key

    :type data: dict | list
    :type key: str | unicode
    :rtype: list
    """
    result = []
    if isinstance(data, dict):
        for k, v in data.items():
            if k == key and (type(v) is list or type(v) is tuple):
                result.extend(v)
                continue
            result.extend(safe_get_list_all(v, key))
    if isinstance(data, list):
        for v in data:
            result.extend(safe_get_list_all(v, key))
    return result


def safe_get_dict(data, key):
    """Read attribute from a dictionary, which is expected to be a dictionary. If it is not - return empty dictionary

    :type data: dict
    :type key: str | unicode
    :rtype: dict
    """
    if key not in data:
        return {}
    else:
        if type(data[key]) is dict:
            return data[key]
        else:
            return {}


def safe_get_struct(data, key):
    """Read attribute from a dictionary, which is expected to be a dictionary. If it is not - return None

    :type data: dict
    :type key: str | unicode
    :rtype: dict | None
    """
    if key not in data:
        return None
    else:
        if type(data[key]) is dict:
            return data[key]
        else:
            return None


def safe_dict(data):
    """If variable is dictionary - return it as is, otherwise return empty dictionary

    :rtype: dict
    """
    if isinstance(data, dict):
        return data
    else:
        return {}
