Reputation: 63
So I'm writing an application using PySide2 that shall redirect everything from stdout
to an intermediate queue.Queue
. That Queue
emits a signal that will be processed by a QThread, appending all strings in the queue to a QTextEdit.
I have looked around SO quite a bit but unfortunately nothing really seems to work for me.
That's the code I'm referring to.
from PySide2 import QtWidgets, QtGui, QtCore
import sys
from queue import Queue
class WriteStream(object):
""" Redirects sys.stdout to a thread-safe Queue
Arguments:
object {object} -- base class
"""
def __init__(self, queue):
self.queue = queue
def write(self, msg):
self.queue.put(msg)
def flush(self):
""" Passing to create non-blocking stream (?!)
https://docs.python.org/3/library/io.html#io.IOBase.flush
"""
pass
class WriteStreamThread(QtCore.QThread):
queue_updated = QtCore.Signal(str)
def __init__(self, queue):
super(WriteStreamThread, self).__init__()
self.stop = False
self.queue = queue
def set_stop(self):
self.stop = True
self.wait() # waits till finished signal has been emitted
def run(self):
while not self.stop: # i guess this is blocking
msg = self.queue.get()
self.queue_updated.emit(msg)
self.sleep(1) # if commented out, app crashes
self.finished.emit()
class Verifyr(QtWidgets.QMainWindow):
def __init__(self, queue, parent=None):
super(Verifyr, self).__init__(parent)
self.centralwidget = QtWidgets.QWidget(self)
layout = QtWidgets.QVBoxLayout(self.centralwidget)
self.textedit = QtWidgets.QTextEdit(self)
layout.addWidget(self.textedit)
self.setLayout(layout)
self.setCentralWidget(self.centralwidget)
print("Verifyr initialised...")
self.listener_thread = WriteStreamThread(queue)
self.listener_thread.queue_updated.connect(self._log_to_qtextedit)
self.listener_thread.start()
@QtCore.Slot(str)
def _log_to_qtextedit(self, msg):
self.textedit.insertPlainText(msg)
if __name__ == '__main__':
# create Queue to be passed to WriteStream and WriteStreamListener
queue = Queue()
# redirect stdout to WriteStream()
sys.stdout = WriteStream(queue)
print("Redirected sys.stdout to WriteStream")
# launching the app
app = QtWidgets.QApplication(sys.argv)
window = Verifyr(queue)
app.aboutToQuit.connect(window.listener_thread.set_stop)
window.show()
sys.exit(app.exec_())
In WriteStreamThread
I'm using a while
loop that keeps emitting signals, caught by the main application to append to its QTextEdit. When I comment out the self.sleep(1)
the application ill be stuck in an infinite loop. If not the thread will exit out just fine.
Can somebody please explain this to me?
UPDATE:
like I mentioned in my comment I've found the bug... here's the updated run()
method of WriteStreamThread
:
def run(self):
while not self.stop:
try:
msg = self.queue.get(block=False) # nasty little kwarg
except:
msg = "No items in queue. Sleeping 1sec.."
self.sleep(1)
self.queue_updated.emit(msg)
self.finished.emit() # optional
Upvotes: 0
Views: 370
Reputation: 63
I found the bug. It was queue.get()
in the run()
method of WriteStreamThread
that was blocking.
Changing it to queue.get(block=False)
and surrounded with try/catch does the job.
Stupid me...
Upvotes: 1