Catch a worker thread's exception in main thread - python

I have a very similar problem with this post, but in Python.
I have a GUI with Pyqt5 as the main thread (e.g. gui.py) and a worker thread in a different python code (e.g. worker.py). The code in the worker.py can raise exceptions, such as FileNotFoundError. I need the main thread to catch these exceptions, stops the worker thread, and show the error message in a QMessageBox with an OK button. When the OK Button is pressed, the QMessageBox is closed and the app is restarted.
What I have tried so far:
Make a QMessagebox in worker.py as the error handling --> QMessagebox shows the error, but then the whole app is terminated. I assume because the main thread is a while True Loop and it is forced to stop
Make an Exception Hook using this tutorial --> A QMessagebox is shown without the error message and the whole app freezes.
I read this post, however I still don't understand how to put the exception of the worker thread in a bucket then connect it to the main thread, if the worker and main thread not in the same python file.

Related

QMessage in a function thread? [duplicate]

This question already has answers here:
In PyQt, what is the best way to share data between the main window and a thread
(1 answer)
Background thread with QThread in PyQt
(7 answers)
Example of the right way to use QThread in PyQt?
(3 answers)
Closed 3 months ago.
I want to do a popup when the function in a thread finish but when it run the popup the program crash. I tried doing a thread in the main function thread but crash the app.
I put a large and slow funtion in a thread to not crash the GUI but I want when this slow function finish, run a popup with QMessageBox, my sollution work but when I press the 'Ok' button in the popup crash the program, but I dont want that, so I tried to make a thread from the main thread but do the same, only crash the program.
I want something like this:
def popup():
msg = QMessageBox()
msg.setWindowTitle("Alert")
...
a = msg.exec_()
def slow_func():
time.sleep(10) # exemple of slow
popup() # when I press 'Ok' crash so I tried...
# I tried...
def slow_func():
time.sleep(10) # exemple of slow
threading.Thread(target=popup).start() # still crashing
threading.Thread(target=slow_func).start()
I don't know how to do it, I tried a thread in a thread but still crashing when I press 'Ok' button. The popup works but crash the app when I press 'Ok'
I'm in Windows 11 using python 3.10 and PyQt 5.15
You must not use any GUI functions outside of the main thread. So you can not call popup() from your calculation thread and you can't create a new thread in your calculation thread and have that call it. You must make the main thread call it.
For possible solutions see How to properly execute GUI operations in Qt main thread?
In short: Use the signal-slot-mechanism or QMetaObject::invokeMethod()

Python- executing code lines after host force closing [duplicate]

I have a python 3 script and it runs on boot. And it work with some resources I want it free on exit.
How can I manage that script is going to exit if I'm killing it with kill -6 $PID.
Or any other ideas about how to send exit command and detect it in script.
The signal module is what you are looking for.
import signal
def handler(signum, frame):
print('Signal handler called with signal', signum)
signal.signal(signal.SIGABRT, handler)
Within the handler function you could terminate with sys.exit().
However, it is more common to use SIGINT (that's what happens when you press CTRL+C in the terminal) or SIGTERM to terminate a program. If you don't have cleanup code you don't need to write a single line of code to handle SIGINT - by default it raises a KeyboardInterrupt exception which, if not caught (that's a reason why you should never use blank except: statements), causes your program to terminate.

Threading in GTK3 python

I'm building a GTK GUI in Python and I need to get some data from the database which takes quite long, so the GUI freezes.
So I'm now using Threads to run the refreshing "in the background":
Thread(target=self.updateOrderList).start()
I have GUI class with alle relevant methods to manipulate the GUI. My solution work 80% of the time, but when it doesn't GTK crashed and it outputs this:
[xcb] Unknown request in queue while dequeuing
[xcb] Most likely this is a multi-threaded client and XInitThreads has not been called
[xcb] Aborting, sorry about that.
python3.6: ../../src/xcb_io.c:165: dequeue_pending_request:
The other times it works good, the data get loaded and its refreshing the gui.
edit: Sometimes I get this error:
Gdk-Message: 11:13:42.848: main.py: Fatal IO error 11 (Die Ressource ist zur Zeit nicht verfügbar) on X server :0
Sometimes I click the refresh button several times and it works, but then it doesn't at some point.
My main.py looks like this:
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk, GObject
import gui
GObject.threads_init()
# start gui
gui.Gui()
Gtk.main()
Any ideas whats happening here?
Markus
Okay, GTK3 is not threadsafe. So I changed the program logic - doing requests in a new thread, and handling the GUI manipulation in the GUI thread ONLY. So that means I have to emit a "requests done" signal to the event loop:
Creating a new signal and registering it:
GObject.signal_new("my-custom-signal", self.window, GObject.SIGNAL_RUN_LAST, GObject.TYPE_PYOBJECT,
(GObject.TYPE_PYOBJECT,))
self.window.connect("my-custom-signal", self.updateOrderListCallback)
So when I click a button, start a thread:
Thread(target=self.updateOrderListThread).start()
In that thread, do the calculations, and then emit the signal:
self.window.emit("my-custom-signal", None)
so than the callback will be called after the calculations/requests/whatever are done and it works!

Python detect kill request

I have a python 3 script and it runs on boot. And it work with some resources I want it free on exit.
How can I manage that script is going to exit if I'm killing it with kill -6 $PID.
Or any other ideas about how to send exit command and detect it in script.
The signal module is what you are looking for.
import signal
def handler(signum, frame):
print('Signal handler called with signal', signum)
signal.signal(signal.SIGABRT, handler)
Within the handler function you could terminate with sys.exit().
However, it is more common to use SIGINT (that's what happens when you press CTRL+C in the terminal) or SIGTERM to terminate a program. If you don't have cleanup code you don't need to write a single line of code to handle SIGINT - by default it raises a KeyboardInterrupt exception which, if not caught (that's a reason why you should never use blank except: statements), causes your program to terminate.

How to run separate threads in pygtk

I have a pygtk application which runs as soon as my python script is opened. Along with gtk.main() I have a thread which is started at the beginning of the script, which refreshes a gtk.TextView() instance:
def listen(self):
while True:
print "refreshing"
data = self.socket.recv(buffer_size)
if data:
self.txtBuffer.insert(self.txtBuffer.get_end_iter(), data + "\n")
print data
thread.start_new_thread(self.listen, ())
self.set_up_gui() # gtk.main()
However, when I run the program, the gui opens, but no "refreshing" text is printed, nor is any data printed when sent to the socket. I have attempted to use glib.add_idle() to thread this program, however that only runs the separate thread when the gui is idle (which is infrequent). Thank you!
You are accessing the text buffer from a different thread without any synchronization, which is unsupported. To fix that, replace self.txtBuffer.insert(...) with gobject.idle_add(lambda: self.txtBuffer.insert(...)). That tells the GUI thread to update the text buffer at the next main loop iteration, which is guaranteed to work without explicit synchronization.
You should make sure that the GUI thread is not blocked, i.e. that it's running gtk.main() and only processing GUI updates such as the above textBuffer.insert. Long-running/blocking tasks should be delegated to other threads or processes, as your code already tries to do. When this is implemented, GUI updates will appear to happen instantaneously.
See this answer for additional details on PyGTK and threading.

Categories