I am trying to create a generic function lifecycle handler in python. Working in brief:
- Logs the signature and return values.
- Handles the exception with or without retry.
- Provide cleanup in case of exception.
The issue which I encountered while doing the cleanup is as follows: Function-based decorator:
def handler(exception=Exception,cleanup=None):
def func_wrapper(func):
def wrapper(*args,**kwargs):
response=None
try:
print(args)
response=func(*args,**kwargs)
except exception as ex:
print(f'Exception occurred:{str(ex)}\nCleaning up resources')
#Passing the object for cleanup, it fails for class based decorators as it does not passes self as argument
cleanup(args[0])
return response
return wrapper
return func_wrapper
The data which is supposed to be cleaned up is stored in the class instance and is cleaned based on the method provided. For example:
Store some information using third party API.
In case of exception, the cleanup operation passed would invoke a delete API.
class Test: def __init__(self,data): self.main_data=data @handler(exception=Exception,cleanup=lambda x:print(f"Cleaning data:{x.main_data}")) def test_data(self): print(f'Data is :{self.main_data}') i=1/0
Output:
Exception occurred:division by zero
Cleaning up resources
Cleaning:John Doe
I was more inclinded towards Class based decorator.
class LifeCycleHandler:
def __init__(self,*,func=None,exception=Exception,cleanup=None):
self.__exception=exception
self.__cleanup=cleanup
self.__func=func
def __call__(self,*args,**kwargs):
response=None
try:
print(args)
response=self.__func(*args,**kwargs)
except self.__exception as ex:
print(f'Exception occurred:{str(ex)}\n cleaning up resources')
#Passing the object for cleanup
self.__cleanup(args[0])
return response
def lifecycle_handler(exception=Exception,cleanup=None):
def wrapper(func):
response=LifeCycleHandler(func=func,exception=exception,cleanup=cleanup)
return response
return wrapper
With class based decorator with similar functionality i faced the following error:
()
Exception occurred:test_data() missing 1 required positional argument: 'self'
cleaning up resources
Traceback (most recent call last):
File "test.py", line 27, in __call__
response=self.__func(*args,**kwargs)
TypeError: test_data() missing 1 required positional argument: 'self'
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "test.py", line 54, in <module>
test.test_data()
File "test.py", line 31, in __call__
self.__cleanup(args[0])
IndexError: tuple index out of range
Can someone guide me regarding the the argument interpretation for callable classes?