diff --git a/src/client/datascience/jupyter/kernels/kernelSelector.ts b/src/client/datascience/jupyter/kernels/kernelSelector.ts index 4e9a172ce817..93ff0a676d8b 100644 --- a/src/client/datascience/jupyter/kernels/kernelSelector.ts +++ b/src/client/datascience/jupyter/kernels/kernelSelector.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import type { nbformat } from '@jupyterlab/coreutils'; import type { Kernel } from '@jupyterlab/services'; +import { sha256 } from 'hash.js'; import { inject, injectable } from 'inversify'; // tslint:disable-next-line: no-require-imports import cloneDeep = require('lodash/cloneDeep'); @@ -18,6 +19,7 @@ import { PythonEnvironment } from '../../../pythonEnvironments/info'; import { IEventNamePropertyMapping, sendTelemetryEvent } from '../../../telemetry'; import { Commands, KnownNotebookLanguages, Settings, Telemetry } from '../../constants'; import { IKernelFinder } from '../../kernel-launcher/types'; +import { getInterpreterInfoStoredInMetadata } from '../../notebookStorage/baseModel'; import { reportAction } from '../../progress/decorator'; import { ReportableAction } from '../../progress/types'; import { @@ -486,6 +488,17 @@ export class KernelSelector implements IKernelSelectionUsage { } } } + private async findInterpreterStoredInNotebookMetadata( + resource: Resource, + notebookMetadata?: nbformat.INotebookMetadata + ): Promise { + const info = getInterpreterInfoStoredInMetadata(notebookMetadata); + if (!info) { + return; + } + const interpreters = await this.interpreterService.getInterpreters(resource); + return interpreters.find((item) => sha256().update(item.path).digest('hex') === info.hash); + } // Get our kernelspec and interpreter for a local raw connection private async getKernelForLocalRawConnection( @@ -494,6 +507,19 @@ export class KernelSelector implements IKernelSelectionUsage { cancelToken?: CancellationToken, ignoreDependencyCheck?: boolean ): Promise { + // If user had selected an interpreter (raw kernel), then that interpreter would be stored in the kernelspec metadata. + // Find this matching interpreter & start that using raw kernel. + const interpreterStoredInKernelSpec = await this.findInterpreterStoredInNotebookMetadata( + resource, + notebookMetadata + ); + if (interpreterStoredInKernelSpec) { + return { + kind: 'startUsingPythonInterpreter', + interpreter: interpreterStoredInKernelSpec + }; + } + // First use our kernel finder to locate a kernelspec on disk const kernelSpec = await this.kernelFinder.findKernelSpec( resource, diff --git a/src/client/datascience/notebookStorage/baseModel.ts b/src/client/datascience/notebookStorage/baseModel.ts index db62829a4d0e..1a4de63db0b5 100644 --- a/src/client/datascience/notebookStorage/baseModel.ts +++ b/src/client/datascience/notebookStorage/baseModel.ts @@ -23,6 +23,19 @@ type KernelIdListEntry = { kernelId: string | undefined; }; +export function getInterpreterInfoStoredInMetadata( + metadata?: nbformat.INotebookMetadata +): { displayName: string; hash: string } | undefined { + if (!metadata || !metadata.kernelspec || !metadata.kernelspec.name) { + return; + } + // See `updateNotebookMetadata` to determine how & where exactly interpreter hash is stored. + // tslint:disable-next-line: no-any + const kernelSpecMetadata: undefined | any = metadata.kernelspec.metadata as any; + const interpreterHash = kernelSpecMetadata?.interpreter?.hash; + return interpreterHash ? { displayName: metadata.kernelspec.name, hash: interpreterHash } : undefined; +} + // tslint:disable-next-line: cyclomatic-complexity export function updateNotebookMetadata( metadata?: nbformat.INotebookMetadata,