dabeaz / curio

Good Curio!
Other
4.04k stars 243 forks source link

Access stack of a crashed child task? #203

Closed goldcode closed 7 years ago

goldcode commented 7 years ago
import traceback
import sys
import curio

def some_evil_function():
    raise Exception('oops')

async def child():
    some_evil_function()

async def parent():
    try:
        task = await curio.spawn(child)
        await task.join()
    except curio.TaskError as e:
        pass

curio.run(parent)

running the above outputs the following below. however i am unable to access the stack of the crashing task- child in this case.

how would i access this? If not accessible, would it be possible to pin either the task or the TaskError exception object with the sys.exc_info of the crashing task? it's useful for rerouting this information to other programs in my case for faster error handling.

Task 3 crashed
Traceback (most recent call last):
  File "c:\Users\DSARN\AppData\Local\Programs\Python\Python36\lib\site-packages\curio\kernel.py", line 835, in _run_coro
    trap = current._send(current.next_value)
  File "c:\Users\DSARN\AppData\Local\Programs\Python\Python36\lib\site-packages\curio\task.py", line 96, in _task_runner
    return await coro
  File "c:\Evobase2005\Main\EvoPro\PyTools\tests\sandbox.py", line 9, in child
    some_evil_function()
  File "c:\Evobase2005\Main\EvoPro\PyTools\tests\sandbox.py", line 6, in some_evil_function
    raise Exception('oops')
Exception: oops
Task crash
kalvdans commented 7 years ago

If we were to attach the original stack trace to the TaskError, I prefer using the raise ... from ... syntax. Then the original exception will be available at e.__cause__

njsmith commented 7 years ago

I think you're looking for e.__traceback__? But yeah, if you just want to preserve the traceback while propagating the exception to another task, reraising the exception object, or using raise ... from ... will do that, because exception objects carry their traceback with them.

dabeaz commented 7 years ago

I'm pretty sure that e.__cause__.__traceback__ would have the traceback. Definitely in the weeds a bit once the exception chains start to get long though...

njsmith commented 7 years ago

Oh right, I forgot the TaskError wrapping... e.__cause__ is how you get the original exception.

goldcode commented 7 years ago

i think i figured out what my problem actually was. Below gives information about the entire exception chain.

except curio.TaskError as te:
            tuple_strings = traceback.format_exception(curio.TaskError, te, None)
            message = ''.join(tuple_strings)

as opposed to only the top most exception traceback like so. message = ''.join(traceback.format_tb(te.__cause__.__traceback__))