Issue45894
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2021-11-24 20:35 by Amos.Anderson, last changed 2022-04-11 14:59 by admin.
Messages (4) | |||
---|---|---|---|
msg406957 - (view) | Author: Amos Anderson (Amos.Anderson) | Date: 2021-11-24 20:35 | |
I found a case where an exception is lost if the loop is stopped in a `finally`. ``` import asyncio import logging logging.basicConfig(level=logging.DEBUG) logger = logging.getLogger() async def method_that_raises(): loop = asyncio.get_event_loop() try: logger.info("raising exception") raise ValueError("my exception1") # except Exception as e: # logger.info("in catcher") # logger.exception(e) # raise finally: logger.info("stopped") loop.stop() # await asyncio.sleep(0.5) return async def another_level(): try: await method_that_raises() except Exception as e: logger.info("trapping from another_level") logger.exception(e) if __name__ == "__main__": logger.info("start") try: asyncio.run(another_level()) except Exception as e: logger.exception(e) logger.info("done") ``` gives this output in python 3.10.0 and 3.8.10 (tested in Ubuntu Windows Subsystem Linux) and 3.8.11 in Windows: ``` INFO:root:start DEBUG:asyncio:Using selector: EpollSelector INFO:root:raising exception INFO:root:stopped INFO:root:done ``` i.e., no evidence an exception was raised (other than the log message included to prove one was raised) If I remove the `return`, then the exception propagates as expected. I believe the exception should be propagated regardless of whether there's a `return` in the `finally` block. |
|||
msg406961 - (view) | Author: Amos Anderson (Amos.Anderson) | Date: 2021-11-24 20:55 | |
If I do this instead: ``` try: logger.info("raising exception") raise ValueError("my exception1") finally: logger.info("stopped") loop.stop() await asyncio.sleep(0.5) ``` i.e., do an `await` instead of a `return`, then the original exception is also lost: ``` INFO:root:start DEBUG:asyncio:Using selector: EpollSelector INFO:root:raising exception INFO:root:stopped ERROR:root:Event loop stopped before Future completed. Traceback (most recent call last): File "test.py", line 37, in <module> asyncio.run(another_level()) File "/home/amos/miniconda3/lib/python3.8/asyncio/runners.py", line 44, in run return loop.run_until_complete(main) File "/home/amos/miniconda3/lib/python3.8/asyncio/base_events.py", line 614, in run_until_complete raise RuntimeError('Event loop stopped before Future completed.') RuntimeError: Event loop stopped before Future completed. INFO:root:done ``` it's also a bit surprising that my handler in `another_level` didn't see either exception, but I'm not really sure what I'd expect in that case. |
|||
msg406962 - (view) | Author: Serhiy Storchaka (serhiy.storchaka) * | Date: 2021-11-24 21:30 | |
It is not related to loop.stop() and asyncio in general. It is the return statement which eats the exception. Simpler example: >>> def f(): ... try: ... 1/0 ... finally: ... return 42 ... >>> f() 42 Return (and also break and continue) in the finally block cancel an exception if it was raised. |
|||
msg406970 - (view) | Author: Amos Anderson (Amos.Anderson) | Date: 2021-11-25 00:34 | |
Ah, thank you, Serhiy. I didn't know that, but I see that in the documentation: https://docs.python.org/3/reference/compound_stmts.html#the-try-statement But what about the 2nd case I presented where a `RuntimeError` was raised? That's the actual case I'm working on. Based on this: > If the finally clause raises another exception, the saved exception is set as the context of the new exception. My expectation is that the two exceptions would be chained. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:59:52 | admin | set | github: 90052 |
2021-11-25 00:34:04 | Amos.Anderson | set | messages: + msg406970 |
2021-11-24 21:30:36 | serhiy.storchaka | set | nosy:
+ serhiy.storchaka messages: + msg406962 |
2021-11-24 20:55:56 | Amos.Anderson | set | messages: + msg406961 |
2021-11-24 20:35:15 | Amos.Anderson | create |