@@ -11,7 +11,7 @@ import { IWorkspaceService } from '../../common/application/types';
11
11
import { PYTHON_LANGUAGE } from '../../common/constants' ;
12
12
import { traceDecorators , traceError , traceInfo , traceInfoIf } from '../../common/logger' ;
13
13
import { IFileSystem , IPlatformService } from '../../common/platform/types' ;
14
- import { IExtensionContext , IPathUtils , Resource } from '../../common/types' ;
14
+ import { IExtensionContext , IPathUtils , ReadWrite , Resource } from '../../common/types' ;
15
15
import { IEnvironmentVariablesProvider } from '../../common/variables/types' ;
16
16
import { IInterpreterService } from '../../interpreter/contracts' ;
17
17
import { PythonEnvironment } from '../../pythonEnvironments/info' ;
@@ -189,35 +189,59 @@ export class LocalKernelFinder implements ILocalKernelFinder {
189
189
let filteredInterpreters = [ ...interpreters ] ;
190
190
191
191
// Then go through all of the kernels and generate their metadata
192
- const kernelMetadata = kernelSpecs . map ( ( k ) => {
193
- // Find the interpreter that matches. If we find one, we want to use
194
- // this to start the kernel.
195
- const matchingInterpreters = this . findMatchingInterpreters ( k , interpreters ) ;
196
- if ( matchingInterpreters && matchingInterpreters . length ) {
197
- const result : PythonKernelConnectionMetadata = {
198
- kind : 'startUsingPythonInterpreter' ,
199
- kernelSpec : k ,
200
- interpreter : matchingInterpreters [ 0 ] ,
201
- id : getKernelId ( k , matchingInterpreters [ 0 ] )
202
- } ;
203
-
204
- // If interpreters were found, remove them from the interpreter list we'll eventually
205
- // return as interpreter only items
206
- filteredInterpreters = filteredInterpreters . filter ( ( i ) => ! matchingInterpreters . includes ( i ) ) ;
192
+ const kernelMetadata = await Promise . all (
193
+ kernelSpecs . map ( async ( k ) => {
194
+ // Find the interpreter that matches. If we find one, we want to use
195
+ // this to start the kernel.
196
+ const matchingInterpreters = this . findMatchingInterpreters ( k , interpreters ) ;
197
+ if ( matchingInterpreters && matchingInterpreters . length ) {
198
+ const result : PythonKernelConnectionMetadata = {
199
+ kind : 'startUsingPythonInterpreter' ,
200
+ kernelSpec : k ,
201
+ interpreter : matchingInterpreters [ 0 ] ,
202
+ id : getKernelId ( k , matchingInterpreters [ 0 ] )
203
+ } ;
207
204
208
- // Return our metadata that uses an interpreter to start
209
- return result ;
210
- } else {
211
- // No interpreter found. If python, use the active interpreter anyway
212
- const result : KernelSpecConnectionMetadata = {
213
- kind : 'startUsingKernelSpec' ,
214
- kernelSpec : k ,
215
- interpreter : k . language === PYTHON_LANGUAGE ? activeInterpreter : undefined ,
216
- id : getKernelId ( k , activeInterpreter )
217
- } ;
218
- return result ;
219
- }
220
- } ) ;
205
+ // If interpreters were found, remove them from the interpreter list we'll eventually
206
+ // return as interpreter only items
207
+ filteredInterpreters = filteredInterpreters . filter ( ( i ) => ! matchingInterpreters . includes ( i ) ) ;
208
+
209
+ // Return our metadata that uses an interpreter to start
210
+ return result ;
211
+ } else {
212
+ let interpreter = k . language === PYTHON_LANGUAGE ? activeInterpreter : undefined ;
213
+ // If the interpreter information is stored in kernelspec.json then use that to determine the interpreter.
214
+ // This can happen under the following circumstances:
215
+ // 1. Open workspace folder XYZ, and create a virtual environment named venvA
216
+ // 2. Now assume we don't have raw kernels, and a kernel gets registered for venvA in kernelspecs folder.
217
+ // 3. The kernel spec will contain metadata pointing to venvA.
218
+ // 4. Now open a different folder (e.g. a sub directory of XYZ or a completely different folder).
219
+ // 5. Now venvA will not be listed as an interpreter as Python will not discover this.
220
+ // 6. However the kernel we registered against venvA will be in global kernels folder
221
+ // In such an instance the interpreter information is stored in the kernelspec.json file.
222
+ if (
223
+ k . language === PYTHON_LANGUAGE &&
224
+ this . extensionChecker . isPythonExtensionInstalled &&
225
+ k . metadata ?. interpreter ?. path &&
226
+ k . metadata ?. interpreter ?. path !== activeInterpreter ?. path
227
+ ) {
228
+ interpreter = await this . interpreterService
229
+ . getInterpreterDetails ( k . metadata ?. interpreter ?. path )
230
+ . catch ( ( ex ) => {
231
+ traceError ( `Failed to get interpreter details for Kernel Spec ${ k . specFile } ` , ex ) ;
232
+ return interpreter ;
233
+ } ) ;
234
+ }
235
+ const result : KernelSpecConnectionMetadata = {
236
+ kind : 'startUsingKernelSpec' ,
237
+ kernelSpec : k ,
238
+ interpreter,
239
+ id : getKernelId ( k , activeInterpreter )
240
+ } ;
241
+ return result ;
242
+ }
243
+ } )
244
+ ) ;
221
245
222
246
// Combine the two into our list
223
247
const results = [
@@ -424,7 +448,7 @@ export class LocalKernelFinder implements ILocalKernelFinder {
424
448
interpreter ?: PythonEnvironment ,
425
449
cancelToken ?: CancellationToken
426
450
) : Promise < IJupyterKernelSpec | undefined > {
427
- let kernelJson ;
451
+ let kernelJson : ReadWrite < IJupyterKernelSpec > ;
428
452
try {
429
453
traceInfo ( `Loading kernelspec from ${ specPath } for ${ interpreter ?. path } ` ) ;
430
454
kernelJson = JSON . parse ( await this . fs . readLocalFile ( specPath ) ) ;
@@ -447,7 +471,13 @@ export class LocalKernelFinder implements ILocalKernelFinder {
447
471
? interpreter ?. displayName || kernelJson . display_name
448
472
: kernelJson . display_name ;
449
473
450
- const kernelSpec : IJupyterKernelSpec = new JupyterKernelSpec ( kernelJson , specPath , interpreter ?. path ) ;
474
+ const kernelSpec : IJupyterKernelSpec = new JupyterKernelSpec (
475
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
476
+ kernelJson as any ,
477
+ specPath ,
478
+ // Interpreter information may be saved in the metadata (if this is a kernel spec created/registered by us).
479
+ interpreter ?. path || kernelJson ?. metadata ?. interpreter ?. path
480
+ ) ;
451
481
452
482
// Some registered kernel specs do not have a name, in this case use the last part of the path
453
483
kernelSpec . name = kernelJson ?. name || path . basename ( path . dirname ( specPath ) ) ;
0 commit comments