Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update API to allow opening notebook with the Python Env Id #15022

Merged
merged 2 commits into from
Jan 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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