-
-
Notifications
You must be signed in to change notification settings - Fork 367
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
Tests for debugging imports #878
base: main
Are you sure you want to change the base?
Conversation
Not sure why this is not needed on CI, but I seem to need it locally.
Test to cover what happens if we step past the end of a cell's code. Expected behavior is to continue until next execute arrives, and then stop on the first statement in the new code.
Thx for working on this @vidartf
|
Yes. My statement is that master has a bug 😉 |
Probably redundant, but more robust
When launching the kernel in-process, there might be frames before the ipykernel root, making the assumption that it is the first frame invalid.
Monkey patches pydevd's global debugger instance so that frames from `__tracebackhide__ == "__ipython_bottom__"` and below are excluded from both stack traces and tracing (aka stepping). This should prevent users stepping out into the IPython/ipykernel internals between statements, and after cells. Points of note and/or discussion: - Doesn't yet handle display hooks I think. - Path/module filters are not sufficient, as the same file/frames can appear on both sides of the IPython stack "bottom". - For the same reason, caching of the filter can not be used. - Monkey patching is not ideal, especially since we also access some internals that are probably not considered part of the public API. - Are threads / forking important here? - Note that using `traitlets.validate()` for the test is useful, since it also shows up below the "bottom" of the IPython stack (at the time of writing). Maybe using a more central IPython function would be more reliable?
Some of these might be nice to keep around, especially during the review phase. We can remove (parts of) this before merging if we want to keep things tidy!
@fabioz: Do you have any input on my dirty monkey patching of your very nice library? 😅 |
So, this is an initial draft for filtering frames (proof of concept if you'd like): Monkey patches pydevd's global debugger instance so that frames from Points of note and/or discussion:
|
Regarding the monkey-patching, I'm a bit wary of it as it's bound to break as the debugger moves forward (if this functionality is really needed, this should probably be in the debugger itself).
And going up the stack every time the file type is needed is bound to be slow... Is this use-case common where a frame from code |
@fabioz Thanks for the input. As mentioned, this is mainly proof-of-concept at this stage, and anything that can be done to clean it up will be very welcome. Making it not rely on internal implementation details of pydevd is definitely one of these things.
Anything that IPython or ipykernel uses or calls out to while processing its message loop are things to consider. Some packages/libs I've observed in logs include: traitlets, asyncio, concurrent, zmq, threading, iostream, jupyter_client, json, hmac, date_utils, logging, queue, tornado, selectors, enum, signal, inspect, tokenize, contextlib, os, tempfile, codeop, dis, decorator, etc. These were only the ones I could find from quickly scanning the logs after running the tests here. I'm sure there will be others as well. Not being able to debug these (or where the ability to trace these are based on a race) seems a deal-breaker. That said, the goal would of course be to:
|
Additionally: If these frames show up above the "bottom" frame for the first time, than a step command will suddenly trace out into these outer frames, or they will confusingly show up in the stack trace. These behaviors might be much more detrimental to the user experience than not being able to trace these libs. |
Humm, if you know the points when you want to start/stop tracing and want absolute control, maybe using |
I couldn't find any reference to p.s.: the enable/disable tracing would still leave items showing in the stack frames, but those could be removed in the wrapper that sends the info to the client. |
Interesting. I can see a context manager applying this before calling into user code. Some questions/concerns come to mind though:
|
The main place that |
This shouldn't be a problem. The tracing enabling/disabling is supported by the debugger and it should make sure everything works properly (if there's any issue that'd be a bug to be fixed).
The async is indeed trickier because whenever you enter the async part you want to enable the debugger and when you get back to the loop you want to disable it (this may be a blocker... I'm not sure if there's a way to implement that). |
After thinking a bit more about it I think that your original approach of having a root frame from which the debugging happens (relying on I have to thinker a bit more about how to implement that efficiently though... |
@vidartf I've added some thoughts on the plans to tackle this in the debugger (see: microsoft/debugpy#869 (comment)). After I finish tackling that issue, I'll give you a heads up so that you can update this PR to make use of those new arguments in the |
Encoding some expected behavior in tests.
CC @echarles