I've created an GUI app in PyQt, which I want to share with many people. Sometimes I get unexpected exceptions and I take it for granted - after every exception I improve my code and it gets better and better.
I use a logger for recording these exceptions and special hook for PyQt silenced exceptions. My code looks like this:
Logger
def setLogger(level=logging.DEBUG,
name="my_logger",
file=join("src", "log.out")):
logger = logging.getLogger(name)
logger.setLevel(level)
# console logger
ch = logging.StreamHandler()
console_lvl = logging.DEBUG
ch.setLevel(console_lvl)
formatter = logging.Formatter('%(message)s')
ch.setFormatter(formatter)
#file logger
fh = logging.FileHandler(file)
fh.setLevel(level)
formatter = logging.Formatter(
'%(asctime)s :: %(name)s - %(message)s',
datefmt='%m/%d/%Y %I:%M:%S %p')
fh.setFormatter(formatter)
logger.addHandler(ch)
logger.addHandler(fh)
return logger
2 typical classes in GUI
class MainWindow(QtGui.QMainWindow):
def __init__(self):
self.logger = setLogger(name='main_window')
[...]
class UploadDialog(QtGui.QDialog):
def __init__(self):
self.logger = setLogger(name='upload_dialog')
[...]
and so on
PyQt has its silenced exceptions - exception occurs but program keeps running. I use the special hook for this situation (have seen it somewhere, this is not my code)
import sys
sys._excepthook = sys.excepthook
def exception_hook(exctype, value, traceback):
sys._excepthook(exctype, value, traceback)
sys.exit(1)
And now I want to grab any exception, so the users of my program in case of any crash could just send me their log.out and I would see the full log.
I've started from something like this.
try:
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
except Exception:
logger.exception("MainWindow exception")
I worked well, until an exception was raised inside UploadDialog. Nothing was 'recorded'. So I just did:
#inside MainWindow class
def runDialog(self):
try:
dialog = UploadDialog()
dialog.exec_()
except Exception:
self.logger.exception("Dialog exception")
sys.exit(1)
Again, everything was OK, until an exception was rised inside WorkThread (Inherited from QThread class for background upload). And again.
#inside UploadDialog
def upload(self):
# initialized as self.task = WorkThread()
try:
self.task.start()
except Exception:
self.logger.exception("Exception in WorkThread")
And then an exception was raised not after start of WorkThread but when initializing, so
class UploadDialog(QtGui.QDialog):
def __init__(self):
try:
self.task = WorkThread()
except Exception:
self.logger.exception("Exception in WorkThread")
And here I just took my head and screamed to myself - "STOP IT. YOU'RE DOING IT WRONG. It's not pythonic, it's dirty, it makes my eyes bleed".
So, I'm asking - is there any elegant and pythonic way to grab ABSOLUTELY any exception, raised in PyQt app with one try...except
block?