SQLAlchemy: Session richtig verstehen

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.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Den Teil mit der Erzeugung der URL kannst du übrigens einfacher haben, wenn du die übergebenen Argumente ohnehin als Instanzattribute bindest:

Code: Alles auswählen

class DatabaseConnection(object):
    def __init__(self, dbms, dbdriver, dbuser, dbuser_pwd, db_server_host, dbport, db_name):

        self.dbms = dbms
        self.dbdriver = dbdriver
        self.dbuser = dbuser
        self.dbuser_pwd = dbuser_pwd
        self.db_server_host = db_server_host
        self.dbport = dbport
        self.db_name = db_name
       
        self.url = '{.dbms}+{.dbdriver}://{.dbuser}:{.dbuser_pwd}@{.db_server_host}:{.dbport}/{.db_name}'.format(self)
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@snafu: In meinem konkreten Beispiel wird ja die Verbindung in der DatebaseConnection()-Klasse eingerichtet. Herrgestellt wird ja erst eine Verbindung, wenn eine Abfrage abgesetzt wird, da das Session()-Objekt et dann die Verbindung aufbaut. Wie dem auch sei. Auf meiner View-Seite (auch GUI genannt) kann ich schlecht eine Exception abfangen. Denn die DatebaseConnection()-Klasse wirft ja keine Fehlermeldung bei falscher Eingabe zurück.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Sophus hat geschrieben:Denn die DatebaseConnection()-Klasse wirft ja keine Fehlermeldung bei falscher Eingabe zurück.
In `__init__()` fängst du doch selber den möglicherweise auftretenden `SQLAlchemyError` ab. Wenn du dieses Abfangen weglässt, dann wird der Fehler automatisch hochgereicht und die Klasseninstanz wird infolgedessen nicht erzeugt. Das macht ja IMHO auch Sinn, weil mit einer `DatabaseConnection()`-Instanz, die keine erfolgreiche Verbindung herstellen konnte, wohl wenig anzufangen ist. Man würde den Anwender dann über die GUI bitten, die Angaben zu korrigieren und eine Istanziierung der `DatabaseConnection()` mit den korrigierten Angaben vornehmen.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@snafu: Manchmal brauche ich eine Weile, bis ich etwas verstehe. Ich habe es eben einfach mal ausprobiert und dir vertraut. Ich habe mit Absicht falsche LogIn-Daten eingegeben und tatsächlich. Ich konnte auf der Seite der GUI die Fehler abfangen. Danke dir.

Da ich allerdings auf der GUI-Seite kein SQLAlchemy importieren möchte, habe ich meine Try/Exeption wie folgt konstruiert:

Code: Alles auswählen

    def db_login_access_data(self, dbm_system, dbm_driver, db_user,
                 db_passwd, db_host, db_port, db_name):
        try:
            self.db_connection = DatabaseConnection(dbm_system, dbm_driver, db_user,
                                                db_passwd, db_host, db_port, db_name)
            return True
        except Exception as Err:
            print "MyEX", Err
            return Err[0]
Ich weiß, dass Exception eine Art Basis-Klasse ist, um alle Exceptions abzufangen. Sollte man nicht machen. Denn genauso gut könnte ich auch eine nackte Exception benutzen. Da ich aber nicht explizit SQLAlchemyError abfangen kann, erschien mir das als mögliche Lösung?
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

@Sophus:
Dieses Stochern hilft doch nicht weiter. Bitte lies Dir die Grundlagen an - was Exceptions sind, wie sie sich verhalten und was hieraus die Implikationen für den korrekten Umgang damit sind.
Sophus hat geschrieben:Da ich allerdings auf der GUI-Seite kein SQLAlchemy importieren möchte, habe ich meine Try/Exeption wie folgt konstruiert:
Ja und warum möchtest Du das dort nicht importieren? Hast Du Angst, das der Namensraum "dreckig" wird? Ich frage das, weil sowas bei Dir schon öfter durchklang. Auch müsstest Du hierfür nicht alles von Sqlalchemy importierten sondern nur den Exceptiontypen, welchen Du dort SINNVOLL behandeln kannst. ALLES ANDERE BLEIBT UNBEHANDELT. Deine Dummy-print-Exception-Behandlungen machen Dir das Leben nicht leichter sondern schwerer.
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@jerch: Das Wort "dreckig" trifft es gut. Ich hatte gehofft, dass ich den Namensraum nicht zukleistern muss. Aber gut, dann setze ich noch einen weiteren Kandidaten in den Namensraum. Danke dir.
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Jetzt verlagerst du das Abfangen der Exception, ohne etwas sinnvolles damit zu tun, an eine andere Stelle im Code.

