Search code examples
pythonpython-3.xpython-asyncioaiohttp

Is there any way to find which one of multiple timers raised exception?


import asyncio
from aiohttp import Timeout


async def main():
    try:
        with Timeout(1) as t1:
            with Timeout(1) as t2:
                await asyncio.sleep(2)
    except asyncio.TimeoutError as exc:        

        # Which one of timers raised this `exc`?
        # Something like:

        # get_caller(exc) is t1 -> False
        # get_caller(exc) is t2 -> True

        pass


if __name__ == '__main__':
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())

Since both timers have same timeout, both of them can raise TimeoutError. I want to know which one did it. Is it possible?


Solution

  • async def main_async():
        try:
            with NamedTimeout('outer', 0.5) as t1:
                with NamedTimeout('inner', 0.3) as t2:
                    await asyncio.sleep(2)
        except asyncio.TimeoutError as e:
            print(e.timeout_name)
    
    class NamedTimeout(Timeout):
        def __init__(self, name, timeout, *, loop=None):
            super().__init__(timeout, loop=loop)
            self.name = name
    
        def __exit__(self, exc_type, exc_val, exc_tb):
            try:
                super().__exit__(exc_type, exc_val, exc_tb)
            except asyncio.TimeoutError as e:
                e.timeout_name = self.name
                raise
    

    If you vary the timeout values you will see it always prints out the name of the shorter timeout.