From 1187591e79816bda4e0a07fb0e368801dcc97ef2 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Thu, 30 Jan 2025 10:42:52 -0800 Subject: [PATCH 01/15] use sendText for >=3.13 --- src/client/common/terminal/service.ts | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/src/client/common/terminal/service.ts b/src/client/common/terminal/service.ts index b02670836015..db80b3fe54de 100644 --- a/src/client/common/terminal/service.ts +++ b/src/client/common/terminal/service.ts @@ -25,6 +25,7 @@ import { useEnvExtension } from '../../envExt/api.internal'; import { ensureTerminalLegacy } from '../../envExt/api.legacy'; import { sleep } from '../utils/async'; import { isWindows } from '../utils/platform'; +import { getActiveInterpreter } from '../../repl/replUtils'; @injectable() export class TerminalService implements ITerminalService, Disposable { @@ -108,7 +109,17 @@ export class TerminalService implements ITerminalService, Disposable { const config = getConfiguration('python'); const pythonrcSetting = config.get('terminal.shellIntegration.enabled'); - if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows())) { + + // Need to check for if Python version is >= 3.13 since we have turned off SI on python side. + // Because we are not sending explicit commandline info to core, it will inject ^C. (We want to avoid) + if (this.options && this.options.resource) { + const pythonVersion = await getActiveInterpreter( + this.options.resource, + this.serviceContainer.get(IInterpreterService), + ); + const minorVersion = pythonVersion?.version?.minor; + + if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows()) || ((minorVersion ?? 0) >= 13)) { // If user has explicitly disabled SI for Python, use sendText for inside Terminal REPL. terminal.sendText(commandLine); return undefined; From fdca3c162069a66fe6183f8f72baeadd502bfa6d Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Thu, 30 Jan 2025 11:50:32 -0800 Subject: [PATCH 02/15] use sendText when sending to >= 3.13 --- src/client/common/terminal/service.ts | 6 ++- .../common/terminals/service.unit.test.ts | 54 ++++++++++++++++++- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/src/client/common/terminal/service.ts b/src/client/common/terminal/service.ts index db80b3fe54de..1e57fe722bad 100644 --- a/src/client/common/terminal/service.ts +++ b/src/client/common/terminal/service.ts @@ -110,6 +110,7 @@ export class TerminalService implements ITerminalService, Disposable { const config = getConfiguration('python'); const pythonrcSetting = config.get('terminal.shellIntegration.enabled'); + let minorVersion: number | undefined; // Need to check for if Python version is >= 3.13 since we have turned off SI on python side. // Because we are not sending explicit commandline info to core, it will inject ^C. (We want to avoid) if (this.options && this.options.resource) { @@ -117,9 +118,10 @@ export class TerminalService implements ITerminalService, Disposable { this.options.resource, this.serviceContainer.get(IInterpreterService), ); - const minorVersion = pythonVersion?.version?.minor; + minorVersion = pythonVersion?.version?.minor; + } - if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows()) || ((minorVersion ?? 0) >= 13)) { + if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows()) || (minorVersion ?? 0) >= 13) { // If user has explicitly disabled SI for Python, use sendText for inside Terminal REPL. terminal.sendText(commandLine); return undefined; diff --git a/src/test/common/terminals/service.unit.test.ts b/src/test/common/terminals/service.unit.test.ts index 9903f6781f28..b0ec45e44443 100644 --- a/src/test/common/terminals/service.unit.test.ts +++ b/src/test/common/terminals/service.unit.test.ts @@ -11,6 +11,7 @@ import { TerminalShellExecution, TerminalShellExecutionEndEvent, TerminalShellIntegration, + Uri, Terminal as VSCodeTerminal, WorkspaceConfiguration, } from 'vscode'; @@ -18,7 +19,12 @@ import { ITerminalManager, IWorkspaceService } from '../../../client/common/appl import { EXTENSION_ROOT_DIR } from '../../../client/common/constants'; import { IPlatformService } from '../../../client/common/platform/types'; import { TerminalService } from '../../../client/common/terminal/service'; -import { ITerminalActivator, ITerminalHelper, TerminalShellType } from '../../../client/common/terminal/types'; +import { + ITerminalActivator, + ITerminalHelper, + TerminalCreationOptions, + TerminalShellType, +} from '../../../client/common/terminal/types'; import { IDisposableRegistry } from '../../../client/common/types'; import { IServiceContainer } from '../../../client/ioc/types'; import { ITerminalAutoActivation } from '../../../client/terminals/types'; @@ -26,6 +32,8 @@ import { createPythonInterpreter } from '../../utils/interpreters'; import * as workspaceApis from '../../../client/common/vscodeApis/workspaceApis'; import * as platform from '../../../client/common/utils/platform'; import * as extapi from '../../../client/envExt/api.internal'; +import { IInterpreterService } from '../../../client/interpreter/contracts'; +import { PythonEnvironment } from '../../../client/pythonEnvironments/info'; suite('Terminal Service', () => { let service: TerminalService; @@ -46,6 +54,8 @@ suite('Terminal Service', () => { let editorConfig: TypeMoq.IMock; let isWindowsStub: sinon.SinonStub; let useEnvExtensionStub: sinon.SinonStub; + let interpreterService: TypeMoq.IMock; + let options: TypeMoq.IMock; setup(() => { useEnvExtensionStub = sinon.stub(extapi, 'useEnvExtension'); @@ -92,6 +102,13 @@ suite('Terminal Service', () => { disposables = []; mockServiceContainer = TypeMoq.Mock.ofType(); + interpreterService = TypeMoq.Mock.ofType(); + interpreterService + .setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny())) + .returns(() => Promise.resolve(({ path: 'ps' } as unknown) as PythonEnvironment)); + + options = TypeMoq.Mock.ofType(); + options.setup((o) => o.resource).returns(() => Uri.parse('a')); mockServiceContainer.setup((c) => c.get(ITerminalManager)).returns(() => terminalManager.object); mockServiceContainer.setup((c) => c.get(ITerminalHelper)).returns(() => terminalHelper.object); @@ -100,6 +117,7 @@ suite('Terminal Service', () => { mockServiceContainer.setup((c) => c.get(IWorkspaceService)).returns(() => workspaceService.object); mockServiceContainer.setup((c) => c.get(ITerminalActivator)).returns(() => terminalActivator.object); mockServiceContainer.setup((c) => c.get(ITerminalAutoActivation)).returns(() => terminalAutoActivator.object); + mockServiceContainer.setup((c) => c.get(IInterpreterService)).returns(() => interpreterService.object); getConfigurationStub = sinon.stub(workspaceApis, 'getConfiguration'); isWindowsStub = sinon.stub(platform, 'isWindows'); pythonConfig = TypeMoq.Mock.ofType(); @@ -117,6 +135,8 @@ suite('Terminal Service', () => { } disposables.filter((item) => !!item).forEach((item) => item.dispose()); sinon.restore(); + // reset setup for interpreterService + interpreterService.reset(); }); test('Ensure terminal is disposed', async () => { @@ -239,7 +259,7 @@ suite('Terminal Service', () => { terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.exactly(1)); }); - test('Ensure sendText is NOT called when Python shell integration and terminal shell integration are both enabled - Mac, Linux', async () => { + test('Ensure sendText is NOT called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python < 3.13', async () => { isWindowsStub.returns(false); pythonConfig .setup((p) => p.get('terminal.shellIntegration.enabled')) @@ -261,6 +281,36 @@ suite('Terminal Service', () => { terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.never()); }); + test('Ensure sendText is called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python >= 3.13', async () => { + interpreterService.reset(); + + interpreterService + .setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny())) + .returns(() => + Promise.resolve({ path: 'yo', version: { major: 3, minor: 13, patch: 0 } } as PythonEnvironment), + ); + + isWindowsStub.returns(false); + pythonConfig + .setup((p) => p.get('terminal.shellIntegration.enabled')) + .returns(() => true) + .verifiable(TypeMoq.Times.once()); + + terminalHelper + .setup((helper) => helper.getEnvironmentActivationCommands(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns(() => Promise.resolve(undefined)); + + service = new TerminalService(mockServiceContainer.object, options.object); + const textToSend = 'Some Text'; + terminalHelper.setup((h) => h.identifyTerminalShell(TypeMoq.It.isAny())).returns(() => TerminalShellType.bash); + terminalManager.setup((t) => t.createTerminal(TypeMoq.It.isAny())).returns(() => terminal.object); + + await service.ensureTerminal(); + await service.executeCommand(textToSend, true); + + terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.once()); + }); + test('Ensure sendText IS called even when Python shell integration and terminal shell integration are both enabled - Window', async () => { isWindowsStub.returns(true); pythonConfig From 78f9298f0208254e14d075b59873f3a75f5155fa Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Thu, 30 Jan 2025 22:04:06 -0800 Subject: [PATCH 03/15] make my code cleaner --- src/client/common/terminal/service.ts | 18 +++++++----------- src/client/repl/replUtils.ts | 14 ++++++++++++++ 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/src/client/common/terminal/service.ts b/src/client/common/terminal/service.ts index 1e57fe722bad..a051d66f015f 100644 --- a/src/client/common/terminal/service.ts +++ b/src/client/common/terminal/service.ts @@ -25,7 +25,7 @@ import { useEnvExtension } from '../../envExt/api.internal'; import { ensureTerminalLegacy } from '../../envExt/api.legacy'; import { sleep } from '../utils/async'; import { isWindows } from '../utils/platform'; -import { getActiveInterpreter } from '../../repl/replUtils'; +import { getPythonMinorVersion } from '../../repl/replUtils'; @injectable() export class TerminalService implements ITerminalService, Disposable { @@ -110,16 +110,12 @@ export class TerminalService implements ITerminalService, Disposable { const config = getConfiguration('python'); const pythonrcSetting = config.get('terminal.shellIntegration.enabled'); - let minorVersion: number | undefined; - // Need to check for if Python version is >= 3.13 since we have turned off SI on python side. - // Because we are not sending explicit commandline info to core, it will inject ^C. (We want to avoid) - if (this.options && this.options.resource) { - const pythonVersion = await getActiveInterpreter( - this.options.resource, - this.serviceContainer.get(IInterpreterService), - ); - minorVersion = pythonVersion?.version?.minor; - } + const minorVersion = this.options?.resource + ? await getPythonMinorVersion( + this.options.resource, + this.serviceContainer.get(IInterpreterService), + ) + : undefined; if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows()) || (minorVersion ?? 0) >= 13) { // If user has explicitly disabled SI for Python, use sendText for inside Terminal REPL. diff --git a/src/client/repl/replUtils.ts b/src/client/repl/replUtils.ts index 0c2c4ba0d84e..8e23218c2870 100644 --- a/src/client/repl/replUtils.ts +++ b/src/client/repl/replUtils.ts @@ -118,3 +118,17 @@ export function getTabNameForUri(uri: Uri): string | undefined { return undefined; } + +/** + * Function that will return the minor version of current active Python interpreter. + */ +export async function getPythonMinorVersion( + uri: Uri | undefined, + interpreterService: IInterpreterService, +): Promise { + if (uri) { + const pythonVersion = await getActiveInterpreter(uri, interpreterService); + return pythonVersion?.version?.minor; + } + return undefined; +} From c6dfed7fcdbbdba9a7d4322b13695d27f9815dfb Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Sat, 1 Feb 2025 22:48:24 -0800 Subject: [PATCH 04/15] why --- src/client/common/terminal/service.ts | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/client/common/terminal/service.ts b/src/client/common/terminal/service.ts index a051d66f015f..5eddf2d07fc5 100644 --- a/src/client/common/terminal/service.ts +++ b/src/client/common/terminal/service.ts @@ -25,7 +25,7 @@ import { useEnvExtension } from '../../envExt/api.internal'; import { ensureTerminalLegacy } from '../../envExt/api.legacy'; import { sleep } from '../utils/async'; import { isWindows } from '../utils/platform'; -import { getPythonMinorVersion } from '../../repl/replUtils'; +// import { getPythonMinorVersion } from '../../repl/replUtils'; @injectable() export class TerminalService implements ITerminalService, Disposable { @@ -110,14 +110,15 @@ export class TerminalService implements ITerminalService, Disposable { const config = getConfiguration('python'); const pythonrcSetting = config.get('terminal.shellIntegration.enabled'); - const minorVersion = this.options?.resource - ? await getPythonMinorVersion( - this.options.resource, - this.serviceContainer.get(IInterpreterService), - ) - : undefined; + // const minorVersion = this.options?.resource + // ? await getPythonMinorVersion( + // this.options.resource, + // this.serviceContainer.get(IInterpreterService), + // ) + // : undefined; + // || (minorVersion ?? 0) >= 13 - if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows()) || (minorVersion ?? 0) >= 13) { + if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows())) { // If user has explicitly disabled SI for Python, use sendText for inside Terminal REPL. terminal.sendText(commandLine); return undefined; From 3b338ee0a7c96c44cb36bdc8b05aa638b2b6fff0 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Sat, 1 Feb 2025 23:00:29 -0800 Subject: [PATCH 05/15] why --- .../common/terminals/service.unit.test.ts | 116 +++++++++--------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/src/test/common/terminals/service.unit.test.ts b/src/test/common/terminals/service.unit.test.ts index b0ec45e44443..0dd70ca5c834 100644 --- a/src/test/common/terminals/service.unit.test.ts +++ b/src/test/common/terminals/service.unit.test.ts @@ -102,13 +102,13 @@ suite('Terminal Service', () => { disposables = []; mockServiceContainer = TypeMoq.Mock.ofType(); - interpreterService = TypeMoq.Mock.ofType(); - interpreterService - .setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny())) - .returns(() => Promise.resolve(({ path: 'ps' } as unknown) as PythonEnvironment)); + // interpreterService = TypeMoq.Mock.ofType(); + // interpreterService + // .setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny())) + // .returns(() => Promise.resolve(({ path: 'ps' } as unknown) as PythonEnvironment)); - options = TypeMoq.Mock.ofType(); - options.setup((o) => o.resource).returns(() => Uri.parse('a')); + // options = TypeMoq.Mock.ofType(); + // options.setup((o) => o.resource).returns(() => Uri.parse('a')); mockServiceContainer.setup((c) => c.get(ITerminalManager)).returns(() => terminalManager.object); mockServiceContainer.setup((c) => c.get(ITerminalHelper)).returns(() => terminalHelper.object); @@ -136,7 +136,7 @@ suite('Terminal Service', () => { disposables.filter((item) => !!item).forEach((item) => item.dispose()); sinon.restore(); // reset setup for interpreterService - interpreterService.reset(); + // interpreterService.reset(); }); test('Ensure terminal is disposed', async () => { @@ -259,57 +259,57 @@ suite('Terminal Service', () => { terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.exactly(1)); }); - test('Ensure sendText is NOT called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python < 3.13', async () => { - isWindowsStub.returns(false); - pythonConfig - .setup((p) => p.get('terminal.shellIntegration.enabled')) - .returns(() => true) - .verifiable(TypeMoq.Times.once()); - - terminalHelper - .setup((helper) => helper.getEnvironmentActivationCommands(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns(() => Promise.resolve(undefined)); - service = new TerminalService(mockServiceContainer.object); - const textToSend = 'Some Text'; - terminalHelper.setup((h) => h.identifyTerminalShell(TypeMoq.It.isAny())).returns(() => TerminalShellType.bash); - terminalManager.setup((t) => t.createTerminal(TypeMoq.It.isAny())).returns(() => terminal.object); - - service.ensureTerminal(); - service.executeCommand(textToSend, true); - - terminal.verify((t) => t.show(TypeMoq.It.isValue(true)), TypeMoq.Times.exactly(1)); - terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.never()); - }); - - test('Ensure sendText is called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python >= 3.13', async () => { - interpreterService.reset(); - - interpreterService - .setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny())) - .returns(() => - Promise.resolve({ path: 'yo', version: { major: 3, minor: 13, patch: 0 } } as PythonEnvironment), - ); - - isWindowsStub.returns(false); - pythonConfig - .setup((p) => p.get('terminal.shellIntegration.enabled')) - .returns(() => true) - .verifiable(TypeMoq.Times.once()); - - terminalHelper - .setup((helper) => helper.getEnvironmentActivationCommands(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns(() => Promise.resolve(undefined)); - - service = new TerminalService(mockServiceContainer.object, options.object); - const textToSend = 'Some Text'; - terminalHelper.setup((h) => h.identifyTerminalShell(TypeMoq.It.isAny())).returns(() => TerminalShellType.bash); - terminalManager.setup((t) => t.createTerminal(TypeMoq.It.isAny())).returns(() => terminal.object); - - await service.ensureTerminal(); - await service.executeCommand(textToSend, true); - - terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.once()); - }); + // test('Ensure sendText is NOT called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python < 3.13', async () => { + // isWindowsStub.returns(false); + // pythonConfig + // .setup((p) => p.get('terminal.shellIntegration.enabled')) + // .returns(() => true) + // .verifiable(TypeMoq.Times.once()); + + // terminalHelper + // .setup((helper) => helper.getEnvironmentActivationCommands(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + // .returns(() => Promise.resolve(undefined)); + // service = new TerminalService(mockServiceContainer.object); + // const textToSend = 'Some Text'; + // terminalHelper.setup((h) => h.identifyTerminalShell(TypeMoq.It.isAny())).returns(() => TerminalShellType.bash); + // terminalManager.setup((t) => t.createTerminal(TypeMoq.It.isAny())).returns(() => terminal.object); + + // service.ensureTerminal(); + // service.executeCommand(textToSend, true); + + // terminal.verify((t) => t.show(TypeMoq.It.isValue(true)), TypeMoq.Times.exactly(1)); + // terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.never()); + // }); + + // test('Ensure sendText is called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python >= 3.13', async () => { + // interpreterService.reset(); + + // interpreterService + // .setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny())) + // .returns(() => + // Promise.resolve({ path: 'yo', version: { major: 3, minor: 13, patch: 0 } } as PythonEnvironment), + // ); + + // isWindowsStub.returns(false); + // pythonConfig + // .setup((p) => p.get('terminal.shellIntegration.enabled')) + // .returns(() => true) + // .verifiable(TypeMoq.Times.once()); + + // terminalHelper + // .setup((helper) => helper.getEnvironmentActivationCommands(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + // .returns(() => Promise.resolve(undefined)); + + // service = new TerminalService(mockServiceContainer.object, options.object); + // const textToSend = 'Some Text'; + // terminalHelper.setup((h) => h.identifyTerminalShell(TypeMoq.It.isAny())).returns(() => TerminalShellType.bash); + // terminalManager.setup((t) => t.createTerminal(TypeMoq.It.isAny())).returns(() => terminal.object); + + // await service.ensureTerminal(); + // await service.executeCommand(textToSend, true); + + // terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.once()); + // }); test('Ensure sendText IS called even when Python shell integration and terminal shell integration are both enabled - Window', async () => { isWindowsStub.returns(true); From 399847e1c388c90c5d14fb7bc5eab573c028f132 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Sat, 1 Feb 2025 23:00:57 -0800 Subject: [PATCH 06/15] why --- src/test/common/terminals/service.unit.test.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/test/common/terminals/service.unit.test.ts b/src/test/common/terminals/service.unit.test.ts index 0dd70ca5c834..8d0b441df64f 100644 --- a/src/test/common/terminals/service.unit.test.ts +++ b/src/test/common/terminals/service.unit.test.ts @@ -11,7 +11,7 @@ import { TerminalShellExecution, TerminalShellExecutionEndEvent, TerminalShellIntegration, - Uri, + // Uri, Terminal as VSCodeTerminal, WorkspaceConfiguration, } from 'vscode'; @@ -22,7 +22,7 @@ import { TerminalService } from '../../../client/common/terminal/service'; import { ITerminalActivator, ITerminalHelper, - TerminalCreationOptions, + // TerminalCreationOptions, TerminalShellType, } from '../../../client/common/terminal/types'; import { IDisposableRegistry } from '../../../client/common/types'; @@ -33,7 +33,7 @@ import * as workspaceApis from '../../../client/common/vscodeApis/workspaceApis' import * as platform from '../../../client/common/utils/platform'; import * as extapi from '../../../client/envExt/api.internal'; import { IInterpreterService } from '../../../client/interpreter/contracts'; -import { PythonEnvironment } from '../../../client/pythonEnvironments/info'; +// import { PythonEnvironment } from '../../../client/pythonEnvironments/info'; suite('Terminal Service', () => { let service: TerminalService; @@ -55,7 +55,7 @@ suite('Terminal Service', () => { let isWindowsStub: sinon.SinonStub; let useEnvExtensionStub: sinon.SinonStub; let interpreterService: TypeMoq.IMock; - let options: TypeMoq.IMock; + // let options: TypeMoq.IMock; setup(() => { useEnvExtensionStub = sinon.stub(extapi, 'useEnvExtension'); From 33ec0ab591fc248ccc760d7b5a32f88d66b6e56d Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Sat, 1 Feb 2025 23:22:03 -0800 Subject: [PATCH 07/15] see if different --- .../terminals/codeExecution/smartSend.test.ts | 129 +++++++++--------- 1 file changed, 66 insertions(+), 63 deletions(-) diff --git a/src/test/terminals/codeExecution/smartSend.test.ts b/src/test/terminals/codeExecution/smartSend.test.ts index b81d581033aa..5a8171bbabd8 100644 --- a/src/test/terminals/codeExecution/smartSend.test.ts +++ b/src/test/terminals/codeExecution/smartSend.test.ts @@ -21,7 +21,7 @@ import { IServiceContainer } from '../../../client/ioc/types'; import { ICodeExecutionHelper } from '../../../client/terminals/types'; import { Commands, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; import { EnvironmentType, PythonEnvironment } from '../../../client/pythonEnvironments/info'; -import { PYTHON_PATH } from '../../common'; +import { PYTHON_PATH, getPythonSemVer } from '../../common'; import { Architecture } from '../../../client/common/utils/platform'; import { ProcessService } from '../../../client/common/process/proc'; import { l10n } from '../../mocks/vsc'; @@ -29,7 +29,7 @@ import { ReplType } from '../../../client/repl/types'; const TEST_FILES_PATH = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'python_files', 'terminalExec'); -suite('REPL - Smart Send', () => { +suite('REPL - Smart Send', async () => { let documentManager: TypeMoq.IMock; let applicationShell: TypeMoq.IMock; @@ -168,67 +168,70 @@ suite('REPL - Smart Send', () => { commandManager.verifyAll(); }); - test('Smart send should perform smart selection and move cursor', async () => { - configurationService - .setup((c) => c.getSettings(TypeMoq.It.isAny())) - .returns({ - REPL: { - REPLSmartSend: true, - }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any); - - const activeEditor = TypeMoq.Mock.ofType(); - const firstIndexPosition = new Position(0, 0); - const selection = TypeMoq.Mock.ofType(); - const wholeFileContent = await fs.readFile(path.join(TEST_FILES_PATH, `sample_smart_selection.py`), 'utf8'); - - selection.setup((s) => s.anchor).returns(() => firstIndexPosition); - selection.setup((s) => s.active).returns(() => firstIndexPosition); - selection.setup((s) => s.isEmpty).returns(() => true); - activeEditor.setup((e) => e.selection).returns(() => selection.object); - - documentManager.setup((d) => d.activeTextEditor).returns(() => activeEditor.object); - document.setup((d) => d.getText(TypeMoq.It.isAny())).returns(() => wholeFileContent); - const actualProcessService = new ProcessService(); - - const { execObservable } = actualProcessService; - - processService - .setup((p) => p.execObservable(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns((file, args, options) => execObservable.apply(actualProcessService, [file, args, options])); - - const actualSmartOutput = await codeExecutionHelper.normalizeLines( - 'my_dict = {', - ReplType.terminal, - wholeFileContent, - ); - - // my_dict = { <----- smart shift+enter here - // "key1": "value1", - // "key2": "value2" - // } <---- cursor should be here afterwards, hence offset 3 - commandManager - .setup((c) => c.executeCommand('cursorMove', TypeMoq.It.isAny())) - .callback((_, arg2) => { - assert.deepEqual(arg2, { - to: 'down', - by: 'line', - value: 3, - }); - return Promise.resolve(); - }) - .verifiable(TypeMoq.Times.once()); - - commandManager - .setup((c) => c.executeCommand('cursorEnd')) - .returns(() => Promise.resolve()) - .verifiable(TypeMoq.Times.once()); - - const expectedSmartOutput = 'my_dict = {\n "key1": "value1",\n "key2": "value2"\n}\n'; - expect(actualSmartOutput).to.be.equal(expectedSmartOutput); - commandManager.verifyAll(); - }); + const pythonVersion = await getPythonSemVer(); + if (pythonVersion && pythonVersion.minor < 13) { + test('Smart send should perform smart selection and move cursor', async () => { + configurationService + .setup((c) => c.getSettings(TypeMoq.It.isAny())) + .returns({ + REPL: { + REPLSmartSend: true, + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any); + + const activeEditor = TypeMoq.Mock.ofType(); + const firstIndexPosition = new Position(0, 0); + const selection = TypeMoq.Mock.ofType(); + const wholeFileContent = await fs.readFile(path.join(TEST_FILES_PATH, `sample_smart_selection.py`), 'utf8'); + + selection.setup((s) => s.anchor).returns(() => firstIndexPosition); + selection.setup((s) => s.active).returns(() => firstIndexPosition); + selection.setup((s) => s.isEmpty).returns(() => true); + activeEditor.setup((e) => e.selection).returns(() => selection.object); + + documentManager.setup((d) => d.activeTextEditor).returns(() => activeEditor.object); + document.setup((d) => d.getText(TypeMoq.It.isAny())).returns(() => wholeFileContent); + const actualProcessService = new ProcessService(); + + const { execObservable } = actualProcessService; + + processService + .setup((p) => p.execObservable(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns((file, args, options) => execObservable.apply(actualProcessService, [file, args, options])); + + const actualSmartOutput = await codeExecutionHelper.normalizeLines( + 'my_dict = {', + ReplType.terminal, + wholeFileContent, + ); + + // my_dict = { <----- smart shift+enter here + // "key1": "value1", + // "key2": "value2" + // } <---- cursor should be here afterwards, hence offset 3 + commandManager + .setup((c) => c.executeCommand('cursorMove', TypeMoq.It.isAny())) + .callback((_, arg2) => { + assert.deepEqual(arg2, { + to: 'down', + by: 'line', + value: 3, + }); + return Promise.resolve(); + }) + .verifiable(TypeMoq.Times.once()); + + commandManager + .setup((c) => c.executeCommand('cursorEnd')) + .returns(() => Promise.resolve()) + .verifiable(TypeMoq.Times.once()); + + const expectedSmartOutput = 'my_dict = {\n "key1": "value1",\n "key2": "value2"\n}\n'; + expect(actualSmartOutput).to.be.equal(expectedSmartOutput); + commandManager.verifyAll(); + }); + } // Do not perform smart selection when there is explicit selection test('Smart send should not perform smart selection when there is explicit selection', async () => { From f1e8d44002778c2f6273b573c665230bf12c4206 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Sat, 1 Feb 2025 23:28:01 -0800 Subject: [PATCH 08/15] why no async --- .../terminals/codeExecution/helper.test.ts | 2 +- .../terminals/codeExecution/smartSend.test.ts | 125 +++++++++--------- 2 files changed, 62 insertions(+), 65 deletions(-) diff --git a/src/test/terminals/codeExecution/helper.test.ts b/src/test/terminals/codeExecution/helper.test.ts index 166c4db12e7d..7cc0e551ef2a 100644 --- a/src/test/terminals/codeExecution/helper.test.ts +++ b/src/test/terminals/codeExecution/helper.test.ts @@ -38,7 +38,7 @@ import { ReplType } from '../../../client/repl/types'; const TEST_FILES_PATH = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'python_files', 'terminalExec'); -suite('Terminal - Code Execution Helper', () => { +suite('Terminal - Code Execution Helper', async () => { let activeResourceService: TypeMoq.IMock; let documentManager: TypeMoq.IMock; let applicationShell: TypeMoq.IMock; diff --git a/src/test/terminals/codeExecution/smartSend.test.ts b/src/test/terminals/codeExecution/smartSend.test.ts index 5a8171bbabd8..d5458ab16e21 100644 --- a/src/test/terminals/codeExecution/smartSend.test.ts +++ b/src/test/terminals/codeExecution/smartSend.test.ts @@ -168,70 +168,67 @@ suite('REPL - Smart Send', async () => { commandManager.verifyAll(); }); - const pythonVersion = await getPythonSemVer(); - if (pythonVersion && pythonVersion.minor < 13) { - test('Smart send should perform smart selection and move cursor', async () => { - configurationService - .setup((c) => c.getSettings(TypeMoq.It.isAny())) - .returns({ - REPL: { - REPLSmartSend: true, - }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any); - - const activeEditor = TypeMoq.Mock.ofType(); - const firstIndexPosition = new Position(0, 0); - const selection = TypeMoq.Mock.ofType(); - const wholeFileContent = await fs.readFile(path.join(TEST_FILES_PATH, `sample_smart_selection.py`), 'utf8'); - - selection.setup((s) => s.anchor).returns(() => firstIndexPosition); - selection.setup((s) => s.active).returns(() => firstIndexPosition); - selection.setup((s) => s.isEmpty).returns(() => true); - activeEditor.setup((e) => e.selection).returns(() => selection.object); - - documentManager.setup((d) => d.activeTextEditor).returns(() => activeEditor.object); - document.setup((d) => d.getText(TypeMoq.It.isAny())).returns(() => wholeFileContent); - const actualProcessService = new ProcessService(); - - const { execObservable } = actualProcessService; - - processService - .setup((p) => p.execObservable(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns((file, args, options) => execObservable.apply(actualProcessService, [file, args, options])); - - const actualSmartOutput = await codeExecutionHelper.normalizeLines( - 'my_dict = {', - ReplType.terminal, - wholeFileContent, - ); - - // my_dict = { <----- smart shift+enter here - // "key1": "value1", - // "key2": "value2" - // } <---- cursor should be here afterwards, hence offset 3 - commandManager - .setup((c) => c.executeCommand('cursorMove', TypeMoq.It.isAny())) - .callback((_, arg2) => { - assert.deepEqual(arg2, { - to: 'down', - by: 'line', - value: 3, - }); - return Promise.resolve(); - }) - .verifiable(TypeMoq.Times.once()); - - commandManager - .setup((c) => c.executeCommand('cursorEnd')) - .returns(() => Promise.resolve()) - .verifiable(TypeMoq.Times.once()); - - const expectedSmartOutput = 'my_dict = {\n "key1": "value1",\n "key2": "value2"\n}\n'; - expect(actualSmartOutput).to.be.equal(expectedSmartOutput); - commandManager.verifyAll(); - }); - } + test('Smart send should perform smart selection and move cursor', async () => { + configurationService + .setup((c) => c.getSettings(TypeMoq.It.isAny())) + .returns({ + REPL: { + REPLSmartSend: true, + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any); + + const activeEditor = TypeMoq.Mock.ofType(); + const firstIndexPosition = new Position(0, 0); + const selection = TypeMoq.Mock.ofType(); + const wholeFileContent = await fs.readFile(path.join(TEST_FILES_PATH, `sample_smart_selection.py`), 'utf8'); + + selection.setup((s) => s.anchor).returns(() => firstIndexPosition); + selection.setup((s) => s.active).returns(() => firstIndexPosition); + selection.setup((s) => s.isEmpty).returns(() => true); + activeEditor.setup((e) => e.selection).returns(() => selection.object); + + documentManager.setup((d) => d.activeTextEditor).returns(() => activeEditor.object); + document.setup((d) => d.getText(TypeMoq.It.isAny())).returns(() => wholeFileContent); + const actualProcessService = new ProcessService(); + + const { execObservable } = actualProcessService; + + processService + .setup((p) => p.execObservable(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns((file, args, options) => execObservable.apply(actualProcessService, [file, args, options])); + + const actualSmartOutput = await codeExecutionHelper.normalizeLines( + 'my_dict = {', + ReplType.terminal, + wholeFileContent, + ); + + // my_dict = { <----- smart shift+enter here + // "key1": "value1", + // "key2": "value2" + // } <---- cursor should be here afterwards, hence offset 3 + commandManager + .setup((c) => c.executeCommand('cursorMove', TypeMoq.It.isAny())) + .callback((_, arg2) => { + assert.deepEqual(arg2, { + to: 'down', + by: 'line', + value: 3, + }); + return Promise.resolve(); + }) + .verifiable(TypeMoq.Times.once()); + + commandManager + .setup((c) => c.executeCommand('cursorEnd')) + .returns(() => Promise.resolve()) + .verifiable(TypeMoq.Times.once()); + + const expectedSmartOutput = 'my_dict = {\n "key1": "value1",\n "key2": "value2"\n}\n'; + expect(actualSmartOutput).to.be.equal(expectedSmartOutput); + commandManager.verifyAll(); + }); // Do not perform smart selection when there is explicit selection test('Smart send should not perform smart selection when there is explicit selection', async () => { From ec4a0487e273a2623929c15b38760e508a33ed96 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Sat, 1 Feb 2025 23:29:48 -0800 Subject: [PATCH 09/15] remove unused --- src/test/terminals/codeExecution/smartSend.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/terminals/codeExecution/smartSend.test.ts b/src/test/terminals/codeExecution/smartSend.test.ts index d5458ab16e21..2b0ec73c2503 100644 --- a/src/test/terminals/codeExecution/smartSend.test.ts +++ b/src/test/terminals/codeExecution/smartSend.test.ts @@ -21,7 +21,7 @@ import { IServiceContainer } from '../../../client/ioc/types'; import { ICodeExecutionHelper } from '../../../client/terminals/types'; import { Commands, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; import { EnvironmentType, PythonEnvironment } from '../../../client/pythonEnvironments/info'; -import { PYTHON_PATH, getPythonSemVer } from '../../common'; +import { PYTHON_PATH } from '../../common'; import { Architecture } from '../../../client/common/utils/platform'; import { ProcessService } from '../../../client/common/process/proc'; import { l10n } from '../../mocks/vsc'; From f2fbb9f7d5ab471331fad565db631538cf61243e Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Sat, 1 Feb 2025 23:41:29 -0800 Subject: [PATCH 10/15] a --- .../terminals/codeExecution/smartSend.test.ts | 129 +++++++++--------- 1 file changed, 67 insertions(+), 62 deletions(-) diff --git a/src/test/terminals/codeExecution/smartSend.test.ts b/src/test/terminals/codeExecution/smartSend.test.ts index 2b0ec73c2503..b71a297c2c44 100644 --- a/src/test/terminals/codeExecution/smartSend.test.ts +++ b/src/test/terminals/codeExecution/smartSend.test.ts @@ -21,7 +21,7 @@ import { IServiceContainer } from '../../../client/ioc/types'; import { ICodeExecutionHelper } from '../../../client/terminals/types'; import { Commands, EXTENSION_ROOT_DIR } from '../../../client/common/constants'; import { EnvironmentType, PythonEnvironment } from '../../../client/pythonEnvironments/info'; -import { PYTHON_PATH } from '../../common'; +import { PYTHON_PATH, getPythonSemVer } from '../../common'; import { Architecture } from '../../../client/common/utils/platform'; import { ProcessService } from '../../../client/common/process/proc'; import { l10n } from '../../mocks/vsc'; @@ -168,67 +168,72 @@ suite('REPL - Smart Send', async () => { commandManager.verifyAll(); }); - test('Smart send should perform smart selection and move cursor', async () => { - configurationService - .setup((c) => c.getSettings(TypeMoq.It.isAny())) - .returns({ - REPL: { - REPLSmartSend: true, - }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any); - - const activeEditor = TypeMoq.Mock.ofType(); - const firstIndexPosition = new Position(0, 0); - const selection = TypeMoq.Mock.ofType(); - const wholeFileContent = await fs.readFile(path.join(TEST_FILES_PATH, `sample_smart_selection.py`), 'utf8'); - - selection.setup((s) => s.anchor).returns(() => firstIndexPosition); - selection.setup((s) => s.active).returns(() => firstIndexPosition); - selection.setup((s) => s.isEmpty).returns(() => true); - activeEditor.setup((e) => e.selection).returns(() => selection.object); - - documentManager.setup((d) => d.activeTextEditor).returns(() => activeEditor.object); - document.setup((d) => d.getText(TypeMoq.It.isAny())).returns(() => wholeFileContent); - const actualProcessService = new ProcessService(); - - const { execObservable } = actualProcessService; - - processService - .setup((p) => p.execObservable(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())) - .returns((file, args, options) => execObservable.apply(actualProcessService, [file, args, options])); - - const actualSmartOutput = await codeExecutionHelper.normalizeLines( - 'my_dict = {', - ReplType.terminal, - wholeFileContent, - ); - - // my_dict = { <----- smart shift+enter here - // "key1": "value1", - // "key2": "value2" - // } <---- cursor should be here afterwards, hence offset 3 - commandManager - .setup((c) => c.executeCommand('cursorMove', TypeMoq.It.isAny())) - .callback((_, arg2) => { - assert.deepEqual(arg2, { - to: 'down', - by: 'line', - value: 3, - }); - return Promise.resolve(); - }) - .verifiable(TypeMoq.Times.once()); - - commandManager - .setup((c) => c.executeCommand('cursorEnd')) - .returns(() => Promise.resolve()) - .verifiable(TypeMoq.Times.once()); - - const expectedSmartOutput = 'my_dict = {\n "key1": "value1",\n "key2": "value2"\n}\n'; - expect(actualSmartOutput).to.be.equal(expectedSmartOutput); - commandManager.verifyAll(); - }); + const pythonVersion = await getPythonSemVer(); + console.log('Just printed pythoNVersion: \n'); + console.log(pythonVersion); + if (pythonVersion && pythonVersion.minor < 13) { + test('Smart send should perform smart selection and move cursor', async () => { + configurationService + .setup((c) => c.getSettings(TypeMoq.It.isAny())) + .returns({ + REPL: { + REPLSmartSend: true, + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any); + + const activeEditor = TypeMoq.Mock.ofType(); + const firstIndexPosition = new Position(0, 0); + const selection = TypeMoq.Mock.ofType(); + const wholeFileContent = await fs.readFile(path.join(TEST_FILES_PATH, `sample_smart_selection.py`), 'utf8'); + + selection.setup((s) => s.anchor).returns(() => firstIndexPosition); + selection.setup((s) => s.active).returns(() => firstIndexPosition); + selection.setup((s) => s.isEmpty).returns(() => true); + activeEditor.setup((e) => e.selection).returns(() => selection.object); + + documentManager.setup((d) => d.activeTextEditor).returns(() => activeEditor.object); + document.setup((d) => d.getText(TypeMoq.It.isAny())).returns(() => wholeFileContent); + const actualProcessService = new ProcessService(); + + const { execObservable } = actualProcessService; + + processService + .setup((p) => p.execObservable(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns((file, args, options) => execObservable.apply(actualProcessService, [file, args, options])); + + const actualSmartOutput = await codeExecutionHelper.normalizeLines( + 'my_dict = {', + ReplType.terminal, + wholeFileContent, + ); + + // my_dict = { <----- smart shift+enter here + // "key1": "value1", + // "key2": "value2" + // } <---- cursor should be here afterwards, hence offset 3 + commandManager + .setup((c) => c.executeCommand('cursorMove', TypeMoq.It.isAny())) + .callback((_, arg2) => { + assert.deepEqual(arg2, { + to: 'down', + by: 'line', + value: 3, + }); + return Promise.resolve(); + }) + .verifiable(TypeMoq.Times.once()); + + commandManager + .setup((c) => c.executeCommand('cursorEnd')) + .returns(() => Promise.resolve()) + .verifiable(TypeMoq.Times.once()); + + const expectedSmartOutput = 'my_dict = {\n "key1": "value1",\n "key2": "value2"\n}\n'; + expect(actualSmartOutput).to.be.equal(expectedSmartOutput); + commandManager.verifyAll(); + }); + } // Do not perform smart selection when there is explicit selection test('Smart send should not perform smart selection when there is explicit selection', async () => { From 70629bf799b48f517986b03ccd29a81ff10c72b6 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Sat, 1 Feb 2025 23:48:11 -0800 Subject: [PATCH 11/15] see if its because of 3.13 --- .../terminals/codeExecution/helper.test.ts | 43 ++++++++++--------- 1 file changed, 22 insertions(+), 21 deletions(-) diff --git a/src/test/terminals/codeExecution/helper.test.ts b/src/test/terminals/codeExecution/helper.test.ts index 7cc0e551ef2a..be1af7f8d62e 100644 --- a/src/test/terminals/codeExecution/helper.test.ts +++ b/src/test/terminals/codeExecution/helper.test.ts @@ -33,7 +33,7 @@ import { IServiceContainer } from '../../../client/ioc/types'; import { EnvironmentType, PythonEnvironment } from '../../../client/pythonEnvironments/info'; import { CodeExecutionHelper } from '../../../client/terminals/codeExecution/helper'; import { ICodeExecutionHelper } from '../../../client/terminals/types'; -import { PYTHON_PATH } from '../../common'; +import { PYTHON_PATH, getPythonSemVer } from '../../common'; import { ReplType } from '../../../client/repl/types'; const TEST_FILES_PATH = path.join(EXTENSION_ROOT_DIR, 'src', 'test', 'python_files', 'terminalExec'); @@ -233,27 +233,28 @@ suite('Terminal - Code Execution Helper', async () => { const normalizedExpected = expectedSource.replace(/\r\n/g, '\n'); expect(normalizedCode).to.be.equal(normalizedExpected); } - - ['', '1', '2', '3', '4', '5', '6', '7', '8'].forEach((fileNameSuffix) => { - test(`Ensure code is normalized (Sample${fileNameSuffix})`, async () => { - configurationService - .setup((c) => c.getSettings(TypeMoq.It.isAny())) - .returns({ - REPL: { - EnableREPLSmartSend: false, - REPLSmartSend: false, - }, - // eslint-disable-next-line @typescript-eslint/no-explicit-any - } as any); - const code = await fs.readFile(path.join(TEST_FILES_PATH, `sample${fileNameSuffix}_raw.py`), 'utf8'); - const expectedCode = await fs.readFile( - path.join(TEST_FILES_PATH, `sample${fileNameSuffix}_normalized_selection.py`), - 'utf8', - ); - await ensureCodeIsNormalized(code, expectedCode); + const pythonVersion = await getPythonSemVer(); + if (pythonVersion && pythonVersion.minor < 13) { + ['', '1', '2', '3', '4', '5', '6', '7', '8'].forEach((fileNameSuffix) => { + test(`Ensure code is normalized (Sample${fileNameSuffix})`, async () => { + configurationService + .setup((c) => c.getSettings(TypeMoq.It.isAny())) + .returns({ + REPL: { + EnableREPLSmartSend: false, + REPLSmartSend: false, + }, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + } as any); + const code = await fs.readFile(path.join(TEST_FILES_PATH, `sample${fileNameSuffix}_raw.py`), 'utf8'); + const expectedCode = await fs.readFile( + path.join(TEST_FILES_PATH, `sample${fileNameSuffix}_normalized_selection.py`), + 'utf8', + ); + await ensureCodeIsNormalized(code, expectedCode); + }); }); - }); - + } test("Display message if there's no active file", async () => { documentManager.setup((doc) => doc.activeTextEditor).returns(() => undefined); From eb3122deb9442c0267b3b833e7be3d2bb895aa13 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Mon, 3 Feb 2025 09:17:05 -0800 Subject: [PATCH 12/15] resolve merge conflict --- src/test/terminals/codeExecution/helper.test.ts | 8 +++++--- src/test/terminals/codeExecution/smartSend.test.ts | 9 ++++----- 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/src/test/terminals/codeExecution/helper.test.ts b/src/test/terminals/codeExecution/helper.test.ts index be1af7f8d62e..a43c5f8746ed 100644 --- a/src/test/terminals/codeExecution/helper.test.ts +++ b/src/test/terminals/codeExecution/helper.test.ts @@ -233,10 +233,11 @@ suite('Terminal - Code Execution Helper', async () => { const normalizedExpected = expectedSource.replace(/\r\n/g, '\n'); expect(normalizedCode).to.be.equal(normalizedExpected); } - const pythonVersion = await getPythonSemVer(); - if (pythonVersion && pythonVersion.minor < 13) { + + const pythonTestVersion = await getPythonSemVer(); + if (pythonTestVersion && pythonTestVersion.minor < 13) { ['', '1', '2', '3', '4', '5', '6', '7', '8'].forEach((fileNameSuffix) => { - test(`Ensure code is normalized (Sample${fileNameSuffix})`, async () => { + test(`Ensure code is normalized (Sample${fileNameSuffix}) - Python < 3.13`, async () => { configurationService .setup((c) => c.getSettings(TypeMoq.It.isAny())) .returns({ @@ -255,6 +256,7 @@ suite('Terminal - Code Execution Helper', async () => { }); }); } + test("Display message if there's no active file", async () => { documentManager.setup((doc) => doc.activeTextEditor).returns(() => undefined); diff --git a/src/test/terminals/codeExecution/smartSend.test.ts b/src/test/terminals/codeExecution/smartSend.test.ts index b71a297c2c44..99ccd5d51d80 100644 --- a/src/test/terminals/codeExecution/smartSend.test.ts +++ b/src/test/terminals/codeExecution/smartSend.test.ts @@ -168,11 +168,10 @@ suite('REPL - Smart Send', async () => { commandManager.verifyAll(); }); - const pythonVersion = await getPythonSemVer(); - console.log('Just printed pythoNVersion: \n'); - console.log(pythonVersion); - if (pythonVersion && pythonVersion.minor < 13) { - test('Smart send should perform smart selection and move cursor', async () => { + const pythonTestVersion = await getPythonSemVer(); + + if (pythonTestVersion && pythonTestVersion.minor < 13) { + test('Smart send should perform smart selection and move cursor - Python < 3.13', async () => { configurationService .setup((c) => c.getSettings(TypeMoq.It.isAny())) .returns({ From 7b4fb2afad0bbf3e7fcb10a2ef2909e9408c2f8f Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Mon, 3 Feb 2025 09:25:38 -0800 Subject: [PATCH 13/15] uncomment my code --- src/client/common/terminal/service.ts | 16 +-- .../common/terminals/service.unit.test.ts | 122 +++++++++--------- 2 files changed, 69 insertions(+), 69 deletions(-) diff --git a/src/client/common/terminal/service.ts b/src/client/common/terminal/service.ts index 5eddf2d07fc5..0a1271d8153d 100644 --- a/src/client/common/terminal/service.ts +++ b/src/client/common/terminal/service.ts @@ -25,7 +25,7 @@ import { useEnvExtension } from '../../envExt/api.internal'; import { ensureTerminalLegacy } from '../../envExt/api.legacy'; import { sleep } from '../utils/async'; import { isWindows } from '../utils/platform'; -// import { getPythonMinorVersion } from '../../repl/replUtils'; +import { getPythonMinorVersion } from '../../repl/replUtils'; @injectable() export class TerminalService implements ITerminalService, Disposable { @@ -110,13 +110,13 @@ export class TerminalService implements ITerminalService, Disposable { const config = getConfiguration('python'); const pythonrcSetting = config.get('terminal.shellIntegration.enabled'); - // const minorVersion = this.options?.resource - // ? await getPythonMinorVersion( - // this.options.resource, - // this.serviceContainer.get(IInterpreterService), - // ) - // : undefined; - // || (minorVersion ?? 0) >= 13 + const minorVersion = this.options?.resource + ? await getPythonMinorVersion( + this.options.resource, + this.serviceContainer.get(IInterpreterService), + ) + : undefined; + || (minorVersion ?? 0) >= 13 if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows())) { // If user has explicitly disabled SI for Python, use sendText for inside Terminal REPL. diff --git a/src/test/common/terminals/service.unit.test.ts b/src/test/common/terminals/service.unit.test.ts index 8d0b441df64f..39512133f6b5 100644 --- a/src/test/common/terminals/service.unit.test.ts +++ b/src/test/common/terminals/service.unit.test.ts @@ -11,7 +11,7 @@ import { TerminalShellExecution, TerminalShellExecutionEndEvent, TerminalShellIntegration, - // Uri, + Uri, Terminal as VSCodeTerminal, WorkspaceConfiguration, } from 'vscode'; @@ -22,7 +22,7 @@ import { TerminalService } from '../../../client/common/terminal/service'; import { ITerminalActivator, ITerminalHelper, - // TerminalCreationOptions, + TerminalCreationOptions, TerminalShellType, } from '../../../client/common/terminal/types'; import { IDisposableRegistry } from '../../../client/common/types'; @@ -33,7 +33,7 @@ import * as workspaceApis from '../../../client/common/vscodeApis/workspaceApis' import * as platform from '../../../client/common/utils/platform'; import * as extapi from '../../../client/envExt/api.internal'; import { IInterpreterService } from '../../../client/interpreter/contracts'; -// import { PythonEnvironment } from '../../../client/pythonEnvironments/info'; +import { PythonEnvironment } from '../../../client/pythonEnvironments/info'; suite('Terminal Service', () => { let service: TerminalService; @@ -55,7 +55,7 @@ suite('Terminal Service', () => { let isWindowsStub: sinon.SinonStub; let useEnvExtensionStub: sinon.SinonStub; let interpreterService: TypeMoq.IMock; - // let options: TypeMoq.IMock; + let options: TypeMoq.IMock; setup(() => { useEnvExtensionStub = sinon.stub(extapi, 'useEnvExtension'); @@ -102,13 +102,13 @@ suite('Terminal Service', () => { disposables = []; mockServiceContainer = TypeMoq.Mock.ofType(); - // interpreterService = TypeMoq.Mock.ofType(); - // interpreterService - // .setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny())) - // .returns(() => Promise.resolve(({ path: 'ps' } as unknown) as PythonEnvironment)); + interpreterService = TypeMoq.Mock.ofType(); + interpreterService + .setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny())) + .returns(() => Promise.resolve(({ path: 'ps' } as unknown) as PythonEnvironment)); - // options = TypeMoq.Mock.ofType(); - // options.setup((o) => o.resource).returns(() => Uri.parse('a')); + options = TypeMoq.Mock.ofType(); + options.setup((o) => o.resource).returns(() => Uri.parse('a')); mockServiceContainer.setup((c) => c.get(ITerminalManager)).returns(() => terminalManager.object); mockServiceContainer.setup((c) => c.get(ITerminalHelper)).returns(() => terminalHelper.object); @@ -259,57 +259,57 @@ suite('Terminal Service', () => { terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.exactly(1)); }); - // test('Ensure sendText is NOT called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python < 3.13', async () => { - // isWindowsStub.returns(false); - // pythonConfig - // .setup((p) => p.get('terminal.shellIntegration.enabled')) - // .returns(() => true) - // .verifiable(TypeMoq.Times.once()); - - // terminalHelper - // .setup((helper) => helper.getEnvironmentActivationCommands(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - // .returns(() => Promise.resolve(undefined)); - // service = new TerminalService(mockServiceContainer.object); - // const textToSend = 'Some Text'; - // terminalHelper.setup((h) => h.identifyTerminalShell(TypeMoq.It.isAny())).returns(() => TerminalShellType.bash); - // terminalManager.setup((t) => t.createTerminal(TypeMoq.It.isAny())).returns(() => terminal.object); - - // service.ensureTerminal(); - // service.executeCommand(textToSend, true); - - // terminal.verify((t) => t.show(TypeMoq.It.isValue(true)), TypeMoq.Times.exactly(1)); - // terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.never()); - // }); - - // test('Ensure sendText is called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python >= 3.13', async () => { - // interpreterService.reset(); - - // interpreterService - // .setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny())) - // .returns(() => - // Promise.resolve({ path: 'yo', version: { major: 3, minor: 13, patch: 0 } } as PythonEnvironment), - // ); - - // isWindowsStub.returns(false); - // pythonConfig - // .setup((p) => p.get('terminal.shellIntegration.enabled')) - // .returns(() => true) - // .verifiable(TypeMoq.Times.once()); - - // terminalHelper - // .setup((helper) => helper.getEnvironmentActivationCommands(TypeMoq.It.isAny(), TypeMoq.It.isAny())) - // .returns(() => Promise.resolve(undefined)); - - // service = new TerminalService(mockServiceContainer.object, options.object); - // const textToSend = 'Some Text'; - // terminalHelper.setup((h) => h.identifyTerminalShell(TypeMoq.It.isAny())).returns(() => TerminalShellType.bash); - // terminalManager.setup((t) => t.createTerminal(TypeMoq.It.isAny())).returns(() => terminal.object); - - // await service.ensureTerminal(); - // await service.executeCommand(textToSend, true); - - // terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.once()); - // }); + test('Ensure sendText is NOT called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python < 3.13', async () => { + isWindowsStub.returns(false); + pythonConfig + .setup((p) => p.get('terminal.shellIntegration.enabled')) + .returns(() => true) + .verifiable(TypeMoq.Times.once()); + + terminalHelper + .setup((helper) => helper.getEnvironmentActivationCommands(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns(() => Promise.resolve(undefined)); + service = new TerminalService(mockServiceContainer.object); + const textToSend = 'Some Text'; + terminalHelper.setup((h) => h.identifyTerminalShell(TypeMoq.It.isAny())).returns(() => TerminalShellType.bash); + terminalManager.setup((t) => t.createTerminal(TypeMoq.It.isAny())).returns(() => terminal.object); + + service.ensureTerminal(); + service.executeCommand(textToSend, true); + + terminal.verify((t) => t.show(TypeMoq.It.isValue(true)), TypeMoq.Times.exactly(1)); + terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.never()); + }); + + test('Ensure sendText is called when Python shell integration and terminal shell integration are both enabled - Mac, Linux && Python >= 3.13', async () => { + interpreterService.reset(); + + interpreterService + .setup((i) => i.getActiveInterpreter(TypeMoq.It.isAny())) + .returns(() => + Promise.resolve({ path: 'yo', version: { major: 3, minor: 13, patch: 0 } } as PythonEnvironment), + ); + + isWindowsStub.returns(false); + pythonConfig + .setup((p) => p.get('terminal.shellIntegration.enabled')) + .returns(() => true) + .verifiable(TypeMoq.Times.once()); + + terminalHelper + .setup((helper) => helper.getEnvironmentActivationCommands(TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .returns(() => Promise.resolve(undefined)); + + service = new TerminalService(mockServiceContainer.object, options.object); + const textToSend = 'Some Text'; + terminalHelper.setup((h) => h.identifyTerminalShell(TypeMoq.It.isAny())).returns(() => TerminalShellType.bash); + terminalManager.setup((t) => t.createTerminal(TypeMoq.It.isAny())).returns(() => terminal.object); + + await service.ensureTerminal(); + await service.executeCommand(textToSend, true); + + terminal.verify((t) => t.sendText(TypeMoq.It.isValue(textToSend)), TypeMoq.Times.once()); + }); test('Ensure sendText IS called even when Python shell integration and terminal shell integration are both enabled - Window', async () => { isWindowsStub.returns(true); From 53c80fa14b73987ae70d3086dd8072f212813097 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Mon, 3 Feb 2025 09:27:27 -0800 Subject: [PATCH 14/15] reset interpreterService for tests --- src/test/common/terminals/service.unit.test.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/test/common/terminals/service.unit.test.ts b/src/test/common/terminals/service.unit.test.ts index 39512133f6b5..63a1cd544940 100644 --- a/src/test/common/terminals/service.unit.test.ts +++ b/src/test/common/terminals/service.unit.test.ts @@ -135,8 +135,7 @@ suite('Terminal Service', () => { } disposables.filter((item) => !!item).forEach((item) => item.dispose()); sinon.restore(); - // reset setup for interpreterService - // interpreterService.reset(); + interpreterService.reset(); }); test('Ensure terminal is disposed', async () => { From 7e5a10caf9298bd87288461dc1dfb73261b7d746 Mon Sep 17 00:00:00 2001 From: Anthony Kim Date: Mon, 3 Feb 2025 09:32:13 -0800 Subject: [PATCH 15/15] bring my code back --- src/client/common/terminal/service.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/client/common/terminal/service.ts b/src/client/common/terminal/service.ts index 0a1271d8153d..a051d66f015f 100644 --- a/src/client/common/terminal/service.ts +++ b/src/client/common/terminal/service.ts @@ -116,9 +116,8 @@ export class TerminalService implements ITerminalService, Disposable { this.serviceContainer.get(IInterpreterService), ) : undefined; - || (minorVersion ?? 0) >= 13 - if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows())) { + if ((isPythonShell && !pythonrcSetting) || (isPythonShell && isWindows()) || (minorVersion ?? 0) >= 13) { // If user has explicitly disabled SI for Python, use sendText for inside Terminal REPL. terminal.sendText(commandLine); return undefined;