I want to mark class methods with decorators in such a way that a GUI can be automatically built to interact with the class. The simplest case for this is a 'button' method, which requires no arguments.
Here is how I define the decorator:
class Button(Control):
def __init__(self, callback: Callable, label: Optional[str] = None):
super(Button, self).__init__()
self.callback = callback
self.label = label
def __call__(self, *args, **kwargs):
return self.callback(*args, **kwargs)
def button(label: Optional[str]):
"""Decorator to denote function as one-shot button press"""
def decorator(f):
obj = Button(f, label)
return obj
return decorator
class SignalGenerator(BaseMockInstrument):
def __init__(self):
super(SignalGenerator, self).__init__()
@button('Reset')
def reset(self):
pass
a = SignalGenerator()
a.reset() #TypeError: reset() missing 1 required positional argument: 'self'
a.reset(a) # Works
But this doesn't work because reset is called without the self
argument.
TypeError: reset() missing 1 required positional argument: 'self'
I think this is happening because during the decorator call, reset
is a function, but it is not a bound instance method (because how could it be when the object doesn't exist yet).
So, the instance isn't passed to the callback.
How do I fix the bug and have the callback appropriately bound, and is there a better way to approach the problem overall?
You can use descriptors
[Python-docs] to get the instance Button accessed on.
class Button(Control):
def __init__(self, callback: Callable, label: Optional[str] = None):
super(Button, self).__init__()
self.callback = callback
self.label = label
self.bound = None
def __get__(self, instance, _):
self.bound = instance
return self
def __call__(self, *args, **kwargs):
return self.callback(self.bound, *args, **kwargs)