Skip to content

Commit 400b193

Browse files
authored
Add Python: Launch TensorBoard command (#14751)
1 parent f1d0c60 commit 400b193

File tree

17 files changed

+438
-2
lines changed

17 files changed

+438
-2
lines changed

news/1 Enhancements/14806.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Add Python: Launch TensorBoard command behind an experiment.

package.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,7 @@
8383
"onCommand:python.resetInterpreterSecurityStorage",
8484
"onCommand:python.startPage.open",
8585
"onCommand:python.enableSourceMapSupport",
86+
"onCommand:python.launchTensorBoard",
8687
"workspaceContains:mspythonconfig.json",
8788
"workspaceContains:pyproject.toml"
8889
],
@@ -352,6 +353,11 @@
352353
"command": "python.analysis.restartLanguageServer",
353354
"title": "%python.command.python.analysis.restartLanguageServer.title%",
354355
"category": "Python"
356+
},
357+
{
358+
"command": "python.launchTensorBoard",
359+
"title": "%python.command.python.launchTensorBoard.title%",
360+
"category": "Python"
355361
}
356362
],
357363
"menus": {
@@ -486,6 +492,11 @@
486492
"command": "python.startPage.open",
487493
"title": "%python.command.python.startPage.open.title%",
488494
"category": "Python"
495+
},
496+
{
497+
"command": "python.launchTensorBoard",
498+
"category": "Python",
499+
"when": "python.isInNativeTensorBoardExperiment"
489500
}
490501
],
491502
"view/title": [
@@ -1043,6 +1054,7 @@
10431054
"jediLSP",
10441055
"debuggerDataViewer",
10451056
"pythonSendEntireLineToREPL",
1057+
"nativeTensorBoard",
10461058
"All"
10471059
]
10481060
},
@@ -1070,6 +1082,7 @@
10701082
"jediLSP",
10711083
"debuggerDataViewer",
10721084
"pythonSendEntireLineToREPL",
1085+
"nativeTensorBoard",
10731086
"All"
10741087
]
10751088
},

package.nls.json

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
"python.command.python.startPage.open.title": "Open Start Page",
3737
"python.command.python.analysis.clearCache.title": "Clear Module Analysis Cache",
3838
"python.command.python.analysis.restartLanguageServer.title": "Restart Language Server",
39+
"python.command.python.launchTensorBoard.title": "Launch TensorBoard",
3940
"python.snippet.launch.standard.label": "Python: Current File",
4041
"python.snippet.launch.module.label": "Python: Module",
4142
"python.snippet.launch.module.default": "enter-your-module-name",
@@ -219,5 +220,11 @@
219220
"StartPage.openFolder": "Open a Folder or Workspace",
220221
"StartPage.folderDesc": "- Open a <div class=\"link\" role=\"button\" onclick={0}>Folder</div><br /> - Open a <div class=\"link\" role=\"button\" onclick={1}>Workspace</div>",
221222
"StartPage.badWebPanelFormatString": "<html><body><h1>{0} is not a valid file name</h1></body></html>",
222-
"Jupyter.extensionRequired": "The Jupyter extension is required to perform that task. Click Yes to open the Jupyter extension installation page."
223+
"Jupyter.extensionRequired": "The Jupyter extension is required to perform that task. Click Yes to open the Jupyter extension installation page.",
224+
"TensorBoard.logDirectoryPrompt" : "Please select a log directory to start TensorBoard with.",
225+
"TensorBoard.installPrompt" : "The package TensorBoard is required in order to launch a TensorBoard session. Would you like to install it?",
226+
"TensorBoard.failedToStartSessionError" : "We failed to start a TensorBoard session due to the following error: {0}",
227+
"TensorBoard.progressMessage" : "Starting TensorBoard session...",
228+
"TensorBoard.usingCurrentWorkspaceFolder": "We are using the current workspace folder as the log directory for your TensorBoard session.",
229+
"TensorBoard.selectAFolder": "Select a folder"
223230
}

pythonFiles/tensorboard_launcher.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import os
2+
import time
3+
import sys
4+
import tensorboard
5+
6+
7+
def main(logdir):
8+
tb = tensorboard.program.TensorBoard()
9+
tb.configure(bind_all=False, logdir=logdir)
10+
url = tb.launch()
11+
sys.stdout.write("TensorBoard started at %s\n" % (url))
12+
sys.stdout.flush()
13+
while True:
14+
try:
15+
time.sleep(60)
16+
except KeyboardInterrupt:
17+
break
18+
sys.stdout.write("TensorBoard is shutting down")
19+
sys.stdout.flush()
20+
21+
22+
if __name__ == "__main__":
23+
if len(sys.argv) == 2:
24+
logdir = str(sys.argv[1])
25+
sys.stdout.write("Starting TensorBoard with logdir %s" % (logdir))
26+
main(logdir)

src/client/common/application/commands.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ interface ICommandNameWithoutArgumentTypeMapping {
5151
[Commands.OpenStartPage]: [];
5252
[LSCommands.ClearAnalyisCache]: [];
5353
[LSCommands.RestartLS]: [];
54+
[Commands.LaunchTensorBoard]: [];
5455
}
5556

