Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,6 @@
"DataScience.fallbackToUseActiveInterpeterAsKernel": "Couldn't find kernel '{0}' that the notebook was created with. Using the current interpreter.",
"DataScience.fallBackToRegisterAndUseActiveInterpeterAsKernel": "Couldn't find kernel '{0}' that the notebook was created with. Registering a new kernel using the current interpreter.",
"DataScience.fallBackToPromptToUseActiveInterpreterOrSelectAKernel": "Couldn't find kernel '{0}' that the notebook was created with.",
"DataScience.kernelDescriptionForKernelPicker": "(kernel)",
"DataScience.selectKernel": "Select a Kernel",
"products.installingModule": "Installing {0}"
}
2 changes: 1 addition & 1 deletion src/client/common/utils/localize.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ export namespace DataScience {
export const noRowsInDataViewer = localize('DataScience.noRowsInDataViewer', 'No rows match current filter');
export const jupyterServer = localize('DataScience.jupyterServer', 'Jupyter Server');
export const noKernel = localize('DataScience.noKernel', 'No Kernel');
export const selectKernel = localize('DataScience.selectKernel', 'Select a Kernel');
export const localJupyterServer = localize('DataScience.localJupyterServer', 'local');
export const pandasTooOldForViewingFormat = localize('DataScience.pandasTooOldForViewingFormat', 'Python package \'pandas\' is version {0}. Version 0.20 or greater is required for viewing data.');
export const pandasRequiredForViewing = localize('DataScience.pandasRequiredForViewing', 'Python package \'pandas\' is required for viewing data.');
Expand Down Expand Up @@ -311,7 +312,6 @@ export namespace DataScience {
export const savePngTitle = localize('DataScience.savePngTitle', 'Save Image');
export const fallbackToUseActiveInterpeterAsKernel = localize('DataScience.fallbackToUseActiveInterpeterAsKernel', 'Couldn\'t find kernel \'{0}\' that the notebook was created with. Using the current interpreter.');
export const fallBackToRegisterAndUseActiveInterpeterAsKernel = localize('DataScience.fallBackToRegisterAndUseActiveInterpeterAsKernel', 'Couldn\'t find kernel \'{0}\' that the notebook was created with. Registering a new kernel using the current interpreter.');
export const kernelDescriptionForKernelPicker = localize('DataScience.kernelDescriptionForKernelPicker', '(kernel)');
export const fallBackToPromptToUseActiveInterpreterOrSelectAKernel = localize('DataScience.fallBackToPromptToUseActiveInterpreterOrSelectAKernel', 'Couldn\'t find kernel \'{0}\' that the notebook was created with.');
}

Expand Down
22 changes: 14 additions & 8 deletions src/client/datascience/jupyter/kernels/kernelSelections.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import { IKernelSelectionListProvider, IKernelSpecQuickPickItem } from './types'
function getQuickPickItemForKernelSpec(kernelSpec: IJupyterKernelSpec): IKernelSpecQuickPickItem {
return {
label: kernelSpec.display_name,
description: localize.DataScience.kernelDescriptionForKernelPicker(),
selection: { kernelModel: undefined, kernelSpec: kernelSpec, interpreter: undefined }
};
}
Expand Down Expand Up @@ -101,6 +100,9 @@ export class InterpreterKernelSelectionListProvider implements IKernelSelectionL
return items.map(item => {
return {
...item,
// We don't want details & descriptions.
detail: '',
description: '',
selection: { kernelModel: undefined, interpreter: item.interpreter, kernelSpec: undefined }
};
});
Expand Down Expand Up @@ -128,7 +130,11 @@ export class KernelSelectionProvider {
* @memberof KernelSelectionProvider
*/
public async getKernelSelectionsForRemoteSession(sessionManager: IJupyterSessionManager, cancelToken?: CancellationToken): Promise<IKernelSpecQuickPickItem[]> {
return new ActiveJupyterSessionKernelSelectionListProvider(sessionManager).getKernelSelections(cancelToken);
const list = await new ActiveJupyterSessionKernelSelectionListProvider(sessionManager).getKernelSelections(cancelToken);
// Sorty by name.
list.sort((a, b) => a.label === b.label ? 0 : (a.label > b.label ? 1 : -1));

return list;
}
/**
* Gets a selection of kernel specs for a local session.
Expand All @@ -154,14 +160,14 @@ export class KernelSelectionProvider {
}
return true;
}).map(item => {
// to indicate we're registering/adding these as kernels.
item.label = `$(plus) ${item.label}`;
return item;
// We don't want details & descriptions.
return {...item, detail: '', description: ''};
});

const unifiedList = [...installedKernels!, ...interpreters];
// Sorty by name.
// Do not sort interpreter list, as that's pre-sorted (there's an algorithm for that).
installedKernels.sort((a, b) => a.label === b.label ? 0 : (a.label > b.label ? 1 : -1));
unifiedList.sort((a, b) => a.label === b.label ? 0 : (a.label > b.label ? 1 : -1));

return [...installedKernels!, ...interpreters];
return unifiedList;
}
}
41 changes: 18 additions & 23 deletions src/client/datascience/jupyter/kernels/kernelSelector.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { nbformat } from '@jupyterlab/coreutils';
import { inject, injectable } from 'inversify';
import { CancellationToken } from 'vscode-jsonrpc';
import { IApplicationShell } from '../../../common/application/types';
import '../../../common/extensions';
import { traceError, traceInfo, traceVerbose } from '../../../common/logger';
import { IInstaller, Product } from '../../../common/types';
import * as localize from '../../../common/utils/localize';
Expand All @@ -15,6 +16,7 @@ import { IInterpreterService, PythonInterpreter } from '../../../interpreter/con
import { IJupyterKernelSpec, IJupyterSessionManager } from '../../types';
import { KernelSelectionProvider } from './kernelSelections';
import { KernelService } from './kernelService';
import { IKernelSpecQuickPickItem } from './types';

export type KernelSpecInterpreter = {
kernelSpec?: IJupyterKernelSpec;
Expand Down Expand Up @@ -46,18 +48,8 @@ export class KernelSelector {
* @memberof KernelSelector
*/
public async selectRemoteKernel(session: IJupyterSessionManager, cancelToken?: CancellationToken): Promise<KernelSpecInterpreter> {
Comment thread
DonJayamanne marked this conversation as resolved.
const suggestions = this.selectionProvider.getKernelSelectionsForRemoteSession(session, cancelToken);
const selection = await this.applicationShell.showQuickPick(suggestions, undefined, cancelToken);
if (!selection) {
return {};
}

if (selection.selection.kernelSpec) {
const interpreter = await this.kernelService.findMatchingInterpreter(selection.selection.kernelSpec, cancelToken);
return { kernelSpec: selection.selection.kernelSpec, interpreter };
}
// This is not possible (remote kernels selector can only display remote kernels).
throw new Error('Invalid Selection in kernel spec (somehow a local kernel/interpreter has been selected for a remote session!');
const suggestions = await this.selectionProvider.getKernelSelectionsForRemoteSession(session, cancelToken);
return this.selectKernel(suggestions, session, cancelToken);
}
/**
* Select a kernel from a local session.
Expand All @@ -69,17 +61,7 @@ export class KernelSelector {
*/
public async selectLocalKernel(session?: IJupyterSessionManager, cancelToken?: CancellationToken): Promise<KernelSpecInterpreter> {
const suggestions = await this.selectionProvider.getKernelSelectionsForLocalSession(session, cancelToken);
const selection = await this.applicationShell.showQuickPick(suggestions, undefined, cancelToken);
if (!selection) {
return {};
}
// Check if ipykernel is installed in this kernel.
if (selection.selection.interpreter) {
return this.useInterpreterAsKernel(selection.selection.interpreter, undefined, session, cancelToken);
} else {
const interpreter = selection.selection.kernelSpec ? await this.kernelService.findMatchingInterpreter(selection.selection.kernelSpec, cancelToken) : undefined;
return { kernelSpec: selection.selection.kernelSpec, interpreter };
}
return this.selectKernel(suggestions, session, cancelToken);
}
/**
* Gets a kernel that needs to be used with a local session.
Expand Down Expand Up @@ -124,6 +106,19 @@ export class KernelSelector {
}
return selection;
}
private async selectKernel(suggestions: IKernelSpecQuickPickItem[], session?: IJupyterSessionManager, cancelToken?: CancellationToken){
const selection = await this.applicationShell.showQuickPick(suggestions, { placeHolder: localize.DataScience.selectKernel() }, cancelToken);
if (!selection?.selection) {
return {};
}
// Check if ipykernel is installed in this kernel.
if (selection.selection.interpreter) {
return this.useInterpreterAsKernel(selection.selection.interpreter, undefined, session, cancelToken);
} else {
const interpreter = selection.selection.kernelSpec ? await this.kernelService.findMatchingInterpreter(selection.selection.kernelSpec, cancelToken) : undefined;
return { kernelSpec: selection.selection.kernelSpec, interpreter };
}
}
/**
* Use the provided interpreter as a kernel.
* If `displayNameOfKernelNotFound` is provided, then display a message indicating we're using the `current interpreter`.
Expand Down
2 changes: 2 additions & 0 deletions src/test/datascience/dataScienceIocContainer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ import {
} from '../../client/common/types';
import { Deferred, sleep } from '../../client/common/utils/async';
import { noop } from '../../client/common/utils/misc';
import { IMultiStepInputFactory, MultiStepInputFactory } from '../../client/common/utils/multiStepInput';
import { Architecture } from '../../client/common/utils/platform';
import { EnvironmentVariablesService } from '../../client/common/variables/environment';
import { EnvironmentVariablesProvider } from '../../client/common/variables/environmentVariablesProvider';
Expand Down Expand Up @@ -508,6 +509,7 @@ export class DataScienceIocContainer extends UnitTestIocContainer {
this.serviceManager.addSingleton<IProductPathService>(IProductPathService, TestFrameworkProductPathService, ProductType.TestFramework);
this.serviceManager.addSingleton<IProductPathService>(IProductPathService, RefactoringLibraryProductPathService, ProductType.RefactoringLibrary);
this.serviceManager.addSingleton<IProductPathService>(IProductPathService, DataScienceProductPathService, ProductType.DataScience);
this.serviceManager.addSingleton<IMultiStepInputFactory>(IMultiStepInputFactory, MultiStepInputFactory);

// Don't check for dot net compatibility
const dotNetCompability = mock(DotNetCompatibilityService);
Expand Down
23 changes: 15 additions & 8 deletions src/test/datascience/jupyter/kernels/kernelSelections.unit.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,22 @@ suite('Data Science - KernelSelections', () => {
label: 'Hello1',
interpreter: { architecture: Architecture.Unknown, path: 'p1', sysPrefix: '', sysVersion: '', type: InterpreterType.Conda, displayName: 'Hello1' },
path: 'p1',
detail: 'p1'
detail: '',
description: ''
},
{
label: 'Hello1',
interpreter: { architecture: Architecture.Unknown, path: 'p2', sysPrefix: '', sysVersion: '', type: InterpreterType.Conda, displayName: 'Hello2' },
path: 'p1',
detail: 'p1'
detail: '',
description: ''
},
{
label: 'Hello1',
interpreter: { architecture: Architecture.Unknown, path: 'p3', sysPrefix: '', sysVersion: '', type: InterpreterType.Conda, displayName: 'Hello3' },
path: 'p1',
detail: 'p1'
detail: '',
description: ''
}
];

Expand Down Expand Up @@ -91,6 +94,8 @@ suite('Data Science - KernelSelections', () => {
)
}
];
expectedItems.sort((a, b) => a.label === b.label ? 0 : (a.label > b.label ? 1 : -1));

const items = await kernelSelectionProvider.getKernelSelectionsForRemoteSession(instance(sessionManager));

verify(sessionManager.getRunningKernels()).once();
Expand All @@ -109,22 +114,24 @@ suite('Data Science - KernelSelections', () => {
const expectedKernelItems: IKernelSpecQuickPickItem[] = [python1KernelSpecModel, python3KernelSpecModel].map(item => {
return {
label: item.display_name,
selection: { interpreter: undefined, kernelModel: undefined, kernelSpec: item },
description: localize.DataScience.kernelDescriptionForKernelPicker()
selection: { interpreter: undefined, kernelModel: undefined, kernelSpec: item }
};
});
const expectedInterpreterItems: IKernelSpecQuickPickItem[] = allInterpreters.map(item => {
return {
...item,
label: `$(plus) ${item.label}`,
label: item.label,
detail: '',
description: '',
selection: { kernelModel: undefined, interpreter: item.interpreter, kernelSpec: undefined }
};
});
expectedKernelItems.sort((a, b) => a.label === b.label ? 0 : (a.label > b.label ? 1 : -1));
const expectedList = [...expectedKernelItems, ...expectedInterpreterItems];
expectedList.sort((a, b) => a.label === b.label ? 0 : (a.label > b.label ? 1 : -1));

const items = await kernelSelectionProvider.getKernelSelectionsForLocalSession(instance(sessionManager));

verify(kernelService.getKernelSpecs(anything(), anything())).once();
assert.deepEqual(items, [...expectedKernelItems, ...expectedInterpreterItems]);
assert.deepEqual(items, expectedList);
});
});
Loading