<div dir="ltr"><div>I have some cases where I want to decorate my slots, where the decorator has a typical (*args, **kwargs) catch-all signature. Unfortunately, when doing this, I'm unable to connect the signals and slots properly to a parameter-free overload when one with parameters is available.<br>
</div><div><br></div><div><div>From the docs I thought it could be explicitly done at the connection side with the use of:<br></div></div><div><br></div><div><font face="courier new, monospace"> button.clicked[].connect(foo)</font></div>
<div><br></div><div>or it could be explicit at the slot instead (?) that we want the parameter-free one via:</div><div><br></div><div><font face="courier new, monospace"> @pyqtSlot()</font></div><div><font face="courier new, monospace"> def foo():</font></div>
<div><br></div><div>but I can't get either of these to work. When my button slot has *args in the params, I always get the 'checked' boolean.</div><div><br></div><div>How do I force PyQt5 to *not* connect up the version with the (bool, ) signature?</div>
<div><br></div><div>Full example code is below, with a stripped down example of the decorator issue:<br></div><div><br></div><div><div><font face="courier new, monospace">import sys</font></div><div><font face="courier new, monospace">from PyQt5 import QtWidgets</font></div>
<div><font face="courier new, monospace">from PyQt5.QtCore import pyqtSlot</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">app = QtWidgets.QApplication(sys.argv)</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">w = QtWidgets.QWidget()</font></div>
<div><font face="courier new, monospace">w.setWindowTitle('Signal connection checking')</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">b1 = QtWidgets.QPushButton("Connection to ()")</font></div>
<div><font face="courier new, monospace">b2 = QtWidgets.QPushButton("Connection to (checked)")</font></div><div><font face="courier new, monospace">b3 = QtWidgets.QPushButton("Connection to (*args)")</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">layout = QtWidgets.QVBoxLayout(w)</font></div><div><font face="courier new, monospace">layout.addWidget(b1)</font></div>
<div><font face="courier new, monospace">layout.addWidget(b2)</font></div><div><font face="courier new, monospace">layout.addWidget(b3)</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">def bogus_decorator(f):</font></div>
<div><font face="courier new, monospace"> def wrapper(*args):</font></div><div><font face="courier new, monospace"> print "wrapper called with args = %r" % (args, )</font></div>
<div><font face="courier new, monospace"> return f() #<-- have to do this to make the code work</font></div><div><font face="courier new, monospace"> #should be the code below, but it fails since we call with</font></div>
<div><font face="courier new, monospace"> #an unexpected arg and get a corresponding TypeError.</font></div>
<div><font face="courier new, monospace"> #return f(*args) #<--- will fails since it passes an unexpected arg</font></div><div><font face="courier new, monospace"> return wrapper</font></div><div><font face="courier new, monospace"><br>
</font></div><div><font face="courier new, monospace">def onVoidClick():</font></div><div><font face="courier new, monospace"> print "normal (void) clicked!"</font></div><div>
<font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">def onBoolClick(checked):</font></div><div><font face="courier new, monospace"> print "normal (bool) clicked!"</font></div>
<div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">@pyqtSlot() #<-- shouldn't this force the parameter-free overload?</font></div><div><font face="courier new, monospace">@bogus_decorator</font></div>
<div><font face="courier new, monospace">#@pyqtSlot() #<--- order does not matter</font></div><div><font face="courier new, monospace">def onWrappedStarClick():</font></div><div><font face="courier new, monospace"> #this always gets called with the (bool) overload</font></div>
<div><font face="courier new, monospace"> print "Actual handler fired!"</font></div><div><font face="courier new, monospace"><br></font></div>
<div><font face="courier new, monospace">b1.clicked.connect(onVoidClick)</font></div><div><font face="courier new, monospace">b2.clicked.connect(onBoolClick)</font></div><div><font face="courier new, monospace"><br></font></div>
<div><font face="courier new, monospace">#How to connect this next one so that it works like onVoidClick()?</font></div><div><font face="courier new, monospace"># - explicitly defining the slot with @pyqtSlot() does not work</font></div>
<div><font face="courier new, monospace"># - explicitly connecting an overload with clicked[()].connect doesn't work</font></div><div><font face="courier new, monospace">b3.clicked.connect(onWrappedStarClick)</font></div>
<div><font face="courier new, monospace">#b3.clicked[()].connect(onStarClick)</font></div><div><font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">w.show()</font></div><div>
<font face="courier new, monospace"><br></font></div><div><font face="courier new, monospace">sys.exit(app.exec_())</font></div><div><br></div></div>
</div>