From bc4b853eb0ab4dd6b369b0f1ca5c31f2facc0f22 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Mon, 14 Jun 2021 22:49:28 -0700 Subject: [PATCH 1/3] Recommend >= 0.2.0 of `torch-tb-profiler` (#16440) * Recommend >= 0.2.0 of torch-tb-profiler * Update CHANGELOG.md and delete news --- CHANGELOG.md | 83 +++++++++++++++++++ src/client/common/utils/localize.ts | 4 +- src/client/tensorBoard/tensorBoardSession.ts | 36 +++++--- .../tensorBoard/tensorBoardSession.test.ts | 69 ++++++++++----- 4 files changed, 155 insertions(+), 37 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2be3d4bc127..3975b48ee664 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,88 @@ # Changelog +## 2021.6.0-rc (9 June 2021) + +### Enhancements + +1. Improved telemetry around the availability of `pip` for installation of Jupyter dependencies. + ([#15937](https://github.com/Microsoft/vscode-python/issues/15937)) +1. Move the Jupyter extension from being a hard dependency to an optional one, and display an informational prompt if Jupyter commands try to be executed from the Start Page. + ([#16102](https://github.com/Microsoft/vscode-python/issues/16102)) +1. Add an `enumDescriptions` key under the `python.languageServer` setting to describe all language server options. + ([#16141](https://github.com/Microsoft/vscode-python/issues/16141)) +1. Ensure users upgrade to v0.2.0 of the torch-tb-profiler TensorBoard plugin to access jump-to-source functionality. + ([#16330](https://github.com/Microsoft/vscode-python/issues/16339)) + +### Fixes +1. Fixes a bug in the bandit linter where messages weren't being propagated to the editor. + (thanks [Anthony Shaw](https://github.com/tonybaloney)) + ([#15561](https://github.com/Microsoft/vscode-python/issues/15561)) +1. Workaround existing MIME type misconfiguration on Windows preventing TensorBoard from loading when starting TensorBoard. + ([#16072](https://github.com/Microsoft/vscode-python/issues/16072)) +1. Changed the version of npm to version 6 instead of 7 in the lockfile. + ([#16208](https://github.com/Microsoft/vscode-python/issues/16208)) +1. Ensure selected interpreter doesn't change when the extension is starting up and in experiment. + ([#16291](https://github.com/Microsoft/vscode-python/issues/16291)) +1. Fix issue with sys.prefix when getting environment details. + ([#16355](https://github.com/Microsoft/vscode-python/issues/16355)) +1. Activate the extension when selecting the command `Clear Internal Extension Cache (python.clearPersistentStorage)`. + ([#16397](https://github.com/Microsoft/vscode-python/issues/16397)) + +### Thanks + +Thanks to the following projects which we fully rely on to provide some of +our features: + +- [debugpy](https://pypi.org/project/debugpy/) +- [isort](https://pypi.org/project/isort/) +- [jedi](https://pypi.org/project/jedi/) + and [parso](https://pypi.org/project/parso/) +- [jedi-language-server](https://pypi.org/project/jedi-language-server/) +- [Microsoft Python Language Server](https://github.com/microsoft/python-language-server) +- [Pylance](https://github.com/microsoft/pylance-release) +- [exuberant ctags](http://ctags.sourceforge.net/) (user-installed) +- [rope](https://pypi.org/project/rope/) (user-installed) + +Also thanks to the various projects we provide integrations with which help +make this extension useful: + +- Debugging support: + [Django](https://pypi.org/project/Django/), + [Flask](https://pypi.org/project/Flask/), + [gevent](https://pypi.org/project/gevent/), + [Jinja](https://pypi.org/project/Jinja/), + [Pyramid](https://pypi.org/project/pyramid/), + [PySpark](https://pypi.org/project/pyspark/), + [Scrapy](https://pypi.org/project/Scrapy/), + [Watson](https://pypi.org/project/Watson/) +- Formatting: + [autopep8](https://pypi.org/project/autopep8/), + [black](https://pypi.org/project/black/), + [yapf](https://pypi.org/project/yapf/) +- Interpreter support: + [conda](https://conda.io/), + [direnv](https://direnv.net/), + [pipenv](https://pypi.org/project/pipenv/), + [pyenv](https://github.com/pyenv/pyenv), + [venv](https://docs.python.org/3/library/venv.html#module-venv), + [virtualenv](https://pypi.org/project/virtualenv/) +- Linting: + [bandit](https://pypi.org/project/bandit/), + [flake8](https://pypi.org/project/flake8/), + [mypy](https://pypi.org/project/mypy/), + [prospector](https://pypi.org/project/prospector/), + [pylint](https://pypi.org/project/pylint/), + [pydocstyle](https://pypi.org/project/pydocstyle/), + [pylama](https://pypi.org/project/pylama/) +- Testing: + [nose](https://pypi.org/project/nose/), + [pytest](https://pypi.org/project/pytest/), + [unittest](https://docs.python.org/3/library/unittest.html#module-unittest) + +And finally thanks to the [Python](https://www.python.org/) development team and +community for creating a fantastic programming language and community to be a +part of! + ## 2021.5.2 (14 May 2021) ### Fixes diff --git a/src/client/common/utils/localize.ts b/src/client/common/utils/localize.ts index d266f9805eef..d4d4d8004256 100644 --- a/src/client/common/utils/localize.ts +++ b/src/client/common/utils/localize.ts @@ -182,11 +182,11 @@ export namespace TensorBoard { ); export const installTensorBoardAndProfilerPluginPrompt = localize( 'TensorBoard.installTensorBoardAndProfilerPluginPrompt', - 'TensorBoard >= 2.4.1 and the PyTorch Profiler TensorBoard plugin are required. Would you like to install these packages?', + 'TensorBoard >= 2.4.1 and the PyTorch Profiler TensorBoard plugin >= 0.2.0 are required. Would you like to install these packages?', ); export const installProfilerPluginPrompt = localize( 'TensorBoard.installProfilerPluginPrompt', - 'We recommend installing the PyTorch Profiler TensorBoard plugin. Would you like to install the package?', + 'We recommend installing version >= 0.2.0 of the PyTorch Profiler TensorBoard plugin. Would you like to install the package?', ); export const upgradePrompt = localize( 'TensorBoard.upgradePrompt', diff --git a/src/client/tensorBoard/tensorBoardSession.ts b/src/client/tensorBoard/tensorBoardSession.ts index 8a9598f67f75..2fb59e63c564 100644 --- a/src/client/tensorBoard/tensorBoardSession.ts +++ b/src/client/tensorBoard/tensorBoardSession.ts @@ -143,7 +143,7 @@ export class TensorBoardSession { private async promptToInstall( tensorBoardInstallStatus: ProductInstallStatus, - shouldInstallProfilerPlugin: boolean, + profilerPluginInstallStatus: ProductInstallStatus, ) { sendTelemetryEvent(EventName.TENSORBOARD_INSTALL_PROMPT_SHOWN); const yes = Common.bannerLabelYes(); @@ -151,10 +151,13 @@ export class TensorBoardSession { const isUpgrade = tensorBoardInstallStatus === ProductInstallStatus.NeedsUpgrade; let message; - if (tensorBoardInstallStatus === ProductInstallStatus.Installed && shouldInstallProfilerPlugin) { + if ( + tensorBoardInstallStatus === ProductInstallStatus.Installed && + profilerPluginInstallStatus !== ProductInstallStatus.Installed + ) { // PyTorch user already has TensorBoard, just ask if they want the profiler plugin message = TensorBoard.installProfilerPluginPrompt(); - } else if (shouldInstallProfilerPlugin) { + } else if (profilerPluginInstallStatus !== ProductInstallStatus.Installed) { // PyTorch user doesn't have compatible TensorBoard or the profiler plugin message = TensorBoard.installTensorBoardAndProfilerPluginPrompt(); } else if (isUpgrade) { @@ -194,14 +197,14 @@ export class TensorBoardSession { // First see what dependencies we're missing let [tensorboardInstallStatus, profilerPluginInstallStatus] = await Promise.all([ this.installer.isProductVersionCompatible(Product.tensorboard, '>= 2.4.1', interpreter), - this.installer.isInstalled(Product.torchProfilerImportName, interpreter), + this.installer.isProductVersionCompatible(Product.torchProfilerImportName, '>= 0.2.0', interpreter), ]); const isTorchUserAndInExperiment = ImportTracker.hasModuleImport('torch') && this.isInTorchProfilerExperiment; const needsTensorBoardInstall = tensorboardInstallStatus !== ProductInstallStatus.Installed; - const needsProfilerPluginInstall = isTorchUserAndInExperiment && profilerPluginInstallStatus !== true; + const needsProfilerPluginInstall = profilerPluginInstallStatus !== ProductInstallStatus.Installed; if ( // PyTorch user, in profiler install experiment, TensorBoard and profiler plugin already installed - (isTorchUserAndInExperiment && !needsTensorBoardInstall && profilerPluginInstallStatus === true) || + (isTorchUserAndInExperiment && !needsTensorBoardInstall && !needsProfilerPluginInstall) || // Not PyTorch user or not in profiler install experiment, so no need for profiler plugin, // and TensorBoard is already installed (!isTorchUserAndInExperiment && tensorboardInstallStatus === ProductInstallStatus.Installed) @@ -212,7 +215,7 @@ export class TensorBoardSession { // Ask the user if they want to install packages to start a TensorBoard session const selection = await this.promptToInstall( tensorboardInstallStatus, - isTorchUserAndInExperiment && !profilerPluginInstallStatus, + isTorchUserAndInExperiment ? profilerPluginInstallStatus : ProductInstallStatus.Installed, ); if (selection !== Common.bannerLabelYes() && !needsTensorBoardInstall) { return true; @@ -243,26 +246,35 @@ export class TensorBoardSession { ), ); } - if (needsProfilerPluginInstall) { - installPromises.push(this.installer.install(Product.torchProfilerInstallName, interpreter, installerToken)); + if (isTorchUserAndInExperiment && needsProfilerPluginInstall) { + installPromises.push( + this.installer.install( + Product.torchProfilerInstallName, + interpreter, + installerToken, + profilerPluginInstallStatus === ProductInstallStatus.NeedsUpgrade + ? ModuleInstallFlags.upgrade + : undefined, + ), + ); } await Promise.race([...installPromises, cancellationPromise]); // Check install status again after installing [tensorboardInstallStatus, profilerPluginInstallStatus] = await Promise.all([ this.installer.isProductVersionCompatible(Product.tensorboard, '>= 2.4.1', interpreter), - this.installer.isInstalled(Product.torchProfilerImportName, interpreter), + this.installer.isProductVersionCompatible(Product.torchProfilerImportName, '>= 0.2.0', interpreter), ]); // Send telemetry regarding results of install sendTelemetryEvent(EventName.TENSORBOARD_PACKAGE_INSTALL_RESULT, undefined, { wasTensorBoardAttempted: needsTensorBoardInstall, wasProfilerPluginAttempted: needsProfilerPluginInstall, wasTensorBoardInstalled: tensorboardInstallStatus === ProductInstallStatus.Installed, - wasProfilerPluginInstalled: profilerPluginInstallStatus, + wasProfilerPluginInstalled: profilerPluginInstallStatus === ProductInstallStatus.Installed, }); // Profiler plugin is not required to start TensorBoard. If it failed, note that it failed // in the log, but report success only based on TensorBoard package install status. - if (isTorchUserAndInExperiment && profilerPluginInstallStatus === false) { + if (isTorchUserAndInExperiment && profilerPluginInstallStatus !== ProductInstallStatus.Installed) { traceError(`Failed to install torch-tb-plugin. Profiler plugin will not appear in TensorBoard session.`); } return tensorboardInstallStatus === ProductInstallStatus.Installed; diff --git a/src/test/tensorBoard/tensorBoardSession.test.ts b/src/test/tensorBoard/tensorBoardSession.test.ts index 3926b04021c1..e1842f0c1e7f 100644 --- a/src/test/tensorBoard/tensorBoardSession.test.ts +++ b/src/test/tensorBoard/tensorBoardSession.test.ts @@ -43,6 +43,12 @@ const info: PythonEnvironment = { sysVersion: '', }; +const interpreter: PythonEnvironment = { + ...info, + envType: EnvironmentType.Unknown, + path: PYTHON_PATH, +}; + suite('TensorBoard session creation', async () => { let serviceManager: IServiceManager; let errorMessageStub: Sinon.SinonStub; @@ -67,12 +73,6 @@ suite('TensorBoard session creation', async () => { sandbox.stub(ExperimentHelpers, 'inDiscoveryExperiment').resolves(false); experimentService = serviceManager.get(IExperimentService); - // Ensure we use CI Python - const interpreter: PythonEnvironment = { - ...info, - envType: EnvironmentType.Unknown, - path: PYTHON_PATH, - }; const interpreterService = serviceManager.get(IInterpreterService); sandbox.stub(interpreterService, 'getActiveInterpreter').resolves(interpreter); @@ -94,7 +94,7 @@ suite('TensorBoard session creation', async () => { isInTorchProfilerExperiment: boolean, hasTorchImports: boolean, tensorBoardInstallStatus: ProductInstallStatus, - isTorchProfilerPackageInstalled: boolean, + torchProfilerPackageInstallStatus: ProductInstallStatus, installPromptSelection: 'Yes' | 'No', ) { sandbox @@ -102,8 +102,13 @@ suite('TensorBoard session creation', async () => { .withArgs(TorchProfiler.experiment) .resolves(isInTorchProfilerExperiment); sandbox.stub(ImportTracker, 'hasModuleImport').withArgs('torch').returns(hasTorchImports); - sandbox.stub(installer, 'isProductVersionCompatible').resolves(tensorBoardInstallStatus); - sandbox.stub(installer, 'isInstalled').resolves(isTorchProfilerPackageInstalled); + const isProductVersionCompatible = sandbox.stub(installer, 'isProductVersionCompatible'); + isProductVersionCompatible + .withArgs(Product.tensorboard, '>= 2.4.1', interpreter) + .resolves(tensorBoardInstallStatus); + isProductVersionCompatible + .withArgs(Product.torchProfilerImportName, '>= 0.2.0', interpreter) + .resolves(torchProfilerPackageInstallStatus); errorMessageStub = sandbox.stub(applicationShell, 'showErrorMessage'); errorMessageStub.resolves(installPromptSelection); } @@ -170,7 +175,7 @@ suite('TensorBoard session creation', async () => { async function runTest(expectTensorBoardUpgrade: boolean) { const installStub = sandbox.stub(installer, 'install').resolves(InstallerResponse.Installed); await createSessionAndVerifyMessage(TensorBoard.installTensorBoardAndProfilerPluginPrompt()); - assert.ok(installStub.calledTwice, 'Did not install anything'); + assert.ok(installStub.calledTwice, `Expected 2 installs but got ${installStub.callCount} calls`); assert.ok(installStub.calledWith(Product.torchProfilerInstallName)); assert.ok( installStub.calledWith( @@ -182,17 +187,17 @@ suite('TensorBoard session creation', async () => { ); } test('In experiment: true, has torch imports: true, is profiler package installed: false, TensorBoard needs upgrade', async () => { - configureStubs(true, true, ProductInstallStatus.NeedsUpgrade, false, 'Yes'); + configureStubs(true, true, ProductInstallStatus.NeedsUpgrade, ProductInstallStatus.NotInstalled, 'Yes'); await runTest(true); }); test('In experiment: true, has torch imports: true, is profiler package installed: false, TensorBoard not installed', async () => { - configureStubs(true, true, ProductInstallStatus.NotInstalled, false, 'Yes'); + configureStubs(true, true, ProductInstallStatus.NotInstalled, ProductInstallStatus.NotInstalled, 'Yes'); await runTest(false); }); }); suite('Install profiler only', async () => { test('In experiment: true, has torch imports: true, is profiler package installed: false, TensorBoard installed', async () => { - configureStubs(true, true, ProductInstallStatus.Installed, false, 'Yes'); + configureStubs(true, true, ProductInstallStatus.Installed, ProductInstallStatus.NotInstalled, 'Yes'); sandbox .stub(applicationShell, 'showQuickPick') .resolves({ label: TensorBoard.useCurrentWorkingDirectory() }); @@ -222,14 +227,20 @@ suite('TensorBoard session creation', async () => { suite('Install tensorboard only', async () => { [false, true].forEach(async (inExperiment) => { [false, true].forEach(async (hasTorchImports) => { - [false, true].forEach(async (isTorchProfilerPackageInstalled) => { + [ + ProductInstallStatus.Installed, + ProductInstallStatus.NotInstalled, + ProductInstallStatus.NeedsUpgrade, + ].forEach(async (torchProfilerInstallStatus) => { + const isTorchProfilerPackageInstalled = + torchProfilerInstallStatus === ProductInstallStatus.Installed; if (!(inExperiment && hasTorchImports && !isTorchProfilerPackageInstalled)) { test(`In experiment: ${inExperiment}, has torch imports: ${hasTorchImports}, is profiler package installed: ${isTorchProfilerPackageInstalled}, TensorBoard not installed`, async () => { configureStubs( inExperiment, hasTorchImports, ProductInstallStatus.NotInstalled, - isTorchProfilerPackageInstalled, + torchProfilerInstallStatus, 'No', ); await createSessionAndVerifyMessage(TensorBoard.installPrompt()); @@ -244,7 +255,7 @@ suite('TensorBoard session creation', async () => { const installStub = sandbox.stub(installer, 'install').resolves(InstallerResponse.Installed); await createSessionAndVerifyMessage(TensorBoard.upgradePrompt()); - assert.ok(installStub.calledOnce, 'Did not install anything'); + assert.ok(installStub.calledOnce, `Expected 1 install but got ${installStub.callCount} installs`); assert.ok(installStub.args[0][0] === Product.tensorboard, 'Did not install tensorboard'); assert.ok( installStub.args.filter((argsList) => argsList[0] === Product.torchProfilerInstallName).length === @@ -254,14 +265,20 @@ suite('TensorBoard session creation', async () => { } [false, true].forEach(async (inExperiment) => { [false, true].forEach(async (hasTorchImports) => { - [false, true].forEach(async (isTorchProfilerPackageInstalled) => { + [ + ProductInstallStatus.Installed, + ProductInstallStatus.NotInstalled, + ProductInstallStatus.NeedsUpgrade, + ].forEach(async (torchProfilerInstallStatus) => { + const isTorchProfilerPackageInstalled = + torchProfilerInstallStatus === ProductInstallStatus.Installed; if (!(inExperiment && hasTorchImports && !isTorchProfilerPackageInstalled)) { test(`In experiment: ${inExperiment}, has torch imports: ${hasTorchImports}, is profiler package installed: ${isTorchProfilerPackageInstalled}, TensorBoard needs upgrade`, async () => { configureStubs( inExperiment, hasTorchImports, ProductInstallStatus.NeedsUpgrade, - isTorchProfilerPackageInstalled, + torchProfilerInstallStatus, 'Yes', ); await runTest(); @@ -285,14 +302,20 @@ suite('TensorBoard session creation', async () => { } [false, true].forEach(async (inExperiment) => { [false, true].forEach(async (hasTorchImports) => { - [false, true].forEach(async (isTorchProfilerPackageInstalled) => { + [ + ProductInstallStatus.Installed, + ProductInstallStatus.NotInstalled, + ProductInstallStatus.NeedsUpgrade, + ].forEach(async (torchProfilerInstallStatus) => { + const isTorchProfilerPackageInstalled = + torchProfilerInstallStatus === ProductInstallStatus.Installed; if (!(inExperiment && hasTorchImports && !isTorchProfilerPackageInstalled)) { test(`In experiment: ${inExperiment}, has torch imports: ${hasTorchImports}, is profiler package installed: ${isTorchProfilerPackageInstalled}, TensorBoard installed`, async () => { configureStubs( inExperiment, hasTorchImports, ProductInstallStatus.Installed, - isTorchProfilerPackageInstalled, + torchProfilerInstallStatus, 'Yes', ); await runTest(); @@ -335,7 +358,7 @@ suite('TensorBoard session creation', async () => { assert.ok(quickPickStub.notCalled, 'User opted not to upgrade and we proceeded to create session'); }); test('If TensorBoard is not installed and user chooses not to install, do not show error', async () => { - configureStubs(true, true, ProductInstallStatus.NotInstalled, false, 'Yes'); + configureStubs(true, true, ProductInstallStatus.NotInstalled, ProductInstallStatus.NotInstalled, 'Yes'); sandbox.stub(installer, 'install').resolves(InstallerResponse.Ignore); await commandManager.executeCommand( @@ -385,7 +408,7 @@ suite('TensorBoard session creation', async () => { assert.ok(errorMessageStub.called, 'TensorBoard timed out but no error was shown'); }); test('If installing the profiler package fails, do not show error, continue to create session', async () => { - configureStubs(true, true, ProductInstallStatus.Installed, false, 'Yes'); + configureStubs(true, true, ProductInstallStatus.Installed, ProductInstallStatus.NotInstalled, 'Yes'); sandbox .stub(applicationShell, 'showQuickPick') .resolves({ label: TensorBoard.useCurrentWorkingDirectory() }); @@ -404,7 +427,7 @@ suite('TensorBoard session creation', async () => { assert.ok(session.panel?.visible, 'Webview panel not shown, expected successful session creation'); }); test('If user opts not to install profiler package and tensorboard is already installed, continue to create session', async () => { - configureStubs(true, true, ProductInstallStatus.Installed, false, 'No'); + configureStubs(true, true, ProductInstallStatus.Installed, ProductInstallStatus.NotInstalled, 'No'); sandbox .stub(applicationShell, 'showQuickPick') .resolves({ label: TensorBoard.useCurrentWorkingDirectory() }); From ce0a1b4630f7cc195b8d509f50c9233d1e9b7587 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 16 Jun 2021 13:16:49 -0700 Subject: [PATCH 2/3] Extract semver requirements into constants --- src/client/tensorBoard/tensorBoardSession.ts | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/client/tensorBoard/tensorBoardSession.ts b/src/client/tensorBoard/tensorBoardSession.ts index 2fb59e63c564..6f66343be2f2 100644 --- a/src/client/tensorBoard/tensorBoardSession.ts +++ b/src/client/tensorBoard/tensorBoardSession.ts @@ -50,6 +50,8 @@ import { ModuleInstallFlags } from '../common/installer/types'; enum Messages { JumpToSource = 'jump_to_source', } +const TensorBoardSemVerRequirement = '>= 2.4.1'; +const TorchProfilerSemVerRequirement = '>= 0.2.0'; /** * Manages the lifecycle of a TensorBoard session. @@ -196,8 +198,12 @@ export class TensorBoardSession { // First see what dependencies we're missing let [tensorboardInstallStatus, profilerPluginInstallStatus] = await Promise.all([ - this.installer.isProductVersionCompatible(Product.tensorboard, '>= 2.4.1', interpreter), - this.installer.isProductVersionCompatible(Product.torchProfilerImportName, '>= 0.2.0', interpreter), + this.installer.isProductVersionCompatible(Product.tensorboard, TensorBoardSemVerRequirement, interpreter), + this.installer.isProductVersionCompatible( + Product.torchProfilerImportName, + TorchProfilerSemVerRequirement, + interpreter, + ), ]); const isTorchUserAndInExperiment = ImportTracker.hasModuleImport('torch') && this.isInTorchProfilerExperiment; const needsTensorBoardInstall = tensorboardInstallStatus !== ProductInstallStatus.Installed; @@ -262,8 +268,12 @@ export class TensorBoardSession { // Check install status again after installing [tensorboardInstallStatus, profilerPluginInstallStatus] = await Promise.all([ - this.installer.isProductVersionCompatible(Product.tensorboard, '>= 2.4.1', interpreter), - this.installer.isProductVersionCompatible(Product.torchProfilerImportName, '>= 0.2.0', interpreter), + this.installer.isProductVersionCompatible(Product.tensorboard, TensorBoardSemVerRequirement, interpreter), + this.installer.isProductVersionCompatible( + Product.torchProfilerImportName, + TorchProfilerSemVerRequirement, + interpreter, + ), ]); // Send telemetry regarding results of install sendTelemetryEvent(EventName.TENSORBOARD_PACKAGE_INSTALL_RESULT, undefined, { From a8a80bfaeaf580aae11f247a73d7f8e1b1df4fd5 Mon Sep 17 00:00:00 2001 From: Joyce Er Date: Wed, 16 Jun 2021 14:15:45 -0700 Subject: [PATCH 3/3] Update CHANGELOG.md Co-authored-by: Kim-Adeline Miguel <51720070+kimadeline@users.noreply.github.com> --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3975b48ee664..43905ff343f4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,7 +11,7 @@ 1. Add an `enumDescriptions` key under the `python.languageServer` setting to describe all language server options. ([#16141](https://github.com/Microsoft/vscode-python/issues/16141)) 1. Ensure users upgrade to v0.2.0 of the torch-tb-profiler TensorBoard plugin to access jump-to-source functionality. - ([#16330](https://github.com/Microsoft/vscode-python/issues/16339)) + ([#16330](https://github.com/Microsoft/vscode-python/issues/16330)) ### Fixes 1. Fixes a bug in the bandit linter where messages weren't being propagated to the editor.