Worin besteht für dich das Problem, die Exception erst dort abzufangen, wo du sie in der GUI als Fenster mit Fehlermeldung ausgeben kannst?

Mal ganz direkt gesagt: Das Konstrukt ``except SomeError as err: return err[0]`` ist fast immer eine schlechte Idee. Falls es dir darum geht, den Code zum Erstellen der Fehlermeldung in der GUI auslagern willst, dann reiche besser das komplette Exception-Objekt weiter:

Code: Alles auswählen

try:
    # was auch immer
except SomeError as error:
    show_error_message(error)
    # alternativ: Übergabe der Meldung als String
    show_error_message(str(error))
Der Punkt ist, die Rückgabe irgendwelcher Fehlerwerte zu vermeiden. Das ist in Sprachen mit eingebauten Exceptions einfach unschön.
jerch
User
Beiträge: 1669
Registriert: Mittwoch 4. März 2009, 14:19

Sophus hat geschrieben:Ich hatte gehofft, dass ich den Namensraum nicht zukleistern muss.
Die Sorge dürfte unbegründet sein, ein Namesraum hat nicht nur 4 Wände wo jeweils nur ein Wort draufpasst ;)
Benutzeravatar
Sophus
User
Beiträge: 1109
Registriert: Freitag 25. April 2014, 12:46
Wohnort: Osnabrück

@↓snafu: Besten dank für den Hinweis. Ich habe deinen Rat gefolgt:

Code: Alles auswählen

    def create_generally_msg(self, err_msg):
        from xarphus.core.manage_qt import custom_message_box
        mBox = custom_message_box(self, err_msg[0], self.tr('Fehler'), QMessageBox.Critical)
        setIc_OK = QIcon(self.check_icon)
        mBox.addButton(
            QPushButton(setIc_OK, self.tr(" Ok")),
            mBox.AcceptRole) # An "OK" button defined with the AcceptRole

        mBox.exec_()    # QDialog.exec_ is the way that it blocks window
        # execution and allows a developer to wait for user
        # input before continuing.

    def db_login_access_data(self, dbm_system, dbm_driver, db_user,
                 db_passwd, db_host, db_port, db_name):
        try:
            self.db_connection = DatabaseConnection(dbm_system, dbm_driver, db_user,
                                                db_passwd, db_host, db_port, db_name)
            return True
        except SQLAlchemyError as Err:
            self.create_generally_msg(str(Err))
Anmerkung: Ich kreiere mir meine eigene Messagebox, mit eigenen Buttons etc. Ich habe das Import mit Absicht in die Funktion gepackt, damit es für euch nachvollziehbarer ist, woher custom_message_box() stammt.

Und aussehen tut das so:
Bild
Benutzeravatar
snafu
User
Beiträge: 6740
Registriert: Donnerstag 21. Februar 2008, 17:31
Wohnort: Gelsenkirchen

Streng genommen ist die Rückgabe von `True` auch wieder unnötig. Warum nimmst du nicht einfach eine Endlosschleife, die solange nach den Benutzereingaben fragt bis erfolgreich eine `DatabaseConnection` erzeugt und zurückgegeben werden konnte?

Falls der Anwender dabei auch auf "Abbrechen" drücken darf, dann wäre das ja auch über eine Art ``while not cancelled:`` möglich.

EDIT: Wobei das wohl eine Stilfrage ist, ob man eine Endlosschleife mit Abbruchmöglichkeit baut, oder ob man quasi schon nach dem ersten Mal aufgibt und dem Anwender die freie Entscheidung überlässt, ob er es erneut versuchen möchte. Jedenfalls finde ich die Rückgabe eines sinnvollen Objektes als Resultat besser als ein bloßes `True`. Denn um zu signalisieren, dass etwas *nicht* funktioniert hat, nutzt man - wie schon zigmal geschrieben - in Python üblicherweise Exceptions anstelle von Wahrheitswerten.
Antworten