diff --git a/src/client/datascience/jupyter/jupyterDebugger.ts b/src/client/datascience/jupyter/jupyterDebugger.ts index e1c27677eb2..e2ea69f6deb 100644 --- a/src/client/datascience/jupyter/jupyterDebugger.ts +++ b/src/client/datascience/jupyter/jupyterDebugger.ts @@ -10,7 +10,7 @@ import { traceInfo, traceWarning } from '../../common/logger'; import { IPlatformService } from '../../common/platform/types'; import { IConfigurationService } from '../../common/types'; import * as localize from '../../common/utils/localize'; -import { isUsingIpykernel6OrLater } from '../../debugger/jupyter/helper'; +import { IpykernelCheckResult, isUsingIpykernel6OrLater } from '../../debugger/jupyter/helper'; import { Identifiers } from '../constants'; import { ICellHashListener, @@ -56,7 +56,7 @@ export class JupyterDebugger implements IJupyterDebugger, ICellHashListener { } const settings = this.configService.getSettings(notebook.resource); - this.isUsingPyKernel6OrLater = await isUsingIpykernel6OrLater(kernel); + this.isUsingPyKernel6OrLater = (await isUsingIpykernel6OrLater(kernel)) === IpykernelCheckResult.Ok; return this.startDebugSession( (c) => this.debugService.startDebugging(undefined, c), notebook, diff --git a/src/client/debugger/jupyter/debuggingManager.ts b/src/client/debugger/jupyter/debuggingManager.ts index fbf9ada3f63..5fb60bf3fb4 100644 --- a/src/client/debugger/jupyter/debuggingManager.ts +++ b/src/client/debugger/jupyter/debuggingManager.ts @@ -36,7 +36,7 @@ import { IDebuggingManager, IKernelDebugAdapterConfig, KernelDebugMode } from '. import { DebuggingTelemetry, pythonKernelDebugAdapter } from '../constants'; import { sendTelemetryEvent } from '../../telemetry'; import { DebugCellController, RunByLineController } from './debugControllers'; -import { assertIsDebugConfig, isUsingIpykernel6OrLater } from './helper'; +import { assertIsDebugConfig, IpykernelCheckResult, isUsingIpykernel6OrLater } from './helper'; import { Debugger } from './debugger'; /** @@ -238,9 +238,9 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb return; } - try { - this.notebookInProgress.add(editor.document); - if (await this.checkForIpykernel6(editor.document)) { + const checkIpykernelAndStart = async (allowSelectKernel = true): Promise => { + const ipykernelResult = await this.checkForIpykernel6(editor.document); + if (ipykernelResult === IpykernelCheckResult.Ok) { switch (mode) { case KernelDebugMode.Everything: await this.startDebugging(editor.document); @@ -260,9 +260,20 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb } break; } - } else { - void this.installIpykernel6(); + } else if ( + ipykernelResult === IpykernelCheckResult.Missing || + ipykernelResult === IpykernelCheckResult.Unknown + ) { + void this.promptInstallIpykernel6(); + } else if (ipykernelResult === IpykernelCheckResult.NoKernel && allowSelectKernel) { + await this.commandManager.executeCommand('notebook.selectKernel', { notebookEditor: editor }); + return checkIpykernelAndStart(false); } + }; + + try { + this.notebookInProgress.add(editor.document); + await checkIpykernelAndStart(); } finally { this.notebookInProgress.delete(editor.document); } @@ -410,7 +421,7 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb return kernel; } - private async checkForIpykernel6(doc: NotebookDocument): Promise { + private async checkForIpykernel6(doc: NotebookDocument): Promise { try { let kernel = this.kernelProvider.get(doc); @@ -429,17 +440,19 @@ export class DebuggingManager implements IExtensionSingleActivationService, IDeb if (kernel) { const result = await isUsingIpykernel6OrLater(kernel); sendTelemetryEvent(DebuggingTelemetry.ipykernel6Status, undefined, { - status: result ? 'installed' : 'notInstalled' + status: result === IpykernelCheckResult.Ok ? 'installed' : 'notInstalled' }); return result; + } else { + return IpykernelCheckResult.NoKernel; } } catch { traceError('Debugging: Could not check for ipykernel 6'); } - return false; + return IpykernelCheckResult.Unknown; } - private async installIpykernel6() { + private async promptInstallIpykernel6() { const response = await this.appShell.showInformationMessage( DataScience.needIpykernel6(), { modal: true }, diff --git a/src/client/debugger/jupyter/helper.ts b/src/client/debugger/jupyter/helper.ts index 48efd56c4fb..54338bf1065 100644 --- a/src/client/debugger/jupyter/helper.ts +++ b/src/client/debugger/jupyter/helper.ts @@ -5,17 +5,24 @@ import { DebugProtocol } from 'vscode-debugprotocol'; import { IKernel } from '../../datascience/jupyter/kernels/types'; import { IKernelDebugAdapterConfig, KernelDebugMode } from '../types'; -export async function isUsingIpykernel6OrLater(kernel: IKernel): Promise { +export enum IpykernelCheckResult { + Unknown, + Ok, + Missing, + NoKernel +} + +export async function isUsingIpykernel6OrLater(kernel: IKernel): Promise { const code = 'import ipykernel\nprint(ipykernel.__version__)'; const output = await kernel.executeHidden(code); if (output[0].text) { const version = output[0].text.toString().split('.'); const majorVersion = Number(version[0]); - return majorVersion >= 6; + return majorVersion >= 6 ? IpykernelCheckResult.Ok : IpykernelCheckResult.Missing; } - return false; + return IpykernelCheckResult.Unknown; } export function assertIsDebugConfig(thing: unknown): asserts thing is IKernelDebugAdapterConfig {