1

what I am trying to do with a python script: Use a pytest test method to print a text line to a label in the pyqt GUI.

When running the main python file, the GUI starts and a click on the "test" button runs the test without blocking the GUI (see full code example below). But I have no clue how to proceed now.

Code:

import sys

import pytest
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget


class Window(QtWidgets.QMainWindow):
    signal_start_background_job = QtCore.pyqtSignal()

    def __init__(self):
        super(Window, self).__init__()

        layout = QVBoxLayout()
        self.button = QtWidgets.QPushButton("test", self)
        self.label = QtWidgets.QLabel("console output")
        layout.addWidget(self.button)
        layout.addWidget(self.label)
        widget = QWidget()
        widget.setLayout(layout)
        self.setCentralWidget(widget)

        self.worker = WorkerObject()
        self.thread = QtCore.QThread()
        self.worker.moveToThread(self.thread)

        self.signal_start_background_job.connect(self.worker.background_job)
        self.button.clicked.connect(self.start_background_job)

    def start_background_job(self):
        self.thread.start()
        self.signal_start_background_job.emit()


class WorkerObject(QtCore.QObject):
    @QtCore.pyqtSlot()
    def background_job(self):
        pytest.main(["-s", "-k test_something"])


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())


def test_something():
    print("unit test some stuff")
    assert 0 == 0
TylMH
  • 55
  • 1
  • 2
  • 7

2 Answers2

1

Instead of using pytest directly you could use QProcess to launch it and then capture the output:

import os
import sys

from PyQt5 import QtWidgets, QtCore
from PyQt5.QtWidgets import QApplication, QVBoxLayout, QWidget

CURRENT_DIR = os.path.dirname(os.path.realpath(__file__))


class Window(QtWidgets.QMainWindow):
    def __init__(self):
        super(Window, self).__init__()

        self.button = QtWidgets.QPushButton("test", self)
        self.label = QtWidgets.QLabel("console output")
        self.textedit = QtWidgets.QTextEdit(readOnly=True)

        widget = QWidget()
        layout = QVBoxLayout(widget)
        layout.addWidget(self.button)
        layout.addWidget(self.label)
        layout.addWidget(self.textedit)
        self.setCentralWidget(widget)

        self.process = QtCore.QProcess()
        self.process.setProgram(sys.executable)
        self.process.readyReadStandardError.connect(self.on_readyReadStandardError)
        self.process.readyReadStandardOutput.connect(self.on_readyReadStandardOutput)

        self.button.clicked.connect(self.on_clicked)

    @QtCore.pyqtSlot()
    def on_clicked(self):
        self.process.setWorkingDirectory(CURRENT_DIR)
        self.process.setArguments(["-m", "pytest", "-s", "-k", "test_something"])
        self.process.start()

    @QtCore.pyqtSlot()
    def on_readyReadStandardError(self):
        err = self.process.readAllStandardError().data().decode()
        self.textedit.append(err)

    @QtCore.pyqtSlot()
    def on_readyReadStandardOutput(self):
        out = self.process.readAllStandardOutput().data().decode()
        self.textedit.append(out)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Window()
    window.show()
    sys.exit(app.exec_())
eyllanesc
  • 235,170
  • 19
  • 170
  • 241
0

I'm thinking you need to check out sys.stdout, and route that to an io object that you can route to the label in your widget. Then I would set a timer and every 0.1 seconds or so set the text of your label to that object. Alternatively you can implement a widget that grabs the stdout text in qt, example here: https://stackoverflow.com/a/1220002/6615517 I haven't tried it but the other answers to that question should help. You'll probably want to clear the label on each test to prevent it from getting too long.

rwalroth
  • 320
  • 2
  • 10