def _get_sub_types_of_compositional_types(compositional_type: str) ->tuple:
    """
    Extract the sub-types of compositional types.

    This method handles both specification types (e.g. pt:set[], pt:dict[]) as well as python types (e.g. FrozenSet[], Union[]).

    :param compositional_type: the compositional type string whose sub-types are to be extracted.
    :return: tuple containing all extracted sub-types.
    """
    sub_types_list = list()
    if compositional_type.startswith('Optional'
        ) or compositional_type.startswith('pt:optional'):
        sub_type1 = compositional_type[compositional_type.index('[') + 1:
            compositional_type.rindex(']')].strip()
        sub_types_list.append(sub_type1)
    if compositional_type.startswith('FrozenSet'
        ) or compositional_type.startswith('pt:set'
        ) or compositional_type.startswith('pt:list'):
        sub_type1 = compositional_type[compositional_type.index('[') + 1:
            compositional_type.rindex(']')].strip()
        sub_types_list.append(sub_type1)
    if compositional_type.startswith('Tuple'):
        sub_type1 = compositional_type[compositional_type.index('[') + 1:
            compositional_type.rindex(']')].strip()
        sub_type1 = sub_type1[:-5]
        sub_types_list.append(sub_type1)
    if compositional_type.startswith('Dict') or compositional_type.startswith(
        'pt:dict'):
        sub_type1 = compositional_type[compositional_type.index('[') + 1:
            compositional_type.index(',')].strip()
        sub_type2 = compositional_type[compositional_type.index(',') + 1:
            compositional_type.rindex(']')].strip()
        sub_types_list.extend([sub_type1, sub_type2])
    if compositional_type.startswith('Union') or compositional_type.startswith(
        'pt:union'):
        inside_union = compositional_type[compositional_type.index('[') + 1
            :compositional_type.rindex(']')].strip()
        while inside_union != '':
            if inside_union.startswith('Dict') or inside_union.startswith(
                'pt:dict'):
                sub_type = inside_union[:inside_union.index(']') + 1].strip()
                rest_of_inside_union = inside_union[inside_union.index(']') +
                    1:].strip()
                if rest_of_inside_union.find(',') == -1:
                    inside_union = rest_of_inside_union.strip()
                else:
                    inside_union = rest_of_inside_union[
                        rest_of_inside_union.index(',') + 1:].strip()
            elif inside_union.startswith('Tuple'):
                sub_type = inside_union[:inside_union.index(']') + 1].strip()
                rest_of_inside_union = inside_union[inside_union.index(']') +
                    1:].strip()
                if rest_of_inside_union.find(',') == -1:
                    inside_union = rest_of_inside_union.strip()
                else:
                    inside_union = rest_of_inside_union[
                        rest_of_inside_union.index(',') + 1:].strip()
            elif inside_union.find(',') == -1:
                sub_type = inside_union.strip()
                inside_union = ''
            else:
                sub_type = inside_union[:inside_union.index(',')].strip()
                inside_union = inside_union[inside_union.index(',') + 1:
                    ].strip()
            sub_types_list.append(sub_type)
    return tuple(sub_types_list)
