-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Move tensorboard support into a separate extension #22197
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,6 +21,7 @@ import { IDiscoveryAPI } from './pythonEnvironments/base/locator'; | |
| import { buildEnvironmentApi } from './environmentApi'; | ||
| import { ApiForPylance } from './pylanceApi'; | ||
| import { getTelemetryReporter } from './telemetry'; | ||
| import { TensorboardExtensionIntegration } from './tensorBoard/tensorboardIntegration'; | ||
|
|
||
| export function buildApi( | ||
| ready: Promise<void>, | ||
|
|
@@ -31,7 +32,14 @@ export function buildApi( | |
| const configurationService = serviceContainer.get<IConfigurationService>(IConfigurationService); | ||
| const interpreterService = serviceContainer.get<IInterpreterService>(IInterpreterService); | ||
| serviceManager.addSingleton<JupyterExtensionIntegration>(JupyterExtensionIntegration, JupyterExtensionIntegration); | ||
| serviceManager.addSingleton<TensorboardExtensionIntegration>( | ||
| TensorboardExtensionIntegration, | ||
| TensorboardExtensionIntegration, | ||
| ); | ||
| const jupyterIntegration = serviceContainer.get<JupyterExtensionIntegration>(JupyterExtensionIntegration); | ||
| const tensorboardIntegration = serviceContainer.get<TensorboardExtensionIntegration>( | ||
| TensorboardExtensionIntegration, | ||
| ); | ||
| const outputChannel = serviceContainer.get<ILanguageServerOutputChannel>(ILanguageServerOutputChannel); | ||
|
|
||
| const api: PythonExtension & { | ||
|
|
@@ -41,6 +49,12 @@ export function buildApi( | |
| jupyter: { | ||
| registerHooks(): void; | ||
| }; | ||
| /** | ||
| * Internal API just for Tensorboard, hence don't include in the official types. | ||
| */ | ||
| tensorboard: { | ||
| registerHooks(): void; | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simple (temoprary) tensorboard specific private API |
||
| }; | ||
| } & { | ||
| /** | ||
| * @deprecated Temporarily exposed for Pylance until we expose this API generally. Will be removed in an | ||
|
|
@@ -92,6 +106,9 @@ export function buildApi( | |
| jupyter: { | ||
| registerHooks: () => jupyterIntegration.integrateWithJupyterExtension(), | ||
| }, | ||
| tensorboard: { | ||
| registerHooks: () => tensorboardIntegration.integrateWithTensorboardExtension(), | ||
| }, | ||
| debug: { | ||
| async getRemoteLauncherCommand( | ||
| host: string, | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -12,6 +12,7 @@ import { sendTelemetryEvent } from '../telemetry'; | |
| import { EventName } from '../telemetry/constants'; | ||
| import { TensorBoardEntrypoint, TensorBoardEntrypointTrigger } from './constants'; | ||
| import { containsNotebookExtension } from './helpers'; | ||
| import { useNewTensorboardExtension } from './tensorboarExperiment'; | ||
|
|
||
| @injectable() | ||
| export class TensorBoardNbextensionCodeLensProvider implements IExtensionSingleActivationService { | ||
|
|
@@ -27,6 +28,9 @@ export class TensorBoardNbextensionCodeLensProvider implements IExtensionSingleA | |
| constructor(@inject(IDisposableRegistry) private disposables: IDisposableRegistry) {} | ||
|
|
||
| public async activate(): Promise<void> { | ||
| if (useNewTensorboardExtension()) { | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If tensorboard extension is installed, disable Python extension functionality for tensoboards |
||
| return; | ||
| } | ||
| this.activateInternal().ignoreErrors(); | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| // Copyright (c) Microsoft Corporation. | ||
| // Licensed under the MIT License. | ||
|
|
||
| import { extensions } from 'vscode'; | ||
|
|
||
| export function useNewTensorboardExtension(): boolean { | ||
| return !!extensions.getExtension('ms-toolsai.tensorboard'); | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| import { inject, injectable } from 'inversify'; | ||
| import { Uri, ViewColumn } from 'vscode'; | ||
| import { IApplicationShell, ICommandManager, IWorkspaceService } from '../common/application/types'; | ||
| import { IPythonExecutionFactory } from '../common/process/types'; | ||
| import { | ||
| IInstaller, | ||
| IPersistentState, | ||
| IPersistentStateFactory, | ||
| IConfigurationService, | ||
| IDisposable, | ||
| } from '../common/types'; | ||
| import { IMultiStepInputFactory } from '../common/utils/multiStepInput'; | ||
| import { IInterpreterService } from '../interpreter/contracts'; | ||
| import { TensorBoardSession } from './tensorBoardSession'; | ||
| import { disposeAll } from '../common/utils/resourceLifecycle'; | ||
| import { PREFERRED_VIEWGROUP } from './tensorBoardSessionProvider'; | ||
|
|
||
| @injectable() | ||
| export class TensorboardDependencyChecker { | ||
| private preferredViewGroupMemento: IPersistentState<ViewColumn>; | ||
|
|
||
| constructor( | ||
| @inject(IInstaller) private readonly installer: IInstaller, | ||
| @inject(IInterpreterService) private readonly interpreterService: IInterpreterService, | ||
| @inject(IApplicationShell) private readonly applicationShell: IApplicationShell, | ||
| @inject(IWorkspaceService) private readonly workspaceService: IWorkspaceService, | ||
| @inject(ICommandManager) private readonly commandManager: ICommandManager, | ||
| @inject(IPythonExecutionFactory) private readonly pythonExecFactory: IPythonExecutionFactory, | ||
| @inject(IPersistentStateFactory) private stateFactory: IPersistentStateFactory, | ||
| @inject(IMultiStepInputFactory) private readonly multiStepFactory: IMultiStepInputFactory, | ||
| @inject(IConfigurationService) private readonly configurationService: IConfigurationService, | ||
| ) { | ||
| this.preferredViewGroupMemento = this.stateFactory.createGlobalPersistentState<ViewColumn>( | ||
| PREFERRED_VIEWGROUP, | ||
| ViewColumn.Active, | ||
| ); | ||
| } | ||
|
|
||
| public async ensureDependenciesAreInstalled(resource?: Uri): Promise<boolean> { | ||
| const disposables: IDisposable[] = []; | ||
| const newSession = new TensorBoardSession( | ||
| this.installer, | ||
| this.interpreterService, | ||
| this.workspaceService, | ||
| this.pythonExecFactory, | ||
| this.commandManager, | ||
| disposables, | ||
| this.applicationShell, | ||
| this.preferredViewGroupMemento, | ||
| this.multiStepFactory, | ||
| this.configurationService, | ||
| ); | ||
| const result = await newSession.ensurePrerequisitesAreInstalled(resource); | ||
| disposeAll(disposables); | ||
| return result; | ||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| /* eslint-disable comma-dangle */ | ||
|
|
||
| /* eslint-disable implicit-arrow-linebreak */ | ||
| // Copyright (c) Microsoft Corporation. All rights reserved. | ||
| // Licensed under the MIT License. | ||
|
|
||
| import { inject, injectable } from 'inversify'; | ||
| import { Extension, Uri, commands } from 'vscode'; | ||
| import { IWorkspaceService } from '../common/application/types'; | ||
| import { TENSORBOARD_EXTENSION_ID } from '../common/constants'; | ||
| import { IDisposableRegistry, IExtensions, Resource } from '../common/types'; | ||
| import { IEnvironmentActivationService } from '../interpreter/activation/types'; | ||
| import { TensorBoardPrompt } from './tensorBoardPrompt'; | ||
| import { TensorboardDependencyChecker } from './tensorboardDependencyChecker'; | ||
|
|
||
| type PythonApiForTensorboardExtension = { | ||
| /** | ||
| * Gets activated env vars for the active Python Environment for the given resource. | ||
| */ | ||
| getActivatedEnvironmentVariables(resource: Resource): Promise<NodeJS.ProcessEnv | undefined>; | ||
| /** | ||
| * Ensures that the dependencies required for TensorBoard are installed in Active Environment for the given resource. | ||
| */ | ||
| ensureDependenciesAreInstalled(resource?: Uri): Promise<boolean>; | ||
| /** | ||
| * Whether to allow displaying tensorboard prompt. | ||
| */ | ||
| isPromptEnabled(): boolean; | ||
|
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Simple and temporary API scoped to Tensorboard |
||
| }; | ||
|
|
||
| type TensorboardExtensionApi = { | ||
| /** | ||
| * Registers python extension specific parts with the tensorboard extension | ||
| */ | ||
| registerPythonApi(interpreterService: PythonApiForTensorboardExtension): void; | ||
| }; | ||
|
|
||
| @injectable() | ||
| export class TensorboardExtensionIntegration { | ||
| private tensorboardExtension: Extension<TensorboardExtensionApi> | undefined; | ||
|
|
||
| constructor( | ||
| @inject(IExtensions) private readonly extensions: IExtensions, | ||
| @inject(IEnvironmentActivationService) private readonly envActivation: IEnvironmentActivationService, | ||
| @inject(IWorkspaceService) private workspaceService: IWorkspaceService, | ||
| @inject(TensorboardDependencyChecker) private readonly dependencyChcker: TensorboardDependencyChecker, | ||
| @inject(TensorBoardPrompt) private readonly tensorBoardPrompt: TensorBoardPrompt, | ||
| @inject(IDisposableRegistry) disposables: IDisposableRegistry, | ||
| ) { | ||
| this.hideCommands(); | ||
| extensions.onDidChange(this.hideCommands, this, disposables); | ||
| } | ||
|
|
||
| public registerApi(tensorboardExtensionApi: TensorboardExtensionApi): TensorboardExtensionApi | undefined { | ||
| this.hideCommands(); | ||
| if (!this.workspaceService.isTrusted) { | ||
| this.workspaceService.onDidGrantWorkspaceTrust(() => this.registerApi(tensorboardExtensionApi)); | ||
| return undefined; | ||
| } | ||
| tensorboardExtensionApi.registerPythonApi({ | ||
| getActivatedEnvironmentVariables: async (resource: Resource) => | ||
| this.envActivation.getActivatedEnvironmentVariables(resource, undefined, true), | ||
| ensureDependenciesAreInstalled: async (resource?: Uri): Promise<boolean> => | ||
| this.dependencyChcker.ensureDependenciesAreInstalled(resource), | ||
| isPromptEnabled: () => this.tensorBoardPrompt.isPromptEnabled(), | ||
| }); | ||
| return undefined; | ||
| } | ||
|
|
||
| public hideCommands(): void { | ||
| if (this.extensions.getExtension(TENSORBOARD_EXTENSION_ID)) { | ||
| console.error('TensorBoard extension is installed'); | ||
| void commands.executeCommand('setContext', 'python.tensorboardExtInstalled', true); | ||
| } else { | ||
| console.error('TensorBoard extension not installed'); | ||
| } | ||
| } | ||
|
|
||
| public async integrateWithTensorboardExtension(): Promise<void> { | ||
| const api = await this.getExtensionApi(); | ||
| if (api) { | ||
| this.registerApi(api); | ||
| } | ||
| } | ||
|
|
||
| private async getExtensionApi(): Promise<TensorboardExtensionApi | undefined> { | ||
| if (!this.tensorboardExtension) { | ||
| const extension = this.extensions.getExtension<TensorboardExtensionApi>(TENSORBOARD_EXTENSION_ID); | ||
| if (!extension) { | ||
| return undefined; | ||
| } | ||
| await extension.activate(); | ||
| if (extension.isActive) { | ||
| this.tensorboardExtension = extension; | ||
| return this.tensorboardExtension.exports; | ||
| } | ||
| } else { | ||
| return this.tensorboardExtension.exports; | ||
| } | ||
| return undefined; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If tensorboard extension is installed, then the Python command will not be displayed