2017-02-17 3 views
7

Ich habe ein Skript zusammengestellt, das Daten in S3 hochlädt. Wenn die Datei weniger als 5 MB groß ist, wird sie als ein Chunk hochgeladen, aber wenn die Datei größer ist, führt sie einen mehrteiligen Upload durch. Ich weiß, dass die Schwellenwerte derzeit klein sind. Ich teste das Skript einfach in der Zwischenzeit. Wenn ich das Skript von Python aus starte, indem ich jede Funktion importiere und sie so laufe, funktioniert alles wie beabsichtigt. Ich bin mir bewusst, dass der Code gereinigt werden muss, da er noch nicht vollständig ist. Allerdings, wenn ich das Skript von der Kommandozeile ausgeführt Ich bin mit diesem Fehler begrüßt:Unterschiedliche Ergebnisse beim Ausführen eines Uploader-Skripts

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 

Hier ist der 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() 

Dank!

+1

Höchstwahrscheinlich verwenden Sie eine andere Umgebung in der Befehlszeile als die, in der Sie alles von Hand importieren. Was benutzt du in beiden Fällen? –

+0

Ich führe das Skript von einem 'virtualenv' in IPython. Die Befehlszeile wird nur durch 'virtualenv' ausgeführt –

+0

OK - so ist es nicht unmöglich, dass es eine Nichtübereinstimmung gibt. Können Sie 'boto .__ version__' in beiden Fällen überprüfen? –

Antwort

0

Sie haben eine Versionskonflikt zwischen Ihren beiden Fällen. Wenn Sie die ältere Version von Boto verwenden, wird das falsche Schema für AWS verwendet, und Sie sehen den Fehler.

Etwas genauer, wenn Sie in IPython (mit dem virtualenv) ausführen, haben Sie die Version 2.45.0 und wenn Sie über die Befehlszeile ausführen, haben Sie die Version 2.8.0 von boto. Da Version 2.8.0 auf das Jahr 2013 zurückgeht, ist es nicht verwunderlich, dass Sie einen Schema-Fehler erhalten.

Die Fehlerbehebung besteht darin, entweder die Systemversion von Boto (die Sie gerade in Ihrem Skript erfassen) zu aktualisieren, indem Sie pip install -U boto ausführen oder Ihr Skript in die virtuelle Umgebung konvertieren. Für einen Hinweis auf Letzteres, sieh dir diese andere Antwort zu SO an: Running python script from inside virtualenv bin is not working

+0

Ich habe 'pip install -U boto' installiert und beide Versionen in 2.46.1 geändert. Ich bekomme jedoch immer noch die gleiche Fehlermeldung. Denken Sie daran, wenn ich dies ausgeführt habe, das letzte Mal habe ich kein 'virtualenv' verwendet –

+0

Und Sie sehen immer noch das unterschiedliche Ergebnis in IPython von der Ausführung in der Befehlszeile? –

+0

Nein, sie beide drucken die gleiche Version, '2.46.1' –

Verwandte Themen