import types
from functools import wraps
trace_types = (
types.MethodType,
types.FunctionType,
types.BuiltinFunctionType,
types.BuiltinMethodType,
types.MethodDescriptorType,
types.ClassMethodDescriptorType
)
def trace_func(func):
if hasattr(func, 'tracing'):
return func
@wraps(func)
def wrapper(*args, **kwargs):
result = None
try:
result = func(*args, **kwargs)
return result
except Exception as e:
result = e
raise
finally:
print(f'{func.__name__} ({args!r}, {kwargs!r}) -> {result!r}')
wrapper.tracing = True
return wrapper
def trace(decorated_class):
for key in dir(decorated_class):
value = getattr(decorated_class, key)
if isinstance(value, trace_types) and key != "__new__": # __new__ can't be called this way (https://stackoverflow.com/questions/59217884/new-method-giving-error-object-new-takes-exactly-one-argument-the-typ)
wrapped = trace_func(value)
setattr(decorated_class, key, wrapped)
return decorated_class
@trace
class Name:
def __init__(self, name: str):
self.name = name
def name_uppercase(self, force: bool):
return self.name + " is upper " + force.__str__()
n = Name("aaaaa")
print(n.name_uppercase(True))
print(n.name)