Skip to content

Commit

Permalink
Python kernel picker based on new base picker (#14050)
Browse files Browse the repository at this point in the history
* Python kernel picker based on new base picker

* Oops

* Wip

* Misc
  • Loading branch information
DonJayamanne authored Aug 3, 2023
1 parent 0514eda commit 0e016b0
Show file tree
Hide file tree
Showing 7 changed files with 379 additions and 258 deletions.
71 changes: 51 additions & 20 deletions src/kernels/jupyter/interpreter/jupyterInterpreterSelector.node.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,22 @@ import { CancellationTokenSource, workspace } from 'vscode';
import { IInterpreterService } from '../../../platform/interpreter/contracts';
import { InputFlowAction } from '../../../platform/common/utils/multiStepInput';
import { traceError } from '../../../platform/logging';
import { PythonEnvironmentPicker } from '../../../platform/interpreter/pythonEnvironmentPicker.node';
import {
getPythonEnvironmentCategory,
pythonEnvironmentQuickPick
} from '../../../platform/interpreter/pythonEnvironmentPicker.node';
import { JupyterInterpreterStateStore } from './jupyterInterpreterStateStore';
import { areInterpreterPathsSame } from '../../../platform/pythonEnvironments/info/interpreter';
import { PlatformService } from '../../../platform/common/platform/platformService.node';
import { getDisplayPath } from '../../../platform/common/platform/fs-paths';
import { DataScience } from '../../../platform/common/utils/localize';
import { ServiceContainer } from '../../../platform/ioc/container';
import { PythonEnvironmentQuickPickItemProvider } from '../../../platform/interpreter/pythonEnvironmentQuickPickProvider.node';
import { IDisposable } from '../../../platform/common/types';
import { disposeAllDisposables } from '../../../platform/common/helpers';
import { isCondaEnvironmentWithoutPython } from '../../../platform/interpreter/helpers';
import { PythonEnvironmentFilter } from '../../../platform/interpreter/filter/filterService';
import { BaseProviderBasedQuickPick } from '../../../platform/common/providerBasedQuickPick';

/**
* Displays interpreter select and returns the selection to the user.
Expand All @@ -29,37 +39,58 @@ export class JupyterInterpreterSelector {
*/
public async selectInterpreter(): Promise<PythonEnvironment | undefined> {
const token = new CancellationTokenSource();
const platformService = new PlatformService();
const selectedInterpreter =
this.serviceContainer.get<JupyterInterpreterStateStore>(JupyterInterpreterStateStore).selectedPythonPath;
const platformService = new PlatformService();
const filter = ServiceContainer.instance.get<PythonEnvironmentFilter>(PythonEnvironmentFilter);
const provider = ServiceContainer.instance
.get<PythonEnvironmentQuickPickItemProvider>(PythonEnvironmentQuickPickItemProvider)
.withFilter((item) => !isCondaEnvironmentWithoutPython(item) && !filter.isPythonEnvironmentExcluded(item));
const findSelectedEnvironment = () =>
provider.items.find((item) =>
areInterpreterPathsSame(item.executable.uri, selectedInterpreter, platformService.osType)
);

const placeholder = selectedInterpreter
? DataScience.currentlySelectedJupyterInterpreterForPlaceholder(
getDisplayPath(selectedInterpreter, workspace.workspaceFolders || [], platformService.homeDir)
)
: '';
const selector = new PythonEnvironmentPicker({
token: token.token,
supportsBack: false,
placeholder,
isSelected: (item) =>
areInterpreterPathsSame(item.executable.uri, selectedInterpreter, platformService.osType)
});

const disposables: IDisposable[] = [];

const selector = new BaseProviderBasedQuickPick(
provider,
pythonEnvironmentQuickPick,
getPythonEnvironmentCategory,
{ supportsBack: false }
);
selector.placeholder = placeholder;
selector.selected = findSelectedEnvironment();
disposables.push(selector);
disposables.push(token);
try {
const item = await selector.selectItem();
if (item && !(item instanceof InputFlowAction)) {
const interpreter = await this.serviceContainer
.get<IInterpreterService>(IInterpreterService)
.getInterpreterDetails(item.path);
if (!interpreter) {
return;
}
return interpreter;
if (!selector.selected && selectedInterpreter) {
const onDidChangeHandler = provider.onDidChange(() => {
selector.selected = findSelectedEnvironment();
if (selector.selected) {
onDidChangeHandler.dispose();
}
});
disposables.push(onDidChangeHandler);
}

const item = await selector.selectItem(token.token);
if (!item || item instanceof InputFlowAction) {
return;
}
return await this.serviceContainer
.get<IInterpreterService>(IInterpreterService)
.getInterpreterDetails(item.path);
} catch (ex) {
traceError(`Failed to select a Python Environment to start Jupyter`, ex);
} finally {
selector.dispose();
token.dispose();
disposeAllDisposables(disposables);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.

import { CancellationToken, NotebookDocument } from 'vscode';
import { ServiceContainer } from '../../../platform/ioc/container';
import { PythonKernelConnectionMetadata } from '../../../kernels/types';
import { IInterpreterService } from '../../../platform/interpreter/contracts';
import { JupyterPaths } from '../../../kernels/raw/finder/jupyterPaths.node';
import { createInterpreterKernelSpec, getKernelId } from '../../../kernels/helpers';
import { InputFlowAction } from '../../../platform/common/utils/multiStepInput';
import {
getPythonEnvironmentCategory,
pythonEnvironmentQuickPick
} from '../../../platform/interpreter/pythonEnvironmentPicker.node';
import { BaseProviderBasedQuickPick } from '../../../platform/common/providerBasedQuickPick';
import { Environment } from '../../../platform/api/pythonApiTypes';
import { DataScience } from '../../../platform/common/utils/localize';
import { PythonEnvKernelConnectionCreator } from '../pythonEnvKernelConnectionCreator.node';
import { IPythonApiProvider, IPythonExtensionChecker } from '../../../platform/api/types';
import { PythonEnvironmentQuickPickItemProvider } from '../../../platform/interpreter/pythonEnvironmentQuickPickProvider.node';
import { Disposables } from '../../../platform/common/utils';
import { PythonEnvironmentFilter } from '../../../platform/interpreter/filter/filterService';

export class LocalPythonKernelSelector extends Disposables {
private readonly pythonEnvPicker: BaseProviderBasedQuickPick<Environment>;
constructor(
private readonly notebook: NotebookDocument,
private readonly token: CancellationToken
) {
super();
const filter = ServiceContainer.instance.get<PythonEnvironmentFilter>(PythonEnvironmentFilter);
const provider = ServiceContainer.instance
.get<PythonEnvironmentQuickPickItemProvider>(PythonEnvironmentQuickPickItemProvider)
.withFilter((item) => !filter.isPythonEnvironmentExcluded(item));
this.pythonEnvPicker = new BaseProviderBasedQuickPick(
provider,
pythonEnvironmentQuickPick,
getPythonEnvironmentCategory,
{ supportsBack: true }
);
this.disposables.push(this.pythonEnvPicker);
this.pythonEnvPicker.addCommand(
{ label: `$(add) ${DataScience.createPythonEnvironmentInQuickPick}` },
this.createNewEnvironment.bind(this)
);
}

public async selectKernel(): Promise<
PythonKernelConnectionMetadata | typeof InputFlowAction.back | typeof InputFlowAction.cancel
> {
const result = await this.pythonEnvPicker.selectItem(this.token);
if (!result || result instanceof InputFlowAction) {
return result || InputFlowAction.cancel;
}
const interpreters = ServiceContainer.instance.get<IInterpreterService>(IInterpreterService);
const jupyterPaths = ServiceContainer.instance.get<JupyterPaths>(JupyterPaths);
const interpreter = await interpreters.getInterpreterDetails(result.path);
if (!interpreter) {
return InputFlowAction.cancel;
}
const spec = await createInterpreterKernelSpec(
interpreter,
await jupyterPaths.getKernelSpecTempRegistrationFolder()
);
return PythonKernelConnectionMetadata.create({
kernelSpec: spec,
interpreter: interpreter,
id: getKernelId(spec, interpreter)
});
}

private async createNewEnvironment(): Promise<Environment | InputFlowAction | undefined> {
const apiProvider = ServiceContainer.instance.get<IPythonApiProvider>(IPythonApiProvider);
const extChecker = ServiceContainer.instance.get<IPythonExtensionChecker>(IPythonExtensionChecker);
if (!extChecker.isPythonExtensionInstalled) {
return;
}

const creator = new PythonEnvKernelConnectionCreator(this.notebook, this.token);
this.disposables.push(creator);
const result = await creator.createPythonEnvFromKernelPicker();
if (!result) {
return InputFlowAction.cancel;
}
if ('action' in result) {
return result.action === 'Back' ? InputFlowAction.back : InputFlowAction.cancel;
}
const api = await apiProvider.getNewApi();
return api?.environments.known.find((e) => e.id === result.kernelConnection.interpreter.id);
}
}

This file was deleted.

Loading

0 comments on commit 0e016b0

Please sign in to comment.