CSV-Problem

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
pooner
User
Beiträge: 37
Registriert: Montag 15. Mai 2006, 08:04

Hallo Leute,

ich brauche Eure Hilfe, da mir die Ideen ausgehen. Mein Problem liegt in der der Programmlogik, speziell beim Schreiben von einer CSV-Datei. Ausgangssituation ist das ich SQL-Abfragen mache und die in eine csv-Datei schreiben möchte. Diese csv-Datei soll dann per Mail versendet werden. Dies klappt auch alles, jedoch erhalte ich niemals alle Zeilen der scv-Datei per Mail. Am Anfang dachte ich das die Mail-Fkt. nicht in Ordnung ist, bis ich einen Zähler eingebaut habe und feststellen muuste das die letzten Zeilen erts in die Datei geschrieben werden wenn die Mail schon versendet wurde. Dies kann aber eigentlich gar nicht sein, daher bin ich jetzt leicht konfus :?:

Hier sind meine Funktionen, vielleicht sieht einer von euch den Fehler :idea:

Code: Alles auswählen


def main():
 """Hauptfunktion"""
#

 try:
   if len(sys.argv) != 4:
       help()
       sys.exit(2)
   else:
       str_name = sys.argv[2]
       recipient =sys.argv[3]  
       opts, args = getopt.getopt(sys.argv[1:], "hrbs", ["help", "room", "building", "site"])
       for o, a in opts:
         if o in ("-h", "--help"):
              help()
              sys.exit(0)
         if o in ("-r", "--room"):
              db_connect()
              get_oneRoom(str_name)
              db_close()
              print zaehler
              send_CSV(str_mailtext, csvFile, recipient)
              sys.exit(0)     
         if o in ("-b", "--building"):
              db_connect()
              get_allFromHouse(str_name)
              db_close()
              send_CSV(str_mailtext, csvFile, recipient)
              sys.exit(0)
         if o in ("-s", "--site"):
              db_connect()
              get_allRooms(str_name)
              db_close()
              send_CSV(str_mailtext, csvFile, recipient)
              sys.exit(0)
         else:
               print "Zu viele, oder falsche Argumente uebergeben"
               sys.exit(1)

 except getopt.GetoptError:
        # print help information and exit:
        print "Falsche Parameter uebergeben. Bitte nutzen Sie den Parameter -h fuer die richtige Syntax"
        sys.exit(2)

def start_CSV(str_name):
 """ Funktion start_CSV:  definiert globale Variablen und gibt csv-File-Handler """
#
 global csvFile
 csvFile = "/tmp/%s.csv" %str_name
 csv.register_dialect("excel", delimiter=";", quoting=csv.QUOTE_MINIMAL)
 global writer  # definiert die Variable global, fuer die Verwendung in Fkt.write_CSV
 try:
     writer = csv.writer(open(csvFile, "wb"), dialect="excel")

 except csv.Error, e:
    sys.exit('file %s: %s' % (csvFile, e))


def get_oneRoom(str_name):
#
#
 start_CSV(str_name)
 count=0
 #print " Eingeben wurde Raum: %s " % str_name
 cursor.execute("SELECT DISTINCT a.id FROM configitem AS a INNER JOIN  configitem_version AS b ON a.id = b.configitem_id where b.name like '%s'" % str_name )
 room_id = cursor.fetchall()
 for a in room_id:
   count=count+1

 if count == 1:
    print "Der Raum %s wurde gefunden. Die ID lautet: %s" % (str_name, a)
    get_Details(str_name,a)
 else:
     error(str_name)



#
def get_Details(raumname, b):
#
 print "%s" % b
 cursor.execute(" SELECT source_key from link_relation where target_key = '%s' AND target_object_id=4" % b)
 itemlist = cursor.fetchall()
 #print " Die CI-Objecte zum Raum %s lauten:" % raumname
 results = []
 for c in itemlist:
       d = int(c[0])           # print type(d)
       cursor.execute("SELECT DISTINCT a.id AS ID,a.configitem_number AS CiNumber, a.class_id as Devicegroup, a.last_version_id, b.name as Bezeichnung  FROM configitem AS a INNER JOIN  configitem_version AS b ON a.id = b.configitem_id where a.id = '%d' order by b.create_time desc limit 1" % d )

       while(1):
           raumobjekt = cursor.fetchone()
           if raumobjekt == None:
               break
           i = int(raumobjekt[3])
           for s in searchparams:
                            
             cursor.execute("select xml_content_value from xml_storage where xml_key = '%s' AND xml_content_key like '%s'"  % (i,s) )
             while(1):
                         invnumber = cursor.fetchone()
                         if invnumber == None:
                                        break
                         results.append(invnumber[0])
             
           results.insert(1,raumobjekt[1])
           results.insert(2,raumobjekt[4])
           write_CSV(results, raumname)
           results = []

#
def write_CSV(results, location):
 #zaehler = zaehler+1
 rowresult=[]
 for i in results:
     p = re.compile('[0-9]{9,}')
     m = p.match(i)
     if m:
        # schreibt die CI-Nummer  
        rowresult.append(i) 
       # print ('match found: ', m.group())
     else:
         rowresult.append(i)
 rowresult.append(location)       
 writer.writerow(rowresult)


 
Benutzeravatar
Hyperion
Moderator
Beiträge: 7478
Registriert: Freitag 4. August 2006, 14:56
Wohnort: Hamburg
Kontaktdaten:

Sorry, aber bei dem miesen Code ist es schwer einen Fehler zu finden!

Du solltest Dein Programm imho besser strukturieren und Dich an PEP8 halten! (Wieso sind es teilweise 4 und dann wieder 2 Leerzeichen-Einrückung?)

Wozu diese ganzen global-Geschichten? Ich sehe darin keinen Sinn.

