Get stacktrace including child class method call when exception is raised from parent classmethod

17 views Asked by At

I have a relatively complex codebase that has a Decorator to catch exceptions, log them and prevent some boilerplate code. I also have several Services that inherit from a parent BaseService which has methods to access ORM entities. Here's the main points:

def catch_exceptions(return_type, ...):
    def _decorator(func):

        @wraps(func)
        async def async_function(*args, **kwargs):
            try:
                return await func(*args, **kwargs)
            except Exception as e:
                _log_exception(func, e, args, kwargs)
                return _handle_return(e, return_type, args, kwargs)
                
        @wraps(func)
        def sync_function(*args, **kwargs):
            #SAME AS async_func but for non async methods
            pass
        
        
        return async_function if inspect.iscoroutinefunction(func) else sync_function
    return _decorator

The BaseService has some methods like:

class BaseService:

    @classmethod
    @catch_exceptions(None)
    async def get(cls, ctx:CyContext, id:str=None,   **kwargs):
        ...

        #Suppose this throws an exception because ctx.session is missing
        item = (await ctx.session.scalars(query.limit(1))).first()


class AppointmentService(BaseService):
    pass

If I get an error in this BaseService.get() method, even when it was called from a given previous stacktrace called from AppointmentService, the stacktrace error shows only:

Suppose we use:

async def throw_a():
    ...
    await AppointmentService.get(CyContext(session=None), ...)
    ...
await throw_a()

Results in:

Traceback (most recent call last):
File "/rest/tools/exceptions.py", line 73, in async_function
    return await func(*args, **kwargs)
File "/rest/common/base/services.py", line 188, in get
    item = (await ctx.session.scalars(query.limit(1))).first()
AttributeError: 'NoneType' object has no attribute 'scalars'

As if the tree of method calls originated solely on the Wrapper/Decorator, and forcing me to search across all the method calls trying to figure out which one might have sent the incorrect arguments. So the question is: How can I make the decorator be a 'part' of the stacktrace instead of the origin? Or how to print the entire stacktrace including the childmethod call, and it's previous calls?

0

There are 0 answers