Skip to content

Channel context manager eats exceptions when cancelled #746

Closed

Description

@oremanj

I ran into this today:

import trio

async def produce(send_channel):
    async with send_channel:
        print("in async with send_channel")
        raise RuntimeError("kaboom")

async def test():
    send_channel, receive_channel = trio.open_memory_channel(0)
    with trio.open_cancel_scope() as scope:
        scope.cancel()
        await produce(send_channel)

trio.run(test)
print("where's the kaboom?")

Prints:

in async with send_channel
where's the kaboom?

I'm guessing this is because channel.aclose() is a checkpoint? Seems like this exception-eating might be the same or an overlapping issue as #455, but it was especially surprising to me, and I think might create user confusion as people start using async with foo_channel: in more and more places.

Activity

  1. m-u-xyz commented on Oct 23, 2018

    @m-u-xyz
    Contributor

    It is. There's not much that Trio can do internally to fix that IMHO, but what about a

    def __aexit__(self, *tb):  # and/or __exit__
        with merge_exceptions(*tb):
            foo()
    

    context manager that packages the exception(s) raised by foo, and the traceback if one exists, into a MultiError (or whatever Python's stdlib ends up naming the thing)? At least then we'd have a standard idiom that we can use, and the one additional line of boilerplate won't hurt (too much) (and can be checked for by a linter).

  2. njsmith commented on Oct 23, 2018

    @njsmith
    Member

    Yeah, this is exactly the same as #455, so I'll close it to consolidate the discussion.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions