Native call stack support for VS Code Jupyter Debugger#9
Open
mattChrisP wants to merge 1 commit intobterwijn:mainfrom
Open
Native call stack support for VS Code Jupyter Debugger#9mattChrisP wants to merge 1 commit intobterwijn:mainfrom
mattChrisP wants to merge 1 commit intobterwijn:mainfrom
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Feature: Native call stack support for VS Code Jupyter Debugger
This PR introduces call stack parsing for Jupyter Notebook environments, ensuring
memory_graphcan seamlessly visualize cell executions without blowing up or rendering kernel noise.Demonstration
memory_graph_2x.mov
(Note: This demonstration uses a locally installed version of memory_graph containing these PR changes, alongside a background script that watches the generated .gv file and automatically renders it to .png.)
Feature Summary
stack_multi_slice: A robust version ofstack_slicethat acts like an eraser across the entire stack sequence, rather than terminating early on the first match.is_vscode_jupyter_banned: A universal safety net that filters outIPythonnoise while utilizing a strict prefix bypass (__main__/<ipython-input>) to mathematically guarantee user code is never accidentally dropped.__pydevd_ret_val_dict, strips out underlying Jupyter I/O stream returns (likeOutStream.write), and ensures return values are visually mapped back to the originating function's frame dictionary.vscode_jupyter: Addedmg.vscode_jupyter()as a top-level wrapper, keeping the API consistent with existing debuggers and allowing instant usage in the VS Code Watch panel.Why
stack_slicefails in this environmentThe legacy approach (
stack_slice) searches from the top (innermost) frame downward, finds the very first match (e.g.,trace_dispatch), adds a static frame offset (e.g.,+ 2), and blindly traces everything beneath it.(Note: The following stack slices are drawn from exact, raw call stacks (using save_call_stack() function) logged from a live Jupyter notebook under VS Code)
Example 1 (Two
trace_dispatchframes)Example 2 (One
trace_dispatchframe)Result: If we use
stack_slicewith an offset of 3 (calibrated to work for Example 1), running that exact same slice on Example 2 would blindly skiptrace_dispatch, skipsquare, and skipsum_of_squares. It mathematically guarantees accidentally deleting user code or leaving debugger garbage in the graph.✅ How
stack_multi_slicefixes itInstead of relying on a static offset to jump over internal debugger hooks,
stack_multi_slicecoupled withis_vscode_jupyter_bannedevaluates the entire sequence of frames.stack_multi_slicescans the full stack and acts like an eraser. Every time it sees atrace_dispatch(offset 1), it deletes that frame. If it sees_do_wait_suspend(offset 2), it deletes that frame and its immediately bound companion frame.is_vscode_jupyter_bannedloops through what's left and erases every frame originating fromIPython,debugpy,tornado,asyncio, etc.Clean Output from
stack_multi_sliceBecause it iterates and explicitly deletes garbage frames wherever they appear, it seamlessly handles Example 1 and Example 2 without dropping user variables.