From e5ebde62c25da6b9e00361775ec5a0d83f780ec0 Mon Sep 17 00:00:00 2001 From: Anthony Kim <62267334+anthonykim1@users.noreply.github.com> Date: Mon, 14 Jul 2025 11:52:26 -0700 Subject: [PATCH 1/3] Return early in activate from env var collection (#25286) Resolves: https://github.com/microsoft/vscode-python/issues/25275 https://github.com/microsoft/vscode-python/issues/25284 It seems like python env var experiment is interfering when env extension is being used. We should not implicit activate with env var experiment if environment extension is installed and being used. --------- Co-authored-by: Eleanor Boyd <26030610+eleanorjboyd@users.noreply.github.com> --- src/client/terminals/envCollectionActivation/service.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/client/terminals/envCollectionActivation/service.ts b/src/client/terminals/envCollectionActivation/service.ts index bd2ce1c6f717..2ce8d5d5d86a 100644 --- a/src/client/terminals/envCollectionActivation/service.ts +++ b/src/client/terminals/envCollectionActivation/service.ts @@ -97,6 +97,14 @@ export class TerminalEnvVarCollectionService implements IExtensionActivationServ public async activate(resource: Resource): Promise { try { + if (useEnvExtension()) { + traceVerbose('Ignoring environment variable experiment since env extension is being used'); + this.context.environmentVariableCollection.clear(); + // Needed for shell integration + await registerPythonStartup(this.context); + return; + } + if (!inTerminalEnvVarExperiment(this.experimentService)) { this.context.environmentVariableCollection.clear(); await this.handleMicroVenv(resource); From 9fe753a7486d7271ecbc64a58446ed7a2e5f1376 Mon Sep 17 00:00:00 2001 From: Anthony Kim <62267334+anthonykim1@users.noreply.github.com> Date: Thu, 17 Jul 2025 16:07:43 -0700 Subject: [PATCH 2/3] Resolve REPL regression on indentation, disable PyREPL only when shell integration is enabled (#25296) Resolves: https://github.com/microsoft/vscode-python/issues/25295 https://github.com/microsoft/vscode-python/issues/25240 https://github.com/microsoft/vscode-python/issues/25242 --- package.nls.json | 2 +- python_files/pythonrc.py | 3 +-- src/client/common/configSettings.ts | 4 +++- src/client/common/types.ts | 4 +++- src/client/extensionActivation.ts | 3 +-- src/client/terminals/codeExecution/helper.ts | 12 ++++++++++++ src/client/terminals/pythonStartup.ts | 8 +++----- .../terminals/shellIntegration/pythonStartup.test.ts | 7 ++++--- 8 files changed, 28 insertions(+), 15 deletions(-) diff --git a/package.nls.json b/package.nls.json index 00c96c09b19a..b2fdd1b7c36e 100644 --- a/package.nls.json +++ b/package.nls.json @@ -72,7 +72,7 @@ "python.tensorBoard.logDirectory.description": "Set this setting to your preferred TensorBoard log directory to skip log directory prompt when starting TensorBoard.", "python.tensorBoard.logDirectory.markdownDeprecationMessage": "Tensorboard support has been moved to the extension [Tensorboard extension](https://marketplace.visualstudio.com/items?itemName=ms-toolsai.tensorboard). Instead use the setting `tensorBoard.logDirectory`.", "python.tensorBoard.logDirectory.deprecationMessage": "Tensorboard support has been moved to the extension Tensorboard extension. Instead use the setting `tensorBoard.logDirectory`.", - "python.terminal.shellIntegration.enabled.description": "Enable [shell integration](https://code.visualstudio.com/docs/terminal/shell-integration) for the terminals running python. Shell integration enhances the terminal experience by enabling command decorations, run recent command, improving accessibility among other things.", + "python.terminal.shellIntegration.enabled.description": "Enable [shell integration](https://code.visualstudio.com/docs/terminal/shell-integration) for the terminals running python. Shell integration enhances the terminal experience by enabling command decorations, run recent command, improving accessibility among other things. Note: PyREPL (available in Python 3.13+) is automatically disabled when shell integration is enabled to avoid cursor indentation issues.", "python.terminal.activateEnvInCurrentTerminal.description": "Activate Python Environment in the current Terminal on load of the Extension.", "python.terminal.activateEnvironment.description": "Activate Python Environment in all Terminals created.", "python.terminal.executeInFileDir.description": "When executing a file in the terminal, whether to use execute in the file's directory, instead of the current open folder.", diff --git a/python_files/pythonrc.py b/python_files/pythonrc.py index afd32520cf01..005b06bcdd15 100644 --- a/python_files/pythonrc.py +++ b/python_files/pythonrc.py @@ -5,7 +5,6 @@ import readline original_ps1 = ">>> " -use_shell_integration = sys.version_info < (3, 13) is_wsl = "microsoft-standard-WSL" in platform.release() @@ -75,7 +74,7 @@ def __str__(self): return result -if sys.platform != "win32" and (not is_wsl) and use_shell_integration: +if sys.platform != "win32" and (not is_wsl): sys.ps1 = PS1() if sys.platform == "darwin": diff --git a/src/client/common/configSettings.ts b/src/client/common/configSettings.ts index 634e0106fe7b..91c06d9331fd 100644 --- a/src/client/common/configSettings.ts +++ b/src/client/common/configSettings.ts @@ -377,7 +377,9 @@ export class PythonSettings implements IPythonSettings { launchArgs: [], activateEnvironment: true, activateEnvInCurrentTerminal: false, - enableShellIntegration: false, + shellIntegration: { + enabled: false, + }, }; this.REPL = pythonSettings.get('REPL')!; diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 2cb393d89bdf..c30ad704b6c1 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -188,7 +188,9 @@ export interface ITerminalSettings { readonly launchArgs: string[]; readonly activateEnvironment: boolean; readonly activateEnvInCurrentTerminal: boolean; - readonly enableShellIntegration: boolean; + readonly shellIntegration: { + enabled: boolean; + }; } export interface IREPLSettings { diff --git a/src/client/extensionActivation.ts b/src/client/extensionActivation.ts index 8fae9d5131ff..8330d5010f7a 100644 --- a/src/client/extensionActivation.ts +++ b/src/client/extensionActivation.ts @@ -53,7 +53,7 @@ import { DebuggerTypeName } from './debugger/constants'; import { StopWatch } from './common/utils/stopWatch'; import { registerReplCommands, registerReplExecuteOnEnter, registerStartNativeReplCommand } from './repl/replCommands'; import { registerTriggerForTerminalREPL } from './terminals/codeExecution/terminalReplWatcher'; -import { registerBasicRepl, registerPythonStartup } from './terminals/pythonStartup'; +import { registerPythonStartup } from './terminals/pythonStartup'; import { registerPixiFeatures } from './pythonEnvironments/common/environmentManagers/pixi'; import { registerCustomTerminalLinkProvider } from './terminals/pythonStartupLinkProvider'; import { registerEnvExtFeatures } from './envExt/api.internal'; @@ -184,7 +184,6 @@ async function activateLegacy(ext: ExtensionState, startupStopWatch: StopWatch): serviceManager.get(ITerminalAutoActivation).register(); await registerPythonStartup(ext.context); - await registerBasicRepl(ext.context); serviceManager.get(ICodeExecutionManager).registerCommands(); diff --git a/src/client/terminals/codeExecution/helper.ts b/src/client/terminals/codeExecution/helper.ts index 26ebe35aae43..4efad5ee174e 100644 --- a/src/client/terminals/codeExecution/helper.ts +++ b/src/client/terminals/codeExecution/helper.ts @@ -99,10 +99,12 @@ export class CodeExecutionHelper implements ICodeExecutionHelper { const endLineVal = activeEditor?.selection?.end.line ?? 0; const emptyHighlightVal = activeEditor?.selection?.isEmpty ?? true; let smartSendSettingsEnabledVal = true; + let shellIntegrationEnabled = false; const configuration = this.serviceContainer.get(IConfigurationService); if (configuration) { const pythonSettings = configuration.getSettings(this.activeResourceService.getActiveResource()); smartSendSettingsEnabledVal = pythonSettings.REPL.enableREPLSmartSend; + shellIntegrationEnabled = pythonSettings.terminal.shellIntegration.enabled; } const input = JSON.stringify({ @@ -125,6 +127,16 @@ export class CodeExecutionHelper implements ICodeExecutionHelper { await this.moveToNextBlock(lineOffset, activeEditor); } + // For new _pyrepl for Python3.13+ && !shellIntegration, we need to send code via bracketed paste mode. + if (object.attach_bracket_paste && !shellIntegrationEnabled && _replType === ReplType.terminal) { + let trimmedNormalized = object.normalized.replace(/\n$/, ''); + if (trimmedNormalized.endsWith(':\n')) { + // In case where statement is unfinished via :, truncate so auto-indentation lands nicely. + trimmedNormalized = trimmedNormalized.replace(/\n$/, ''); + } + return `\u001b[200~${trimmedNormalized}\u001b[201~`; + } + return parse(object.normalized); } catch (ex) { traceError(ex, 'Python: Failed to normalize code for execution in terminal'); diff --git a/src/client/terminals/pythonStartup.ts b/src/client/terminals/pythonStartup.ts index 1a2576dce772..f0c3bf89c3b4 100644 --- a/src/client/terminals/pythonStartup.ts +++ b/src/client/terminals/pythonStartup.ts @@ -21,8 +21,11 @@ async function applyPythonStartupSetting(context: ExtensionContext): Promise { - // TODO: Configurable by setting - context.environmentVariableCollection.replace('PYTHON_BASIC_REPL', '1'); -} diff --git a/src/test/terminals/shellIntegration/pythonStartup.test.ts b/src/test/terminals/shellIntegration/pythonStartup.test.ts index 3c755adf0d9b..833a4f29e972 100644 --- a/src/test/terminals/shellIntegration/pythonStartup.test.ts +++ b/src/test/terminals/shellIntegration/pythonStartup.test.ts @@ -16,7 +16,7 @@ import { } from 'vscode'; import { assert } from 'chai'; import * as workspaceApis from '../../../client/common/vscodeApis/workspaceApis'; -import { registerBasicRepl, registerPythonStartup } from '../../../client/terminals/pythonStartup'; +import { registerPythonStartup } from '../../../client/terminals/pythonStartup'; import { IExtensionContext } from '../../../client/common/types'; import * as pythonStartupLinkProvider from '../../../client/terminals/pythonStartupLinkProvider'; import { CustomTerminalLinkProvider } from '../../../client/terminals/pythonStartupLinkProvider'; @@ -135,8 +135,9 @@ suite('Terminal - Shell Integration with PYTHONSTARTUP', () => { globalEnvironmentVariableCollection.verify((c) => c.delete('PYTHONSTARTUP'), TypeMoq.Times.once()); }); - test('PYTHON_BASIC_REPL is set when registerBasicRepl is called', async () => { - await registerBasicRepl(context.object); + test('PYTHON_BASIC_REPL is set when shell integration is enabled', async () => { + pythonConfig.setup((p) => p.get('terminal.shellIntegration.enabled')).returns(() => true); + await registerPythonStartup(context.object); globalEnvironmentVariableCollection.verify( (c) => c.replace('PYTHON_BASIC_REPL', '1', TypeMoq.It.isAny()), TypeMoq.Times.once(), From 205084f9ec25082d33eefd4c47af3de6d260c9db Mon Sep 17 00:00:00 2001 From: Eleanor Boyd <26030610+eleanorjboyd@users.noreply.github.com> Date: Mon, 21 Jul 2025 09:38:15 -0700 Subject: [PATCH 3/3] bundle envs ext with stable (#25309) reverts https://github.com/microsoft/vscode-python/commit/8c3a49fe6ec4aabef26f10feda9452aa259811bc which switched to only bundling with pre-release so now it is bundled for stable and pre-release --- .github/actions/build-vsix/action.yml | 9 +-------- build/azure-pipeline.pre-release.yml | 2 +- gulpfile.js | 19 ++++++------------- package.json | 1 - 4 files changed, 8 insertions(+), 23 deletions(-) diff --git a/.github/actions/build-vsix/action.yml b/.github/actions/build-vsix/action.yml index 1922f6196ee5..eaabe5141e8b 100644 --- a/.github/actions/build-vsix/action.yml +++ b/.github/actions/build-vsix/action.yml @@ -70,15 +70,8 @@ runs: shell: bash - name: Update optional extension dependencies - run: | - if [[ "${VSIX_NAME}" == *"insiders"* ]]; then - npm run addExtensionPackDependenciesPreRelease - else - npm run addExtensionPackDependencies - fi + run: npm run addExtensionPackDependencies shell: bash - env: - VSIX_NAME: ${{ inputs.vsix_name }} - name: Build Webpack run: | diff --git a/build/azure-pipeline.pre-release.yml b/build/azure-pipeline.pre-release.yml index 82c991189a82..ab087673f1e7 100644 --- a/build/azure-pipeline.pre-release.yml +++ b/build/azure-pipeline.pre-release.yml @@ -91,7 +91,7 @@ extends: - script: python ./build/update_package_file.py displayName: Update telemetry in package.json - - script: npm run addExtensionPackDependenciesPreRelease + - script: npm run addExtensionPackDependencies displayName: Update optional extension dependencies - script: npx gulp prePublishBundle diff --git a/gulpfile.js b/gulpfile.js index 3a03332c4f5c..0b919f16572a 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -93,23 +93,16 @@ gulp.task('addExtensionPackDependencies', async () => { await addExtensionPackDependencies(); }); -// This task adds 'ms-python.vscode-python-envs' as required deps only for pre-release builds. -gulp.task('addExtensionPackDependenciesPreRelease', async () => { - await buildLicense(); - await addExtensionPackDependencies(true); -}); - -async function addExtensionPackDependencies(isPreRelease = false) { +async function addExtensionPackDependencies() { // Update the package.json to add extension pack dependencies at build time so that // extension dependencies need not be installed during development const packageJsonContents = await fsExtra.readFile('package.json', 'utf-8'); const packageJson = JSON.parse(packageJsonContents); - let deps = ['ms-python.vscode-pylance', 'ms-python.debugpy']; - if (isPreRelease) { - deps.push('ms-python.vscode-python-envs'); - } - packageJson.extensionPack = deps.concat(packageJson.extensionPack ? packageJson.extensionPack : []); - + packageJson.extensionPack = [ + 'ms-python.vscode-pylance', + 'ms-python.debugpy', + 'ms-python.vscode-python-envs', + ].concat(packageJson.extensionPack ? packageJson.extensionPack : []); // Remove potential duplicates. packageJson.extensionPack = packageJson.extensionPack.filter( (item, index) => packageJson.extensionPack.indexOf(item) === index, diff --git a/package.json b/package.json index 4377dddd4e5b..9b09015993af 100644 --- a/package.json +++ b/package.json @@ -1671,7 +1671,6 @@ "format-fix": "prettier --write 'src/**/*.ts' 'build/**/*.js' '.github/**/*.yml' gulpfile.js", "clean": "gulp clean", "addExtensionPackDependencies": "gulp addExtensionPackDependencies", - "addExtensionPackDependenciesPreRelease": "gulp addExtensionPackDependenciesPreRelease", "updateBuildNumber": "gulp updateBuildNumber", "verifyBundle": "gulp verifyBundle", "webpack": "webpack"