@@ -79,7 +79,7 @@ export class KernelService {
79
79
*/
80
80
public async findMatchingKernelSpec (
81
81
interpreter : PythonInterpreter ,
82
- sessionManager : IJupyterSessionManager | undefined ,
82
+ sessionManager ? : IJupyterSessionManager | undefined ,
83
83
cancelToken ?: CancellationToken
84
84
) : Promise < IJupyterKernelSpec | undefined > ;
85
85
public async findMatchingKernelSpec (
@@ -151,38 +151,48 @@ export class KernelService {
151
151
*/
152
152
@captureTelemetry ( Telemetry . RegisterInterpreterAsKernel , undefined , true )
153
153
@traceDecorators . error ( 'Failed to register an interpreter as a kernel' )
154
- public async registerKernel ( interpreter : PythonInterpreter , cancelToken ?: CancellationToken ) : Promise < IJupyterKernelSpec > {
155
- if ( ! interpreter . displayName ) {
154
+ public async registerKernel ( interpreter : PythonInterpreter , cancelToken ?: CancellationToken ) : Promise < IJupyterKernelSpec | undefined > {
155
+ if ( ! interpreter . displayName ) {
156
156
throw new Error ( 'Interpreter does not have a display name' ) ;
157
157
}
158
158
const ipykernelCommand = await this . commandFinder . findBestCommand ( JupyterCommands . KernelCreateCommand , cancelToken ) ;
159
- if ( ipykernelCommand . status === ModuleExistsStatus . NotFound || ! ipykernelCommand . command ) {
159
+ if ( ipykernelCommand . status === ModuleExistsStatus . NotFound || ! ipykernelCommand . command ) {
160
160
throw new Error ( 'Command not found to install the kernel' ) ;
161
161
}
162
+ if ( Cancellation . isCanceled ( cancelToken ) ) {
163
+ return ;
164
+ }
162
165
const name = await this . generateKernelNameForIntepreter ( interpreter ) ;
163
166
const output = await ipykernelCommand . command . exec ( [ 'install' , '--user' , '--name' , name , '--display-name' , interpreter . displayName ] , {
164
167
throwOnStdErr : true ,
165
168
encoding : 'utf8' ,
166
169
token : cancelToken
167
170
} ) ;
168
- const kernel = await this . findMatchingKernelSpec ( { display_name : interpreter . displayName , name} , undefined , cancelToken ) ;
169
- if ( ! kernel ) {
171
+ if ( Cancellation . isCanceled ( cancelToken ) ) {
172
+ return ;
173
+ }
174
+
175
+ const kernel = await this . findMatchingKernelSpec ( { display_name : interpreter . displayName , name } , undefined , cancelToken ) ;
176
+ if ( Cancellation . isCanceled ( cancelToken ) ) {
177
+ return ;
178
+ }
179
+ if ( ! kernel ) {
170
180
const error = `Kernel not created with the name ${ name } , display_name ${ interpreter . displayName } . Output is ${ output . stdout } ` ;
171
181
throw new Error ( error ) ;
172
182
}
173
183
if ( ! ( kernel instanceof JupyterKernelSpec ) ) {
174
184
const error = `Kernel not registered locally, created with the name ${ name } , display_name ${ interpreter . displayName } . Output is ${ output . stdout } ` ;
175
185
throw new Error ( error ) ;
176
186
}
177
- if ( ! kernel . specFile ) {
187
+ if ( ! kernel . specFile ) {
178
188
const error = `kernel.json not created with the name ${ name } , display_name ${ interpreter . displayName } . Output is ${ output . stdout } ` ;
179
189
throw new Error ( error ) ;
180
190
}
181
191
const specModel : ReadWrite < Kernel . ISpecModel > = JSON . parse ( await this . fileSystem . readFile ( kernel . specFile ) ) ;
182
192
183
193
// Ensure we use a fully qualified path to the python interpreter in `argv`.
184
194
if ( [ 'python' , 'python2' , 'python3' ] . includes ( specModel . argv [ 0 ] . toLowerCase ( ) ) ) {
185
- if ( specModel . argv [ 0 ] . toLowerCase ( ) !== 'conda' ) {
195
+ if ( specModel . argv [ 0 ] . toLowerCase ( ) !== 'conda' ) {
186
196
// If conda is the first word, its possible its a conda activation command.
187
197
specModel . argv [ 0 ] = interpreter . path ;
188
198
} else {
@@ -192,9 +202,14 @@ export class KernelService {
192
202
193
203
// Get the activated environment variables (as a work around for `conda run` and similar).
194
204
// This ensures the code runs within the context of an activated environment.
195
- specModel . env = await this . activationHelper . getActivatedEnvironmentVariables ( undefined , interpreter , true )
196
- // tslint:disable-next-line: no-any
197
- . catch ( noop ) . then ( env => ( env || { } ) as any ) ;
205
+ specModel . env = await this . activationHelper
206
+ . getActivatedEnvironmentVariables ( undefined , interpreter , true )
207
+ . catch ( noop )
208
+ // tslint:disable-next-line: no-any
209
+ . then ( env => ( env || { } ) as any ) ;
210
+ if ( Cancellation . isCanceled ( cancelToken ) ) {
211
+ return ;
212
+ }
198
213
199
214
// Ensure we update the metadata to include interpreter stuff as well (we'll use this to search kernels that match an interpreter).
200
215
// We'll need information such as interpreter type, display name, path, etc...
@@ -248,7 +263,7 @@ export class KernelService {
248
263
249
264
// If no active interpreter, just act like everything is okay as we can't find a new spec anyway
250
265
return true ;
251
- }
266
+ } ;
252
267
253
268
private async addMatchingSpec ( bestInterpreter : PythonInterpreter , cancelToken ?: CancellationToken ) : Promise < void > {
254
269
const displayName = localize . DataScience . historyTitle ( ) ;
@@ -309,7 +324,7 @@ export class KernelService {
309
324
return js && js . name === specName ;
310
325
} ) as JupyterKernelSpec ;
311
326
return match ? match . specFile : undefined ;
312
- }
327
+ } ;
313
328
314
329
//tslint:disable-next-line:cyclomatic-complexity
315
330
private findSpecMatch = async ( enumerator : ( ) => Promise < ( IJupyterKernelSpec | undefined ) [ ] > ) : Promise < IJupyterKernelSpec | undefined > => {
@@ -399,7 +414,7 @@ export class KernelService {
399
414
400
415
traceInfo ( `Found kernelspec match ${ bestSpec ? `${ bestSpec . name } ' '${ bestSpec . path } ` : 'undefined' } ` ) ;
401
416
return bestSpec ;
402
- }
417
+ } ;
403
418
404
419
private enumerateSpecs = async ( _cancelToken ?: CancellationToken ) : Promise < JupyterKernelSpec [ ] > => {
405
420
// Ignore errors if there are no kernels.
@@ -417,28 +432,30 @@ export class KernelService {
417
432
traceInfo ( 'Parsing kernelspecs from jupyter' ) ;
418
433
// This should give us back a key value pair we can parse
419
434
const kernelSpecs = JSON . parse ( output . stdout . trim ( ) ) as Record < string , { resource_dir : string ; spec : Omit < Kernel . ISpecModel , 'name' > } > ;
420
- const specs = await Promise . all ( Object . keys ( kernelSpecs ) . map ( async kernelName => {
421
- const specFile = path . join ( kernelSpecs [ kernelName ] . resource_dir , 'kernel.json' ) ;
422
- const spec = kernelSpecs [ kernelName ] . spec ;
423
- // Add the missing name property.
424
- const model = {
425
- ...spec ,
426
- name : kernelName
427
- } ;
428
- // Check if the spec file exists.
429
- if ( await this . fileSystem . fileExists ( specFile ) ) {
430
- return new JupyterKernelSpec ( model as Kernel . ISpecModel , specFile ) ;
431
- } else {
432
- return ;
433
- }
434
- } ) ) ;
435
+ const specs = await Promise . all (
436
+ Object . keys ( kernelSpecs ) . map ( async kernelName => {
437
+ const specFile = path . join ( kernelSpecs [ kernelName ] . resource_dir , 'kernel.json' ) ;
438
+ const spec = kernelSpecs [ kernelName ] . spec ;
439
+ // Add the missing name property.
440
+ const model = {
441
+ ...spec ,
442
+ name : kernelName
443
+ } ;
444
+ // Check if the spec file exists.
445
+ if ( await this . fileSystem . fileExists ( specFile ) ) {
446
+ return new JupyterKernelSpec ( model as Kernel . ISpecModel , specFile ) ;
447
+ } else {
448
+ return ;
449
+ }
450
+ } )
451
+ ) ;
435
452
return specs . filter ( item => ! ! item ) . map ( item => item as JupyterKernelSpec ) ;
436
453
} catch ( ex ) {
437
454
traceError ( 'Failed to list kernels' , ex ) ;
438
455
// This is failing for some folks. In that case return nothing
439
456
return [ ] ;
440
457
}
441
- }
458
+ } ;
442
459
private async getInterpreterDetailsFromProcess ( baseProcessName : string ) : Promise < PythonInterpreter | undefined > {
443
460
if ( path . basename ( baseProcessName ) !== baseProcessName ) {
444
461
// This function should only be called with a non qualified path. We're using this
0 commit comments