@@ -19,36 +19,48 @@ import { IExtensions } from '../../../common/types';
19
19
import { JUPYTER_EXTENSION_ID } from '../../../common/constants' ;
20
20
21
21
/**
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.
25
26
*/
26
27
class DataFrameVariableTracker implements DebugAdapterTracker {
27
28
private readonly extensions : IExtensions ;
29
+
30
+ /** Flag to ensure we only show the notification once per debug session to avoid spam */
28
31
private hasNotifiedAboutJupyter = false ;
29
32
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
+ */
31
37
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
40
46
] ;
41
47
42
48
constructor ( _session : DebugSession , extensions : IExtensions ) {
43
49
this . extensions = extensions ;
44
50
}
45
51
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
+ */
46
58
public onDidSendMessage ( message : DebugProtocol . Message ) : void {
47
59
if ( this . hasNotifiedAboutJupyter ) {
48
60
return ; // Only notify once per debug session
49
61
}
50
62
51
- // Check if this is a variables response
63
+ // Check if this is a variables response from the debug protocol
52
64
if ( 'type' in message && message . type === 'response' && 'command' in message && message . command === 'variables' ) {
53
65
const response = message as unknown as DebugProtocol . VariablesResponse ;
54
66
if ( response . success && response . body ?. variables ) {
@@ -57,13 +69,20 @@ class DataFrameVariableTracker implements DebugAdapterTracker {
57
69
}
58
70
}
59
71
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
+ */
60
79
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
62
81
const hasDataFrame = variables . some ( ( variable ) =>
63
82
this . dataFrameTypes . some ( ( dfType ) =>
64
83
variable . type ?. includes ( dfType ) ||
65
84
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)
67
86
( variable . name ?. match ( / ^ ( d f | d a t a | d a t a f r a m e ) / i) && variable . type ?. includes ( 'pandas' ) )
68
87
)
69
88
) ;
@@ -75,8 +94,12 @@ class DataFrameVariableTracker implements DebugAdapterTracker {
75
94
return hasDataFrame ;
76
95
}
77
96
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
+ */
78
101
private checkAndNotifyJupyterExtension ( ) : void {
79
- // Check if Jupyter extension is installed
102
+ // Check if Jupyter extension is installed using VS Code extension API
80
103
const jupyterExtension = this . extensions . getExtension ( JUPYTER_EXTENSION_ID ) ;
81
104
82
105
if ( ! jupyterExtension ) {
@@ -85,6 +108,10 @@ class DataFrameVariableTracker implements DebugAdapterTracker {
85
108
}
86
109
}
87
110
111
+ /**
112
+ * Displays an information message suggesting Jupyter extension installation.
113
+ * Provides a direct action button to open the extension marketplace.
114
+ */
88
115
private showJupyterInstallNotification ( ) : void {
89
116
const message = l10n . t ( 'Install Jupyter extension to inspect dataframe objects in the data viewer.' ) ;
90
117
const installAction = l10n . t ( 'Install Jupyter Extension' ) ;
@@ -99,10 +126,22 @@ class DataFrameVariableTracker implements DebugAdapterTracker {
99
126
}
100
127
}
101
128
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
+ */
102
134
@injectable ( )
103
135
export class DataFrameTrackerFactory implements DebugAdapterTrackerFactory {
104
136
constructor ( @inject ( IExtensions ) private readonly extensions : IExtensions ) { }
105
137
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
+ */
106
145
public createDebugAdapterTracker ( session : DebugSession ) : ProviderResult < DebugAdapterTracker > {
107
146
return new DataFrameVariableTracker ( session , this . extensions ) ;
108
147
}
0 commit comments