<div class="gmail_quote">2011/10/13 Phil Thompson <span dir="ltr"><<a href="mailto:phil@riverbankcomputing.com" target="_blank">phil@riverbankcomputing.com</a>></span><br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
On Wed, 12 Oct 2011 15:57:17 +0200, Luper Rouch <<a href="mailto:luper.rouch@gmail.com" target="_blank">luper.rouch@gmail.com</a>><br>
wrote:<br>
<div><div></div><div>> PyQt seems to ignore the signature of functools.partial objects (the<br>
'args'<br>
> and 'keywords' attributes [1]), when connecting a callable. Here is an<br>
> example demonstrating the problem :<br>
><br>
> import functools<br>
> from PyQt4.QtCore import QObject, pyqtSignal<br>
><br>
> class Sender(QObject):<br>
><br>
> hello = pyqtSignal(bool)<br>
><br>
> def receiver():<br>
> print "foo"<br>
><br>
> def decorator(func):<br>
> @functools.wraps(func)<br>
> def wrapped(*args, **kwargs):<br>
> return func(*args, **kwargs)<br>
> return wrapped<br>
><br>
> decorated_receiver = decorator(receiver)<br>
><br>
> if __name__ == "__main__":<br>
> sender = Sender()<br>
> sender.hello.connect(receiver)<br>
> sender.hello.connect(decorated_receiver)<br>
> sender.hello.emit(True)<br>
><br>
> When executed, the script gives the following error :<br>
><br>
> $ python test_signature.py<br>
> foo<br>
> Traceback (most recent call last):<br>
> File "test_signature.py", line 17, in wrapped<br>
> return func(*args, **kwargs)<br>
> TypeError: receiver() takes no arguments (1 given)<br>
><br>
> Connecting to a lambda is not a good solution, because PyQt increases<br>
its<br>
> reference count to keep it alive ("However, if a slot is a lambda<br>
function<br>
> or a partial function then its reference count is automatically<br>
incremented<br>
> to prevent it from being immediately garbage collected", see [2]).<br>
><br>
> If you do this in a widget that is later deleted, the lambda stays<br>
alive,<br>
> leading to complex bugs. The only solution is to connect to a normal<br>
method<br>
> calling the decorated method, which can quickly become cumbersome.<br>
><br>
> It would be nice if PyQt did some additional checks when connecting to a<br>
> functools.partial object.<br>
<br>
</div></div>Like what?<br>
<br>
The problem isn't when connecting but when emitting. PyQt emulates the Qt<br>
behaviour of allowing a slot to take fewer arguments than the signal is<br>
providing. It does this by detecting a TypeError raised by the act of<br>
calling the slot. In this case the exception is raised in the body of the<br>
slot and there is no way for PyQt to distinguish between that and any other<br>
TypeError raised while executing the slot.<br>
<font color="#888888"></font><br clear="all"></blockquote></div><br>Maybe with a special path for partials and the likes:<br><br>if hasattr(slot, "args"):<br> # use slot.args to adapt slot call<br>else:<br>
# call the slot the normally<br><br>Could you please point me where the slot calling code lives so I can have a better understanding of how things work ?<br><br>-- <br>Luper Rouch<br>