@@ -80,6 +80,16 @@ export abstract class BaseConfigurationResolver<T extends DebugConfiguration>
8080 return undefined ;
8181 }
8282
83+ /**
84+ * Resolves and updates file paths and Python interpreter paths in the debug configuration.
85+ *
86+ * This method performs two main operations:
87+ * 1. Resolves workspace variables in the envFile path (if specified)
88+ * 2. Resolves and updates Python interpreter paths, handling legacy pythonPath deprecation
89+ *
90+ * @param workspaceFolder The workspace folder URI for variable resolution
91+ * @param debugConfiguration The launch configuration to update
92+ */
8393 protected async resolveAndUpdatePaths (
8494 workspaceFolder : Uri | undefined ,
8595 debugConfiguration : LaunchRequestArguments ,
@@ -88,76 +98,130 @@ export abstract class BaseConfigurationResolver<T extends DebugConfiguration>
8898 await this . resolveAndUpdatePythonPath ( workspaceFolder , debugConfiguration ) ;
8999 }
90100
101+ /**
102+ * Resolves workspace variables in the envFile path.
103+ *
104+ * Expands variables like ${workspaceFolder} in the envFile configuration using the
105+ * workspace folder path or current working directory as the base for resolution.
106+ *
107+ * @param workspaceFolder The workspace folder URI for variable resolution
108+ * @param debugConfiguration The launch configuration containing the envFile path
109+ */
91110 protected static resolveAndUpdateEnvFilePath (
92111 workspaceFolder : Uri | undefined ,
93112 debugConfiguration : LaunchRequestArguments ,
94113 ) : void {
95- if ( ! debugConfiguration ) {
114+ // Early exit if no configuration or no envFile to resolve
115+ if ( ! debugConfiguration ?. envFile ) {
96116 return ;
97117 }
98- if ( debugConfiguration . envFile && ( workspaceFolder || debugConfiguration . cwd ) ) {
99- debugConfiguration . envFile = resolveWorkspaceVariables (
100- debugConfiguration . envFile ,
101- ( workspaceFolder ? workspaceFolder . fsPath : undefined ) || debugConfiguration . cwd ,
102- undefined ,
103- ) ;
118+
119+ const basePath = workspaceFolder ?. fsPath || debugConfiguration . cwd ;
120+
121+ if ( basePath ) {
122+ // update envFile with resolved variables
123+ debugConfiguration . envFile = resolveWorkspaceVariables ( debugConfiguration . envFile , basePath , undefined ) ;
104124 }
105125 }
106126
127+ /**
128+ * Resolves Python interpreter paths and handles the legacy pythonPath deprecation.
129+ *
130+ * @param workspaceFolder The workspace folder URI for variable resolution and interpreter detection
131+ * @param debugConfiguration The launch configuration to update with resolved Python paths
132+ */
107133 protected async resolveAndUpdatePythonPath (
108134 workspaceFolder : Uri | undefined ,
109135 debugConfiguration : LaunchRequestArguments ,
110136 ) : Promise < void > {
111137 if ( ! debugConfiguration ) {
112138 return ;
113139 }
140+
141+ // get the interpreter details in the context of the workspace folder
142+ const interpreterDetail = await getInterpreterDetails ( workspaceFolder ) ;
143+ const interpreterPath = interpreterDetail ?. path ?? ( await getSettingsPythonPath ( workspaceFolder ) ) ;
144+ const resolvedInterpreterPath = interpreterPath ? interpreterPath [ 0 ] : interpreterPath ;
145+
146+ traceLog (
147+ `resolveAndUpdatePythonPath - Initial state: ` +
148+ `pythonPath='${ debugConfiguration . pythonPath } ', ` +
149+ `python='${ debugConfiguration . python } ', ` +
150+ `debugAdapterPython='${ debugConfiguration . debugAdapterPython } ', ` +
151+ `debugLauncherPython='${ debugConfiguration . debugLauncherPython } ', ` +
152+ `workspaceFolder='${ workspaceFolder ?. fsPath } '` +
153+ `resolvedInterpreterPath='${ resolvedInterpreterPath } '` ,
154+ ) ;
155+
156+ // STEP 1: Resolve legacy pythonPath property (DEPRECATED)
157+ // pythonPath will equal user set value, or getInterpreterDetails if undefined or set to command
114158 if ( debugConfiguration . pythonPath === '${command:python.interpreterPath}' || ! debugConfiguration . pythonPath ) {
115- const interpreterDetail = await getInterpreterDetails ( workspaceFolder ) ;
116- const interpreterPath = interpreterDetail
117- ? interpreterDetail . path
118- : await getSettingsPythonPath ( workspaceFolder ) ;
119- debugConfiguration . pythonPath = interpreterPath ? interpreterPath [ 0 ] : interpreterPath ;
159+ this . pythonPathSource = PythonPathSource . settingsJson ;
160+ debugConfiguration . pythonPath = resolvedInterpreterPath ;
120161 } else {
162+ // User provided explicit pythonPath in launch.json
121163 debugConfiguration . pythonPath = resolveWorkspaceVariables (
122- debugConfiguration . pythonPath ? debugConfiguration . pythonPath : undefined ,
164+ debugConfiguration . pythonPath ,
123165 workspaceFolder ?. fsPath ,
124166 undefined ,
125167 ) ;
126168 }
127169
170+ // STEP 2: Resolve current python property (CURRENT STANDARD)
128171 if ( debugConfiguration . python === '${command:python.interpreterPath}' ) {
172+ // if python is set to the command, resolve it
129173 this . pythonPathSource = PythonPathSource . settingsJson ;
130- const interpreterDetail = await getInterpreterDetails ( workspaceFolder ) ;
131- const interpreterPath = interpreterDetail . path
132- ? interpreterDetail . path
133- : await getSettingsPythonPath ( workspaceFolder ) ;
134- debugConfiguration . python = interpreterPath ? interpreterPath [ 0 ] : interpreterPath ;
135- } else if ( debugConfiguration . python === undefined ) {
136- this . pythonPathSource = PythonPathSource . settingsJson ;
174+ debugConfiguration . python = resolvedInterpreterPath ;
175+ } else if ( ! debugConfiguration . python ) {
176+ // fallback to pythonPath if python undefined
137177 debugConfiguration . python = debugConfiguration . pythonPath ;
138178 } else {
179+ // User provided explicit python path in launch.json
139180 this . pythonPathSource = PythonPathSource . launchJson ;
140181 debugConfiguration . python = resolveWorkspaceVariables (
141- debugConfiguration . python ?? debugConfiguration . pythonPath ,
182+ debugConfiguration . python ,
142183 workspaceFolder ?. fsPath ,
143184 undefined ,
144185 ) ;
145186 }
146187
147- if (
188+ // STEP 3: Set debug adapter and launcher Python paths (backwards compatible)
189+ this . setDebugComponentPythonPaths ( debugConfiguration ) ;
190+
191+ // STEP 4: Clean up - remove the deprecated pythonPath property
192+ delete debugConfiguration . pythonPath ;
193+ }
194+
195+ /**
196+ * Sets debugAdapterPython and debugLauncherPython with backwards compatibility.
197+ * Prefers pythonPath over python for these internal properties.
198+ *
199+ * @param debugConfiguration The debug configuration to update
200+ */
201+ private setDebugComponentPythonPaths ( debugConfiguration : LaunchRequestArguments ) : void {
202+ const shouldSetDebugAdapter =
148203 debugConfiguration . debugAdapterPython === '${command:python.interpreterPath}' ||
149- debugConfiguration . debugAdapterPython === undefined
150- ) {
151- debugConfiguration . debugAdapterPython = debugConfiguration . pythonPath ?? debugConfiguration . python ;
152- }
153- if (
204+ debugConfiguration . debugAdapterPython === undefined ;
205+
206+ const shouldSetDebugLauncher =
154207 debugConfiguration . debugLauncherPython === '${command:python.interpreterPath}' ||
155- debugConfiguration . debugLauncherPython === undefined
156- ) {
157- debugConfiguration . debugLauncherPython = debugConfiguration . pythonPath ?? debugConfiguration . python ;
208+ debugConfiguration . debugLauncherPython === undefined ;
209+
210+ // Default fallback path (prefer pythonPath for backwards compatibility)
211+ const fallbackPath = debugConfiguration . pythonPath ?? debugConfiguration . python ;
212+
213+ if ( debugConfiguration . pythonPath !== debugConfiguration . python ) {
214+ sendTelemetryEvent ( EventName . DEPRECATED_CODE_PATH_USAGE , undefined , {
215+ codePath : 'different_python_paths_in_debug_config' ,
216+ } ) ;
158217 }
159218
160- delete debugConfiguration . pythonPath ;
219+ if ( shouldSetDebugAdapter ) {
220+ debugConfiguration . debugAdapterPython = fallbackPath ;
221+ }
222+ if ( shouldSetDebugLauncher ) {
223+ debugConfiguration . debugLauncherPython = fallbackPath ;
224+ }
161225 }
162226
163227 protected static debugOption ( debugOptions : DebugOptions [ ] , debugOption : DebugOptions ) : void {
0 commit comments