Utility method to create an object from a dictionary of constructor arguments. Constructor arguments that dont have
    the correct type are intelligently converted if possible

    :param desired_type:
    :param contents_dict:
    :param logger:
    :param options:
    :param conversion_finder:
    :param is_dict_of_dicts:
    :return:

def _dict_to_object(desired_type: Type[T], contents_dict: Dict[str, Any], logger: Logger,
                    options: Dict[str, Dict[str, Any]], conversion_finder: ConversionFinder = None,
                    is_dict_of_dicts: bool = False) -> T:
    """
    Utility method to create an object from a dictionary of constructor arguments. Constructor arguments that dont have
    the correct type are intelligently converted if possible

    :param desired_type:
    :param contents_dict:
    :param logger:
    :param options:
    :param conversion_finder:
    :param is_dict_of_dicts:
    :return:
    """
    # collect pep-484 information in the constructor to be able to understand what is required
    constructor_args_types_and_opt = get_constructor_attributes_types(desired_type)

    try:
        # for each attribute, convert the types of its parsed values if required
        dict_for_init = dict()
        for attr_name, provided_attr_value in contents_dict.items():

            # check if this attribute name is required by the constructor
            if attr_name in constructor_args_types_and_opt.keys():

                # check the theoretical type wanted by the constructor
                attr_type_required = constructor_args_types_and_opt[attr_name][0]

                # resolve forward references
                attr_type_required = resolve_forward_ref(attr_type_required)

                if not is_dict_of_dicts:
                    if is_valid_pep484_type_hint(attr_type_required):
                        # this will not fail if type information is not present;the attribute will only be used 'as is'
                        full_attr_name = get_pretty_type_str(desired_type) + '.' + attr_name

                        dict_for_init[attr_name] = ConversionFinder.try_convert_value(conversion_finder, full_attr_name,
                                                                                      provided_attr_value,
                                                                                      attr_type_required, logger,
                                                                                      options)

                    else:
                        warn("Constructor for type <{t}> has no valid PEP484 Type hint for attribute {att}, trying to "
                             "use the parsed value in the dict directly".format(t=get_pretty_type_str(desired_type),
                                                                         att=attr_name))
                        dict_for_init[attr_name] = provided_attr_value

                else:
                    # in that mode, the attribute value itself is a dict, so the attribute needs to be built from that
                    # dict first
                    if isinstance(provided_attr_value, dict):
                        # recurse : try to build this attribute from the dictionary provided. We need to know the type
                        # for this otherwise we wont be able to call the constructor :)
                        if (attr_type_required is None) or (attr_type_required is Parameter.empty):
                            raise TypeInformationRequiredError.create_for_object_attributes(desired_type, attr_name,
                                                                                            attr_type_required)

                        elif not is_valid_pep484_type_hint(attr_type_required):
                            raise InvalidPEP484TypeHint.create_for_object_attributes(desired_type, attr_name,
                                                                                     attr_type_required)

                        else:
                            # we can build the attribute from the sub-dict
                            dict_for_init[attr_name] = dict_to_object(attr_type_required, provided_attr_value,
                                                                      logger, options,
                                                                      conversion_finder=conversion_finder)

                    else:
                        raise ValueError('Error while trying to build object of type ' + str(desired_type) + ' from a '
                                         'dictionary of dictionaries. Entry \'' + attr_name + '\' is not a dictionary')
            else:
                if is_dict_of_dicts and attr_name is 'DEFAULT':
                    # -- tolerate but ignore - this is probably due to a configparser
                    # warning('Property name \'' + attr_name + '\' is not an attribute of the object constructor. <'
                    #         + get_pretty_type_str(desired_type) + '> constructor attributes are : '
                    #         + list(set(constructor_args_types.keys()) - {'self'}) + '. However it is named DEFAULT')
                    pass
                else:
                    # the dictionary entry does not correspond to a valid attribute of the object
                    raise InvalidAttributeNameForConstructorError.create(desired_type,
                                                                         list(set(constructor_args_types_and_opt.keys()) - {'self'}),
                                                                         attr_name)

        # create the object using its constructor
        try:
            return desired_type(**dict_for_init)
        except Exception as e:
            # Wrap into an Exception
            raise ObjectInstantiationException.create(desired_type, dict_for_init, e)

    except TypeError as e:
        raise CaughtTypeErrorDuringInstantiation.create(desired_type, contents_dict, e)