ich habe ein kleines Problem mit der gedanklichen Ordnung. Fangen wir erst einmal an. Wir sehen hier zwei Klassen, die diesen Context-Manager-Protokoll unterstützen. Soweit so gut. Was habe ich nun vor? Ich möchte (wie man anhand der View-Klasse sieht) dem Benutzer die Möglichkeit geben, dass er/sie sich komplett von der Datenbank abmelden kann. Das Programm muss aber nicht geschlossen werden. Kann ja sein, dass er sich denkt: "Arbeite später mal weiter, muss jetzt schwimmen gehen". Nur alle Verbindungen sollen also geschlossen werden. Daher habe ich einmal die Engine und die Session in zwei separate Klassen untergebracht. In Zeile 135 bis 139 sehen wir, dass mit der with-Anweisung ein Engine-Objekt erzeugt wird, und anschließend wird ein Session-Objekt erzeugt, das dann das Engine-Objekt übergeben bekommt.
Jetzt kommen wir zum Problem. In meinem Beisiel möchte ich simulieren, dass die Verbindung solange aufrecht erhalten wird, bist die with-Anweisung verlassen wird. Dies soll geschehen, sobald der Benutzer auf "Abmelden" oder "Disconnect" klickt. Bis dahin wird die with-Anweisung der Engine durch die While-Schleife aufrecht erhalten. Wie und wo bringe ich die Engine unter, damit diese während der Arbeit nicht blockiert? Denn ich muss ja auch bedenken, dass ich an unterschiedlichen Stellen meines Programms (wir stellen uns mehrere Eingabefenster vor) die Session brauche. Das heißt, ich stehe jetzt vor dem Überlegungs-Problem. Wie kriege ich diese beiden Klassen unter deinem Hut, so dass die While-Schleife niemanden blockiert, und damit ich auch während dessen mit der Session an verschiedenen Stellen arbeiten kann?
Ich hoffe, ich konnte mein Problem halbwegs erklären.
Code: Alles auswählen
from sys import argv
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.exc import SQLAlchemyError
from PyQt4.QtCore import QObject, pyqtSignal, QThread, Qt
 
from PyQt4.QtGui import QDialog, QApplication, QPushButton, \
     QLineEdit, QFormLayout, QTextEdit 
 
class SessionScope(object):
    def __init__(self, engine):
        self.engine = engine
        # store a sessionmaker for this db connection object
        self._Session = sessionmaker(bind=self.engine)
        self.session = None
    def __enter__(self):
        self.session = self._Session()
        return self._Session()
    
    def __exit__(self, exception, exc_value, traceback):
        try:
            if exception:
                self.session.rollback()
            else:
                self.session.commit()
        finally:
            self.session.close()
            self.session = None
            
class Engine(object):
    def __init__(self, dbms=None, dbdriver=None,
                 dbuser=None, dbuser_pwd=None,
                 db_server_host=None, dbport=None, db_name=None):
        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
        
        url = '{}+{}://{}:{}@{}:{}/{}'.format(
           self.dbms, self.dbdriver, self.dbuser, self.dbuser_pwd, self.db_server_host, self.dbport, self.db_name)
        self._Engine = create_engine(url, encoding='utf8', echo=True)
    def __enter__(self):
        return self._Engine
    
    def __exit__(self, exception, exc_value, traceback):
        '''
            Make sure the dbconnection gets closed
        '''
        self._Engine.dispose()
class Form(QDialog):
    finish = pyqtSignal()
    test_it = pyqtSignal()
    
    def __init__(self, parent=None):
        QDialog.__init__(self, parent)
        self.engine = None
        self.logged_in = True
        
        self.init_ui()
    def init_ui(self):
        self.db_localhost = QLineEdit()
        self.db_localhost.setText("localhost")
        
        self.db_user = QLineEdit()
        self.db_user.setText("root")
        
        self.db_user_pwd = QLineEdit()
        self.db_user_pwd.setText("password")
        
        self.db_name = QLineEdit()
        self.db_name.setText("test")
        
        self.db_port = QLineEdit()
        self.db_port.setText("3306")
        self.text_edit_status = QTextEdit()
        
        self.pushButton_connection = QPushButton()
        self.pushButton_connection.setText("Connect") 
        
        self.pushButton_disconnection = QPushButton()
        self.pushButton_disconnection.setText("Disconnect")
        self.pushButton_close = QPushButton()
        self.pushButton_close.setText("Close")
        
        layout = QFormLayout()
        layout.addWidget(self.db_localhost)
        layout.addWidget(self.db_user)
        layout.addWidget(self.db_user_pwd)
        layout.addWidget(self.db_name)
        layout.addWidget(self.db_port)
        layout.addWidget(self.text_edit_status)
        
        layout.addWidget(self.pushButton_connection)
        layout.addWidget(self.pushButton_disconnection)
        layout.addWidget(self.pushButton_close)
        
        self.setLayout(layout)
        self.setWindowTitle("Log In")
        self.init_signal_slot_pushButton()
         
    def log_in(self):
        try:
            self._engine = Engine(dbms='mysql',
                                 dbdriver='pymysql',
                                 dbuser=unicode(self.db_user.text()),
                                 dbuser_pwd=unicode(self.db_user_pwd.text()),
                                 db_server_host=unicode(self.db_localhost.text()),
                                 dbport=unicode(self.db_port.text()),
                                 db_name=unicode(self.db_name.text()))
            
            self.text_edit_status.setText("Connecting to the database... please wait!")
            
            with self._engine as engine:
                while logged_in:
                    with Session(engine) as session:
                        pass
                        # do_stuff()
            
        except TypeError as err:
            self.text_edit_status.setText((str(err)))
        
    def log_out(self):
        pass
    def init_signal_slot_pushButton(self):
        self.pushButton_connection.clicked.connect(self.log_in)
        
        self.pushButton_disconnection.clicked.connect(self.log_out)
        
        self.pushButton_close.clicked.connect(self.close)
    def button_click(self):
        pass
app = QApplication(argv)
form = Form()
form.show()
app.exec_()
