Check if all values have defaults and replace errors with their default value

    :param config: the configobj to clean
    :type config: ConfigObj
    :returns: None
    :raises: ConfigError

    The object is validated, so we need a spec file. All failed values will be replaced
    by their default values. If default values are not specified in the spec, a
    MissingDefaultError will be raised. If the replaced values still fail validation,
    a ValueError is raised. This can occur if the default is of the wrong type.

    If the object does not have a config spec, this function does nothing.
    You are on your own then.

def clean_config(config):
    """Check if all values have defaults and replace errors with their default value

    :param config: the configobj to clean
    :type config: ConfigObj
    :returns: None
    :raises: ConfigError

    The object is validated, so we need a spec file. All failed values will be replaced
    by their default values. If default values are not specified in the spec, a
    MissingDefaultError will be raised. If the replaced values still fail validation,
    a ValueError is raised. This can occur if the default is of the wrong type.

    If the object does not have a config spec, this function does nothing.
    You are on your own then.
    """
    if config.configspec is None:
        return
    vld = Validator()
    validation = config.validate(vld, copy=True)
    config.configspec.walk(check_default_values, validator=vld)
    fix_errors(config, validation)
    validation = config.validate(vld, copy=True)
    if not (validation == True):  # NOQA seems unpythonic but this validation evaluates that way only
        msg = 'The config could not be fixed. Make sure that all default values have the right type!'
        log.debug(msg)
        raise ConfigError(msg)