1

I have a problem using Qt signal/slot mechanism in PySide when I want to send None.

Suppose I have a class named Calculator (a subclass of QObject) that can perform certain calculations the result of which can be anything, i.e. any type of Python object or even None. I need the instances of Calculator class to be able to signal the result to some consumer objects (subclasses of QObject).

What I had:

class Calculator(QObject):
    finished = PySide.QtCore.Signal(object)  # object means it can transmit anything

    def calc(self):
        ... # calculation of the result
        self.finished.emit(result)

class Consumer(QObject):
    def __init__(self, calculator):
        ...
        calculator.finished.connect(self.consume)

    def consume(self, result):  # do something with the result
        ...

This works fine except the situation when result is None. Then the program crashes when emitting the signal. It seems as if None is not a Python object (which may be true, I am not that proficient in the language standards).

Now I have a workaround, using two signals:

    finished = PySide.QtCore.Signal((),(object,))

and:

    def calc(self):
        ... # calculation of the result
        if result is None:
            self.finished.emit()
        else:
            self.finished[object].emit(result)

This solution works but it is complicated because it requires the consumer objects to link the signal twice. Either to two slots or to one slot with one default argument equal to None.

class Consumer(QObject):
    def __init__(self, calculator):
        ...
        calculator.finished.connect(self.consume)
        calculator.finished[object].connect(self.consume)

    def consume(self, result=None):  # do something with the result
        ...

This is complicated and prone to errors when creating many different consumer classes. I think this problem is the same with PyQt, with the difference that alternative signals are defined using lists [], [object] rather than tuples (),(object,).

My question is: is there any simple solution to this problem? Ideally with just one signal?

Oliver
  • 27,510
  • 9
  • 72
  • 103
  • 1
    It would be a bug if PySide somehow failed to emit `None` (which most certainly is a bona fide python object). However, I tested using PySide-1.2.1, and couldn't reproduce your problem. I've also never seen such a problem in PyQt. So either you're doing something wrong elsewhere in your code, or it's a bug in the version of PySide you're using. – ekhumoro Jan 13 '14 at 23:37
  • @ ekhumoro OK, I must confirm that when I now tested other versions of PySide and PyQt, the error was gone. I will check the rest of my code once more and will probably delete the question. Obviously the problem is elsewhere. I am upvoting your answer for correcting my claim. – HiFile.app - best file manager Jan 14 '14 at 09:37

2 Answers2

2

As an aside, this bug still exists in PySide where it segfaults on the transmission of a None signal as of version 1.2.1 (has existed since 1.1.0). There is a bug report at:

https://bugreports.qt-project.org/browse/PYSIDE-17

Obviously V.K.'s solution of encapsulating the None within a separate class still works, as does choosing another type to transmit instead (I switched my None to float('nan')). I just wanted to update this as I ran into the same issue and found this, and later the bug report explaining the segfault.

1

Just after posting my problem I found an answer. So I appologize for answering my own question - I know it is not how it should be on StackOverflow. I created a class named ResultHolder which encapsulates the real result (result is a member variable of this class). Then I am transmitting instances of this ResultHolder class. The rest of the solution is then just straightforward.

  • There's nothing wrong with answering your own question. Quite the opposite, in fact, because it avoids people wasting time answering questions which are no longer relevant. Having said that, please see my comments on your question. – ekhumoro Jan 13 '14 at 23:38
  • @ekhumoro: the problem usually comes when there are better answers, and the OPs do not recognize that, and they will stick to their own answers. – László Papp Jan 14 '14 at 02:39
  • @LaszloPapp. Not sure what point you were making, but I wouldn't waste time answering a question if I can see from the OP's own answer that he has truly solved his problem. On the other hand, if his answer is wrong or inadequate in some way, then I can either offer a better answer, or point out the deficiencies with some comments. The [SO guidance](https://meta.stackoverflow.com/help/self-answer) explicitly encourages users to answer their own questions. – ekhumoro Jan 14 '14 at 03:13
  • @ekhumoro: e.g. http://stackoverflow.com/questions/21083277/open-txt-file-with-default-program or http://stackoverflow.com/questions/21077767/qt-console-application-warning-qapplication-was-not-created-in-the-main-thre – László Papp Jan 14 '14 at 03:14
  • @LaszloPapp. Well, sure, "you can lead a horse to water", etc. But if the OP hadn't posted that "wrong" answer, how would you have known to correct it? – ekhumoro Jan 14 '14 at 03:20
  • @ekhumoro: I am not correcting anyone when providing an answer. I am just giving the best of my knowledge. The problem arises when OPs do not accept their answers are not as good as the alternatives... – László Papp Jan 14 '14 at 03:22