I've implemented automatic wrapping of a method as described in how-to-wrap-every-method-of-a-class in the following manner:
from functools import wraps
from somewhere import State
def wrapper(method):
@wraps(method)
def wrapped(_instance, *args, **kwargs):
_instance.state = State.Running
method(_instance, *args, **kwargs)
_instance.state = State.Finished
return wrapped
class MetaClass(type):
def __new__(meta, classname, bases, classDict):
newClassDict = {}
for attributeName, attribute in classDict.items():
if isinstance(attribute, FunctionType) and attributeName == 'run':
# replace it with a wrapped version
attribute = wrapper(attribute)
newClassDict[attributeName] = attribute
return type.__new__(meta, classname, bases, newClassDict)
class AmazingClass(metaclass=MetaClass):
def __init__(self):
self.state = State.Idle
def run(self, *args, **kwargs):
print(self.state) # State.Running
do_something()
# After returning: self.state == State.Finished
An issue arises when deriving from AmazingClass
and overriding run()
class EvenMoreAmazingClass(AmazingClass):
def run(self, *args, **kwargs):
print(self.state) # State.Running
super().run(*args, **kwargs)
print(self.state) # State.Finished set by base-implementation of run (undesired) !!!!
do_something_else()
# self.state should only reach State.Finished after returning from here
The problem is that the base-implementation of run()
already sets self.state
to State.Finished
.
I want to call the base-implementation of run()
and also not have to do any trickery in any classes derived from AmazingClass
to keep self.state == State.Running
.
So the question arises, is there a way to detect and wrap only the outermost implementation of run()
? (In this case EvenMoreAmazingClass.run()
)