Skip to content

Commit

Permalink
Update API to allow opening notebook with the Python Env Id (#15022)
Browse files Browse the repository at this point in the history
* Update API to allow opening notebook with the Python Env Id

* Updates
  • Loading branch information
DonJayamanne authored Jan 17, 2024
1 parent a21e1d7 commit fe605a6
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 5 deletions.
7 changes: 7 additions & 0 deletions src/api.unstable.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ declare module './api' {
* There are a specific set of extensions that are currently allowed to access this API.
*/
getKernelService(): Promise<IExportedKernelService | undefined>;
/**
* Opens a notebook with a specific Python Environment as the active kernel.
* @param {Uri} uri Uri of the notebook to open.
* @param {String} kernelId Id of the Python Environment
* @returns {Promise<NotebookDocument>} Promise that resolves to the notebook document.
*/
openNotebook(uri: Uri, pythonEnvironmentId: string): Promise<NotebookDocument>;
/**
* Opens a notebook with a specific kernel as the active kernel.
* @param {Uri} uri Uri of the notebook to open.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,18 @@ import { JupyterPaths } from '../../../kernels/raw/finder/jupyterPaths.node';
import { IPythonApiProvider, IPythonExtensionChecker } from '../../../platform/api/types';
import { pythonEnvToJupyterEnv } from '../../../platform/api/pythonApi';
import { createInterpreterKernelSpec, getKernelId } from '../../../kernels/helpers';
import { Environment } from '@vscode/python-extension';
import { Environment, EnvironmentPath } from '@vscode/python-extension';
import { noop } from '../../../platform/common/utils/misc';
import { IExtensionSyncActivationService } from '../../../platform/activation/types';
import { KernelFinder } from '../../../kernels/kernelFinder';
import { LocalPythonKernelSelector } from './localPythonKernelSelector.node';
import { InputFlowAction } from '../../../platform/common/utils/multiStepInput';
import { ILocalPythonNotebookKernelSourceSelector } from '../types';
import { DisposableBase } from '../../../platform/common/utils/lifecycle';
import { ServiceContainer } from '../../../platform/ioc/container';
import { IInterpreterService } from '../../../platform/interpreter/contracts';
import { traceWarning } from '../../../platform/logging';
import { getDisplayPath } from '../../../platform/common/platform/fs-paths';

export type MultiStepResult<T extends KernelConnectionMetadata = KernelConnectionMetadata> = {
notebook: NotebookDocument;
Expand Down Expand Up @@ -119,6 +123,35 @@ export class LocalPythonEnvNotebookKernelSourceSelector
dispose(disposables);
}
}
public async getKernelConnection(env: EnvironmentPath): Promise<PythonKernelConnectionMetadata | undefined> {
const interpreters = ServiceContainer.instance.get<IInterpreterService>(IInterpreterService);
const jupyterPaths = ServiceContainer.instance.get<JupyterPaths>(JupyterPaths);
const interpreter = await interpreters.getInterpreterDetails(env.path);
if (!interpreter) {
traceWarning(`Python Env ${getDisplayPath(env.id)} not found}`);
return;
}
if (!interpreter || this.filter.isPythonEnvironmentExcluded(interpreter)) {
traceWarning(`Python Env hidden via filter: ${getDisplayPath(interpreter.id)}`);
return;
}

const spec = await createInterpreterKernelSpec(
interpreter,
await jupyterPaths.getKernelSpecTempRegistrationFolder()
);
const kernelConnection = PythonKernelConnectionMetadata.create({
kernelSpec: spec,
interpreter: interpreter,
id: getKernelId(spec, interpreter)
});
const existingConnection = this._kernels.get(kernelConnection.id);
if (existingConnection) {
return existingConnection;
}
this.addUpdateKernel(kernelConnection);
return kernelConnection;
}
private addUpdateKernel(kernel: PythonKernelConnectionMetadata) {
const existing = this._kernels.get(kernel.id);
if (existing) {
Expand Down
2 changes: 2 additions & 0 deletions src/notebooks/controllers/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import {
import { JupyterNotebookView, InteractiveWindowView } from '../../platform/common/constants';
import { IDisposable } from '../../platform/common/types';
import { JupyterServerCollection } from '../../api';
import { EnvironmentPath } from '@vscode/python-extension';

export const InteractiveControllerIdSuffix = ' (Interactive)';

Expand Down Expand Up @@ -124,6 +125,7 @@ export interface ILocalNotebookKernelSourceSelector {
export const ILocalPythonNotebookKernelSourceSelector = Symbol('ILocalPythonNotebookKernelSourceSelector');
export interface ILocalPythonNotebookKernelSourceSelector {
selectLocalKernel(notebook: vscode.NotebookDocument): Promise<PythonKernelConnectionMetadata | undefined>;
getKernelConnection(env: EnvironmentPath): Promise<PythonKernelConnectionMetadata | undefined>;
}

export interface IConnectionDisplayData extends IDisposable {
Expand Down
27 changes: 23 additions & 4 deletions src/standalone/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ import { CodespaceExtensionId, isTestExecution, JVSC_EXTENSION_ID, Telemetry } f
import { IDisposable, IExtensionContext, IExtensions } from '../../platform/common/types';
import { IServiceContainer, IServiceManager } from '../../platform/ioc/types';
import { traceError } from '../../platform/logging';
import { IControllerRegistration } from '../../notebooks/controllers/types';
import { IControllerRegistration, ILocalPythonNotebookKernelSourceSelector } from '../../notebooks/controllers/types';
import { sendTelemetryEvent } from '../../telemetry';
import { isRemoteConnection } from '../../kernels/types';
import {
Expand All @@ -23,6 +23,8 @@ import {
import { stripCodicons } from '../../platform/common/helpers';
import { getKernelsApi } from '../../kernels/api/api';
import { jupyterServerUriToCollection } from '../../codespaces';
import { isWeb } from '../../platform/common/utils/misc';
import { EnvironmentPath } from '@vscode/python-extension';

export const IExportedKernelServiceFactory = Symbol('IExportedKernelServiceFactory');
export interface IExportedKernelServiceFactory {
Expand Down Expand Up @@ -190,15 +192,32 @@ export function buildApi(
await selector.addJupyterServer({ id: providerId, handle, extensionId });
await controllerCreatedPromise;
},
openNotebook: async (uri: Uri, kernelId: string) => {
openNotebook: async (uri: Uri, kernelOrPythonEnvId: string | EnvironmentPath) => {
sendTelemetryEvent(Telemetry.JupyterApiUsage, undefined, {
clientExtId: extensions.determineExtensionFromCallStack().extensionId,
pemUsed: 'openNotebook'
});
const controllers = serviceContainer.get<IControllerRegistration>(IControllerRegistration);
const id = controllers.all.find((controller) => controller.id === kernelId)?.id;
const kernelId = typeof kernelOrPythonEnvId === 'string' ? kernelOrPythonEnvId : undefined;
const pythonEnv = typeof kernelOrPythonEnvId === 'string' ? undefined : kernelOrPythonEnvId;
let id = kernelId && controllers.all.find((controller) => controller.id === kernelOrPythonEnvId)?.id;
if (!id && pythonEnv && !isWeb()) {
// Look for a python environment with this id.
id = controllers.all.find(
(controller) =>
controller.kind === 'startUsingPythonInterpreter' && controller.interpreter.id === pythonEnv.id
)?.id;
if (!id) {
// Controller has not yet been created.
const selector = serviceContainer.get<ILocalPythonNotebookKernelSourceSelector>(
ILocalPythonNotebookKernelSourceSelector
);
const connection = await selector.getKernelConnection(pythonEnv);
id = connection && controllers.all.find((controller) => controller.id === connection?.id)?.id;
}
}
if (!id) {
throw new Error(`Kernel ${kernelId} not found.`);
throw new Error(`Kernel ${kernelOrPythonEnvId} not found.`);
}
const notebookEditor =
window.activeNotebookEditor?.notebook?.uri?.toString() === uri.toString()
Expand Down

0 comments on commit fe605a6

Please sign in to comment.