Skip to content

More traceback cleaning #3279

@jakkdl

Description

@jakkdl

https://vorpus.org/blog/beautiful-tracebacks-in-trio-v070/ made tracebacks in some scenarios nicer, but afaict it mostly just affects calls to trio.run and when spawning tasks. (Implementation. Tested in test_traceback_frame_removal).

But there's still a lot of other scenarios that cause verbose outputs:

import trio
import trio.testing

cl = trio.CapacityLimiter(1)
async def borrower() -> None:
    await cl.acquire()
    await trio.sleep_forever()

async def main() -> None:
    async with trio.open_nursery() as nursery:
        nursery.start_soon(borrower)
        await trio.testing.wait_all_tasks_blocked()

        with trio.fail_after(1):
            async with cl:
                pass
trio.run(main)
  + Exception Group Traceback (most recent call last):
  |   File "/home/h/Git/trio/clean_tb/test_foo.py", line 16, in <module>
  |     trio.run(main)
  |     ~~~~~~~~^^^^^^
  |   File "/home/h/Git/trio/clean_tb/src/trio/_core/_run.py", line 2529, in run
  |     raise runner.main_task_outcome.error
  |   File "/home/h/Git/trio/clean_tb/test_foo.py", line 10, in main
  |     async with trio.open_nursery() as nursery:
  |                ~~~~~~~~~~~~~~~~~^^
  |   File "/home/h/Git/trio/clean_tb/src/trio/_core/_run.py", line 1122, in __aexit__
  |     raise combined_error_from_nursery
  | ExceptionGroup: Exceptions from Trio nursery (1 sub-exception)
  +-+---------------- 1 ----------------
    | Traceback (most recent call last):
    |   File "/home/h/Git/trio/clean_tb/src/trio/_sync.py", line 342, in acquire_on_behalf_of
    |     self.acquire_on_behalf_of_nowait(borrower)
    |     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^^^^^^^^^
    |   File "/home/h/Git/trio/clean_tb/src/trio/_sync.py", line 312, in acquire_on_behalf_of_nowait
    |     raise trio.WouldBlock
    | trio.WouldBlock
    | 
    | During handling of the above exception, another exception occurred:
    | 
    | Traceback (most recent call last):
    |   File "/home/h/Git/trio/clean_tb/src/trio/_timeouts.py", line 185, in fail_after
    |     yield scope
    |   File "/home/h/Git/trio/clean_tb/test_foo.py", line 14, in main
    |     async with cl:
    |                ^^
    |   File "/home/h/Git/trio/clean_tb/src/trio/_sync.py", line 127, in __aenter__
    |     await self.acquire()
    |   File "/home/h/Git/trio/clean_tb/src/trio/_sync.py", line 323, in acquire
    |     await self.acquire_on_behalf_of(trio.lowlevel.current_task())
    |   File "/home/h/Git/trio/clean_tb/src/trio/_sync.py", line 347, in acquire_on_behalf_of
    |     await self._lot.park()
    |   File "/home/h/Git/trio/clean_tb/src/trio/_core/_parking_lot.py", line 190, in park
    |     await _core.wait_task_rescheduled(abort_fn)
    |   File "/home/h/Git/trio/clean_tb/src/trio/_core/_traps.py", line 208, in wait_task_rescheduled
    |     return (await _async_yield(WaitTaskRescheduled(abort_func))).unwrap()
    |            ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^^
    |   File "/home/h/Git/trio/clean_tb/.venv/lib/python3.13/site-packages/outcome/_impl.py", line 213, in unwrap
    |     raise captured_error
    |   File "/home/h/Git/trio/clean_tb/src/trio/_core/_run.py", line 1657, in raise_cancel
    |     raise Cancelled._create(
    |     ...<3 lines>...
    |     )
    | trio.Cancelled: cancelled due to deadline
    | 
    | During handling of the above exception, another exception occurred:
    | 
    | Traceback (most recent call last):
    |   File "/home/h/Git/trio/clean_tb/test_foo.py", line 13, in main
    |     with trio.fail_after(1):
    |          ~~~~~~~~~~~~~~~^^^
    |   File "/usr/lib/python3.13/contextlib.py", line 162, in __exit__
    |     self.gen.throw(value)
    |     ~~~~~~~~~~~~~~^^^^^^^
    |   File "/home/h/Git/trio/clean_tb/src/trio/_timeouts.py", line 187, in fail_after
    |     raise TooSlowError
    | trio.TooSlowError
    +------------------------------------

I'm not entirely sure what the best approach is to try and clean this up. We could try cleaning up tracebacks in Cancelled.__init__, or a custom [Base]ExceptionGroup that filters the traceback in child exceptions. Other options include modifying sys.excepthook, sprinkling tons of __traceback_hide__, or if there's a few repeat offenders rewriting select code to add fewer frames to the stack.

Would also be great to collect more examples of unhelpfully long tracebacks to see if there are repeat offenders that would give disproportionate impact to improve. @Zac-HD

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