Backup a file on S3

    :param file: full path to the file to be backed up
    :param host: this will be used to locate the file on S3
    :raises TypeError: if an argument in kwargs does not have the type expected
    :raises ValueError: if an argument within kwargs has an invalid value

def backup_file(*, file, host):
    """
    Backup a file on S3

    :param file: full path to the file to be backed up
    :param host: this will be used to locate the file on S3
    :raises TypeError: if an argument in kwargs does not have the type expected
    :raises ValueError: if an argument within kwargs has an invalid value
    """

    # This driver won't do a thing unless it has been properly initialised
    # via load()
    if not _has_init:
        raise RuntimeError("This driver has not been properly initialised!")

    # If the destination bucket does not exist, create one
    try:
        if not _dry_run:
            bucket = _boto_conn.get_bucket(_bucket_name)
    except boto.exception.S3ResponseError:
        log.msg_warn("Bucket '{bucket_name}' does not exist!, creating it..."
                     .format(bucket_name=_bucket_name))
        if not _dry_run:
            bucket = _boto_conn.create_bucket(_bucket_name)
        log.msg("Created bucket '{bucket}'".format(bucket=_bucket_name))

    # The key is the name of the file itself who needs to be stripped
    # from its full path
    key_path = "{key}/{file}".format(key=host, file=ntpath.basename(file))

    # Create a new bucket key
    if not _dry_run:
        k = boto.s3.key.Key(bucket)
        k.key = key_path

    # Upload the file to Amazon
    log.msg("Uploading '{key_path}' to bucket '{bucket_name}' ..."
            .format(key_path=key_path, bucket_name=_bucket_name))

    # It is important to encrypt the data on the server side
    if not _dry_run:
        k.set_contents_from_filename(file, encrypt_key=True)

    # Log the thing
    log.msg("The file '{key_path}' has been successfully uploaded to S3!"
            .format(key_path=key_path))