5657
/**

src/client/common/constants.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export namespace Commands {
7070
export const ClearWorkspaceInterpreter = 'python.clearWorkspaceInterpreter';
7171
export const ResetInterpreterSecurityStorage = 'python.resetInterpreterSecurityStorage';
7272
export const OpenStartPage = 'python.startPage.open';
73+
export const LaunchTensorBoard = 'python.launchTensorBoard';
7374
}
7475
export namespace Octicons {
7576
export const Test_Pass = '$(check)';

src/client/common/experiments/groups.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,11 @@ export enum SendSelectionToREPL {
8383
experiment = 'pythonSendEntireLineToREPL'
8484
}
8585

86+
// Feature flag for 'Python: Launch TensorBoard' feature
87+
export enum NativeTensorBoard {
88+
experiment = 'nativeTensorBoard'
89+
}
90+
8691
// Experiment to show a prompt asking users to install or select linter
8792
export enum LinterInstallationPromptVariants {
8893
pylintFirst = 'pythonInstallPylintButtonFirst',

src/client/common/installer/productInstaller.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -679,6 +679,8 @@ function translateProductToModule(product: Product, purpose: ModuleNamePurpose):
679679
return 'nbconvert';
680680
case Product.kernelspec:
681681
return 'kernelspec';
682+
case Product.tensorboard:
683+
return 'tensorboard';
682684
default: {
683685
throw new Error(`Product ${product} cannot be installed as a Python Module.`);
684686
}

src/client/common/installer/productNames.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ ProductNames.set(Product.pylint, 'pylint');
1919
ProductNames.set(Product.pytest, 'pytest');
2020
ProductNames.set(Product.yapf, 'yapf');
2121
ProductNames.set(Product.rope, 'rope');
22+
ProductNames.set(Product.tensorboard, 'tensorboard');

src/client/common/installer/productService.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ export class ProductService implements IProductService {
3434
this.ProductTypes.set(Product.nbconvert, ProductType.DataScience);
3535
this.ProductTypes.set(Product.kernelspec, ProductType.DataScience);
3636
this.ProductTypes.set(Product.pandas, ProductType.DataScience);
37+
this.ProductTypes.set(Product.tensorboard, ProductType.DataScience);
3738
}
3839
public getProductType(product: Product): ProductType {
3940
return this.ProductTypes.get(product)!;

src/client/common/process/internal/scripts/index.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,3 +347,11 @@ export function visualstudio_py_testlauncher(testArgs: string[]): string[] {
347347
// There is no output to parse, so we do not return a function.
348348
return [script, ...testArgs];
349349
}
350+
351+
//============================
352+
// tensorboard_launcher.py
353+
354+
export function tensorboardLauncher(args: string[]) {
355+
const script = path.join(SCRIPTS_DIR, 'tensorboard_launcher.py');
356+
return [ISOLATED, script, ...args];
357+
}

src/client/common/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,8 @@ export enum Product {
104104
notebook = 20,
105105
kernelspec = 21,
106106
nbconvert = 22,
107-
pandas = 23
107+
pandas = 23,
108+
tensorboard = 24
108109
}
109110

110111
export enum ModuleNamePurpose {

src/client/common/utils/localize.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,6 +133,27 @@ export namespace Jupyter {
133133
);
134134
}
135135

136+
export namespace TensorBoard {
137+
export const logDirectoryPrompt = localize(
138+
'TensorBoard.logDirectoryPrompt',
139+
'Please select a log directory to start TensorBoard with.'
140+
);
141+
export const progressMessage = localize('TensorBoard.progressMessage', 'Starting TensorBoard session...');
142+
export const installTensorBoardPrompt = localize(
143+
'TensorBoard.installPrompt',
144+
'The package TensorBoard is required in order to launch a TensorBoard session. Would you like to install it?'
145+
);
146+
export const failedToStartSessionError = localize(
147+
'TensorBoard.failedToStartSessionError',
148+
'We failed to start a TensorBoard session due to the following error: {0}'
149+
);
150+
export const usingCurrentWorkspaceFolder = localize(
151+
'TensorBoard.usingCurrentWorkspaceFolder',
152+
'We are using the current workspace folder as the log directory for your TensorBoard session.'
153+
);
154+
export const selectAFolder = localize('TensorBoard.selectAFolder', 'Select a folder');
155+
}
156+
136157
export namespace LanguageService {
137158
export const startingJedi = localize('LanguageService.startingJedi', 'Starting Jedi Python language engine.');
138159
export const startingMicrosoft = localize(

src/client/extensionActivation.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ import { activateSimplePythonRefactorProvider } from './providers/simpleRefactor
5757
import { TerminalProvider } from './providers/terminalProvider';
5858
import { ISortImportsEditingProvider } from './providers/types';
5959
import { setExtensionInstallTelemetryProperties } from './telemetry/extensionInstallTelemetry';
60+
import { registerTypes as tensorBoardRegisterTypes } from './tensorBoard/serviceRegistry';
6061
import { registerTypes as commonRegisterTerminalTypes } from './terminals/serviceRegistry';
6162
import { ICodeExecutionManager, ITerminalAutoActivation } from './terminals/types';
6263
import { TEST_OUTPUT_CHANNEL } from './testing/common/constants';
@@ -117,6 +118,7 @@ async function activateLegacy(
117118
installerRegisterTypes(serviceManager);
118119
commonRegisterTerminalTypes(serviceManager);
119120
debugConfigurationRegisterTypes(serviceManager);
121+
tensorBoardRegisterTypes(serviceManager);
120122

121123
const configuration = serviceManager.get<IConfigurationService>(IConfigurationService);
122124
// We should start logging using the log level as soon as possible, so set it as soon as we can access the level.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
// Copyright (c) Microsoft Corporation. All rights reserved.
2+
// Licensed under the MIT License.
3+
4+
import { IExtensionSingleActivationService } from '../activation/types';
5+
import { IServiceManager } from '../ioc/types';
6+
import { TensorBoardSessionProvider } from './tensorBoardSessionProvider';
7+
8+
export function registerTypes(serviceManager: IServiceManager) {
9+
serviceManager.addSingleton<IExtensionSingleActivationService>(
10+
IExtensionSingleActivationService,
11+
TensorBoardSessionProvider
12+
);
13+
}

0 commit comments

Comments
 (0)