Home > front end >  QCoreApplication.postEvent(receiver, event) give good result only with input function
QCoreApplication.postEvent(receiver, event) give good result only with input function

Time:09-17

To perform unitary tests on the following part of a code (I use ... to replace unnecessary things to simplify)

from PyQt5.QtWidgets import QWidget, QLineEdit

// ...

class Controller(QWidget):
    def __init__(self, ...)
        // ...
        self.line_edit_name = QLineEdit()
        // ...
    def display_parameters(self, name, ...)
        self.line_edit_name.setText(name)
            self.line_edit_name.setReadOnly(False)
            self.line_edit_name.returnPressed.connect(
                partial(self.update_name, ...))
    def update_name(self, ...):
        // ...

I use this piece of code for tests using unittest:

from PyQt5 import QtCore, QtGui
from PyQt5.QtCore import QCoreApplication, QEvent
// ...
a = Controller()
a.line_edit_name.setText("Shakespeare")
keyEvent = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Return, QtCore.Qt.NoModifier)
QCoreApplication.postEvent(a.line_edit_name, keyEvent)
// ...

it worked very well during the debugging phase (I use input('foo') a lot to introspect and see step by step what is going on) ... But if I remove the input function it doesn't work anymore !!!!

In summary: the following script gives the right result

    a = Controller()
    a.line_edit_name.setText("Shakespeare")
    keyEvent = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Return, QtCore.Qt.NoModifier)
    QCoreApplication.postEvent(a.line_edit_name, keyEvent)
    input("foo")
    //...

the following not

    a = Controller()
    a.line_edit_name.setText("Shakespeare")
    keyEvent = QtGui.QKeyEvent(QtCore.QEvent.KeyPress, QtCore.Qt.Key_Return, QtCore.Qt.NoModifier)
    QCoreApplication.postEvent(a.line_edit_name, keyEvent)
    // ...

Because unit tests are done automatically during continuous integration we cannot use the input function. Why this result and how to do without input function?

Edit: By doing various tests I think that the input() function just allows processes to finish before the next command. I tried just after QCoreApplication.postEvent(a.line_edit_name, keyEvent), in place of input("foo"), threading.Event().wait(1) or time.sleep(1) without success ...

CodePudding user response:

In Qt, the task of sending the event and invoking the slots associated with signals is asynchronous, so do not expect to get a response instantly, but you must wait. In this case you must use QTest.qWait.

Since you do not provide an MRE then I will only show a simple demo:

from functools import partial

from PyQt5.QtCore import QCoreApplication, QEvent, Qt
from PyQt5.QtGui import QKeyEvent
from PyQt5.QtWidgets import QApplication, QFormLayout, QLineEdit, QWidget
from PyQt5.QtTest import QTest


class Controller(QWidget):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.current_name = ""
        self.line_edit_name = QLineEdit()
        lay = QFormLayout(self)
        lay.addRow("name", self.line_edit_name)

    def display_parameters(self, name):
        self.line_edit_name.setText(name)
        self.line_edit_name.setReadOnly(False)
        self.line_edit_name.returnPressed.connect(partial(self.update_name, name))

    def update_name(self, name):
        self.current_name = name


def test_controller():
    app = QApplication([])

    a = Controller()
    a.display_parameters("Foo")

    assert a.current_name != "Foo"

    keyEvent = QKeyEvent(QEvent.KeyPress, Qt.Key_Return, Qt.NoModifier)
    QCoreApplication.postEvent(a.line_edit_name, keyEvent)
    # QTest.keyClick(a.line_edit_name, Qt.Key_Return)

    QTest.qWait(1000)

    assert a.current_name == "Foo"


test_controller()

On the other hand if you want to do tests then it is better to use the QtTest submodule that already has several simplified functions besides you could use pytest-qt.

  • Related