Search code examples
pythonpython-trio

How Can I Prevent an Exception Raised By a Child Taking Down the Whole Nursery


Consider the following code:

import trio


async def broken_fn():
    await trio.sleep(4)
    print(1 / 0)


async def worker_fn():
    while True:
        print("working...")
        await trio.sleep(1)


async def main():
    async with trio.open_nursery() as nursery:
        nursery.start_soon(broken_fn)
        nursery.start_soon(worker_fn)


trio.run(main)

How do I prevent the exception raised by broken_fn to abort its siblings in the nursery without touching the definition of broken_fn? Is the following the best way?

async def main():
    async def supress(fn):
        try:
            await fn()
        except Exception as e:
            print(f"caught {e}!")

    async with trio.open_nursery() as nursery:
        nursery.start_soon(supress, broken_fn)
        nursery.start_soon(worker_fn)

Do I have any other options?


Solution

  • There is no mechanism in start_soon() to ignore exceptions, if that's what you're looking for.

    You could also do this in a generic fashion, so as not to build wrappers for each individual function:

    from contextlib import suppress
    from functools import wraps
    from typing import Callable
    
    def suppressed(func: Callable, *exceptions: BaseException):
        @wraps(func)
        async def wrapper(*args, **kwargs):
            with suppress(*exceptions):
                return await func(*args, **kwargs)
            
        return wrapper
    

    Then:

    async with trio.open_nursery() as nursery:
        nursery.start_soon(suppressed(broken_fn, Exception))
        nursery.start_soon(worker_fn)