Mein Tipp. Schreibe doch mal die Funktionen sauber um, so dass sie etwas zurückgeben. Diesen Rückgabewert schreibst Du dann in einem Rutsch in die Datei.

Außerdem solltest Du Dir ggf. mal Gedanken zum Encoding machen - oder hast Du nur ASCII-Zeichen in Deiner DB?

Für Pfadmanipulation gibt es das Modul os.path, und da besonders die join()-Funktion!
pooner
User
Beiträge: 37
Registriert: Montag 15. Mai 2006, 08:04

danke für die Hinweise, werde mich bemühen, das Ganze PEP-kompatibel zu formatieren.

Die global Geschichten verwende ich nur um die in einer Funktion lokalen Variablen in einer anderen nutzen zu können. Rückgabewerte sind sicherlich besser. Trotz alledem passiert als Ergebnis immer das folgende:

Programmaufruf --> Aufbau der DB-Verbindung "db_connect"--> Aufruf der Funktion "get_oneRoom" --> Aufruf der Funktion "get_Details" --> Aufruf durch Schleife der Funktion "write_CSV "--> Aufruf der Funktion "send_CSV" --> 77 Einträge in CSV-Datei --> Beendigung des Programms --> 136 Einträge in der CSV-Datei

Das ist mein Problem. Wäre trotzdem nett wenn mir jemand helfen könnte.
pooner
User
Beiträge: 37
Registriert: Montag 15. Mai 2006, 08:04

Danke :D

Du hattest Recht mit der Verwendung von Rückgabewerten, auf einmal bekomme ich sofort alle Antwortzeilen.

Problem gelöst
BlackJack

@pooner: Wenn ich mal raten müsste: Du schliesst die Datei nirgends, d.h. es werden wahrscheinlich die letzten Daten nicht auf die Platte geschrieben, bevor das Programm endet und die Datei implizit vom Betriebssystem geschlossen wird. Dir fehlt da sozusagen das Gegenstück zu `start_CSV()`.

Sonstige Anmerkungen:

Du mischt bei der Verarbeitung von Optionen direkten Zugriff auf `sys.argv` mit `getopt`. Das macht das ganze IMHO etwas unübersichtlicher. Ausserdem ist `optparse` IMHO das bessere Modul zum Auswerten von Optionen.

In der `main()`-Funktion ist viel nahezu identischer Quelltext bei den drei Optionen, die auf die DB zugreifen.

Vergiss, dass es ``global`` gibt! Funktionen haben Argumente und können ein Ergebnis zurückgeben.

`start_CSV` ist IMHO etwas sehr ausführlich. Einen CSV-Dialekt zu registrieren lohnt sich nur, wenn man da auch mehrfach und verschiedenen Stellen im Programm von der dann kürzeren Aufrufmöglichkeit der `csv.writer()`-Funktion gebrauch macht. Das gilt auch für das *ständige* Kompilieren von dem regulären Ausdruck in `write_CSV()`. Wenn man für jeden Datensatz neu kompiliert, kann man sich das auch sparen.

`get_oneRoom()` ist zu kompliziert. `fetchall()` gibt eine Liste zurück -- wenn Du wissen willst, wieviele Elemente die enthält, dann verwende doch einfach `len()` statt in einer ``for``-Schleife mit einem Zähler manuell nachzuzählen. Es wäre vielleicht auch günstiger die CSV-Datei erst zu öffnen, wenn man weiss dass es den Raum überhaupt gibt. Und der Name ist eine Konventionenmischung. Mann muss sich ja nicht zwingend an PEP8 halten, aber mischen sollte man IMHO echt nicht.

``print "%s" % b`` ist die komplizierte Art um ``print b`` zu schreiben.

Man braucht keine Klammer um Bedingungen und ``while`` ist auch keine Funktion. Statt der 1 sollte man `True` verwenden, wenn man das meint. Allerdings sollte man aus diesen beiden Schleifen sowieso ``for``-Schleifen machen. Schau Dir mal die Dokumentation zur `iter()`-Funktion an. Letztendlich sehen mir verschachtelten Schleifen zu komplex aus. Da würde ich auf jeden Fall versuchen mehr von der Datenbank erledigen zu lassen. Und was Du da mit `result` veranstaltest ist an unübersichtlichkeit kaum zu überbieten. Wer soll sich denn da merken können, was in `result` hinterher an welchem Index steht, und welche Bedeutung das jeweils hat?

Den Sinn, von dem, was Du da in `write_CSV()` veranstaltest, habe ich ehrlich gesagt nicht verstanden. Das macht letztendlich nichts anderes als:

Code: Alles auswählen

def write_CSV(results, location):
    writer.writerow(results + [location])
Nur halt wesentlich umständlicher.

Die ganzen einbuchstabigen Namen sollte man durch aussagekräftigere Bezeichner ersetzen. Dann sollte man keine SQL-Anfragen mit Zeichenkettenoperationen zusammensetzen lassen. Insbesondere wenn die Daten dafür von aussen kommen. Und Du könntest die SQL-Anfragen mal vernünftig umbrechen und nicht als überlange Zeilen schreiben.
pooner
User
Beiträge: 37
Registriert: Montag 15. Mai 2006, 08:04

du hast Recht mit deiner Vermutung.

danke für die konstruktiven Tipps. Ich sehe ein hier habe ich ganz schönen Quatsch gemacht. Na gut, man lernt halt nie aus. Ich werde mich jetzt über den Code hermachen und ihn vereinfachen, verbessern und PEP-konform machen.


Danke nochmals
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Soviel ich weiß, kann man mit file.flush() den Puffer jederzeit manuell in die Datei schreiben lassen. Das ist aber keine Alternative zum formellen Schließen der Datei!
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Antworten