Reputation: 2065
I have used decorators in the past without any issue, but I'm stuck on this one. It seems that when my decorated function is called by a PyQt action, it fails. My theory is that PyQt is somehow wrapping the connected function internally and messing with the signature, or some such thing, but I can't find any evidence of this.
By connected I mean like this:
from PyQt4 import QtGui
# In my widget init...
self.action_my_method = QtGui.QAction("action_my_method", self)
self.action_my_method.triggered.connect(self.my_method)
Here is my simple decorator:
from functools import wraps
def simple_decorator(fn):
@wraps(fn)
def wrapper(*args, **kwargs):
from inspect import getargspec
print getargspec(fn)
return fn(*args, **kwargs)
return wrapper
When I use this to decorate a method without any arguments (def my_method(self)
), and execute it directly from my QWidget class, it works fine. When I used a menu to trigger the action, I get:
# Traceback (most recent call last):
# File "[...].py", line 88, in wrapper
# return fn(*args, **kwargs)
# TypeError: my_method() takes exactly 1 argument (2 given)
I'm seeing an arg spec:
ArgSpec(args=['self'], varargs=None, keywords=None, defaults=None)
If I add *args
to my method, so the signature is my_method(self, *args)
, the decorator works fine and the arg spec is:
ArgSpec(args=['self'], varargs='args', keywords=None, defaults=None)
I don't see any clues here, since the decorator works fine when called directly, but fails when triggered by the action.
Can anyone shed some light on this, or offer something I can use to debug it further?
Upvotes: 1
Views: 266
Reputation: 705
Alternatively you can redefine the signature of every method that may be called via a .connect as:
def my_method(self, qtcallparam=None, **kwargs):
So the method will ignore the first unnamed argument, at the price of use strictly keyword arguments in that method (not such a bad thing)
But the solution of @Rafe is probably cleaner
Upvotes: 0
Reputation: 2065
This isn't an answer so much as a workaround. I hope there aren't any downsides to this. I thought of it while I was typing out a simple re-direct function. This uses a lambda to do the same thing at run-time:
self.action_my_method.triggered.connect(lambda: self.my_method())
This sufficiently pads my decorated function against being mangled and prevents the error.
Upvotes: 1