From cb46b4ea5b53da51d2b1898f6e4a8cad1dcb62ba Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Fri, 11 Sep 2020 13:52:44 -0700 Subject: [PATCH 1/4] Extension API --- src/client/api.ts | 9 +++ .../datascience/api/jupyterIntegration.ts | 67 +++++++++++++++++++ 2 files changed, 76 insertions(+) create mode 100644 src/client/datascience/api/jupyterIntegration.ts diff --git a/src/client/api.ts b/src/client/api.ts index b4168856ad9c..58e20bfe2f37 100644 --- a/src/client/api.ts +++ b/src/client/api.ts @@ -8,6 +8,7 @@ import { NotebookCell } from 'vscode-proposed'; import { isTestExecution } from './common/constants'; import { traceError } from './common/logger'; import { IConfigurationService, Resource } from './common/types'; +import { JupyterExtensionIntegration } from './datascience/api/jupyterIntegration'; import { IDataViewerDataProvider, IDataViewerFactory } from './datascience/data-viewing/types'; import { IJupyterUriProvider, IJupyterUriProviderRegistration, INotebookExtensibility } from './datascience/types'; import { getDebugpyLauncherArgs, getDebugpyPackagePath } from './debugger/extension/adapter/remoteLaunchers'; @@ -26,6 +27,9 @@ export interface IExtensionApi { * @memberof IExtensionApi */ ready: Promise; + jupyter: { + registerHooks(): void; + }; debug: { /** * Generate an array of strings for commands to pass to the Python executable to launch the debugger for remote debugging. @@ -103,12 +107,17 @@ export function buildApi( const configurationService = serviceContainer.get(IConfigurationService); const interpreterService = serviceContainer.get(IInterpreterService); const notebookExtensibility = serviceContainer.get(INotebookExtensibility); + serviceManager.addSingleton(JupyterExtensionIntegration, JupyterExtensionIntegration); + const jupyterIntegration = serviceContainer.get(JupyterExtensionIntegration); const api: IExtensionApi = { // 'ready' will propagate the exception, but we must log it here first. ready: ready.catch((ex) => { traceError('Failure during activation.', ex); return Promise.reject(ex); }), + jupyter: { + registerHooks: () => jupyterIntegration.integrateWithJupyterExtension() + }, debug: { async getRemoteLauncherCommand( host: string, diff --git a/src/client/datascience/api/jupyterIntegration.ts b/src/client/datascience/api/jupyterIntegration.ts new file mode 100644 index 000000000000..850720c2c074 --- /dev/null +++ b/src/client/datascience/api/jupyterIntegration.ts @@ -0,0 +1,67 @@ +// Copyright (c) Microsoft Corporation. All rights reserved. +// Licensed under the MIT License. + +import { inject, injectable } from 'inversify'; +import { Uri } from 'vscode'; +import { IExtensions } from '../../common/types'; +import { IEnvironmentActivationService } from '../../interpreter/activation/types'; +import { IInterpreterService } from '../../interpreter/contracts'; +import { PythonEnvironment } from '../../pythonEnvironments/info'; + +type PythonApiForJupyterExtension = { + getInterpreters(resource?: Uri): Promise; + getActiveInterpreter(resource?: Uri): Promise; + getInterpreterDetails(pythonPath: string): Promise; + getActivatedEnvironmentVariables(options: { + pythonPath: string; + resource?: Uri; + }): Promise; +}; + +type JupyterExtensionApi = { + registerPythonApi(interpreterService: PythonApiForJupyterExtension): void; +}; + +@injectable() +export class JupyterExtensionIntegration { + constructor( + @inject(IExtensions) private readonly extensions: IExtensions, + @inject(IInterpreterService) private readonly interpreterService: IInterpreterService, + @inject(IEnvironmentActivationService) private readonly envActivation: IEnvironmentActivationService + ) {} + + public async integrateWithJupyterExtension(): Promise { + const jupyterExtension = this.extensions.getExtension('ms-python.jupyter'); + if (!jupyterExtension) { + return; + } + if (!jupyterExtension.isActive) { + await jupyterExtension.activate(); + } + await jupyterExtension.activate(); + if (jupyterExtension.isActive) { + const jupyterExtensionApi = jupyterExtension.exports; + jupyterExtensionApi.registerPythonApi({ + getActiveInterpreter: async (resource?: Uri) => this.interpreterService.getActiveInterpreter(resource), + getInterpreterDetails: async (pythonPath: string) => + // eslint-disable-next-line implicit-arrow-linebreak + this.interpreterService.getInterpreterDetails(pythonPath), + getInterpreters: async (resource: Uri | undefined) => this.interpreterService.getInterpreters(resource), + getActivatedEnvironmentVariables: async (options: { pythonPath: string; resource?: Uri }) => { + const interpreter = await this.interpreterService.getInterpreterDetails( + options.pythonPath, + // eslint-disable-next-line comma-dangle + options.resource + ); + return this.envActivation.getActivatedEnvironmentVariables( + options.resource, + interpreter, + // eslint-disable-next-line comma-dangle + true + ); + // eslint-disable-next-line comma-dangle + } + }); + } + } +} From 013b77859bef9d49b27b32213042071dd33e1527 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Mon, 14 Sep 2020 10:56:15 -0700 Subject: [PATCH 2/4] Api for DS --- .../datascience/api/jupyterIntegration.ts | 84 ++++++++++++++----- 1 file changed, 61 insertions(+), 23 deletions(-) diff --git a/src/client/datascience/api/jupyterIntegration.ts b/src/client/datascience/api/jupyterIntegration.ts index 850720c2c074..31fe7465c1a5 100644 --- a/src/client/datascience/api/jupyterIntegration.ts +++ b/src/client/datascience/api/jupyterIntegration.ts @@ -1,21 +1,56 @@ +// tslint:disable-next-line: no-single-line-block-comment +/* eslint-disable comma-dangle */ +// tslint:disable-next-line: no-single-line-block-comment +/* eslint-disable implicit-arrow-linebreak */ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import { inject, injectable } from 'inversify'; -import { Uri } from 'vscode'; -import { IExtensions } from '../../common/types'; +import { CancellationToken, Event, Uri } from 'vscode'; +import { InterpreterUri } from '../../common/installer/types'; +import { IExtensions, IInstaller, InstallerResponse, Product, Resource } from '../../common/types'; import { IEnvironmentActivationService } from '../../interpreter/activation/types'; +import { IInterpreterQuickPickItem, IInterpreterSelector } from '../../interpreter/configuration/types'; import { IInterpreterService } from '../../interpreter/contracts'; +import { IWindowsStoreInterpreter } from '../../interpreter/locators/types'; +import { WindowsStoreInterpreter } from '../../pythonEnvironments/discovery/locators/services/windowsStoreInterpreter'; import { PythonEnvironment } from '../../pythonEnvironments/info'; type PythonApiForJupyterExtension = { + /** + * IInterpreterService + */ + onDidChangeInterpreter: Event; + /** + * IInterpreterService + */ getInterpreters(resource?: Uri): Promise; + /** + * IInterpreterService + */ getActiveInterpreter(resource?: Uri): Promise; - getInterpreterDetails(pythonPath: string): Promise; - getActivatedEnvironmentVariables(options: { - pythonPath: string; - resource?: Uri; - }): Promise; + /** + * IInterpreterService + */ + getInterpreterDetails(pythonPath: string, resource?: Uri): Promise; + + /** + * IEnvironmentActivationService + */ + getActivatedEnvironmentVariables( + resource: Resource, + interpreter?: PythonEnvironment, + allowExceptions?: boolean + ): Promise; + isWindowsStoreInterpreter(pythonPath: string): Promise; + /** + * IWindowsStoreInterpreter + */ + getSuggestions(resource: Resource): Promise; + /** + * IInstaller + */ + install(product: Product, resource?: InterpreterUri, cancel?: CancellationToken): Promise; }; type JupyterExtensionApi = { @@ -27,11 +62,14 @@ export class JupyterExtensionIntegration { constructor( @inject(IExtensions) private readonly extensions: IExtensions, @inject(IInterpreterService) private readonly interpreterService: IInterpreterService, + @inject(IInterpreterSelector) private readonly interpreterSelector: IInterpreterSelector, + @inject(WindowsStoreInterpreter) private readonly windowsStoreInterpreter: IWindowsStoreInterpreter, + @inject(IInstaller) private readonly installer: IInstaller, @inject(IEnvironmentActivationService) private readonly envActivation: IEnvironmentActivationService ) {} public async integrateWithJupyterExtension(): Promise { - const jupyterExtension = this.extensions.getExtension('ms-python.jupyter'); + const jupyterExtension = this.extensions.getExtension('ms-ai-tools.jupyter'); if (!jupyterExtension) { return; } @@ -42,25 +80,25 @@ export class JupyterExtensionIntegration { if (jupyterExtension.isActive) { const jupyterExtensionApi = jupyterExtension.exports; jupyterExtensionApi.registerPythonApi({ + onDidChangeInterpreter: this.interpreterService.onDidChangeInterpreter, getActiveInterpreter: async (resource?: Uri) => this.interpreterService.getActiveInterpreter(resource), getInterpreterDetails: async (pythonPath: string) => - // eslint-disable-next-line implicit-arrow-linebreak this.interpreterService.getInterpreterDetails(pythonPath), getInterpreters: async (resource: Uri | undefined) => this.interpreterService.getInterpreters(resource), - getActivatedEnvironmentVariables: async (options: { pythonPath: string; resource?: Uri }) => { - const interpreter = await this.interpreterService.getInterpreterDetails( - options.pythonPath, - // eslint-disable-next-line comma-dangle - options.resource - ); - return this.envActivation.getActivatedEnvironmentVariables( - options.resource, - interpreter, - // eslint-disable-next-line comma-dangle - true - ); - // eslint-disable-next-line comma-dangle - } + getActivatedEnvironmentVariables: async ( + resource: Resource, + interpreter?: PythonEnvironment, + allowExceptions?: boolean + ) => this.envActivation.getActivatedEnvironmentVariables(resource, interpreter, allowExceptions), + isWindowsStoreInterpreter: async (pythonPath: string): Promise => + this.windowsStoreInterpreter.isWindowsStoreInterpreter(pythonPath), + getSuggestions: async (resource: Resource): Promise => + this.interpreterSelector.getSuggestions(resource), + install: async ( + product: Product, + resource?: InterpreterUri, + cancel?: CancellationToken + ): Promise => this.installer.install(product, resource, cancel) }); } } From 5b9d4f9cf3ee793392ff43a9f2eee0e7697a4aeb Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Mon, 14 Sep 2020 11:04:15 -0700 Subject: [PATCH 3/4] Oops --- src/client/datascience/api/jupyterIntegration.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/client/datascience/api/jupyterIntegration.ts b/src/client/datascience/api/jupyterIntegration.ts index 31fe7465c1a5..11e4365fcdca 100644 --- a/src/client/datascience/api/jupyterIntegration.ts +++ b/src/client/datascience/api/jupyterIntegration.ts @@ -73,9 +73,6 @@ export class JupyterExtensionIntegration { if (!jupyterExtension) { return; } - if (!jupyterExtension.isActive) { - await jupyterExtension.activate(); - } await jupyterExtension.activate(); if (jupyterExtension.isActive) { const jupyterExtensionApi = jupyterExtension.exports; From 39ccd95b1c357a45c42339c2ba6f91f4a7bf8d83 Mon Sep 17 00:00:00 2001 From: Don Jayamanne Date: Mon, 14 Sep 2020 11:04:30 -0700 Subject: [PATCH 4/4] Oops --- .../datascience/api/jupyterIntegration.ts | 47 ++++++++++--------- 1 file changed, 24 insertions(+), 23 deletions(-) diff --git a/src/client/datascience/api/jupyterIntegration.ts b/src/client/datascience/api/jupyterIntegration.ts index 11e4365fcdca..4df5a8a7cd11 100644 --- a/src/client/datascience/api/jupyterIntegration.ts +++ b/src/client/datascience/api/jupyterIntegration.ts @@ -74,29 +74,30 @@ export class JupyterExtensionIntegration { return; } await jupyterExtension.activate(); - if (jupyterExtension.isActive) { - const jupyterExtensionApi = jupyterExtension.exports; - jupyterExtensionApi.registerPythonApi({ - onDidChangeInterpreter: this.interpreterService.onDidChangeInterpreter, - getActiveInterpreter: async (resource?: Uri) => this.interpreterService.getActiveInterpreter(resource), - getInterpreterDetails: async (pythonPath: string) => - this.interpreterService.getInterpreterDetails(pythonPath), - getInterpreters: async (resource: Uri | undefined) => this.interpreterService.getInterpreters(resource), - getActivatedEnvironmentVariables: async ( - resource: Resource, - interpreter?: PythonEnvironment, - allowExceptions?: boolean - ) => this.envActivation.getActivatedEnvironmentVariables(resource, interpreter, allowExceptions), - isWindowsStoreInterpreter: async (pythonPath: string): Promise => - this.windowsStoreInterpreter.isWindowsStoreInterpreter(pythonPath), - getSuggestions: async (resource: Resource): Promise => - this.interpreterSelector.getSuggestions(resource), - install: async ( - product: Product, - resource?: InterpreterUri, - cancel?: CancellationToken - ): Promise => this.installer.install(product, resource, cancel) - }); + if (!jupyterExtension.isActive) { + return; } + const jupyterExtensionApi = jupyterExtension.exports; + jupyterExtensionApi.registerPythonApi({ + onDidChangeInterpreter: this.interpreterService.onDidChangeInterpreter, + getActiveInterpreter: async (resource?: Uri) => this.interpreterService.getActiveInterpreter(resource), + getInterpreterDetails: async (pythonPath: string) => + this.interpreterService.getInterpreterDetails(pythonPath), + getInterpreters: async (resource: Uri | undefined) => this.interpreterService.getInterpreters(resource), + getActivatedEnvironmentVariables: async ( + resource: Resource, + interpreter?: PythonEnvironment, + allowExceptions?: boolean + ) => this.envActivation.getActivatedEnvironmentVariables(resource, interpreter, allowExceptions), + isWindowsStoreInterpreter: async (pythonPath: string): Promise => + this.windowsStoreInterpreter.isWindowsStoreInterpreter(pythonPath), + getSuggestions: async (resource: Resource): Promise => + this.interpreterSelector.getSuggestions(resource), + install: async ( + product: Product, + resource?: InterpreterUri, + cancel?: CancellationToken + ): Promise => this.installer.install(product, resource, cancel) + }); } }