Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add documentation on interpreting Trio tracebacks #798

Open
belm0 opened this issue Dec 11, 2018 · 5 comments
Open

Add documentation on interpreting Trio tracebacks #798

belm0 opened this issue Dec 11, 2018 · 5 comments

Comments

@belm0
Copy link
Member

belm0 commented Dec 11, 2018

Perhaps this is a general Python issue, but it's rather confusing that the last line of a nursery block appears in exception traces regardless of the line being reached. Seen with Python 3.6 / Trio 0.9.0:

import trio

async def async_main():
    async with trio.open_nursery() as nursery:
        @nursery.start_soon
        async def raiser():
            await trio.sleep(1)
            raise Exception('boo')

        await trio.sleep_forever()
        assert False
        print("Last line of nursery block")

try:
    trio.run(async_main)
except KeyboardInterrupt:
    pass
Traceback (most recent call last):
  File "trace_mystery.py", line 17, in <module>
    trio.run(async_main)
  File "/.../trio/_core/_run.py", line 1337, in run
    raise runner.main_task_outcome.error
  File "trace_mystery.py", line 13, in async_main
    print("Last line of nursery block")                              <--- ????
  File "/.../trio/_core/_run.py", line 397, in __aexit__
    raise combined_error_from_nursery
  File "trace_mystery.py", line 9, in raiser
    raise Exception('boo')
Exception: boo
@njsmith
Copy link
Member

njsmith commented Dec 11, 2018

Yeah, Python is trying to show you the exception coming out of the invisible call to __aexit__ at the end of the async with block. But that's invisible. So it's just showing you the end of the async with block. Which I guess is logical, but it's confusing and annoying.

I'm pretty sure that in current Python, there's no way to avoid this.

I don't have any fabulous ideas for changes we could propose to Python that would help in future versions. Just not mentioning __exit__ and __aexit__ in tracebacks doesn't feel super helpful either?

@njsmith
Copy link
Member

njsmith commented Dec 11, 2018

Possibly we should treat this as a docs issue? It can be tricky warning about weird corner cases like this in the docs, without it turning into a big pile of confusing issues that most new users don't even notice. But maybe there's a way to avoid that?

@belm0
Copy link
Member Author

belm0 commented Dec 11, 2018

Yes, perhaps a guide to understanding Trio stack traces. Could cover Python deficiencies like this, expand on names like "combined_nursery_error", etc.

@belm0
Copy link
Member Author

belm0 commented Dec 19, 2018

I'd prefer if python traces attributed __aexit__ at the opening line of the block. Reasonable?

Traceback (most recent call last):
  File "trace_mystery.py", line 17, in <module>
    trio.run(async_main)
  File "/.../trio/_core/_run.py", line 1337, in run
    raise runner.main_task_outcome.error
  File "trace_mystery.py", line 5, in __aexit__
    async with trio.open_nursery() as nursery
  File "/.../trio/_core/_run.py", line 397, in __aexit__
    raise combined_error_from_nursery
  File "trace_mystery.py", line 9, in raiser
    raise Exception('boo')

By the way, isn't this issue unique to async control structures? (@njsmith you mentioned __exit__)

@oremanj oremanj changed the title exception trace confusion: last line of nursery block always appears Add documentation on interpreting Trio tracebacks May 1, 2019
@oremanj oremanj added the docs label May 1, 2019
@oremanj
Copy link
Member

oremanj commented May 1, 2019

I think treating this as a docs issue is a good idea -- I personally do agree that mapping to the opening line of the with block would be clearer, but I'm dubious that upstream Python will agree.

@belm0, it's not unique to async:

$ cat t.py
class SyncCM:
  def __enter__(self): pass
  def __exit__(self, *exc): raise RuntimeError

with SyncCM():
  print("Last line of CM")
print("Outside CM")
$ python3.6 t.py
Last line of CM
Traceback (most recent call last):
  File "t.py", line 6, in <module>
    print("Last line of CM")
  File "t.py", line 3, in __exit__
    def __exit__(self, *exc): raise RuntimeError
RuntimeError

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants