[PyQt] PyQt should not ignore functools.partial signature

Luper Rouch luper.rouch at gmail.com
Fri Oct 14 10:10:03 BST 2011


2011/10/13 Phil Thompson <phil at riverbankcomputing.com>

> On Wed, 12 Oct 2011 15:57:17 +0200, Luper Rouch <luper.rouch at gmail.com>
> wrote:
> > PyQt seems to ignore the signature of functools.partial objects (the
> 'args'
> > and 'keywords' attributes [1]), when connecting a callable. Here is an
> > example demonstrating the problem :
> >
> > import functools
> > from PyQt4.QtCore import QObject, pyqtSignal
> >
> > class Sender(QObject):
> >
> >     hello = pyqtSignal(bool)
> >
> > def receiver():
> >     print "foo"
> >
> > def decorator(func):
> >     @functools.wraps(func)
> >     def wrapped(*args, **kwargs):
> >         return func(*args, **kwargs)
> >     return wrapped
> >
> > decorated_receiver = decorator(receiver)
> >
> > if __name__ == "__main__":
> >     sender = Sender()
> >     sender.hello.connect(receiver)
> >     sender.hello.connect(decorated_receiver)
> >     sender.hello.emit(True)
> >
> > When executed, the script gives the following error :
> >
> > $ python test_signature.py
> > foo
> > Traceback (most recent call last):
> >   File "test_signature.py", line 17, in wrapped
> >     return func(*args, **kwargs)
> > TypeError: receiver() takes no arguments (1 given)
> >
> > Connecting to a lambda is not a good solution, because PyQt increases
> its
> > reference count to keep it alive ("However, if a slot is a lambda
> function
> > or a partial function then its reference count is automatically
> incremented
> > to prevent it from being immediately garbage collected", see [2]).
> >
> > If you do this in a widget that is later deleted, the lambda stays
> alive,
> > leading to complex bugs. The only solution is to connect to a normal
> method
> > calling the decorated method, which can quickly become cumbersome.
> >
> > It would be nice if PyQt did some additional checks when connecting to a
> > functools.partial object.
>
> Like what?
>
> The problem isn't when connecting but when emitting. PyQt emulates the Qt
> behaviour of allowing a slot to take fewer arguments than the signal is
> providing. It does this by detecting a TypeError raised by the act of
> calling the slot. In this case the exception is raised in the body of the
> slot and there is no way for PyQt to distinguish between that and any other
> TypeError raised while executing the slot.
>
>
Maybe with a special path for partials and the likes:

if hasattr(slot, "args"):
    # use slot.args to adapt slot call
else:
    # call the slot the normally

Could you please point me where the slot calling code lives so I can have a
better understanding of how things work ?

-- 
Luper Rouch
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20111014/528f3df3/attachment.html>


More information about the PyQt mailing list