Join GitHub today
GitHub is home to over 50 million developers working together to host and review code, manage projects, and build software together.Sign up
GitHub is where the world builds software
Millions of developers and companies build, ship, and maintain their software on GitHub — the largest and most advanced development platform in the world.
Elide task.context.run() and contextvars.callable() frames from tracebacks #631
@@ Coverage Diff @@ ## master #631 +/- ## ========================================== + Coverage 99.28% 99.28% +<.01% ========================================== Files 91 91 Lines 10763 10781 +18 Branches 768 770 +2 ========================================== + Hits 10686 10704 +18 Misses 58 58 Partials 19 19
For a test I guess it'd work do so something like:
async def my_child_task(): raise KeyError() async def test_frame_removal(): try: # Trick: For now cancel/nursery scopes still leave a bunch of tb gunk behind. # But if there's a MultiError, they leave it on the MultiError, which lets us get # a clean look at the KeyError itself. Someday I guess this will always be # a MultiError (#611), but for now we can force it by raising two exceptions. async with trio.open_nursery() as nursery: nursery.start_soon(my_child_task) nursery.start_soon(my_child_task) except trio.MultiError as exc: assert isinstance(exc.exceptions, KeyError) # The top frame in the exception traceback should be inside the child task, # not trio/contextvars internals. And there's only one frame inside the child task, # so this will also detect if our frame-removal is too eager. assert exc.exceptions.__traceback__.tb_frame.f_code is my_child_task.__code__
The first exception of the MultiError is as follows:
File "/Users/john/dev/trio/trio/_core/_run.py", line 201, in open_cancel_scope yield scope File "/Users/john/dev/trio/trio/_core/_run.py", line 319, in __aexit__ await self._nursery._nested_child_finished(exc) File "/Users/john/dev/trio/trio/_core/_run.py", line 425, in _nested_child_finished raise MultiError(self._pending_excs) File "/Users/john/dev/trio/trio/_core/tests/test_run.py", line 1903, in my_child_task raise KeyError()
njsmith left a comment
Oh, that's unfortunate. (And confusing!)
It wouldn't be the end of the world if we had to wait until after we did the next step of #55 (which will clean up those frames you quoted). It'll be much easier to write a test to make sure the tracebacks contain exactly the frames we expect, instead of writing a test to assert particular frames are missing.
I mentioned this a bit in chat, but let me say it again here with more carefully collected thoughts :-).
So the traceback frames that are relevant for this PR are:
At one point I was confused and thought that this was also attempting to address the frames that the nursery aexit machinery is adding, but that was wrong, it can't and doesn't affect those either way. It's just about the frames mentioned above.
So some options include:
These all seem like viable options, with slightly different complexity/reliability tradeoffs.
The current PR has a different approach, based on calling
So I don't think we should be checking filenames here.
On an unrelated note, the test isn't actually testing anything right now, I think? Like, it passes on current master, right, regardless of this change? If we want to test this change specifically we could iterate over the traceback and assert that
This is kind of ridiculous overkill, but I was thinking about how you could do it, then wrote some code to experiment, then realized that I had implemented it so we might as well use it... See also: python-trio#631