Seite 1 von 2
Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Freitag 17. Juli 2015, 23:31
von Sophus
Hallo Leute,
ich habe eine GUI gebastelt, mit der ich mich dann an einen MySQL-Server anmelde. Der Benutzer muss die benötigten Daten eingeben, und am Ende wird die Schaltfläche betätigt, die dann eine Funktion auslöst. Diese sieht dann wie folgt aus:
Code: Alles auswählen
def log_in(self):
server_host = str(self.ui_login.lineEdit_sevrer_host.text())
username = str(self.ui_login.lineEdit_username.text())
password = str(self.ui_login.lineEdit_password.text())
database_name = str(self.ui_login.lineEdit_database_name.text())
port = str(self.ui_login.lineEdit_port.text())
mysql_connection_result = os.system(manage_mysql.connect_to_mysql(server_host, username, password, database_name, port))
if not mysql_connection_result == "True":
self.critical(mysql_connection_result)
else:
self.ui_login.close()
# When the connection fails then call this function and show the messagebox
def critical(self, text_error):
ret = QMessageBox.critical(self, "Critical",
# Show the error message (text_error)
text_error, QMessageBox.Ok)
if ret == QMessageBox.Ok:
pass
Die eingegebenen Daten werden dann mittels Argumente an diese Funktion übertragen:
Code: Alles auswählen
def connect_to_mysql(db_host, db_user, db_passwd, db_name, db_port):
print "STATUS [OK] (", FILE_NAME, "): Try to Connecting to MYSQL-Database"
try:
engine = create_engine('mysql://'+db_user+':'+db_passwd+'@'+db_host+':'+db_port+'/'+db_name,
encoding='latin1', echo=False)
connection = engine.connect()
connection.execute('USE '+ db_name)
print "STATUS [OK] (", FILE_NAME, "): Successfully connected to the database."
connection.close()
print "STATUS [OK] (", FILE_NAME, "): Successfully closed to the database."
return True
except exc.OperationalError as OptErr:
print "STATUS [FAILED] (", FILE_NAME, "): ", OptErr
return OptErr[0]
Für den Fall, dass ein Fehler beim Verbindungsaufbau entsteht, soll dieser durch die
OperationalError-Behandlung abgefangen und zurückgegeben werden.
Unter Python-Interpreter funktioniert alles so wie ich es mir vorgestellt habe. Ist die Eingabe korrekt, dann wird
True zurückgegeben, und das Fenster wird geschlossen. Wenn ich einen Fehler provoziere, indem ich falsche Anmelde-Daten eingebe, bekomme ich meine Messagebox.
Nun wollte ich testen, ob dieses Verhalten auch in einer EXE-Datei beibehalten wird, und habe mittels py2exe die EXE-Datei erzeugt, und das gleiche durchgeführt, und da bekam ich eine Fehlermeldung, mit der ich wenig anfangen kann.
Wie gesagt, im Python-Interpreter bekomme ich keinerlei Fehlermeldung, nur wenn ich eine EXE-Datei kreiere, und dann versuche mich beim MySQL-Server anzumelden. Diese Fehlermeldung kommt immer. Das heißt, es ist egal ob die Daten korrekt oder falsch sind.
Re: Fehler anzeigen.
Verfasst: Samstag 18. Juli 2015, 00:02
von Madmartigan
Du musst doch einfach nur die Fehlermeldung lesen. Da stehen alle notwendigen Informationen drin.
arguments did not match any overload call
und
argument 3 has unexpected type 'tuple'
Ziemlich eindeutig.
Re: Fehler anzeigen.
Verfasst: Samstag 18. Juli 2015, 00:04
von Sophus
@Madmartigan: Und wieso kommen diese Fehlermeldungen nicht im normalen Zustand, also wenn das Programm ais Skript ausgeführt wird?
Lesen ist das Eine, aber verstehen?
Nun arguments did not match any overload call besagt, dass die Argumente keine Überlast-Aufruf(?) fanden. Ich muss ehrlich gestehen, dass ich es nicht mal im Deutschen verstehe.
Und in argument 3 has unexpected type 'tuple' verstehe ich genauso wenig. Argument 3 ist ja das Passwort, und dieser ist ein Tuple?
Re: Fehler anzeigen.
Verfasst: Samstag 18. Juli 2015, 00:25
von jerch
Sophus hat geschrieben:Und wieso kommen diese Fehlermeldungen nicht im normalen Zustand, also wenn das Programm ais Skript ausgeführt wird?
Wenn der Skript-"Zustand" der normale ist - was ist dann der unnormale Zustand?
Re: Fehler anzeigen.
Verfasst: Samstag 18. Juli 2015, 00:35
von Sophus
@jerch: Ich habe mich ein wenig unglücklich ausgedrückt. Ich wollte darauf hinaus, dass das Programm im Python-Interpreter funktioniert. Also ohne EXE-Datei. Sobald ich aus dem Programm eine EXE-Datei kreiere erscheint diese Fehlermeldung - die ich ehrlich gesagt nicht verstehe.
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Samstag 18. Juli 2015, 01:59
von Sophus
Ich glaube, ich bin meinem Problem ein wenig näher gekommen, aber dennoch besteht weiterhin ein Problem, was ich euch im folgenden zeigen werde.
Zunächst habe ich die die Fehlerbehandlung umgeschrieben. Hier bediene ich mich an
SQLAlchemyError, um sämtliche Fehler zu behandeln.
Code: Alles auswählen
try:
from sqlalchemy import create_engine, exc
from sqlalchemy.dialects.mysql import pyodbc
import mysql.connector
from mysql.connector import (connection)
import sys
import MySQLdb
print "STATUS [OK] (", FILE_NAME, "): All required libraries are imported"
except ImportError as ImpErr:
print "STATUS [FAILED] (", FILE_NAME, "): ", ImpErr
except Exception as ex:
print "STATUS [FAILED] (", FILE_NAME, "): ", ex
raise
def connect_to_mysql(db_host, db_user, db_passwd, db_name, db_port):
print "STATUS [OK] (", FILE_NAME, "): Try to Connecting to MYSQL-Database"
try:
engine = create_engine('mysql+mysql://'+db_user+':'+db_passwd+'@'+db_host+':'+db_port+'/'+db_name,
encoding='latin1', echo=True)
connection = engine.connect()
connection.execute('USE '+ db_name)
print "STATUS [OK] (", FILE_NAME, "): Successfully connected to the database."
connection.close()
print "STATUS [OK] (", FILE_NAME, "): Successfully closed to the database."
return True
except exc.SQLAlchemyError as SQLArErr:
print "STATUS [FAILED] (", FILE_NAME, "): ", SQLArErr
return "SQLAlchemyError"
Die Fehlermeldung sieht nun wie folgt aus:
Wenn ich das nun richtig deute, kann er den ODBC-Treiber nicht laden und kann deswegen nicht auf den Server zugreifen? Aber im Namensraum sehen wir ja, dass zwei ODBC-Treiber importiert werden - einmal pyodbc und einmal den mysql connector. Diesen Connector habe ich direkt von der MySQL-Seite geladen. Diese Bibliotheken sind vorhanden, da keinerlei Fehler beim Import entstehen. Also, irgendwie werde ich nicht schlau aus der Sache.
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Samstag 18. Juli 2015, 09:57
von Sirius3
@Sophus: was soll denn das os.system in Zeile 8 Deines ersten Posts?? Ich habe immer noch das Gefühl, dass Du durch Deine übertriebene Exceptionbehandlung Fehler versteckst, die dann irgendwo anders als völlig andere Fehler auftauchen. Z.B. wenn ein ImportError auftritt, dann macht es keinen Sinn, dass das Programm weiterläuft. SQLAlchemy bindet auch viele Module dynamisch ein. Hast Du alle in Deiner setup.py-include-Liste berücksichtigt? Hat Dir schonmal jemand gesagt, dass es logging gibt?
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Samstag 18. Juli 2015, 16:58
von Sophus
@Sirius3: Ja, ich wurde schon ein oder zwei Mal darauf hingewiesen, dass es sowas wie ein Logging gibt. Sind die weitaus besser als eine Print-Anweisung? Und zu deiner Anmerkung, dass ich die Fehlerbehandlung zu übertrieben anwende. Da hast du vermutlich Recht. Aber inwiefern verstecke ich mögliche Fehler? Ich meine, ich benutze ja nicht das nackte
except, sondern versuche schon bestimmte Fehlermeldungen abzufangen. Zum
os.system. Diese Zeile bzw. dieser Inhalt wurde wieder entfernt. War ein Fehler von mir.
Zurück zum Problem. SQLArchemy unterstützt ja einige
DBAPI-Treiber. Einige davon nur mit vorbeihalt. Aber mit MySQL-Connector von MySQL oder mit pymysql hat er weitestgehend keine Bedenken. Deswegen habe ich mich auch für pymysql entschieden. In meiner
setup.py-Datei siehst du gleich in Zeile 9, dass das Modul pymsql importiert und in Zeile 28 pymysql in die includes gepackt wird. Ich habe auch zur Sicherheit die Liste der excludes geleert, damit keine Überschneidungen stattfinden kann.
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Samstag 18. Juli 2015, 17:12
von Sirius3
@Sophus: mit Logging kann man immerhin diese ganzen unnötigen Status-Meldungen einfach abschalten. Auch bei Deinem jetzigen Fehler schmeißt Du den gesamten Stacktrace weg, so dass es unnötig schwierig wird, die genaue Position des Fehlers zu finden. Mein sqlalchemy hat keinen mysql.mysql-Connector.
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Samstag 18. Juli 2015, 17:23
von Sophus
Ich soll also den Try-Block entfernen, wo SQLArchemy zum Einsatz kommt, das wäre ja beim LogIn.
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Samstag 18. Juli 2015, 18:41
von Sirius3
@Sophus: nein, überall dort, wo es keine sinnvolle Behandlung eines Fehlers gibt. Bei Dir also fast überall.
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Samstag 18. Juli 2015, 23:33
von Sophus
@Sirius3: Ich habe die überflüssigen Try-Blöcke entfernt:
Code: Alles auswählen
#!/usr/bin/env python
#-*- coding:utf-8 -*-
FILE_NAME = "manage_mysql.py"
from sqlalchemy import create_engine
import pymysql
def connect_to_mysql(db_host, db_user, db_passwd, db_name, db_port):
print "STATUS [OK] (", FILE_NAME, "): Calling the function (connect_to_mysql)"
print "STATUS [OK] (", FILE_NAME, "): Creating an engine-instance"
engine = create_engine(
'mysql+pymysql://' + db_user + ':' + db_passwd + '@' + db_host + ':' + db_port + '/' + db_name,
encoding='latin1', echo=True)
print "STATUS [OK] (", FILE_NAME, "): Engine-instance was created"
print "STATUS [OK] (", FILE_NAME, "): Try to connect to the database."
connection = engine.connect()
print "STATUS [OK] (", FILE_NAME, "): Successfully connected the database."
connection.execute('USE ' + db_name)
print "STATUS [OK] (", FILE_NAME, "): Using the chosen database"
connection.close()
print "STATUS [OK] (", FILE_NAME, "): Successfully closed to the database."
print "STATUS [OK] (", FILE_NAME, "): Returning a value"
return True
Aber an der Fehlermeldung hat sich nichts großartiges geändert. Er behauptet immer noch, dass der ODBC-Treiber (pymysql) nicht geladen werden kann. Wie gesagt, pymysql ist installiert und funktioniert, solange dies im "Skript-Modus" ausgeführt wird. Nur in der EXE-Datei hat er offenbar Probleme.

Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Sonntag 19. Juli 2015, 00:08
von Sophus
Ich glaube ich habe das Problem gefunden:
hier wird es erklärt. Die beziehen sich dabei auf sqlite, aber ich dachte mir, man könnte es auch für mysql benutzen. Dementsprechend habe ich meine setup.py-Datei angepasst:
hier. In Zeile 9 und 10 importiere ich einmal den ODBC-Treiber pymysql und dann sqlalchemy. Und in Zeile 135 wird dann das entsprechende Dialekt-Paket hinzugepackt. Nun klappt auch der Verbindungsaufbau wie gewünscht. Das man py2exe alles "vorkauen" muss, hätte ich nicht gedacht. Ich ging einfach davon aus, das py2exe die Abhängigkeiten erkennt und diese auch entsprechend annimmt. Offenbar wohl nicht.
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Sonntag 19. Juli 2015, 08:06
von Sirius3
@Sophus: Deine ganzen Statusmeldungen brauchst Du nicht, weil im Stacktrace ja schon steht, dass er in Zeile 109 ein Problem hat, das heißt, alles davor konnte er wohl ausführen, alles danach nicht mehr.
Auf wundersame Weise wurde jetzt aus "mysql+mysql" auch "mysql+pymysql". Warum richtest Du Dein ganzes Programm auf mysql aus? Statt Deine Strings so zusammenzustückeln solltest Du mal .format anschauen. Mit einem anderen Encoding als utf-8 solltest Du Deine Datenbank erst gar nicht aufbauen. Dass SQLAlchemy seine Treiber dynamisch sucht, wurde Dir mit dem Hinweis, dass die in die include-Liste müssen, schon gesagt. Wenn Du das nicht liest, dann braucht man Dir wohl gar nicht erst antworten. Und mit pymysql benutzt Du gerade nicht ODBC. Was hilft es Dir, alle möglichen Pakete in einer setup.py einzubinden, die Du fürs setup gar nicht brauchst?
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Sonntag 19. Juli 2015, 14:31
von Sophus
@Sirius3: Ich weiß, dass man mit der Formatierung arbeiten kann. Hier:
Code: Alles auswählen
def connect_to_mysql(db_host, db_user, db_passwd, db_name, db_port):
try:
engine = create_engine(DB_URI.format(
user=db_user,
password=db_passwd,
host=db_host,
port=db_port,
db=db_name,
connect_args = {'time_zone': '+00:00'},
encoding='latin1',
echo=True))
connection = engine.connect()
connection.execute('USE ' + db_name)
connection.close()
return True
except exception.SQLAlchemyError as AlErr:
return AlErr[0]
Aber im Vergleich dazu, ist meine "Zusammenstückelung" wesentlich kürzer und übersichtlicher:
Code: Alles auswählen
def connect_to_mysql(db_host, db_user, db_passwd, db_name, db_port):
try:
engine = create_engine(
'mysql+pymysql://' + db_user + ':' + db_passwd + '@' + db_host + ':' + db_port + '/' + db_name,
encoding='latin1', echo=False)
connection = engine.connect()
connection.execute('USE ' + db_name)
connection.close()
return True
except exception.SQLAlchemyError as AlErr:
return AlErr[0]
Und abgesehen davon ist das mit der Formatierung eher eine Geschmacksfrage. Ich handhabe es eher mit dem Zusammenstückeln. Schließlich ist alles noch überschaubar. Und über Geschmack lässt sich bekanntlich streiten.
Zu deiner Anmerkung, wieso ich mein Programm auf MySQL ausrichte. Wie ist deine Frage zu verstehen? Magst du MySQL nicht? Aber ich hatte mir da auch überlegt, und versucht
mysql+pymysql genauso "zusammenzustückeln" wie die anderen Parameter. Geht leider nicht. Da bekomme ich eine ellenlange Fehlermeldung. Sonst hätte ich in der funktion ein weiteres Argument gehabt wie
dbm_system und dieses Argument dann wie folgt eingebaut:
Code: Alles auswählen
def connect_to_mysql(dbm_system, db_host, db_user, db_passwd, db_name, db_port):
try:
engine = create_engine(
'mysql'+dbm_system+'://' + db_user + ':' + db_passwd + '@' + db_host + ':' + db_port + '/' + db_name,
encoding='latin1', echo=False)
connection = engine.connect()
connection.execute('USE ' + db_name)
connection.close()
return True
except exception.SQLAlchemyError as AlErr:
return AlErr[0]
Jedoch klappt diese Vorstellung nicht, also muss ich mir was anderes einbauen. Ich habe also nicht vor, mein Programm komplett auf MySQL auszurichten. Und zu deiner Anmerkung mit ODBC oder PyMySQL. Nun, ich brauche etwas, womit mein Programm in der Lage ist mit der Datenbank zu kommunizieren, und da bietet sich PyMySQL sehr gut als Treiber an. Oder verstehe ich deine Frage total falsch?
Bezüglich der Enkodierung: Ich möchte es nur möglich machen, dass man in der Datenbank auch mit Datensätze arbeiten kann die auch Umlaute enthalten. Dies ist ja bei Namen der Filme, Bücher und Personen ja nicht selten. Aus diesem Grund nahm ich
encoding='latin1'. Hier fand ich die
Verwendung von latin1. Gut, russische und chinesische Schriften sind nicht dabei.
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Sonntag 19. Juli 2015, 16:50
von jerch
@Sophus:
Das sieht alles recht zusammengestoppelt aus. Wenn Du das SqlAlchemy-Tutorial ernsthaft durchgearbeitet hättest, kämst Du eher bei sowas raus:
Code: Alles auswählen
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
# default db engine
DB_URI = 'sqlite:///:memory:'
Base = declarative_base()
class MyModel(Base):
__tablename__ = 'mymodel'
id = Column(Integer, primary_key=True)
some_string = Column(String(63))
some_number = Column(Integer)
def __repr__(self):
return "<MyModel(some_string='%s', some_number='%s')>" % (
self.some_string, self.some_number)
def get_db_session(uri=DB_URI):
engine = create_engine(uri, echo=True)
Base.metadata.create_all(engine)
Session = sessionmaker(bind=engine)
return Session()
if __name__ == '__main__':
session = get_db_session()
# create object and write it to database
obj = MyModel(some_string='abc', some_number=123)
session.add(obj)
session.commit()
# query MyModel in database
for obj in session.query(MyModel):
print obj
Solange Du Dich auf die Standardfeldtypen beschränkt, baut SqlAlchemy das wunderbar DBMS-unabhängig zusammen und Du kannst durch Angabe eines anderen Datenbank-URIs das Backend wechseln. Wenn Du aber von Anfang an auf die Dialekte gehst, wirst Du massive Probleme mit anderen Backends bekommen und musst dann händisch patchen oder Workarounds implementieren. Warum machst Du Dir die Sache so schwer?
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Sonntag 19. Juli 2015, 17:35
von Sophus
@jerch: Danke. Ich muss mir das mal verinnerlichen. Jedoch käme es nicht dabei raus, wenn ich das SQLAlchemy ernsthaft befolgt hätte. Mir geht es zunächst um eine ganz normale Anmeldung am MySQL-Server. NUR eine Anmeldung. Du hier hier quasi einen Schritt weiter gegangen. Frage: Wo werden die Anmelde-Daten angegeben? Du gehst hierbei nur auf SQLite ein, richtig? Was ich zunächst einmal versuche, ist, dass ich eine Anmelde-Maske erstelle. Der Benutzer soll sich also erst einmal anmelden, und nicht gleich Datensätze in die Datenbank hinterlegen. Der Benutzer kann sich also "nur" erst einmal anmelden, und später, sagen wir mal 1 Stunde später, Datensätze hinterlegen. Meine Idee ist also, dass die Anmeldedaten, sobald sie die Anmeldung bei der Datenbank erfolgreich war, in einem Wörterbuch gespeichert werden. Und beim Manipulieren der Datensätze werden dann die Anmeldedaten aus dem Wörterbuch gelesen, ind die Session gepackt und dann durchgeführt. Ich werde mal versuchen dein Skript zu verstehen, und auf meine Bedürfnisse anzupassen.
Und inwiefern kriege ich Probleme, wenn ich auf Dialekte eingehe? Das ich am Ende für mehrere Datenbanksysteme mehre LogIn-Funktionen schreiben müsste?
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Sonntag 19. Juli 2015, 17:56
von Sophus
So würde meine "Vorab-Version" aussehen:
Code: Alles auswählen
import pyodbc
from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Integer, String
from sqlalchemy.orm import sessionmaker
Base = declarative_base()
# a function from login-form
def log_in(self):
server_host = str(self.ui_login.lineEdit_sevrer_host.text())
username = str(self.ui_login.lineEdit_username.text())
password = str(self.ui_login.lineEdit_password.text())
database_name = str(self.ui_login.lineEdit_database_name.text())
port = str(self.ui_login.lineEdit_port.text())
mysql_connection_result = manage_mysql.connect_to_mysql(server_host, username, password, database_name, port)
# a function in a core module
def manage_dict(db_host, db_user, db_passwd, db_name, db_port):
# empty dictionary
dict = {'server_host': '',
'username': '',
'password': '',
'database_name': '',
'port': ''};
# updating the dictionary
dict['server_host'] = db_host
dict['username'] = db_user
dict['password'] = db_passwd
dict['database_name'] = db_name
dict['port'] = db_port
def connect_to_mysql(db_host, db_user, db_passwd, db_name, db_port):
try:
DB_URI = "mysql+pyodbc://{user}:{password}@{host}:{port}/{db}"
engine = create_engine(DB_URI.format(
user=db_user,
password=db_passwd,
host=db_host,
port=db_port,
db=db_name,
connect_args = {'time_zone': '+00:00'},
encoding='latin1',
echo=True)) # Die Anmeldung funktioniert, nur wird über die Konsole kein Echo zurückgegeben.
connection = engine.connect() # for testing - connect to database
connection.execute('USE ' + db_name) # is there a datasebase?
Base.metadata.create_all(engine) #
Session = sessionmaker(bind=engine) # create a session
connection.close() # close connection to database
manage_dict(db_host, db_user, db_passwd, db_name, db_port) # write in dictonairy
return True
except exception.SQLAlchemyError as AlErr:
return AlErr[0]
Bedenke, dass es mir zunächst um eine Anmeldung geht, nicht darum gleich irgendwelche Datensätze in die Datenbank zu hinterlegen. Es ist durchaus möglich, und dies soll in meinem Programm auch gegeben werde, dass der Benutzer sich zunächst über die Anmelde-Maske beim MSQL-Server anmeldet. Der Benutzer muss aber nicht gleich mit der Arbeit beginnen. Die Anmelde-Maske ist von der eigentlichen Arbeitsmaske (Filme, Bücher, Adressbuch, Musik) losgelöst. Nicht mehr, und nicht weniger.
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Sonntag 19. Juli 2015, 18:12
von jerch
@Sophus: Meh, ich bin raus. Du wirst das schon machen.
Re: Fehler über Messagebox ausgeben lassen [SQLArchemy]
Verfasst: Sonntag 19. Juli 2015, 18:18
von Sophus
@jerch: Ich wollte dich nicht verjagen. Mir ging es nur darum, dass ich mich zuerst auf die Anmeldung konzentriere, nicht auf die Daten-Manipulation. Bei deinem Skript würde es heißen, dass man gleich zur Datenverarbeitung übergeht. Ich möchte erst einmal eine Anmeldung basteln. Wenn die Anmeldung steht, dann kann man mit den Daten immer auf den Server zugreifen. So war das meine Idee. Wenn du also Kritik an meinem Vorab-Skript hast, denn immer her damit. Ich will ja schließlich was lernen. Mir fehlt nämlich der Schritt, wie ich mich über das ORM-Konzept auf eine Datenbank anmelde, denn in meinem Beispiel stütze ich mich noch zu sehr auf die Dialekte.