I've run into an issue with PySide6 that I cannot subclass QSqlDatabase.
My biggest complaint about the QtSql system is that it does not throw exceptions when things go wrong. You have to manually check if things are really open or if there are any errors. So I want to subclass parts of it to automatically throw errors for me.
I asked this same question 5 years ago about PyQt5. That solution (from the venerable @eyllanesc) still works in PyQt6, but not PySide6. Here's a minimal example:
from PySide6.QtWidgets import (QApplication, QMainWindow, QTableView)
from PySide6.QtSql import (QSqlQuery, QSqlQueryModel, QSqlDatabase)
#from PyQt6.QtWidgets import (QApplication, QMainWindow, QTableView)
#from PyQt6.QtSql import (QSqlQuery, QSqlQueryModel, QSqlDatabase)
import sys
class ExceptionalDatabase(QSqlDatabase):
@staticmethod
def addDatabase(*args, **kwargs):
db = QSqlDatabase.addDatabase(*args, **kwargs)
db.__class__ = ExceptionalDatabase
return db
def open(self, user=None, pwd=None):
if user is None:
retval = super(ExceptionalDatabase, self).open()
else:
retval = super(ExceptionalDatabase, self).open(user=user, password=pwd)
if retval == False:
raise ValueError(self.lastError().text())
app = QApplication(sys.argv)
fid = open('example.db', 'w')
fid.close()
db = ExceptionalDatabase.addDatabase("QSQLITE")
db.setDatabaseName('example.db') # throws error that __init__ was not called
db.open()
if db.isOpen():
print('database opened')
else:
print('database did not open')
db.close()
sys.exit(app.exec())
It throws an error when I make the next call after addDatabase:
RuntimeError: 'init' method of object's base class (ExceptionalDatabase) not called.
If I try to explicitly call the __init__ function (db.__init__()), then it complains that I cannot call __init__ twice.
__class__is probably inappropriate, and, from what I can understand, it may also be impossible to do that for a privately instantiated class. Yet, there may be a solution (which seems to be still valid for PySide6) at least based on this old post: Unable to change__class__of PySide.QtGui objects.QSqlDatabasewould be much easier to handle. There will usually be many higher-level functions that need direct access to a database connection, and the natural place for such functions is a database-manager class. Why worry about the type of the database connection itself? What concrete problem is this intended to solve? As the Qt docs state,QSqlDatabaseis a value class, so keeping references to instances is unnecessary (and often undesirable).openfails, I want to throw an exception.open(), then trying to do all that is inefficient: you're only complicating things. As ekhumoro said, you can simply use a manager class, and eventually use similar function names (with similar argument signatures) used as delegates for the actual calls done to the QSqlDatabase when necessary, while keeping in mind the warninsg suggested in the related docs (eg: don't keep a persistent reference to QSqlDatabase unless you know what you're doing).