Seite 1 von 1

ftp-upload Script (optimierung)

Verfasst: Mittwoch 12. September 2007, 09:08
von Zack
Guten Morgen,
ich brauchte ein kleines Script, dass mir einen lokalen Ordner auf einen ftp-Server spiegelt. Da ich noch nicht so lange dabei bin, schleichen sich bei mir sicherlich noch der ein oder andere Bug oder Schönheitsfehler ein. Vielleicht findet ja einer mal die Zeit kurz durch den Code zu huschen. Kritik erwünscht, sei sie noch so klein :wink:
Danke im Voraus

Code: Alles auswählen

import ftplib, os, glob
from time import sleep

def uploaddir(ftp, directory):
    for filename in glob.glob(directory + '/*'):
        absPath = os.path.abspath(filename)
        basename = os.path.basename(filename)
        if os.path.isdir(absPath):
            try:
                try:
                    print "Befehl: mkd %s"%basename
                    ftp.mkd(basename)
                except:
                    print "Status: %s already exist!"%basename
                try:
                    print "Befehl: CWD %s"%basename
                    ftp.cwd(basename)
                    print "Status: uploaddir: %s"%basename
                    uploaddir(ftp,absPath)
                    print "Befehl: CWD %s"%"../"
                    ftp.cwd("..")
                except:
                    print "Error:  uploading content of "+absPath

            except:
                print "mkd \"%s\" fehlgeschlagen!"%(basename)
        else:
            try:
                filelist = ftp.nlst(".")
                if not filelist.count(basename) > 0:
                    f = open(absPath, "rb")
                    print "Befehl: STOR %s"%basename
                    ftp.storbinary("STOR "+basename, f)
                    f.close()
                else:
                    print "Status: File \"%s\" already exist!"%basename
            except:
                print "Error:  STOR \"%s\" fehlgeschlagen!"%(basename)

try:
    ftp = ftplib.FTP()
    ftp.connect("localhost", 21)
    sleep(0.2)
    ftp.login("user", "pw")
    sleep(0.5)
    uploaddir(ftp,"C:\\ftpfolder")
    ftp.quit()
except:
    print "error: (10054, 'Connection reset by peer')"
Mit freundlichem Gruß
Zack

Verfasst: Mittwoch 12. September 2007, 09:38
von BlackJack
Man sollte keine ``except``\s ohne konkrete Ausnahmen verwenden. Da werden einfach *alle* Ausnahmen behandelt, auch solche mit denen man nicht gerechnet hat und die man vielleicht doch lieber sehen möchte.

Zum Beispiel die Ausnahmebehandlung auf Modulebene: Du gibst den Text ``error: (10054, 'Connection reset by peer')`` aus, egal was *wirklich* die Ursache war. Das ist nicht gut. Das kann von einem `NameError` sein, weil irgendwo ein Name falsch geschrieben wurde, eine Ausnahme wegen Zeitüberschreitung, oder weil es den Server vielleicht gar nicht gibt, oder vielleicht sogar ein `MemoryError` oder ein `RuntimeError` wegen zu tiefer Rekursion sein.

Im ersten ``if``-Zweig von `uploaddir()` ist das ``try``/``except`` toter Code. Da innerhalb des Blocks nur zwei ``print``-Anweisungen stehen sollte man unter normalen Umständen nie in die äussere Ausnahmebehandlung kommen.

Vor und nach binären Operatoren erhöht ein Leerzeichen die Lesbarkeit. Insbesondere beim ``%`` fällt das hier unangenehm auf.

In Zeichenketten die in einfache Anführungszeichen eingeschlossen sind, kann man doppelte Anführungszeichen einfach so verwenden ohne sie mit einem Backslash schützen zu müssen. Eventuell würde sich an den Stellen wo Dateinamen in Zeichenketten formatiert werden auch '%r' statt '"%s"' anbieten, weil man so sicher ist, dass nur ASCII-Zeichen ausgegeben werden und eventuell "komische" Sonderzeichen durch Escape-Sequenzen dargestellt werden.

Verfasst: Mittwoch 12. September 2007, 10:40
von Zack
Hi BlackJack,
erstmal vielen dank für das Feedback. Bis auf die ein oder andere except-Fehlermeldung, bei denen ich mich noch nicht ausreichend auskenne, habe ich alles umzusetzen versucht.
Hier mein Ergebnis:

Code: Alles auswählen

import os, glob
from ftplib import FTP, Error
from time import sleep

def uploaddir(ftp, directory):
    for filename in glob.glob(directory + '/*'):
        absPath = os.path.abspath(filename)
        basename = os.path.basename(filename)
        if os.path.isdir(absPath):
            try:
                print "Befehl: mkd %s" % (basename)
                ftp.mkd(basename)
            except Error:
                print "Status: %r already exist!" % (basename)
            try:
                print "Befehl: CWD %s" % (basename)
                ftp.cwd(basename)
                print "Status: uploaddir: %s" % (basename)
                uploaddir(ftp,absPath)
                print "Befehl: CWD %s" %"../"
                ftp.cwd("..")
            except Error:
                print "Error:  uploading content of " + absPath
        else:
            try:
                filelist = ftp.nlst(".")
                if not filelist.count(basename) > 0:
                    f = open(absPath, "rb")
                    print "Befehl: STOR %s" % (basename)
                    ftp.storbinary("STOR " + basename, f)
                    f.close()
                else:
                    print 'Status: File %r already exist!' % (basename)
            except Error:
                print 'Error:  STOR %r fehlgeschlagen!' % (basename)


ftp = FTP()
print ftp.connect("localhost", 21)
sleep(0.2)
print ftp.login("user", "pass")
sleep(0.5)
uploaddir(ftp,"C:\\ftpfolder")
print ftp.quit()
Sieht auf jeden Fall besser aus.

Bin bei weiterem stöbern auf das ftpmirror-Script in Python25/Tools gestoßen. Ich denke daraus lässt sich auch in kürzester Zeit eine annehmbare Lösung realisieren.

edit: Ich hab alternativ auch ein sehr schönes sync script auf ASPN gefunden.
http://aspn.activestate.com/ASPN/Cookbo ... ipe/327141
Sehr elegant gelöst wie ich finde.