Skip to content

Commit b40c9ab

Browse files
committed
More fixes
1 parent 0b375f6 commit b40c9ab

File tree

2 files changed

+51
-45
lines changed

2 files changed

+51
-45
lines changed

src/client/datascience/jupyter/kernels/kernelSelector.ts

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { JupyterCommandFinder, ModuleExistsStatus } from '../jupyterCommandFinde
1515
import { KernelSelectionProvider } from './kernelSelections';
1616
import { KernelService } from './kernelService';
1717
import { IKernelSelector } from './types';
18+
import { Cancellation } from '../../../common/cancellation';
1819

1920
@injectable()
2021
export class KernelSelector implements IKernelSelector {
@@ -62,14 +63,11 @@ export class KernelSelector implements IKernelSelector {
6263
}
6364

6465
private async isSelectionValid(interpreter: PythonInterpreter, cancelToken?: CancellationToken): Promise<boolean> {
65-
// Do we have the ability to install kernels.
66-
const specCmd = await this.getCreateCmd(cancelToken);
67-
if (!specCmd) {
68-
traceWarning('JupyterCommand not available to install a kernel');
69-
return false;
70-
}
7166
// Is ipykernel installed in this environment.
7267
if (!(await this.installer.isInstalled(Product.ipykernel, interpreter))) {
68+
if (Cancellation.isCanceled(cancelToken)) {
69+
return false;
70+
}
7371
const response = await this.installer.promptToInstall(Product.ipykernel, interpreter);
7472
if (response !== InstallerResponse.Installed) {
7573
traceWarning(`ipykernel not installed in the interpreter ${interpreter.path}`);
@@ -78,13 +76,4 @@ export class KernelSelector implements IKernelSelector {
7876
}
7977
return true;
8078
}
81-
private async getCreateCmd(cancelToken?: CancellationToken): Promise<IJupyterCommand | undefined> {
82-
const specCmd = await this.cmdFinder.findBestCommand(JupyterCommands.KernelCreateCommand, cancelToken);
83-
if (specCmd.status === ModuleExistsStatus.NotFound) {
84-
//this.applicationShell.showInformationMessage('Install?');
85-
}
86-
if (specCmd.command) {
87-
return specCmd.command;
88-
}
89-
}
9079
}

src/client/datascience/jupyter/kernels/kernelService.ts

Lines changed: 47 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ export class KernelService {
7979
*/
8080
public async findMatchingKernelSpec(
8181
interpreter: PythonInterpreter,
82-
sessionManager: IJupyterSessionManager | undefined,
82+
sessionManager?: IJupyterSessionManager | undefined,
8383
cancelToken?: CancellationToken
8484
): Promise<IJupyterKernelSpec | undefined>;
8585
public async findMatchingKernelSpec(
@@ -151,38 +151,48 @@ export class KernelService {
151151
*/
152152
@captureTelemetry(Telemetry.RegisterInterpreterAsKernel, undefined, true)
153153
@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) {
156156
throw new Error('Interpreter does not have a display name');
157157
}
158158
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) {
160160
throw new Error('Command not found to install the kernel');
161161
}
162+
if (Cancellation.isCanceled(cancelToken)) {
163+
return;
164+
}
162165
const name = await this.generateKernelNameForIntepreter(interpreter);
163166
const output = await ipykernelCommand.command.exec(['install', '--user', '--name', name, '--display-name', interpreter.displayName], {
164167
throwOnStdErr: true,
165168
encoding: 'utf8',
166169
token: cancelToken
167170
});
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) {
170180
const error = `Kernel not created with the name ${name}, display_name ${interpreter.displayName}. Output is ${output.stdout}`;
171181
throw new Error(error);
172182
}
173183
if (!(kernel instanceof JupyterKernelSpec)) {
174184
const error = `Kernel not registered locally, created with the name ${name}, display_name ${interpreter.displayName}. Output is ${output.stdout}`;
175185
throw new Error(error);
176186
}
177-
if (!kernel.specFile){
187+
if (!kernel.specFile) {
178188
const error = `kernel.json not created with the name ${name}, display_name ${interpreter.displayName}. Output is ${output.stdout}`;
179189
throw new Error(error);
180190
}
181191
const specModel: ReadWrite<Kernel.ISpecModel> = JSON.parse(await this.fileSystem.readFile(kernel.specFile));
182192

183193
// Ensure we use a fully qualified path to the python interpreter in `argv`.
184194
if (['python', 'python2', 'python3'].includes(specModel.argv[0].toLowerCase())) {
185-
if (specModel.argv[0].toLowerCase() !== 'conda'){
195+
if (specModel.argv[0].toLowerCase() !== 'conda') {
186196
// If conda is the first word, its possible its a conda activation command.
187197
specModel.argv[0] = interpreter.path;
188198
} else {
@@ -192,9 +202,14 @@ export class KernelService {
192202

193203
// Get the activated environment variables (as a work around for `conda run` and similar).
194204
// 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+
}
198213

199214
// Ensure we update the metadata to include interpreter stuff as well (we'll use this to search kernels that match an interpreter).
200215
// We'll need information such as interpreter type, display name, path, etc...
@@ -248,7 +263,7 @@ export class KernelService {
248263

249264
// If no active interpreter, just act like everything is okay as we can't find a new spec anyway
250265
return true;
251-
}
266+
};
252267

253268
private async addMatchingSpec(bestInterpreter: PythonInterpreter, cancelToken?: CancellationToken): Promise<void> {
254269
const displayName = localize.DataScience.historyTitle();
@@ -309,7 +324,7 @@ export class KernelService {
309324
return js && js.name === specName;
310325
}) as JupyterKernelSpec;
311326
return match ? match.specFile : undefined;
312-
}
327+
};
313328

314329
//tslint:disable-next-line:cyclomatic-complexity
315330
private findSpecMatch = async (enumerator: () => Promise<(IJupyterKernelSpec | undefined)[]>): Promise<IJupyterKernelSpec | undefined> => {
@@ -399,7 +414,7 @@ export class KernelService {
399414

400415
traceInfo(`Found kernelspec match ${bestSpec ? `${bestSpec.name}' '${bestSpec.path}` : 'undefined'}`);
401416
return bestSpec;
402-
}
417+
};
403418

404419
private enumerateSpecs = async (_cancelToken?: CancellationToken): Promise<JupyterKernelSpec[]> => {
405420
// Ignore errors if there are no kernels.
@@ -417,28 +432,30 @@ export class KernelService {
417432
traceInfo('Parsing kernelspecs from jupyter');
418433
// This should give us back a key value pair we can parse
419434
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+
);
435452
return specs.filter(item => !!item).map(item => item as JupyterKernelSpec);
436453
} catch (ex) {
437454
traceError('Failed to list kernels', ex);
438455
// This is failing for some folks. In that case return nothing
439456
return [];
440457
}
441-
}
458+
};
442459
private async getInterpreterDetailsFromProcess(baseProcessName: string): Promise<PythonInterpreter | undefined> {
443460
if (path.basename(baseProcessName) !== baseProcessName) {
444461
// This function should only be called with a non qualified path. We're using this

0 commit comments

Comments
 (0)