Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Qt6 Signal Datatype Handling #426

Open
jakeanq opened this issue Jan 13, 2025 · 0 comments
Open

Qt6 Signal Datatype Handling #426

jakeanq opened this issue Jan 13, 2025 · 0 comments

Comments

@jakeanq
Copy link

jakeanq commented Jan 13, 2025

Another quirk for the Qt6 migration section...

If defining a signal with a list or dict datatype (potentially others too?), in Qt6 it will now convert the Python object to a C++ object, then convert it back later when calling a slot, whereas in Qt5 it will return the original object. This conversion seems to be recursive.

Some effects of this:

  • The slot receives a copy of the object, not the original.
  • If you pass a custom type that inherits from list or dict, the slot will be called with a new object of the base type.
  • Dictionary item ordering is lost.

One fix/workaround is to define the signal with object as the datatype, which will maintain the previous behaviour.

Demo script:

from Qt import QtCore, QtWidgets

class Lemur(list):
    def __init__(self, value):
        self.value = value

    def __repr__(self):
        return f"Lemur({self.value!r})"


class TestWidget(QtWidgets.QPushButton):

    test_signal = QtCore.Signal(dict)

    def __init__(self):
        super().__init__()
        self.clicked.connect(self.do_test)
        self.test_signal.connect(self.rx_test)

    def do_test(self):
        data = {"test_dictionary": 10, "lemur": Lemur("Hello")}
        print(f"tx {data=} {id(data)=} {id(data['lemur'])=}")
        self.test_signal.emit(data)

    def rx_test(self, data):
        print(f"rx {data=} {id(data)=} {id(data['lemur'])=}")


if __name__ == "__main__":
    app = QtWidgets.QApplication()
    tw = TestWidget()
    tw.show()

    app.exec_()

With PySide5 I get the exact object returned:

tx data={'test_dictionary': 10, 'lemur': Lemur('Hello')} id(data)=140451434388544 id(data['lemur'])=140451434394304
rx data={'test_dictionary': 10, 'lemur': Lemur('Hello')} id(data)=140451434388544 id(data['lemur'])=140451434394304

With PySide6 the Lemur object ends up as an empty list, dictionary keys are reordered and the dictionary is a different object:

tx data={'test_dictionary': 10, 'lemur': Lemur('Hello')} id(data)=140105873327040 id(data['lemur'])=140105873335856
rx data={'lemur': [], 'test_dictionary': 10} id(data)=140105873326848 id(data['lemur'])=140105990931392
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant