Re: [Async-sig] task.result() and exception traceback display
On Mon, Dec 25, 2017 at 12:48 AM, Nathaniel Smith wrote: > I haven't thought about this enough to have an opinion about whether > this is correct or how it could be improved, but I can explain why > you're seeing what you're seeing :-). > > The traceback is really a trace of where the exception went after it > was raised, with new lines added to the top as it bubbles out. So the > bottom line is the 'raise' statement, because that's where it was > created, and then it bubbled onto the 'call 1' line and was caught. > Then it was raised again and bubbled onto the 'call 2' line. Etc. So > you should think of it not as a snapshot of your stack when it was > created, but as a travelogue. Thanks, Nathaniel. That's a really good explanation. Also, here's a way to see the same behavior without async: def main(): exc = ValueError() try: raise exc # call 1 except Exception: pass try: raise exc # call 2 except Exception: pass raise exc # call 3 main() With this, the traceback looks like-- Traceback (most recent call last): File "test.py", line 16, in main() File "test.py", line 14, in main raise exc # call 3 File "test.py", line 10, in main raise exc # call 2 File "test.py", line 5, in main raise exc # call 1 ValueError Since you can see that the later calls are getting added on the top, it's almost as if it should read: most recent calls **first**. :) (I wonder if there's a 4-word phrase that does accurately describe what's happening.) --Chris > > -n > > On Sun, Dec 24, 2017 at 9:55 PM, Chris Jerdonek > wrote: >> Hi, >> >> I noticed that if a task in asyncio raises an exception, then the >> displayed traceback can be "polluted" by intermediate calls to >> task.result(). Also, the calls to task.result() can appear out of >> order relative to each other and to other lines. >> >> Here is an example: >> >> import asyncio >> >> async def raise_error(): >> raise ValueError() >> >> async def main(): >> task = asyncio.ensure_future(raise_error()) >> >> try: >> await task # call 1 >> except Exception: >> pass >> >> try: >> task.result() # call 2 >> except Exception: >> pass >> >> task.result() # call 3 >> >> asyncio.get_event_loop().run_until_complete(main()) >> >> The above outputs-- >> >> Traceback (most recent call last): >> File "test.py", line 24, in >> asyncio.get_event_loop().run_until_complete(main()) >> File "/Users/.../3.6.4rc1/lib/python3.6/asyncio/base_events.py", >> line 467, in run_until_complete >> return future.result() >> File "test.py", line 21, in main >> task.result() # call 3 >> File "test.py", line 17, in main >> task.result() # call 2 >> File "test.py", line 12, in main >> await task # call 1 >> File "test.py", line 5, in raise_error >> raise ValueError() >> ValueError >> >> Notice that the "call 2" line appears in the traceback, even though it >> doesn't come into play in the exception. Also, the lines don't obey >> the "most recent call last" rule. If this rule were followed, it >> should be something more like-- >> >> Traceback (most recent call last): >> File "test.py", line 24, in >> asyncio.get_event_loop().run_until_complete(main()) >> File "/Users/.../3.6.4rc1/lib/python3.6/asyncio/base_events.py", >> line 467, in run_until_complete >> return future.result() >> File "test.py", line 12, in main >> await task # call 1 >> File "test.py", line 5, in raise_error >> raise ValueError() >> File "test.py", line 17, in main >> task.result() # call 2 >> File "test.py", line 21, in main >> task.result() # call 3 >> ValueError >> >> If people agree there's an issue along these lines, I can file an >> issue in the tracker. I didn't seem to find one when searching for >> open issues with search terms like "asyncio traceback". >> >> Thanks, >> --Chris >> ___ >> Async-sig mailing list >> Async-sig@python.org >> https://mail.python.org/mailman/listinfo/async-sig >> Code of Conduct: https://www.python.org/psf/codeofconduct/ > > > > -- > Nathaniel J. Smith -- https://vorpus.org ___ Async-sig mailing list Async-sig@python.org https://mail.python.org/mailman/listinfo/async-sig Code of Conduct: https://www.python.org/psf/codeofconduct/
Re: [Async-sig] task.result() and exception traceback display
I haven't thought about this enough to have an opinion about whether this is correct or how it could be improved, but I can explain why you're seeing what you're seeing :-). The traceback is really a trace of where the exception went after it was raised, with new lines added to the top as it bubbles out. So the bottom line is the 'raise' statement, because that's where it was created, and then it bubbled onto the 'call 1' line and was caught. Then it was raised again and bubbled onto the 'call 2' line. Etc. So you should think of it not as a snapshot of your stack when it was created, but as a travelogue. -n On Sun, Dec 24, 2017 at 9:55 PM, Chris Jerdonek wrote: > Hi, > > I noticed that if a task in asyncio raises an exception, then the > displayed traceback can be "polluted" by intermediate calls to > task.result(). Also, the calls to task.result() can appear out of > order relative to each other and to other lines. > > Here is an example: > > import asyncio > > async def raise_error(): > raise ValueError() > > async def main(): > task = asyncio.ensure_future(raise_error()) > > try: > await task # call 1 > except Exception: > pass > > try: > task.result() # call 2 > except Exception: > pass > > task.result() # call 3 > > asyncio.get_event_loop().run_until_complete(main()) > > The above outputs-- > > Traceback (most recent call last): > File "test.py", line 24, in > asyncio.get_event_loop().run_until_complete(main()) > File "/Users/.../3.6.4rc1/lib/python3.6/asyncio/base_events.py", > line 467, in run_until_complete > return future.result() > File "test.py", line 21, in main > task.result() # call 3 > File "test.py", line 17, in main > task.result() # call 2 > File "test.py", line 12, in main > await task # call 1 > File "test.py", line 5, in raise_error > raise ValueError() > ValueError > > Notice that the "call 2" line appears in the traceback, even though it > doesn't come into play in the exception. Also, the lines don't obey > the "most recent call last" rule. If this rule were followed, it > should be something more like-- > > Traceback (most recent call last): > File "test.py", line 24, in > asyncio.get_event_loop().run_until_complete(main()) > File "/Users/.../3.6.4rc1/lib/python3.6/asyncio/base_events.py", > line 467, in run_until_complete > return future.result() > File "test.py", line 12, in main > await task # call 1 > File "test.py", line 5, in raise_error > raise ValueError() > File "test.py", line 17, in main > task.result() # call 2 > File "test.py", line 21, in main > task.result() # call 3 > ValueError > > If people agree there's an issue along these lines, I can file an > issue in the tracker. I didn't seem to find one when searching for > open issues with search terms like "asyncio traceback". > > Thanks, > --Chris > ___ > Async-sig mailing list > Async-sig@python.org > https://mail.python.org/mailman/listinfo/async-sig > Code of Conduct: https://www.python.org/psf/codeofconduct/ -- Nathaniel J. Smith -- https://vorpus.org ___ Async-sig mailing list Async-sig@python.org https://mail.python.org/mailman/listinfo/async-sig Code of Conduct: https://www.python.org/psf/codeofconduct/
[Async-sig] task.result() and exception traceback display
Hi, I noticed that if a task in asyncio raises an exception, then the displayed traceback can be "polluted" by intermediate calls to task.result(). Also, the calls to task.result() can appear out of order relative to each other and to other lines. Here is an example: import asyncio async def raise_error(): raise ValueError() async def main(): task = asyncio.ensure_future(raise_error()) try: await task # call 1 except Exception: pass try: task.result() # call 2 except Exception: pass task.result() # call 3 asyncio.get_event_loop().run_until_complete(main()) The above outputs-- Traceback (most recent call last): File "test.py", line 24, in asyncio.get_event_loop().run_until_complete(main()) File "/Users/.../3.6.4rc1/lib/python3.6/asyncio/base_events.py", line 467, in run_until_complete return future.result() File "test.py", line 21, in main task.result() # call 3 File "test.py", line 17, in main task.result() # call 2 File "test.py", line 12, in main await task # call 1 File "test.py", line 5, in raise_error raise ValueError() ValueError Notice that the "call 2" line appears in the traceback, even though it doesn't come into play in the exception. Also, the lines don't obey the "most recent call last" rule. If this rule were followed, it should be something more like-- Traceback (most recent call last): File "test.py", line 24, in asyncio.get_event_loop().run_until_complete(main()) File "/Users/.../3.6.4rc1/lib/python3.6/asyncio/base_events.py", line 467, in run_until_complete return future.result() File "test.py", line 12, in main await task # call 1 File "test.py", line 5, in raise_error raise ValueError() File "test.py", line 17, in main task.result() # call 2 File "test.py", line 21, in main task.result() # call 3 ValueError If people agree there's an issue along these lines, I can file an issue in the tracker. I didn't seem to find one when searching for open issues with search terms like "asyncio traceback". Thanks, --Chris ___ Async-sig mailing list Async-sig@python.org https://mail.python.org/mailman/listinfo/async-sig Code of Conduct: https://www.python.org/psf/codeofconduct/