Skip to content

Commit 2ba5380

Browse files
authored
Refactor KernelSelection type to include a kind (microsoft#13407)
For #13406
1 parent eff739c commit 2ba5380

File tree

7 files changed

+157
-135
lines changed

7 files changed

+157
-135
lines changed

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,12 @@ export class KernelExecution implements IDisposable {
152152
if (!kernel) {
153153
const activeInterpreter = await this.interpreterService.getActiveInterpreter(document.uri);
154154
kernel = this.kernelProvider.getOrCreate(document.uri, {
155-
metadata: { interpreter: activeInterpreter!, kernelModel: undefined, kernelSpec: undefined },
155+
metadata: {
156+
interpreter: activeInterpreter!,
157+
kernelModel: undefined,
158+
kernelSpec: undefined,
159+
kind: 'pythonInterpreter'
160+
},
156161
launchingFile: document.uri.fsPath
157162
});
158163
}

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

Lines changed: 47 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,14 @@ import { IKernelFinder } from '../../kernel-launcher/types';
1616
import { IDataScienceFileSystem, IJupyterKernelSpec, IJupyterSessionManager } from '../../types';
1717
import { detectDefaultKernelName } from './helpers';
1818
import { KernelService } from './kernelService';
19-
import { IKernelSelectionListProvider, IKernelSpecQuickPickItem, LiveKernelModel } from './types';
19+
import {
20+
IKernelSelectionListProvider,
21+
IKernelSpecQuickPickItem,
22+
KernelSpecConnectionMetadata,
23+
LiveKernelConnectionMetadata,
24+
LiveKernelModel,
25+
PythonKernelConnectionMetadata
26+
} from './types';
2027

2128
// Small classes, hence all put into one file.
2229
// tslint:disable: max-classes-per-file
@@ -31,12 +38,12 @@ import { IKernelSelectionListProvider, IKernelSpecQuickPickItem, LiveKernelModel
3138
function getQuickPickItemForKernelSpec(
3239
kernelSpec: IJupyterKernelSpec,
3340
pathUtils: IPathUtils
34-
): IKernelSpecQuickPickItem {
41+
): IKernelSpecQuickPickItem<KernelSpecConnectionMetadata> {
3542
return {
3643
label: kernelSpec.display_name,
3744
// If we have a matching interpreter, then display that path in the dropdown else path of the kernelspec.
3845
detail: pathUtils.getDisplayName(kernelSpec.metadata?.interpreter?.path || kernelSpec.path),
39-
selection: { kernelModel: undefined, kernelSpec: kernelSpec, interpreter: undefined }
46+
selection: { kernelModel: undefined, kernelSpec: kernelSpec, interpreter: undefined, kind: 'kernelSpec' }
4047
};
4148
}
4249

@@ -47,7 +54,10 @@ function getQuickPickItemForKernelSpec(
4754
* @param {IPathUtils} pathUtils
4855
* @returns {IKernelSpecQuickPickItem}
4956
*/
50-
function getQuickPickItemForActiveKernel(kernel: LiveKernelModel, pathUtils: IPathUtils): IKernelSpecQuickPickItem {
57+
function getQuickPickItemForActiveKernel(
58+
kernel: LiveKernelModel,
59+
pathUtils: IPathUtils
60+
): IKernelSpecQuickPickItem<LiveKernelConnectionMetadata> {
5161
const pickPath = kernel.metadata?.interpreter?.path || kernel.path;
5262
return {
5363
label: kernel.display_name || kernel.name || '',
@@ -57,7 +67,7 @@ function getQuickPickItemForActiveKernel(kernel: LiveKernelModel, pathUtils: IPa
5767
kernel.lastActivityTime.toLocaleString(),
5868
kernel.numberOfConnections.toString()
5969
),
60-
selection: { kernelModel: kernel, kernelSpec: undefined, interpreter: undefined }
70+
selection: { kernelModel: kernel, kernelSpec: undefined, interpreter: undefined, kind: 'live' }
6171
};
6272
}
6373

@@ -68,12 +78,13 @@ function getQuickPickItemForActiveKernel(kernel: LiveKernelModel, pathUtils: IPa
6878
* @class ActiveJupyterSessionKernelSelectionListProvider
6979
* @implements {IKernelSelectionListProvider}
7080
*/
71-
export class ActiveJupyterSessionKernelSelectionListProvider implements IKernelSelectionListProvider {
81+
export class ActiveJupyterSessionKernelSelectionListProvider
82+
implements IKernelSelectionListProvider<LiveKernelConnectionMetadata> {
7283
constructor(private readonly sessionManager: IJupyterSessionManager, private readonly pathUtils: IPathUtils) {}
7384
public async getKernelSelections(
7485
_resource: Resource,
7586
_cancelToken?: CancellationToken | undefined
76-
): Promise<IKernelSpecQuickPickItem[]> {
87+
): Promise<IKernelSpecQuickPickItem<LiveKernelConnectionMetadata>[]> {
7788
const [activeKernels, activeSessions, kernelSpecs] = await Promise.all([
7889
this.sessionManager.getRunningKernels(),
7990
this.sessionManager.getRunningSessions(),
@@ -105,7 +116,8 @@ export class ActiveJupyterSessionKernelSelectionListProvider implements IKernelS
105116
* @class InstalledJupyterKernelSelectionListProvider
106117
* @implements {IKernelSelectionListProvider}
107118
*/
108-
export class InstalledJupyterKernelSelectionListProvider implements IKernelSelectionListProvider {
119+
export class InstalledJupyterKernelSelectionListProvider
120+
implements IKernelSelectionListProvider<KernelSpecConnectionMetadata> {
109121
constructor(
110122
private readonly kernelService: KernelService,
111123
private readonly pathUtils: IPathUtils,
@@ -114,19 +126,20 @@ export class InstalledJupyterKernelSelectionListProvider implements IKernelSelec
114126
public async getKernelSelections(
115127
_resource: Resource,
116128
cancelToken?: CancellationToken | undefined
117-
): Promise<IKernelSpecQuickPickItem[]> {
129+
): Promise<IKernelSpecQuickPickItem<KernelSpecConnectionMetadata>[]> {
118130
const items = await this.kernelService.getKernelSpecs(this.sessionManager, cancelToken);
119131
return items.map((item) => getQuickPickItemForKernelSpec(item, this.pathUtils));
120132
}
121133
}
122134

123135
// Provider for searching for installed kernelspecs on disk without using jupyter to search
124-
export class InstalledRawKernelSelectionListProvider implements IKernelSelectionListProvider {
136+
export class InstalledRawKernelSelectionListProvider
137+
implements IKernelSelectionListProvider<KernelSpecConnectionMetadata> {
125138
constructor(private readonly kernelFinder: IKernelFinder, private readonly pathUtils: IPathUtils) {}
126139
public async getKernelSelections(
127140
resource: Resource,
128141
_cancelToken?: CancellationToken
129-
): Promise<IKernelSpecQuickPickItem[]> {
142+
): Promise<IKernelSpecQuickPickItem<KernelSpecConnectionMetadata>[]> {
130143
const items = await this.kernelFinder.listKernelSpecs(resource);
131144
return items
132145
.filter((item) => {
@@ -151,19 +164,25 @@ export class InstalledRawKernelSelectionListProvider implements IKernelSelection
151164
* @class InterpreterKernelSelectionListProvider
152165
* @implements {IKernelSelectionListProvider}
153166
*/
154-
export class InterpreterKernelSelectionListProvider implements IKernelSelectionListProvider {
167+
export class InterpreterKernelSelectionListProvider
168+
implements IKernelSelectionListProvider<PythonKernelConnectionMetadata> {
155169
constructor(private readonly interpreterSelector: IInterpreterSelector) {}
156170
public async getKernelSelections(
157171
resource: Resource,
158-
_cancelToken?: CancellationToken | undefined
159-
): Promise<IKernelSpecQuickPickItem[]> {
172+
_cancelToken?: CancellationToken
173+
): Promise<IKernelSpecQuickPickItem<PythonKernelConnectionMetadata>[]> {
160174
const items = await this.interpreterSelector.getSuggestions(resource);
161175
return items.map((item) => {
162176
return {
163177
...item,
164178
// We don't want descriptions.
165179
description: '',
166-
selection: { kernelModel: undefined, interpreter: item.interpreter, kernelSpec: undefined }
180+
selection: {
181+
kernelModel: undefined,
182+
interpreter: item.interpreter,
183+
kernelSpec: undefined,
184+
kind: 'pythonInterpreter'
185+
}
167186
};
168187
});
169188
}
@@ -177,8 +196,12 @@ export class InterpreterKernelSelectionListProvider implements IKernelSelectionL
177196
*/
178197
@injectable()
179198
export class KernelSelectionProvider {
180-
private localSuggestionsCache: IKernelSpecQuickPickItem[] = [];
181-
private remoteSuggestionsCache: IKernelSpecQuickPickItem[] = [];
199+
private localSuggestionsCache: IKernelSpecQuickPickItem<
200+
KernelSpecConnectionMetadata | PythonKernelConnectionMetadata
201+
>[] = [];
202+
private remoteSuggestionsCache: IKernelSpecQuickPickItem<
203+
LiveKernelConnectionMetadata | KernelSpecConnectionMetadata
204+
>[] = [];
182205
private _listChanged = new EventEmitter<void>();
183206
public get SelectionsChanged() {
184207
return this._listChanged.event;
@@ -203,7 +226,7 @@ export class KernelSelectionProvider {
203226
resource: Resource,
204227
sessionManager: IJupyterSessionManager,
205228
cancelToken?: CancellationToken
206-
): Promise<IKernelSpecQuickPickItem[]> {
229+
): Promise<IKernelSpecQuickPickItem<LiveKernelConnectionMetadata | KernelSpecConnectionMetadata>[]> {
207230
const getSelections = async () => {
208231
const installedKernelsPromise = new InstalledJupyterKernelSelectionListProvider(
209232
this.kernelService,
@@ -222,8 +245,8 @@ export class KernelSelectionProvider {
222245
return [...liveKernels!, ...installedKernels!];
223246
};
224247

225-
const liveItems = getSelections().then((items) => (this.localSuggestionsCache = items));
226-
// If we have someting in cache, return that, while fetching in the background.
248+
const liveItems = getSelections().then((items) => (this.remoteSuggestionsCache = items));
249+
// If we have something in cache, return that, while fetching in the background.
227250
const cachedItems =
228251
this.remoteSuggestionsCache.length > 0 ? Promise.resolve(this.remoteSuggestionsCache) : liveItems;
229252
return Promise.race([cachedItems, liveItems]);
@@ -243,12 +266,14 @@ export class KernelSelectionProvider {
243266
type: 'raw' | 'jupyter' | 'noConnection',
244267
sessionManager?: IJupyterSessionManager,
245268
cancelToken?: CancellationToken
246-
): Promise<IKernelSpecQuickPickItem[]> {
269+
): Promise<IKernelSpecQuickPickItem<KernelSpecConnectionMetadata | PythonKernelConnectionMetadata>[]> {
247270
const getSelections = async () => {
248271
// For raw versus jupyter connections we need to use a different method for fetching installed kernelspecs
249272
// There is a possible unknown case for if we have a guest jupyter notebook that has not yet connected
250273
// in that case we don't use either method
251-
let installedKernelsPromise: Promise<IKernelSpecQuickPickItem[]> = Promise.resolve([]);
274+
let installedKernelsPromise: Promise<
275+
IKernelSpecQuickPickItem<KernelSpecConnectionMetadata>[]
276+
> = Promise.resolve([]);
252277
switch (type) {
253278
case 'raw':
254279
installedKernelsPromise = new InstalledRawKernelSelectionListProvider(

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,12 @@ export class KernelSelector implements IKernelSelectionUsage {
158158
cancelToken?: CancellationToken,
159159
currentKernelDisplayName?: string
160160
): Promise<KernelSpecInterpreter> {
161-
let suggestions = await this.selectionProvider.getKernelSelectionsForLocalSession(
161+
const suggestions = await this.selectionProvider.getKernelSelectionsForLocalSession(
162162
resource,
163163
type,
164164
session,
165165
cancelToken
166166
);
167-
suggestions = suggestions.filter((item) => !this.kernelIdsToHide.has(item.selection.kernelModel?.id || ''));
168167
return this.selectKernel(
169168
resource,
170169
type,

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

Lines changed: 61 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,71 @@ import type { KernelSpecInterpreter } from './kernelSelector';
2222
export type LiveKernelModel = IJupyterKernel & Partial<IJupyterKernelSpec> & { session: Session.IModel };
2323

2424
/**
25-
* Whether a selected kernel is:
26-
* - Kernel spec (IJupyterKernelSpec)
27-
* - Active kernel (IJupyterKernel) or
28-
* - An Interpreter
25+
* Connection metadata for Live Kernels.
26+
* With this we are able connect to an existing kernel (instead of starting a new session).
2927
*/
28+
export type LiveKernelConnectionMetadata = {
29+
kernelModel: LiveKernelModel;
30+
kernelSpec: undefined;
31+
interpreter: undefined;
32+
kind: 'live';
33+
};
34+
/**
35+
* Connection metadata for Kernels started using kernelspec (JSON).
36+
* This could be a raw kernel (spec might have path to executable for .NET or the like).
37+
*/
38+
export type KernelSpecConnectionMetadata = {
39+
kernelModel: undefined;
40+
kernelSpec: IJupyterKernelSpec;
41+
interpreter: undefined;
42+
kind: 'kernelSpec';
43+
};
44+
/**
45+
* Connection metadata for Kernels started using Python interpreter.
46+
* These are not necessarily raw (it could be plain old Jupyter Kernels, where we register Python interpreter as a kernel)
47+
*/
48+
export type PythonKernelConnectionMetadata = {
49+
kernelModel: undefined;
50+
kernelSpec: undefined;
51+
interpreter: PythonInterpreter;
52+
kind: 'pythonInterpreter';
53+
};
54+
// /**
55+
// * Connection metadata for Kernels started using Python interpreter with Kernel spec (JSON).
56+
// * Sometimes, we're unable to determine the exact interpreter associated with a kernelspec, in such cases this is a closes match.
57+
// */
58+
59+
// export type PythonKernelSpecConnectionMetadata = {
60+
// kernelModel: undefined;
61+
// kernelSpec: IJupyterKernelSpec;
62+
// interpreter: PythonInterpreter;
63+
// kind: 'pythonInterpreterKernelSpec';
64+
// };
65+
// /**
66+
// * Connection metadata for Kernels started using kernelspec (JSON).
67+
// * Note, we could be connecting/staring a kernel on a remote jupyter server.
68+
// * Sometimes, we're unable to determine the exact interpreter associated with a kernelspec, in such cases this is a closes match.
69+
// * E.g. when selecting a remote kernel, we do not have the remote interpreter information, we can only try to find a close match.}
70+
// */
71+
72+
// export type PythonLiveKernelConnectionMetadata = {
73+
// kernelModel: undefined;
74+
// kernelSpec: IJupyterKernelSpec;
75+
// interpreter: PythonInterpreter;
76+
// kind: 'pythonInterpreterLive';
77+
// };
3078
export type KernelSelection =
31-
| { kernelModel: LiveKernelModel; kernelSpec: undefined; interpreter: undefined }
32-
| { kernelModel: undefined; kernelSpec: IJupyterKernelSpec; interpreter: undefined }
33-
| { kernelModel: undefined; kernelSpec: undefined; interpreter: PythonInterpreter };
79+
| LiveKernelConnectionMetadata
80+
| KernelSpecConnectionMetadata
81+
| PythonKernelConnectionMetadata;
82+
// | PythonKernelSpecConnectionMetadata
83+
// | PythonLiveKernelConnectionMetadata;
3484

35-
export interface IKernelSpecQuickPickItem extends QuickPickItem {
36-
selection: KernelSelection;
85+
export interface IKernelSpecQuickPickItem<T extends KernelSelection = KernelSelection> extends QuickPickItem {
86+
selection: T;
3787
}
38-
39-
export interface IKernelSelectionListProvider {
40-
getKernelSelections(resource: Resource, cancelToken?: CancellationToken): Promise<IKernelSpecQuickPickItem[]>;
88+
export interface IKernelSelectionListProvider<T extends KernelSelection = KernelSelection> {
89+
getKernelSelections(resource: Resource, cancelToken?: CancellationToken): Promise<IKernelSpecQuickPickItem<T>[]>;
4190
}
4291

4392
export interface IKernelSelectionUsage {

src/test/datascience/commands/notebookCommands.functional.test.ts

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,12 @@ import { KernelSelectionProvider } from '../../../client/datascience/jupyter/ker
2020
import { KernelSelector } from '../../../client/datascience/jupyter/kernels/kernelSelector';
2121
import { KernelService } from '../../../client/datascience/jupyter/kernels/kernelService';
2222
import { KernelSwitcher } from '../../../client/datascience/jupyter/kernels/kernelSwitcher';
23-
import { IKernelSpecQuickPickItem } from '../../../client/datascience/jupyter/kernels/types';
23+
import {
24+
IKernelSpecQuickPickItem,
25+
KernelSpecConnectionMetadata,
26+
LiveKernelConnectionMetadata,
27+
PythonKernelConnectionMetadata
28+
} from '../../../client/datascience/jupyter/kernels/types';
2429
import { IKernelFinder } from '../../../client/datascience/kernel-launcher/types';
2530
import { NativeEditorProvider } from '../../../client/datascience/notebookStorage/nativeEditorProvider';
2631
import { IInteractiveWindowProvider, INotebookEditorProvider } from '../../../client/datascience/types';
@@ -58,31 +63,34 @@ suite('DataScience - Notebook Commands', () => {
5863
sysPrefix: '',
5964
sysVersion: ''
6065
};
61-
const remoteSelections: IKernelSpecQuickPickItem[] = [
66+
const remoteSelections: IKernelSpecQuickPickItem<LiveKernelConnectionMetadata>[] = [
6267
{
6368
label: 'foobar',
6469
selection: {
6570
kernelSpec: undefined,
6671
kernelModel: remoteKernel,
67-
interpreter: undefined
72+
interpreter: undefined,
73+
kind: 'live'
6874
}
6975
}
7076
];
71-
const localSelections: IKernelSpecQuickPickItem[] = [
77+
const localSelections: IKernelSpecQuickPickItem<KernelSpecConnectionMetadata | PythonKernelConnectionMetadata>[] = [
7278
{
7379
label: 'foobar',
7480
selection: {
7581
kernelSpec: localKernel,
7682
kernelModel: undefined,
77-
interpreter: undefined
83+
interpreter: undefined,
84+
kind: 'kernelSpec'
7885
}
7986
},
8087
{
8188
label: 'foobaz',
8289
selection: {
8390
kernelSpec: undefined,
8491
kernelModel: undefined,
85-
interpreter: selectedInterpreter
92+
interpreter: selectedInterpreter,
93+
kind: 'pythonInterpreter'
8694
}
8795
}
8896
];

0 commit comments

Comments
 (0)