No traceback output to console for exceptions raised inside thread
I have a problem with the
PySide2- when the exception is raised in some thread which is not the GUI thread, no traceback is printed to the console which makes debugging really hard. I have tried to set a custom excepthook method but did not help. It works well when using the
PyQt5. What am I doing wrong?
PySide2 - 5.12.3and
Python 3.6.6on the
Linux Mint 19system.
Here is the code snippet:
import sys from traceback import print_exception from PySide2 import QtCore, QtWidgets class MyThreadWorker(QtCore.QObject): def job_with_exception_raised(self): print("This code is reached, but exception traceback is not printed.") raise Exception('Exception!!!!') class MyWidget(QtWidgets.QWidget): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.worker = MyThreadWorker() self.worker_thread = QtCore.QThread() self.worker.moveToThread(self.worker_thread) self.worker_thread.started.connect(self.worker.job_with_exception_raised) self.worker_thread.start() def excepthook(type_, value, traceback): print_exception(type_, value, traceback) if __name__ == '__main__': sys.excepthook = excepthook app = QtWidgets.QApplication(sys.argv) w = MyWidget() w.show() sys.exit(app.exec_())
What you are describing is a common problem with multi-threaded program debugging. Often, the call stack is only valid for the main thread of execution. It is often hit-or-miss whether the call stack of indivual threads is available.
The subject deserves research, but alas, I usually experience the problem you describe.
@nekitamtip what I would do is not rely on the call stack as @Kent-Dorfman points out its unreliable at best and not available due to threading issues (now that does not mean it cannot be just means it would take a lot of work and time to figure it out if it is even possible). So with that said and a much easier methodology for handling this in code regardless of the coding language you use here is what I do.
Any place you plan to "raise" an error or handle an exception include enough information so that you can easily determine where that error occurred along with what that error was. In your example I would change the raise to read:
raise Exception('MyTreadWorker.job_with_exception_raised :' + error_message)
This basically (at a glance) tells you where the error occurred in detail and if the error was dynamic what that error was -- note if the error is static then simply replace [ ' + error_message ] with [ Description of Error ' ] again do this any place you raise an error and/or use a try except -- further I would actually call an error_handler routine in case I want to switch from live debugging to production debugging and want those errors posted to an error-log of some sort.
Basically it is considered quality programming that when you raise an error or handle an exception that you report enough information back so that with that error message you (1) Know exactly where the error occurred (2) Know exactly what the error was (3) and include any extra information that might be available that would make fixing that error much easier
If you do this as a standard within all your code you will soon find out that tracking done bugs becomes a trivial task.