Hi,
the documentation of how to use new style signals and slots is relatively
sparse, thus I wrote some test cases to determine what is to expect. I was
mostly looking at PyQt4 documentation when working with new style signals and
slots.
These test cases raised two questions:
1) Even if a slot was annotated with @Slot(type) the connection is made with
all signals of the same name and not just the signal with the correct overload
type. The PyQt documentation states that it is using a default overload in
these situations. What is the right behavior in this case?
@QtCore.Slot(int)
@QtCore.Slot('double')
@QtCore.Slot(str)
@QtCore.Slot('QVariant')
def slot1(self, value1):
self._value1 = value1
@QtCore.Slot(int)
def slot1Int(self, value1):
self._value1Int = value1
def testAutomaticType(self):
spinBox = QtGui.QSpinBox()
spinBox.valueChanged.connect(self.slot1Int)
spinBox.valueChanged.emit(1)
self.assertEqual(1, self._value1Int)
2) float is no valid type for double signals, although a Python float is a C
signed double. Should the Python type float be a valid type for signal
overrides?
def testDoubleSignal2(self):
spinBox = QtGui.QDoubleSpinBox()
spinBox.valueChanged[float].connect(self.slot1)
spinBox.valueChanged[float].emit(2.0)
self.assertEqual(2.0, self._value1)
The testPartial and testLambda methods are test cases for bug #542. In the case
of the clicked signal of a QPushButton, the optional signal parameter "checked
= false" seems to get passed along to slots that are partial or lambda
functions.
Test output
-----------
Finding files...
['/.../new_style_signals_slots.py'] ... done
Importing test modules ... done.
testAutomaticSignalType (new_style_signals_slots.NewSignalsAndSlotsTestCase)
... FAIL
testDoubleSignal1 (new_style_signals_slots.NewSignalsAndSlotsTestCase) ... ok
testDoubleSignal2 (new_style_signals_slots.NewSignalsAndSlotsTestCase) ... ERROR
testIntSignal1 (new_style_signals_slots.NewSignalsAndSlotsTestCase) ... ok
testIntSignal2 (new_style_signals_slots.NewSignalsAndSlotsTestCase) ... ok
testLambda (new_style_signals_slots.NewSignalsAndSlotsTestCase) ... FAIL
testMultiParameters (new_style_signals_slots.NewSignalsAndSlotsTestCase) ... ok
testPartial (new_style_signals_slots.NewSignalsAndSlotsTestCase) ... FAIL
TypeErrortestPythonSignal (new_style_signals_slots.NewSignalsAndSlotsTestCase)
... ok
testStrSignal1 (new_style_signals_slots.NewSignalsAndSlotsTestCase) ... ok
testStrSignal2 (new_style_signals_slots.NewSignalsAndSlotsTestCase) ... :
slot1() takes exactly 2 arguments (3 given)
ok
testStrSignal3 (new_style_signals_slots.NewSignalsAndSlotsTestCase) ... ok
======================================================================
ERROR: testDoubleSignal2 (new_style_signals_slots.NewSignalsAndSlotsTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/.../new_style_signals_slots.py", line 105, in testDoubleSignal2
spinBox.valueChanged[float].connect(self.slot1)
IndexError: Signature valueChanged(qreal) not found for signal: valueChanged
======================================================================
FAIL: testAutomaticSignalType
(new_style_signals_slots.NewSignalsAndSlotsTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/.../new_style_signals_slots.py", line 65, in testAutomaticSignalType
self.assertEqual(1, self._value1Int)
AssertionError: 1 != u''
======================================================================
FAIL: testLambda (new_style_signals_slots.NewSignalsAndSlotsTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/.../new_style_signals_slots.py", line 114, in testLambda
self.assertEqual('Button', self._value1)
AssertionError: 'Button' != True
======================================================================
FAIL: testPartial (new_style_signals_slots.NewSignalsAndSlotsTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/.../new_style_signals_slots.py", line 121, in testPartial
self.assertEqual('Button', self._value1)
AssertionError: 'Button' != None
----------------------------------------------------------------------
Ran 12 tests in 0.013s
FAILED (failures=3, errors=1)
The test cases are attached.
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import sys
import unittest
import PySide.QtCore as QtCore
import PySide.QtGui as QtGui
from functools import partial
def getApplication():
app = QtCore.QCoreApplication.instance()
if app is None:
app = QtGui.QApplication(sys.argv)
return app
app = getApplication()
class PythonMessage(object):
def __init__(self, message):
super(PythonMessage, self).__init__()
self._message = message
def __repr__(self):
return self._message
class PythonSignalTester(QtCore.QObject):
def __init__(self, parent=None):
super(PythonSignalTester, self).__init__(parent)
signal1 = QtCore.Signal('QVariant')
signal2 = QtCore.Signal(str, 'QVariant')
class NewSignalsAndSlotsTestCase(unittest.TestCase):
def __init__(self, *args, **kwargs):
super(NewSignalsAndSlotsTestCase, self).__init__(*args, **kwargs)
self._value1 = None
self._value1Int = None
self._value2 = None
@QtCore.Slot(int)
@QtCore.Slot(float)
@QtCore.Slot(str)
@QtCore.Slot('QVariant')
def slot1(self, value1):
self._value1 = value1
@QtCore.Slot(int)
def slot1Int(self, value1):
self._value1Int = value1
@QtCore.Slot(str, 'QVariant')
def slot2(self, value1, value2):
self._value1 = value1
self._value2 = value2
def testAutomaticType(self):
spinBox = QtGui.QSpinBox()
spinBox.valueChanged.connect(self.slot1Int)
spinBox.valueChanged.emit(1)
self.assertEqual(1, self._value1Int)
def testIntSignal1(self):
spinBox = QtGui.QSpinBox()
spinBox.valueChanged['int'].connect(self.slot1)
spinBox.valueChanged['int'].emit(1)
self.assertEqual(1, self._value1)
def testIntSignal2(self):
spinBox = QtGui.QSpinBox()
spinBox.valueChanged[int].connect(self.slot1)
spinBox.valueChanged[int].emit(2)
self.assertEqual(2, self._value1)
def testStrSignal1(self):
spinBox = QtGui.QSpinBox()
spinBox.valueChanged['QString'].connect(self.slot1)
spinBox.valueChanged['QString'].emit(u'1')
self.assertEqual(u'1', self._value1)
def testStrSignal2(self):
spinBox = QtGui.QSpinBox()
spinBox.valueChanged[str].connect(self.slot1)
spinBox.valueChanged[str].emit('2')
self.assertEqual('2', self._value1)
def testStrSignal3(self):
spinBox = QtGui.QSpinBox()
spinBox.valueChanged[unicode].connect(self.slot1)
spinBox.valueChanged[unicode].emit(u'3')
self.assertEqual(u'3', self._value1)
def testDoubleSignal1(self):
spinBox = QtGui.QDoubleSpinBox()
spinBox.valueChanged['double'].connect(self.slot1)
spinBox.valueChanged['double'].emit(1.0)
self.assertEqual(1.0, self._value1)
def testDoubleSignal2(self):
spinBox = QtGui.QDoubleSpinBox()
spinBox.valueChanged[float].connect(self.slot1)
spinBox.valueChanged[float].emit(2.0)
self.assertEqual(2.0, self._value1)
def testLambda(self):
func = lambda x='Button' : self.slot1(x)
button = QtGui.QPushButton("Button")
button.clicked.connect(func)
button.clicked.emit()
self.assertEqual('Button', self._value1)
def testPartial(self):
func = partial(self.slot1, 'False')
button = QtGui.QPushButton("Button")
button.clicked.connect(func)
button.clicked.emit()
self.assertEqual('Button', self._value1)
def testPythonSignal(self):
message = PythonMessage('This is a Python Object')
signalTester = PythonSignalTester()
signalTester.signal1.connect(self.slot1)
signalTester.signal1.emit(message)
self.assertEqual(repr(message), repr(self._value1))
self.assertEqual(message, self._value1)
def testMultiParameterSignal(self):
message = PythonMessage('bla')
signalTester = PythonSignalTester()
signalTester.signal2.connect(self.slot2)
signalTester.signal2.emit('foo', message)
self.assertEqual('foo', self._value1)
self.assertEqual(message, self._value2)
Thanks a lot!
/Christian
_______________________________________________
PySide mailing list
[email protected]
http://lists.openbossa.org/listinfo/pyside