2017-02-17 2 views
7

j'ai mis en place un script qui télécharge les données à S3. Si le fichier est inférieur à 5 Mo, il le télécharge en un seul morceau, mais si le fichier est plus volumineux, il effectue un chargement en plusieurs parties. Je sais que les seuils sont actuellement faibles. Je ne fais que tester le script en attendant. Si j'exécute le script à partir de Python en important toutes les fonctions et en l'exécutant de cette façon, tout fonctionne comme prévu. Je suis conscient que le code doit être nettoyé car il n'est pas encore complet. Cependant, quand je lance le script de la ligne de commande, je suis accueilli avec cette erreur:résultats différents lors de l'exécution d'un script Uploader

Traceback (most recent call last): 
    File "upload_files_to_s3.py", line 106, in <module> 
    main() 
    File "upload_files_to_s3.py", line 103, in main 
    check_if_mp_needed(conn, input_file, mb, bucket_name, sub_directory) 
    File "upload_files_to_s3.py", line 71, in check_if_mp_needed 
    multipart_upload(conn, input_file, mb, bucket_name, sub_directory) 
    File "upload_files_to_s3.py", line 65, in multipart_upload 
    mp.complete_upload() 
    File "/usr/local/lib/python2.7/site-packages/boto/s3/multipart.py", line 304, in complete_upload 
    self.id, xml) 
    File "/usr/local/lib/python2.7/site-packages/boto/s3/bucket.py", line 1571, in complete_multipart_upload 
    response.status, response.reason, body) 
boto.exception.S3ResponseError: S3ResponseError: 400 Bad Request 

>The XML you provided was not well-formed or did not validate against our published schema 

Voici le code:

import sys 
import boto 
from boto.s3.key import Key 
import os 
import math 
from filechunkio import FileChunkIO 


KEY = os.environ['AWS_ACCESS_KEY_ID'] 
SECRET = os.environ['AWS_SECRET_ACCESS_KEY'] 

def start_connection(): 
    key = KEY 
    secret = SECRET 
    return boto.connect_s3(key, secret) 

def get_bucket_key(conn, bucket_name): 
    bucket = conn.get_bucket(bucket_name) 
    k = Key(bucket) 
    return k 

def get_key_name(sub_directory, input_file): 
    full_key_name = os.path.join(sub_directory, os.path.basename(input_file)) 
    return full_key_name 

def get_file_info(input_file): 
    source_size = os.stat(input_file).st_size 
    return source_size 

def multipart_request(conn, input_file, bucket_name, sub_directory): 
    bucket = conn.get_bucket(bucket_name) 
    mp = bucket.initiate_multipart_upload(get_key_name(sub_directory, input_file)) 
    return mp 

def get_chunk_size(mb): 
    chunk_size = mb * 1048576 
    return chunk_size 

def get_chunk_count(input_file, mb): 
    chunk_count = int(math.ceil(get_file_info(input_file)/float(get_chunk_size(mb)))) 
    return chunk_count 

def regular_upload(conn, input_file, bucket_name, sub_directory): 
    k = get_bucket_key(conn, bucket_name) 
    k.key = get_key_name(sub_directory, input_file) 
    k.set_contents_from_filename(input_file) 


def multipart_upload(conn, input_file, mb, bucket_name, sub_directory): 
    chunk_size = get_chunk_size(mb) 
    chunks = get_chunk_count(input_file, mb) 
    source_size = get_file_info(input_file) 
    mp = multipart_request(conn, input_file, bucket_name, sub_directory) 
    for i in range(chunks): 
     offset = chunk_size * i 
     b = min(chunk_size, source_size - offset) 
     with FileChunkIO(input_file, 'r', offset = offset, bytes = b) as fp: 
      mp.upload_part_from_file(fp, part_num = i + 1) 
    mp.complete_upload() 

def check_if_mp_needed(conn, input_file, mb, bucket_name, sub_directory): 
    if get_file_info(input_file) <= 5242880: 
     regular_upload(conn, input_file, bucket_name, sub_directory) 
    else: 
     multipart_upload(conn, input_file, mb, bucket_name, sub_directory) 

def main(): 
    input_file = sys.argv[1] 
    mb = sys.argv[2] 
    bucket_name = sys.argv[3] 
    sub_directory = sys.argv[4] 
    conn = start_connection() 
    check_if_mp_needed(conn, input_file, mb, bucket_name, sub_directory) 

if __name__ == '__main__': 
    main() 

Merci!

+1

vous utilisez un environnement différent dans la ligne de commande plus probable que celui où vous importez tout à la main. Qu'utilisez-vous dans les deux cas? –

+0

Je cours le script à partir d'un 'virtualenv' dans IPython. La ligne de commande est exécutée juste à travers 'virtualenv' –

+0

OK - il n'est donc pas impossible qu'il y ait une discordance. Pouvez-vous vérifier 'boto .__ version__' dans les deux cas? –

Répondre

0

Vous avez une incompatibilité de version entre vos deux cas. Lorsque vous utilisez l'ancienne version de boto, il utilise le mauvais schéma pour AWS et vous voyez l'erreur. Pour un peu plus de détails, lorsque vous utilisez IPython (en utilisant virtualenv) vous avez la version 2.45.0 et lorsque vous utilisez la ligne de commande, vous avez la version 2.8.0 de boto. Étant donné que la version 2.8.0 remonte à 2013, il n'est pas surprenant que vous obteniez une erreur de schéma. Le correctif consiste soit à mettre à niveau votre version système de boto (que vous avez actuellement dans votre script) en exécutant pip install -U boto ou à convertir votre script pour utiliser l'environnement virtuel. Pour obtenir des conseils sur ce dernier, regardez cette autre réponse sur le SO: Running python script from inside virtualenv bin is not working

+0

J'ai fait 'pip installer -U boto' et il a changé les deux versions en 2.46.1. Je reçois toujours le même message d'erreur cependant. Gardez à l'esprit quand j'ai couru ceci, la dernière fois que je n'ai pas utilisé un 'virtualenv' –

+0

Et vous voyez toujours le résultat différent dans IPython de courir dans la ligne de commande? –

+0

Nope, ils ont tous deux imprimer la même version, '2.46.1' –