Helper method to convert the values of a collection into the required (pep-declared) value type in desired_type.
        If desired_type does not explicitly mention a type for its values, the collection will be returned as is, otherwise
        a  copy will be created and filled with conversions of the values, performed by the provided conversion_finder

        :param coll_to_convert:
        :param desired_type:
        :param conversion_finder:
        :param logger:
        :param kwargs:
        :return:

def convert_collection_values_according_to_pep(coll_to_convert: Union[Dict, List, Set, Tuple],
                                                   desired_type: Type[T],
                                                   conversion_finder: 'ConversionFinder', logger: Logger, **kwargs) \
            -> T:
        """
        Helper method to convert the values of a collection into the required (pep-declared) value type in desired_type.
        If desired_type does not explicitly mention a type for its values, the collection will be returned as is, otherwise
        a  copy will be created and filled with conversions of the values, performed by the provided conversion_finder

        :param coll_to_convert:
        :param desired_type:
        :param conversion_finder:
        :param logger:
        :param kwargs:
        :return:
        """
        base_desired_type = get_base_generic_type(desired_type)

        if issubclass(base_desired_type, Mapping):  # or issubclass(base_desired_type, dict):
            # get the base collection type if provided (this raises an error if key type is not str)
            item_typ, _ = _extract_collection_base_type(desired_type, exception_if_none=False)

            if item_typ is None:
                # nothing is required in terms of dict values: use the base method
                return ConversionFinder.try_convert_value(conversion_finder, '', coll_to_convert, desired_type,
                                                          logger=logger, options=kwargs)
            else:
                # TODO resuse appropriate container type (not necessary a dict) according to type of coll_to_convert
                # there is a specific type required for the dict values.
                res = dict()
                # convert if required
                for key, val in coll_to_convert.items():
                    res[key] = ConversionFinder.try_convert_value(conversion_finder, key, val, item_typ, logger,
                                                                  options=kwargs)
                return res

        elif issubclass(base_desired_type, Sequence):  # or issubclass(base_desired_type, list):
            # get the base collection type if provided
            item_typ, _ = _extract_collection_base_type(desired_type, exception_if_none=False)

            if item_typ is None:
                # nothing is required in terms of dict values: use the base method
                return ConversionFinder.try_convert_value(conversion_finder, '', coll_to_convert, desired_type,
                                                          logger=logger, options=kwargs)
            else:
                # TODO resuse appropriate container type (not necessary a list) according to type of coll_to_convert
                # there is a specific type required for the list values.
                res = list()

                # special case where base_desired_type is a Tuple: in that case item_typ may be a tuple or else
                if type(item_typ) != tuple:
                    # convert each item if required
                    for val in coll_to_convert:
                        res.append(ConversionFinder.try_convert_value(conversion_finder, '', val, item_typ, logger,
                                                                      options=kwargs))
                else:
                    if len(item_typ) == 1:
                        item_typ_tuple = item_typ * len(coll_to_convert)
                    elif len(item_typ) == len(coll_to_convert):
                        item_typ_tuple = item_typ
                    else:
                        raise ValueError('Collection to convert is of length {} which is not compliant with desired '
                                         'type {}'.format(len(coll_to_convert), item_typ))
                    for val, item_t in zip(coll_to_convert, item_typ_tuple):
                        res.append(ConversionFinder.try_convert_value(conversion_finder, '', val, item_t, logger,
                                                                      options=kwargs))
                    res = tuple(res)

                return res

        elif issubclass(base_desired_type, AbstractSet):  # or issubclass(base_desired_type, set):
            # get the base collection type if provided
            item_typ, _ = _extract_collection_base_type(desired_type, exception_if_none=False)

            if item_typ is None:
                # nothing is required in terms of dict values: use the base method
                return ConversionFinder.try_convert_value(conversion_finder, '', coll_to_convert, desired_type,
                                                          logger=logger, options=kwargs)
            else:
                # TODO resuse appropriate container type (not necessary a set) according to type of coll_to_convert
                # there is a specific type required for the list values.
                res = set()
                # convert if required
                for val in coll_to_convert:
                    res.add(ConversionFinder.try_convert_value(conversion_finder, '', val, item_typ, logger,
                                                               options=kwargs))
                return res

        else:
            raise TypeError('Cannot convert collection values, expected type is not a supported collection '
                            '(dict, list, set, Mapping, Sequence, AbstractSet)! : ' + str(desired_type))