Reputation: 2261
I'm working on a PyQt application and have added the following debug decorator:
def debug_decorator(func):
@functools.wraps(func)
def wrapper_func(*args, **kwargs):
logging.debug(f"Calling {func.__name__}")
ret_val = func(*args, **kwargs)
logging.debug(f"{func.__name__} returned {ret_val!r}")
return ret_val
return wrapper_func
Among other things, i use this for click handler functions, for example:
self.share_qpb = QtWidgets.QPushButton("Share")
self.share_qpb.clicked.connect(self.on_share_clicked)
[...]
@debug_decorator
def on_share_clicked(self):
If i run this code i get the following error when the share button is clicked:
TypeError: on_share_clicked() takes 1 positional argument but 2 were given
The reason for this is that the clicked
signal in Qt/PyQt sends the checked state of the button (documentation)
This is only an issue when i decorate functions with my debug decorator, not otherwise (i guess the extra argument is discarded somewhere)
How can i make my debug decorator work without having to add a parameter for every clicked
signal handler?
(I'd like to find a solution which works both for cases when the arguments match and when there is one extra argument)
I'm running Python 3.8 and PyQt 5.15
Upvotes: 0
Views: 365
Reputation: 2261
I managed to solve this by checking to see if the number of arguments provided len(args)
is more than the number of arguments that the decorated function accepts func.__code__.co_argcount
I also check if the name of the decorated function contains the string "clicked" since i have made a habit of having that as part of the name of my click handler functions. This has the advantage that if another decorated function is called with too many arguments we will (as usual) get an error
def debug_decorator(func):
@functools.wraps(func)
def wrapper_func(*args, **kwargs):
logging.debug(f"=== {func.__name__} was called")
func_arg_count_int = func.__code__.co_argcount
func_name_str = func.__name__
if len(args) > func_arg_count_int and "clicked" in func_name_str: # <----
args = args[:-1]
ret_val = func(*args, **kwargs)
logging.debug(f"=== {func.__name__} returned {ret_val!r}")
return ret_val
return wrapper_func
Thank you to @ekhumoro for helping me out with this!
Upvotes: 1