Uploaded image for project: 'Qt for Python'
  1. Qt for Python
  2. PYSIDE-2348

PySide6: Wrong slot called in unit test after updating from 6.5.0 to 6.5.1

    XMLWordPrintable

Details

    • Bug
    • Resolution: Duplicate
    • Not Evaluated
    • None
    • 6.5.1
    • PySide
    • None
    • Ubuntu 23.04
    • Linux/X11

    Description

      After updating PySide6 from 6.5.0 to 6.5.1 using pip, some of my unit tests failed when running in a row. They work fine if executed one by one, i.e., with a new Python interpreter instance for each test, but not when run by the same instance.

      A minimal "working" example:

      #!/usr/bin/env python3
      
      
      import unittest
      
      from PySide6 import QtCore
      from PySide6.QtWidgets import (
          QApplication,
          QPushButton,
      )
      
      PRINT_OBJ = True
      
      
      class TheButton(QPushButton):
          def __init__(self, text: str) -> None:
              super().__init__(text=text, parent=None)
              self.clicked_count = 0
              def clicked_me() -> None:
                  if PRINT_OBJ:
                      print(self, 'clicked')
                  self.clicked_count += 1
              self.clicked.connect(clicked_me)
      
      
      class TestQt65(unittest.TestCase):
      
          def setUp(self) -> None:
              self._q_app = QApplication.instance() or QApplication()
              print('Qt version:', QtCore.qVersion())
      
          def test_1(self) -> None:
              dut = TheButton('test_1')
              if PRINT_OBJ:
                  print('\ntest_1 obj:', dut)
              dut.click()
              self.assertEqual(dut.clicked_count, 1)
      
          def test_2(self) -> None:
              dut = TheButton('test_2')
              if PRINT_OBJ:
                  print('\ntest_2 obj:', dut)
              dut.click()
              self.assertEqual(dut.clicked_count, 1)
      

      Note that the slot for TheButton.clicked is an inner function of its {}init{}, not a separate instance method.

      Qt 6.5.0

      Running the tests individually: PASS

      $ python3 -m unittest tests.uitests.test_qt65.TestQt65.test_1
      qt.dbus.integration: Could not connect "org.freedesktop.IBus" to globalEngineChanged(QString)
      Qt version: 6.5.0
      
      test_1 obj: <tests.uitests.test_qt65.TheButton(0x5557355a09b0) at 0x7fc959057a40>
      <tests.uitests.test_qt65.TheButton(0x5557355a09b0) at 0x7fc959057a40> clicked
      .
      ----------------------------------------------------------------------
      Ran 1 test in 0.094s
      
      OK
      ltsoftware$ python3 -m unittest tests.uitests.test_qt65.TestQt65.test_2
      qt.dbus.integration: Could not connect "org.freedesktop.IBus" to globalEngineChanged(QString)
      Qt version: 6.5.0
      
      test_2 obj: <tests.uitests.test_qt65.TheButton(0x55c312feda50) at 0x7f97d4057a40>
      <tests.uitests.test_qt65.TheButton(0x55c312feda50) at 0x7f97d4057a40> clicked
      .
      ----------------------------------------------------------------------
      Ran 1 test in 0.136s
      
      OK
      

      Running both tests at once: PASS

      $ python3 -m unittest tests.uitests.test_qt65.TestQt65
      qt.dbus.integration: Could not connect "org.freedesktop.IBus" to globalEngineChanged(QString)
      Qt version: 6.5.0
      
      test_1 obj: <tests.uitests.test_qt65.TheButton(0x557a80fbc870) at 0x7f40aba5fb80>
      <tests.uitests.test_qt65.TheButton(0x557a80fbc870) at 0x7f40aba5fb80> clicked
      .Qt version: 6.5.0
      
      test_2 obj: <tests.uitests.test_qt65.TheButton(0x557a80fbc790) at 0x7f40aba5f800>
      <tests.uitests.test_qt65.TheButton(0x557a80fbc790) at 0x7f40aba5f800> clicked
      .
      ----------------------------------------------------------------------
      Ran 2 tests in 0.102s
      
      OK
      

      Qt 6.5.1

      Running the tests individually: PASS

      $ python3 -m unittest tests.uitests.test_qt65.TestQt65.test_1
      Qt version: 6.5.1
      
      test_1 obj: <tests.uitests.test_qt65.TheButton(0x5652fa86eff0) at 0x7f342e374980>
      <tests.uitests.test_qt65.TheButton(0x5652fa86eff0) at 0x7f342e374980> clicked
      .
      ----------------------------------------------------------------------
      Ran 1 test in 0.142s
      
      OK
      ltsoftware$ python3 -m unittest tests.uitests.test_qt65.TestQt65.test_2
      Qt version: 6.5.1
      
      test_2 obj: <tests.uitests.test_qt65.TheButton(0x5612e17d6220) at 0x7fd0ce898940>
      <tests.uitests.test_qt65.TheButton(0x5612e17d6220) at 0x7fd0ce898940> clicked
      .
      ----------------------------------------------------------------------
      Ran 1 test in 0.134s
      
      OK
      

      Running both tests at once: {}FAIL{}

      $ python3 -m unittest tests.uitests.test_qt65.TestQt65
      Qt version: 6.5.1
      
      test_1 obj: <tests.uitests.test_qt65.TheButton(0x55d8d007cb80) at 0x7f57c6698a80>
      <tests.uitests.test_qt65.TheButton(0x55d8d007cb80) at 0x7f57c6698a80> clicked
      .Qt version: 6.5.1
      
      test_2 obj: <tests.uitests.test_qt65.TheButton(0x55d8d007caa0) at 0x7f57c6698700>
      <tests.uitests.test_qt65.TheButton(0x55d8d007cb80) at 0x7f57c6698a80> clicked
      F
      ======================================================================
      FAIL: test_2 (tests.uitests.test_qt65.TestQt65.test_2)
      ----------------------------------------------------------------------
      Traceback (most recent call last):
        File "/home/phip/phipsfiles/developing/electronics/altatec/lasertrimmer/ltsoftware/tests/uitests/test_qt65.py", line 44, in test_2
          self.assertEqual(dut.clicked_count, 1)
      AssertionError: 0 != 1
      
      ----------------------------------------------------------------------
      Ran 2 tests in 0.097s
      
      FAILED (failures=1)
      

      The problem is apparently that in the second test, the clicked slot still fires, but for the object created in the first test and not the one in the second test.

      Apparent cause/fix

      It appears that the handling of the QApplication changed between versions and it is now required to fully clean it up after the test using QApplication.shutdown(). If I add the call to tearDown(), the problem is gone:

          def tearDown(self) -> None:
              self._q_app.shutdown()
      

      Output:

      $ python3 -m unittest tests.uitests.test_qt65.TestQt65
      Qt version: 6.5.1
      
      test_1 obj: <tests.uitests.test_qt65.TheButton(0x55df351904d0) at 0x7fe580a9cb00>
      <tests.uitests.test_qt65.TheButton(0x55df351904d0) at 0x7fe580a9cb00> clicked
      .Qt version: 6.5.1
      
      test_2 obj: <tests.uitests.test_qt65.TheButton(0x55df34e1b9b0) at 0x7fe5859f8900>
      <tests.uitests.test_qt65.TheButton(0x55df34e1b9b0) at 0x7fe5859f8900> clicked
      .
      ----------------------------------------------------------------------
      Ran 2 tests in 0.164s
      
      OK
      

      It may be that the shutdown() should have been there ever since and it worked more by coincidence up to 6.5.0. However, to me this seems to be rather serious for just a minor version bump and might affect other parts of the software as well.

      Attachments

        Issue Links

          No reviews matched the request. Check your Options in the drop-down menu of this sections header.

          Activity

            People

              crmaurei Cristian Maureira-Fredes
              phip Philipp Burch
              Votes:
              0 Vote for this issue
              Watchers:
              2 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Gerrit Reviews

                  There are no open Gerrit changes