@@ -19,36 +19,48 @@ import { IExtensions } from '../../../common/types';
1919import { JUPYTER_EXTENSION_ID } from '../../../common/constants' ;
2020
2121/**
22- * Debug adapter tracker that monitors for dataframe-like variables
23- * and suggests installing the Jupyter extension when they are detected
24- * but the Jupyter extension is not installed.
22+ * Debug adapter tracker that monitors for dataframe-like variables during debugging sessions
23+ * and suggests installing the Jupyter extension when they are detected but the Jupyter extension
24+ * is not installed. This helps users discover the data viewer functionality when working with
25+ * dataframes without the Jupyter extension.
2526 */
2627class DataFrameVariableTracker implements DebugAdapterTracker {
2728 private readonly extensions : IExtensions ;
29+
30+ /** Flag to ensure we only show the notification once per debug session to avoid spam */
2831 private hasNotifiedAboutJupyter = false ;
2932
30- // Types that are considered dataframe-like
33+ /**
34+ * Known dataframe type patterns from popular Python data processing libraries.
35+ * These patterns are matched against variable type strings in debug protocol responses.
36+ */
3137 private readonly dataFrameTypes = [
32- 'pandas.core.frame.DataFrame' ,
33- 'pandas.DataFrame' ,
34- 'polars.DataFrame' ,
35- 'cudf.DataFrame' ,
36- 'dask.dataframe.core.DataFrame' ,
37- 'modin.pandas.DataFrame' ,
38- 'vaex.dataframe.DataFrame' ,
39- 'geopandas.geodataframe.GeoDataFrame' ,
38+ 'pandas.core.frame.DataFrame' , // Full pandas path
39+ 'pandas.DataFrame' , // Simplified pandas
40+ 'polars.DataFrame' , // Polars dataframes
41+ 'cudf.DataFrame' , // RAPIDS cuDF
42+ 'dask.dataframe.core.DataFrame' , // Dask distributed dataframes
43+ 'modin.pandas.DataFrame' , // Modin pandas-compatible
44+ 'vaex.dataframe.DataFrame' , // Vaex out-of-core dataframes
45+ 'geopandas.geodataframe.GeoDataFrame' , // GeoPandas geographic data
4046 ] ;
4147
4248 constructor ( _session : DebugSession , extensions : IExtensions ) {
4349 this . extensions = extensions ;
4450 }
4551
52+ /**
53+ * Intercepts debug protocol messages to monitor for variable responses.
54+ * When a variables response is detected, checks for dataframe-like objects.
55+ *
56+ * @param message - Debug protocol message from the debug adapter
57+ */
4658 public onDidSendMessage ( message : DebugProtocol . Message ) : void {
4759 if ( this . hasNotifiedAboutJupyter ) {
4860 return ; // Only notify once per debug session
4961 }
5062
51- // Check if this is a variables response
63+ // Check if this is a variables response from the debug protocol
5264 if ( 'type' in message && message . type === 'response' && 'command' in message && message . command === 'variables' ) {
5365 const response = message as unknown as DebugProtocol . VariablesResponse ;
5466 if ( response . success && response . body ?. variables ) {
@@ -57,13 +69,20 @@ class DataFrameVariableTracker implements DebugAdapterTracker {
5769 }
5870 }
5971
72+ /**
73+ * Examines an array of debug variables to detect dataframe-like objects.
74+ * Uses multiple detection strategies: type matching, value inspection, and name heuristics.
75+ *
76+ * @param variables - Array of variables from debug protocol variables response
77+ * @returns true if any dataframe-like variables were detected
78+ */
6079 private checkForDataFrameVariables ( variables : DebugProtocol . Variable [ ] ) : boolean {
61- // Check if any variable is a dataframe-like object
80+ // Check if any variable is a dataframe-like object using multiple detection methods
6281 const hasDataFrame = variables . some ( ( variable ) =>
6382 this . dataFrameTypes . some ( ( dfType ) =>
6483 variable . type ?. includes ( dfType ) ||
6584 variable . value ?. includes ( dfType ) ||
66- // Also check if the variable name suggests it's a dataframe
85+ // Also check if the variable name suggests it's a dataframe (common naming patterns)
6786 ( variable . name ?. match ( / ^ ( d f | d a t a | d a t a f r a m e ) / i) && variable . type ?. includes ( 'pandas' ) )
6887 )
6988 ) ;
@@ -75,8 +94,12 @@ class DataFrameVariableTracker implements DebugAdapterTracker {
7594 return hasDataFrame ;
7695 }
7796
97+ /**
98+ * Checks if the Jupyter extension is installed and shows notification if not.
99+ * This is the core logic that determines whether the user needs the suggestion.
100+ */
78101 private checkAndNotifyJupyterExtension ( ) : void {
79- // Check if Jupyter extension is installed
102+ // Check if Jupyter extension is installed using VS Code extension API
80103 const jupyterExtension = this . extensions . getExtension ( JUPYTER_EXTENSION_ID ) ;
81104
82105 if ( ! jupyterExtension ) {
@@ -85,6 +108,10 @@ class DataFrameVariableTracker implements DebugAdapterTracker {
85108 }
86109 }
87110
111+ /**
112+ * Displays an information message suggesting Jupyter extension installation.
113+ * Provides a direct action button to open the extension marketplace.
114+ */
88115 private showJupyterInstallNotification ( ) : void {
89116 const message = l10n . t ( 'Install Jupyter extension to inspect dataframe objects in the data viewer.' ) ;
90117 const installAction = l10n . t ( 'Install Jupyter Extension' ) ;
@@ -99,10 +126,22 @@ class DataFrameVariableTracker implements DebugAdapterTracker {
99126 }
100127}
101128
129+ /**
130+ * Factory for creating DataFrameVariableTracker instances for debug sessions.
131+ * This factory is registered with VS Code's debug adapter tracker system to
132+ * automatically monitor all Python debug sessions for dataframe variables.
133+ */
102134@injectable ( )
103135export class DataFrameTrackerFactory implements DebugAdapterTrackerFactory {
104136 constructor ( @inject ( IExtensions ) private readonly extensions : IExtensions ) { }
105137
138+ /**
139+ * Creates a new DataFrameVariableTracker for each debug session.
140+ * Each debug session gets its own tracker instance to maintain session-specific state.
141+ *
142+ * @param session - The debug session that this tracker will monitor
143+ * @returns A new DataFrameVariableTracker instance
144+ */
106145 public createDebugAdapterTracker ( session : DebugSession ) : ProviderResult < DebugAdapterTracker > {
107146 return new DataFrameVariableTracker ( session , this . extensions ) ;
108147 }
0 commit comments