Zunächst ein paar Anmerkungen zu meiner Umstrukturierung. Ich habe eine Teilung zwischen Session und Engine vorgenommen. Es gibt die ManagedEgine()-Klasse, die nur einmalig aufgerufen wird. In dieser Klasse wird in einem Atemzug die create_engine() und auch der sessionmaker() erstellt. Es sind beides Objekte, die man nur einmal erstellt. Dann haben wir die ManagedSessionScope()-Klasse, die bei Bedarf immer wieder aufgerufen werden kann.
Dann haben wir die MyCustomDialog()-Klasse, die für die View verantwortlich ist. In dieser Klasse sehen wir einmal die log_in_database()-Methode. Klickt der Benutzer auf die Schaltfläche "LogIn" wird er/sie angemeldet. Es wird eine Instanzt der ManagedEgine()-Klasse erstellt und sessionmaker() wird klassenweit in das self.managed_engine-Attribut gespeichert. Nach dem erfolgreichen LogIn klickt der Benutzer auf die Schaltfläche "Daten abfragen" und ruft dadurch die start_all_selection()-Methode auf. Und genau dort habe ich das Problem. Aber dazu komme ich noch.
Darüber hinaus habe ich eine Worker()-Klasse, die durch die aufgerufenen Threads verwaltet werden. In dieser Worker-Klasse sehen wir, dass dort mit der MasterDataManipulation()-Klasse gewerkelt wird.
Un zu guter Letzt haben wir eine MasterDataManipulation() -Klasse, in welcher die ganzen Abfragen und weitere Operatoren (Update, Add, Delete) befinden. Diese Klasse wird bei jedem Thread erneut instanziiert.
Gedankenproblem:
Ich habe bisher die Session deshalb stets an die Threads übergeben, weil die Sessions in den MasterDataManipulation()-Klassen gebraucht werden, in welcher die Operationen stattfinden. Ursprünglich war es so gedacht: Bei jedem Thread-Start wird jeweils eine Instanz von der MasterDataManipulation()-Klasse erstellt, die Sessions werden dorthin übergeben und anschließend werden die Abfragen bearbeitet. Wenn ich das wie __deets__ und snafu mache, dann müsste ich die ganzen Abfragen in meinen Hauptthread (in dem Falle wäre es die GUI-Klasse) verlegen. Jedoch wollte ich es vermeiden, weil ich nicht will, dass die GUI einfriert, wenn die ganzen Abfragen im Hautthread ausgeführt werden. Und genau da liegt mein Gedankenproblem.
Code: Alles auswählen
[...] # All imports are here
[...]
class ManagedEgine(object):
def __init__(self,
dbms=None,
dbdriver=None,
dbuser=None,
dbuser_pwd=None,
db_server_host=None,
dbport=None,
db_name=None,
echo_verbose=True):
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.echo_verbose = echo_verbose
url = '{}+{}://{}:{}@{}:{}/{}'.format(
self.dbms, self.dbdriver, self.dbuser, self.dbuser_pwd, self.db_server_host, self.dbport, self.db_name)
_engine = create_engine(url, echo=self.echo_verbose)
# I have to persist all tables and create them
Base.metadata.create_all(_engine)
# Create the session factory
self.session_factory = sessionmaker(bind=_engine)
class ManagedSessionScope(object):
def __init__(self, engine=None):
self._enginge = engine
self.session = None
self._Session = scoped_session(self._enginge)
def __enter__(self):
self.session = self._Session # this is now a scoped session
# sqlalchemy.orm.scoping.scoped_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()
class MasterDataManipulation(object):
def __init__(self):
def select_all(self, category):
dict_store_session_query = {
'person_gender': lambda: self._session.query(PERSON_GENDER),
[...]
}
try:
for record in dict_store_session_query[category]():
if category == 'person_gender':
yield record.id, record.gender
self._session.commit()
except Exception:
self._session.rollback()
class Worker(QObject):
[...] # Signals are here
def __init__(self,
combo_box=None,
category=None,
time_interval=None,
parent=None):
QObject.__init__(self, parent)
[...]
def init_object(self):
self.timer = QTimer()
master_data_manipulation = MasterDataManipulation(session_object=self.new_scope)
query_data=master_data_manipulation.select_all
self._element = query_data(self.category)
self.timer.setSingleShot(False)
self.timer.setInterval(int(self.time_interval))
self.timer.timeout.connect(self.populate_item)
self.timer.start()
[...]
class MyCustomDialog(QDialog):
[...] Here are some signals
def __init__(self, parent=None):
QDialog.__init__(self, parent)
[...]
self.managed_engine = None
[...]
def log_in_database(self):
# User wants to program to log in
dbms ="mysql"
dbdriver="pymysql"
dbuser="root"
dbuser_pwd="xxx"
db_server_host="localhost"
dbport=3306
db_name="test"
echo_verbose=True
try:
managed_engine = ManagedEgine(dbms=dbms,
dbdriver=dbdriver,
dbuser=dbuser,
dbuser_pwd=dbuser_pwd,
db_server_host=db_server_host,
dbport=dbport,
db_name=db_name,
echo_verbose=echo_verbose)
self.managed_engine = managed_engine.session_factory
except SQLAlchemyError:
desired_trace = format_exc(exc_info())
print "desired_trace", desired_trace
def start_thread(self,
combo_box=None,
session=None,
time_interval=None,
category=None):
task_thread = QThread(self)
task_thread.work = Worker(new_scope=session,
time_interval=time_interval,
category=category,
combo_box=combo_box)
task_thread.work.moveToThread(task_thread)
[...]
task_thread.started.connect(task_thread.work.init_object)
[...]
[...]
def start_all_selection(self):
[...]
list_tuple = [
("person_salutation", self.combo_person_salutation),
("person_title", self.combo_person_title),
("person_gender", self.combo_person_gender),
("person_religion", self.combo_person_religion),
("person_eye_color", self.combo_person_eye_color),
("person_hair_color", self.combo_person_hair_color),
("person_relationship_status", self.combo_person_relationship_status),
("person_nationality", self.combo_person_nationality)
]
try:
#with ManagedSessionScope(engine=self.managed_engine) as session_that_scoped:
# Here we don't want to share one session with other threads
# What should I do?
for category, combobox in list_tuple:
combobox.clear()
self.start_thread(combo_box=combobox,
session=session_that_scoped,
time_interval=100,
category=category)
except SQLAlchemyError as err:
[...] # Do stuff with Exception
except OperationalError as OpErr:
[...] # Do stuff with Exception