From 2037cd76e1bdafda741216a24ccbc062ed73635e Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 28 Sep 2021 15:43:29 -0700 Subject: [PATCH 01/41] Add conda run command --- .../common/process/pythonEnvironment.ts | 4 +- .../common/process/pythonExecutionFactory.ts | 19 ++++++- .../pythonExecutionFactory.unit.test.ts | 53 +++++++++++++++---- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/client/common/process/pythonEnvironment.ts b/src/client/common/process/pythonEnvironment.ts index 0c4a54cc5fd5..fab6b3583cae 100644 --- a/src/client/common/process/pythonEnvironment.ts +++ b/src/client/common/process/pythonEnvironment.ts @@ -139,7 +139,7 @@ export function createCondaEnv( procs: IProcessService, fs: IFileSystem, ): PythonEnvironment { - const runArgs = ['run']; + const runArgs = ['run', '--no-capture—output']; if (condaInfo.name === '') { runArgs.push('-p', condaInfo.path); } else { @@ -153,7 +153,7 @@ export function createCondaEnv( // TODO: Use pythonArgv here once 'conda run' can be // run without buffering output. // See https://github.com/microsoft/vscode-python/issues/8473. - undefined, + pythonArgv, (file, args, opts) => procs.exec(file, args, opts), (command, opts) => procs.shellExec(command, opts), ); diff --git a/src/client/common/process/pythonExecutionFactory.ts b/src/client/common/process/pythonExecutionFactory.ts index f48a526c23bb..82c64bb03895 100644 --- a/src/client/common/process/pythonExecutionFactory.ts +++ b/src/client/common/process/pythonExecutionFactory.ts @@ -5,7 +5,7 @@ import { gte } from 'semver'; import { Uri } from 'vscode'; import { IEnvironmentActivationService } from '../../interpreter/activation/types'; -import { IComponentAdapter, ICondaService } from '../../interpreter/contracts'; +import { IComponentAdapter, ICondaService, IInterpreterService } from '../../interpreter/contracts'; import { IServiceContainer } from '../../ioc/types'; import { CondaEnvironmentInfo } from '../../pythonEnvironments/common/environmentManagers/conda'; import { sendTelemetryEvent } from '../../telemetry'; @@ -83,6 +83,15 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { } const processService: IProcessService = await this.processServiceFactory.create(options.resource); + const interpreterService = this.serviceContainer.get(IInterpreterService); + const { hasInterpreters } = interpreterService; + if (hasInterpreters()) { + const condaExecutionService = await this.createCondaExecutionService(pythonPath, processService); + if (condaExecutionService) { + return condaExecutionService; + } + } + const windowsStoreInterpreterCheck = this.pyenvs.isWindowsStoreInterpreter.bind(this.pyenvs); return createPythonService( @@ -117,6 +126,14 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { processService.on('exec', this.logger.logProcess.bind(this.logger)); this.disposables.push(processService); + // Allow parts of the code to ignore conda run. + if (!options.bypassCondaExecution) { + const condaExecutionService = await this.createCondaExecutionService(pythonPath, processService); + if (condaExecutionService) { + return condaExecutionService; + } + } + return createPythonService(pythonPath, processService, this.fileSystem); } diff --git a/src/test/common/process/pythonExecutionFactory.unit.test.ts b/src/test/common/process/pythonExecutionFactory.unit.test.ts index b32b116bb6c1..6645dfe6cdb1 100644 --- a/src/test/common/process/pythonExecutionFactory.unit.test.ts +++ b/src/test/common/process/pythonExecutionFactory.unit.test.ts @@ -257,9 +257,46 @@ suite('Process - PythonExecutionFactory', () => { assert.equal(createInvoked, false); }); - test('Ensure `create` returns a CondaExecutionService instance if createCondaExecutionService() returns a valid object', async function () { - return this.skip(); + test("Ensure `create` returns a WindowsStorePythonProcess instance if it's a windows store intepreter path and we're in the discovery experiment", async () => { + const pythonPath = 'path/to/python'; + const pythonSettings = mock(PythonSettings); + + when(processFactory.create(resource)).thenResolve(processService.object); + when(pythonSettings.pythonPath).thenReturn(pythonPath); + when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); + inDiscoveryExperimentStub.resolves(true); + + const service = await factory.create({ resource }); + + expect(service).to.not.equal(undefined); + verify(processFactory.create(resource)).once(); + verify(pythonSettings.pythonPath).once(); + verify(pyenvs.isWindowsStoreInterpreter(pythonPath)).once(); + sinon.assert.calledOnce(inDiscoveryExperimentStub); + sinon.assert.notCalled(isWindowsStoreInterpreterStub); + }); + + test("Ensure `create` returns a WindowsStorePythonProcess instance if it's a windows store intepreter path and we're not in the discovery experiment", async () => { + const pythonPath = 'path/to/python'; + const pythonSettings = mock(PythonSettings); + + when(processFactory.create(resource)).thenResolve(processService.object); + when(pythonSettings.pythonPath).thenReturn(pythonPath); + when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); + inDiscoveryExperimentStub.resolves(false); + + const service = await factory.create({ resource }); + expect(service).to.not.equal(undefined); + verify(processFactory.create(resource)).once(); + verify(pythonSettings.pythonPath).once(); + verify(pyenvs.isWindowsStoreInterpreter(pythonPath)).never(); + sinon.assert.calledOnce(inDiscoveryExperimentStub); + sinon.assert.calledOnce(isWindowsStoreInterpreterStub); + sinon.assert.calledWith(isWindowsStoreInterpreterStub, pythonPath); + }); + + test('Ensure `create` returns a CondaExecutionService instance if createCondaExecutionService() returns a valid object', async () => { const pythonPath = 'path/to/python'; const pythonSettings = mock(PythonSettings); @@ -284,9 +321,7 @@ suite('Process - PythonExecutionFactory', () => { verify(condaService.getCondaFile()).once(); }); - test('Ensure `create` returns a PythonExecutionService instance if createCondaExecutionService() returns undefined', async function () { - return this.skip(); - + test('Ensure `create` returns a PythonExecutionService instance if createCondaExecutionService() returns undefined', async () => { const pythonPath = 'path/to/python'; const pythonSettings = mock(PythonSettings); when(processFactory.create(resource)).thenResolve(processService.object); @@ -305,9 +340,7 @@ suite('Process - PythonExecutionFactory', () => { verify(condaService.getCondaFile()).once(); }); - test('Ensure `createActivatedEnvironment` returns a CondaExecutionService instance if createCondaExecutionService() returns a valid object', async function () { - return this.skip(); - + test('Ensure `createActivatedEnvironment` returns a CondaExecutionService instance if createCondaExecutionService() returns a valid object', async () => { const pythonPath = 'path/to/python'; const pythonSettings = mock(PythonSettings); @@ -336,9 +369,7 @@ suite('Process - PythonExecutionFactory', () => { } }); - test('Ensure `createActivatedEnvironment` returns a PythonExecutionService instance if createCondaExecutionService() returns undefined', async function () { - return this.skip(); - + test('Ensure `createActivatedEnvironment` returns a PythonExecutionService instance if createCondaExecutionService() returns undefined', async () => { let createInvoked = false; const pythonPath = 'path/to/python'; const mockExecService = 'mockService'; From d6b57dc3b4cf22274cefe3ad8c72392f9c71c4b7 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 20 Oct 2021 17:03:37 -0700 Subject: [PATCH 02/41] Fix code run --- src/client/common/process/pythonEnvironment.ts | 4 ++-- src/client/common/process/pythonExecutionFactory.ts | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/client/common/process/pythonEnvironment.ts b/src/client/common/process/pythonEnvironment.ts index fab6b3583cae..3cbd5e82c876 100644 --- a/src/client/common/process/pythonEnvironment.ts +++ b/src/client/common/process/pythonEnvironment.ts @@ -139,13 +139,13 @@ export function createCondaEnv( procs: IProcessService, fs: IFileSystem, ): PythonEnvironment { - const runArgs = ['run', '--no-capture—output']; + const runArgs = ['run']; if (condaInfo.name === '') { runArgs.push('-p', condaInfo.path); } else { runArgs.push('-n', condaInfo.name); } - const pythonArgv = [condaFile, ...runArgs, 'python']; + const pythonArgv = [condaFile, ...runArgs, '--no-capture-output', 'python']; const deps = createDeps( async (filename) => fs.pathExists(filename), pythonArgv, diff --git a/src/client/common/process/pythonExecutionFactory.ts b/src/client/common/process/pythonExecutionFactory.ts index 82c64bb03895..92fb5116428b 100644 --- a/src/client/common/process/pythonExecutionFactory.ts +++ b/src/client/common/process/pythonExecutionFactory.ts @@ -84,8 +84,8 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { const processService: IProcessService = await this.processServiceFactory.create(options.resource); const interpreterService = this.serviceContainer.get(IInterpreterService); - const { hasInterpreters } = interpreterService; - if (hasInterpreters()) { + const hasInterpreters = await interpreterService.hasInterpreters(); + if (hasInterpreters) { const condaExecutionService = await this.createCondaExecutionService(pythonPath, processService); if (condaExecutionService) { return condaExecutionService; @@ -161,6 +161,7 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { procService.on('exec', this.logger.logProcess.bind(this.logger)); this.disposables.push(procService); } + return createPythonService( pythonPath, procService, From 41112101f2c5e75ddd470e6e18422f7b9b7cc549 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 3 Nov 2021 15:30:34 -0500 Subject: [PATCH 03/41] Fix linting --- src/client/linters/flake8.ts | 2 +- src/client/linters/pycodestyle.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/linters/flake8.ts b/src/client/linters/flake8.ts index 71456d9e0eb2..be58d88e3697 100644 --- a/src/client/linters/flake8.ts +++ b/src/client/linters/flake8.ts @@ -14,7 +14,7 @@ export class Flake8 extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ['--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', document.uri.fsPath], + ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", document.uri.fsPath], document, cancellation, ); diff --git a/src/client/linters/pycodestyle.ts b/src/client/linters/pycodestyle.ts index 0a7066df9cb2..05da641b67fb 100644 --- a/src/client/linters/pycodestyle.ts +++ b/src/client/linters/pycodestyle.ts @@ -14,7 +14,7 @@ export class Pycodestyle extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ['--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', document.uri.fsPath], + ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", document.uri.fsPath], document, cancellation, ); From e21243cee63e61adf542767fb2c9e3a5c4d7af43 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 9 Nov 2021 12:47:37 -0500 Subject: [PATCH 04/41] Fix tests --- .../pythonExecutionFactory.unit.test.ts | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/src/test/common/process/pythonExecutionFactory.unit.test.ts b/src/test/common/process/pythonExecutionFactory.unit.test.ts index 6645dfe6cdb1..58cac7ae35d5 100644 --- a/src/test/common/process/pythonExecutionFactory.unit.test.ts +++ b/src/test/common/process/pythonExecutionFactory.unit.test.ts @@ -257,45 +257,6 @@ suite('Process - PythonExecutionFactory', () => { assert.equal(createInvoked, false); }); - test("Ensure `create` returns a WindowsStorePythonProcess instance if it's a windows store intepreter path and we're in the discovery experiment", async () => { - const pythonPath = 'path/to/python'; - const pythonSettings = mock(PythonSettings); - - when(processFactory.create(resource)).thenResolve(processService.object); - when(pythonSettings.pythonPath).thenReturn(pythonPath); - when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); - inDiscoveryExperimentStub.resolves(true); - - const service = await factory.create({ resource }); - - expect(service).to.not.equal(undefined); - verify(processFactory.create(resource)).once(); - verify(pythonSettings.pythonPath).once(); - verify(pyenvs.isWindowsStoreInterpreter(pythonPath)).once(); - sinon.assert.calledOnce(inDiscoveryExperimentStub); - sinon.assert.notCalled(isWindowsStoreInterpreterStub); - }); - - test("Ensure `create` returns a WindowsStorePythonProcess instance if it's a windows store intepreter path and we're not in the discovery experiment", async () => { - const pythonPath = 'path/to/python'; - const pythonSettings = mock(PythonSettings); - - when(processFactory.create(resource)).thenResolve(processService.object); - when(pythonSettings.pythonPath).thenReturn(pythonPath); - when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); - inDiscoveryExperimentStub.resolves(false); - - const service = await factory.create({ resource }); - - expect(service).to.not.equal(undefined); - verify(processFactory.create(resource)).once(); - verify(pythonSettings.pythonPath).once(); - verify(pyenvs.isWindowsStoreInterpreter(pythonPath)).never(); - sinon.assert.calledOnce(inDiscoveryExperimentStub); - sinon.assert.calledOnce(isWindowsStoreInterpreterStub); - sinon.assert.calledWith(isWindowsStoreInterpreterStub, pythonPath); - }); - test('Ensure `create` returns a CondaExecutionService instance if createCondaExecutionService() returns a valid object', async () => { const pythonPath = 'path/to/python'; const pythonSettings = mock(PythonSettings); From 0ca6cfc02d4864ea948a6a5cbbee268a300af619 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 9 Nov 2021 12:58:01 -0500 Subject: [PATCH 05/41] Add news --- news/1 Enhancements/7696.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/1 Enhancements/7696.md diff --git a/news/1 Enhancements/7696.md b/news/1 Enhancements/7696.md new file mode 100644 index 000000000000..0d556b80c7cb --- /dev/null +++ b/news/1 Enhancements/7696.md @@ -0,0 +1 @@ +Add suport for conda run withput output, using --no-capture-output. From efe6155185683f307e35cb01475f402de6556026 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 10 Nov 2021 13:06:02 -0500 Subject: [PATCH 06/41] Fix tests in linter --- src/test/linters/lint.args.test.ts | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/test/linters/lint.args.test.ts b/src/test/linters/lint.args.test.ts index e398818db031..364eb0e421db 100644 --- a/src/test/linters/lint.args.test.ts +++ b/src/test/linters/lint.args.test.ts @@ -152,12 +152,18 @@ suite('Linting - Arguments', () => { } test('Flake8', async () => { const linter = new Flake8(outputChannel.object, serviceContainer); - const expectedArgs = ['--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; + const expectedArgs = [ + "'--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", + fileUri.fsPath, + ]; await testLinter(linter, expectedArgs); }); test('Pycodestyle', async () => { const linter = new Pycodestyle(outputChannel.object, serviceContainer); - const expectedArgs = ['--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; + const expectedArgs = [ + "'--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", + fileUri.fsPath, + ]; await testLinter(linter, expectedArgs); }); test('Prospector', async () => { From 0bd6ddbf17108f5205feb229290524ba7d4f962b Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Mon, 22 Nov 2021 15:58:26 -0800 Subject: [PATCH 07/41] Fix strings --- src/client/common/process/pythonEnvironment.ts | 4 ---- src/client/linters/flake8.ts | 2 +- src/client/linters/pycodestyle.ts | 2 +- src/client/linters/pylint.ts | 2 +- src/test/linters/lint.args.test.ts | 4 ++-- src/test/linters/pylint.unit.test.ts | 2 +- 6 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/client/common/process/pythonEnvironment.ts b/src/client/common/process/pythonEnvironment.ts index 3cbd5e82c876..14828b9fd120 100644 --- a/src/client/common/process/pythonEnvironment.ts +++ b/src/client/common/process/pythonEnvironment.ts @@ -149,10 +149,6 @@ export function createCondaEnv( const deps = createDeps( async (filename) => fs.pathExists(filename), pythonArgv, - - // TODO: Use pythonArgv here once 'conda run' can be - // run without buffering output. - // See https://github.com/microsoft/vscode-python/issues/8473. pythonArgv, (file, args, opts) => procs.exec(file, args, opts), (command, opts) => procs.shellExec(command, opts), diff --git a/src/client/linters/flake8.ts b/src/client/linters/flake8.ts index be58d88e3697..d2103de88096 100644 --- a/src/client/linters/flake8.ts +++ b/src/client/linters/flake8.ts @@ -14,7 +14,7 @@ export class Flake8 extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", document.uri.fsPath], + ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", document.uri.fsPath], document, cancellation, ); diff --git a/src/client/linters/pycodestyle.ts b/src/client/linters/pycodestyle.ts index 05da641b67fb..cdfe03520b97 100644 --- a/src/client/linters/pycodestyle.ts +++ b/src/client/linters/pycodestyle.ts @@ -14,7 +14,7 @@ export class Pycodestyle extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", document.uri.fsPath], + ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", document.uri.fsPath], document, cancellation, ); diff --git a/src/client/linters/pylint.ts b/src/client/linters/pylint.ts index 10a213c2d631..3d92af94234f 100644 --- a/src/client/linters/pylint.ts +++ b/src/client/linters/pylint.ts @@ -19,7 +19,7 @@ export class Pylint extends BaseLinter { const uri = document.uri; const settings = this.configService.getSettings(uri); const args = [ - "--msg-template='{line},{column},{category},{symbol}:{msg}'", + "--msg-template='{line},{column},{category},{symbol}:{msg}''", '--reports=n', '--output-format=text', uri.fsPath, diff --git a/src/test/linters/lint.args.test.ts b/src/test/linters/lint.args.test.ts index 364eb0e421db..dce5113ea96f 100644 --- a/src/test/linters/lint.args.test.ts +++ b/src/test/linters/lint.args.test.ts @@ -153,7 +153,7 @@ suite('Linting - Arguments', () => { test('Flake8', async () => { const linter = new Flake8(outputChannel.object, serviceContainer); const expectedArgs = [ - "'--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", + "--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", fileUri.fsPath, ]; await testLinter(linter, expectedArgs); @@ -161,7 +161,7 @@ suite('Linting - Arguments', () => { test('Pycodestyle', async () => { const linter = new Pycodestyle(outputChannel.object, serviceContainer); const expectedArgs = [ - "'--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", + "--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", fileUri.fsPath, ]; await testLinter(linter, expectedArgs); diff --git a/src/test/linters/pylint.unit.test.ts b/src/test/linters/pylint.unit.test.ts index 46321f9787e2..ebea2cc525cc 100644 --- a/src/test/linters/pylint.unit.test.ts +++ b/src/test/linters/pylint.unit.test.ts @@ -28,7 +28,7 @@ suite('Pylint - Function runLinter()', () => { uri: vscode.Uri.file('path/to/doc'), }; const args = [ - "--msg-template='{line},{column},{category},{symbol}:{msg}'", + "--msg-template='{line},{column},{category},{symbol}:{msg}''", '--reports=n', '--output-format=text', doc.uri.fsPath, From d2944bdd704a04f0b52f84b4ee9ea83762251b9e Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Mon, 22 Nov 2021 17:49:14 -0800 Subject: [PATCH 08/41] Fix linters --- src/client/linters/flake8.ts | 2 +- src/client/linters/pycodestyle.ts | 2 +- src/client/linters/pylint.ts | 2 +- src/test/linters/lint.args.test.ts | 10 ++-------- src/test/linters/pylint.unit.test.ts | 2 +- 5 files changed, 6 insertions(+), 12 deletions(-) diff --git a/src/client/linters/flake8.ts b/src/client/linters/flake8.ts index d2103de88096..ebb76d07ca05 100644 --- a/src/client/linters/flake8.ts +++ b/src/client/linters/flake8.ts @@ -14,7 +14,7 @@ export class Flake8 extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", document.uri.fsPath], + ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', document.uri.fsPath], document, cancellation, ); diff --git a/src/client/linters/pycodestyle.ts b/src/client/linters/pycodestyle.ts index cdfe03520b97..4f2676874d2b 100644 --- a/src/client/linters/pycodestyle.ts +++ b/src/client/linters/pycodestyle.ts @@ -14,7 +14,7 @@ export class Pycodestyle extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", document.uri.fsPath], + ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', document.uri.fsPath], document, cancellation, ); diff --git a/src/client/linters/pylint.ts b/src/client/linters/pylint.ts index 3d92af94234f..acf4b4eac40a 100644 --- a/src/client/linters/pylint.ts +++ b/src/client/linters/pylint.ts @@ -19,7 +19,7 @@ export class Pylint extends BaseLinter { const uri = document.uri; const settings = this.configService.getSettings(uri); const args = [ - "--msg-template='{line},{column},{category},{symbol}:{msg}''", + '--msg-template={line},{column},{category},{symbol}:{msg}', '--reports=n', '--output-format=text', uri.fsPath, diff --git a/src/test/linters/lint.args.test.ts b/src/test/linters/lint.args.test.ts index dce5113ea96f..af35977a6138 100644 --- a/src/test/linters/lint.args.test.ts +++ b/src/test/linters/lint.args.test.ts @@ -152,18 +152,12 @@ suite('Linting - Arguments', () => { } test('Flake8', async () => { const linter = new Flake8(outputChannel.object, serviceContainer); - const expectedArgs = [ - "--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", - fileUri.fsPath, - ]; + const expectedArgs = ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; await testLinter(linter, expectedArgs); }); test('Pycodestyle', async () => { const linter = new Pycodestyle(outputChannel.object, serviceContainer); - const expectedArgs = [ - "--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", - fileUri.fsPath, - ]; + const expectedArgs = ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; await testLinter(linter, expectedArgs); }); test('Prospector', async () => { diff --git a/src/test/linters/pylint.unit.test.ts b/src/test/linters/pylint.unit.test.ts index ebea2cc525cc..a6ddaea3ca50 100644 --- a/src/test/linters/pylint.unit.test.ts +++ b/src/test/linters/pylint.unit.test.ts @@ -28,7 +28,7 @@ suite('Pylint - Function runLinter()', () => { uri: vscode.Uri.file('path/to/doc'), }; const args = [ - "--msg-template='{line},{column},{category},{symbol}:{msg}''", + '--msg-template={line},{column},{category},{symbol}:{msg}', '--reports=n', '--output-format=text', doc.uri.fsPath, From 11680ae23345dafb3efdfe54c6c9f8a37fbba4ee Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Mon, 22 Nov 2021 20:11:04 -0800 Subject: [PATCH 09/41] Fix conda run unit test --- .../process/pythonEnvironment.unit.test.ts | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/test/common/process/pythonEnvironment.unit.test.ts b/src/test/common/process/pythonEnvironment.unit.test.ts index cd28544b576d..6f414a1e88fd 100644 --- a/src/test/common/process/pythonEnvironment.unit.test.ts +++ b/src/test/common/process/pythonEnvironment.unit.test.ts @@ -271,8 +271,8 @@ suite('CondaEnvironment', () => { expect(result).to.deep.equal({ command: condaFile, - args: ['run', '-n', condaInfo.name, 'python', ...args], - python: [condaFile, 'run', '-n', condaInfo.name, 'python'], + args: ['run', '-n', condaInfo.name, '--no-capture-output', 'python', ...args], + python: [condaFile, 'run', '-n', condaInfo.name, '--no-capture-output', 'python'], pythonExecutable: 'python', }); }); @@ -285,15 +285,20 @@ suite('CondaEnvironment', () => { expect(result).to.deep.equal({ command: condaFile, - args: ['run', '-p', condaInfo.path, 'python', ...args], - python: [condaFile, 'run', '-p', condaInfo.path, 'python'], + args: ['run', '-p', condaInfo.path, '--no-capture-output', 'python', ...args], + python: [condaFile, 'run', '-p', condaInfo.path, '--no-capture-output', 'python'], pythonExecutable: 'python', }); }); - test('getExecutionObservableInfo with a named environment should return execution info using pythonPath only', () => { - const expected = { command: pythonPath, args, python: [pythonPath], pythonExecutable: pythonPath }; + test('getExecutionObservableInfo with a named environment should return execution info using conda full path with the name', () => { const condaInfo = { name: 'foo', path: 'bar' }; + const expected = { + command: condaFile, + args: ['run', '-n', condaInfo.name, '--no-capture-output', 'python', ...args], + python: [condaFile, 'run', '-n', condaInfo.name, '--no-capture-output', 'python'], + pythonExecutable: 'python', + }; const env = createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); const result = env.getExecutionObservableInfo(args); @@ -301,9 +306,14 @@ suite('CondaEnvironment', () => { expect(result).to.deep.equal(expected); }); - test('getExecutionObservableInfo with a non-named environment should return execution info using pythonPath only', () => { - const expected = { command: pythonPath, args, python: [pythonPath], pythonExecutable: pythonPath }; + test('getExecutionObservableInfo with a non-named environment should return execution info using conda full path', () => { const condaInfo = { name: '', path: 'bar' }; + const expected = { + command: condaFile, + args: ['run', '-p', condaInfo.path, '--no-capture-output', 'python', ...args], + python: [condaFile, 'run', '-p', condaInfo.path, '--no-capture-output', 'python'], + pythonExecutable: 'python', + }; const env = createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); const result = env.getExecutionObservableInfo(args); From 3c2ae1caae29655d10696dd53fd251bcf5ee9557 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 24 Nov 2021 17:35:32 -0800 Subject: [PATCH 10/41] Fix funtional tests --- src/test/linters/lint.functional.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/linters/lint.functional.test.ts b/src/test/linters/lint.functional.test.ts index 165aa1f3967d..7a1d94117718 100644 --- a/src/test/linters/lint.functional.test.ts +++ b/src/test/linters/lint.functional.test.ts @@ -625,6 +625,11 @@ class TestFixture extends BaseTestFixture { const serviceContainer = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); const configService = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); const processLogger = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); + const componentAdapter = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); + componentAdapter + .setup((c) => c.getCondaEnvironment(TypeMoq.It.isAny())) + .returns(() => Promise.resolve(undefined)); + const filesystem = new FileSystem(); processLogger .setup((p) => p.logProcess(TypeMoq.It.isAnyString(), TypeMoq.It.isAny(), TypeMoq.It.isAny())) @@ -637,6 +642,9 @@ class TestFixture extends BaseTestFixture { serviceContainer .setup((s) => s.get(TypeMoq.It.isValue(IFileSystem), TypeMoq.It.isAny())) .returns(() => filesystem); + serviceContainer + .setup((s) => s.get(TypeMoq.It.isValue(IComponentAdapter), TypeMoq.It.isAny())) + .returns(() => componentAdapter.object); const platformService = new PlatformService(); From bc2713cdf40df681a909a0ccb86431849f8eddce Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Mon, 29 Nov 2021 12:37:11 -0800 Subject: [PATCH 11/41] Fix single workspace tests --- src/client/pythonEnvironments/legacyIOC.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/pythonEnvironments/legacyIOC.ts b/src/client/pythonEnvironments/legacyIOC.ts index 2dc63c60bfee..dba021b6996f 100644 --- a/src/client/pythonEnvironments/legacyIOC.ts +++ b/src/client/pythonEnvironments/legacyIOC.ts @@ -227,14 +227,14 @@ class ComponentAdapter implements IComponentAdapter { } } }); - const initialEnvs = this.api.getEnvs(); + const initialEnvs = this.api.getEnvs() || []; if (initialEnvs.length > 0) { return true; } // We should already have initiated discovery. Wait for an env to be added // to the collection until the refresh has finished. await Promise.race([onAddedToCollection.promise, this.api.refreshPromise]); - const envs = await asyncFilter(this.api.getEnvs(), (e) => filter(convertEnvInfo(e))); + const envs = await asyncFilter(this.api.getEnvs() || [], (e) => filter(convertEnvInfo(e))); return envs.length > 0; } From e8791164e85f3970e37d8461fde6cf86b109b11d Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 7 Dec 2021 12:18:52 -0800 Subject: [PATCH 12/41] update minimum conda versionvalue --- src/client/common/process/pythonExecutionFactory.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/client/common/process/pythonExecutionFactory.ts b/src/client/common/process/pythonExecutionFactory.ts index 92fb5116428b..dd63e3387280 100644 --- a/src/client/common/process/pythonExecutionFactory.ts +++ b/src/client/common/process/pythonExecutionFactory.ts @@ -29,8 +29,8 @@ import { IInterpreterAutoSelectionService } from '../../interpreter/autoSelectio import { sleep } from '../utils/async'; import { traceError } from '../../logging'; -// Minimum version number of conda required to be able to use 'conda run' -export const CONDA_RUN_VERSION = '4.6.0'; +// Minimum version number of conda required to be able to use 'conda run' and '--no-capture--output' option +export const CONDA_RUN_VERSION = '4.9.0'; @injectable() export class PythonExecutionFactory implements IPythonExecutionFactory { @@ -137,8 +137,6 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { return createPythonService(pythonPath, processService, this.fileSystem); } - // Not using this function for now because there are breaking issues with conda run (conda 4.8, PVSC 2020.1). - // See https://github.com/microsoft/vscode-python/issues/9490 public async createCondaExecutionService( pythonPath: string, processService?: IProcessService, From 5ce2665c8c6c5fc8a5b0ef841ef9dde4b0bcf937 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 7 Dec 2021 13:54:21 -0800 Subject: [PATCH 13/41] Change sorting timeput --- src/test/format/extension.sort.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/format/extension.sort.test.ts b/src/test/format/extension.sort.test.ts index e9c04ca55da5..44586d53c081 100644 --- a/src/test/format/extension.sort.test.ts +++ b/src/test/format/extension.sort.test.ts @@ -107,7 +107,7 @@ suite('Sorting', () => { await window.showTextDocument(textDocument); await commands.executeCommand(Commands.Sort_Imports); assert.notEqual(originalContent, textDocument.getText(), 'Contents have not changed'); - }); + }).timeout(TEST_TIMEOUT * 3); test('With Config', async () => { const textDocument = await workspace.openTextDocument(fileToFormatWithConfig); From 619a9b7eb77fc2b2b5f6df11511d288b77fb378e Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 7 Dec 2021 15:10:27 -0800 Subject: [PATCH 14/41] Add timeout time in sorting test --- src/test/format/extension.sort.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/format/extension.sort.test.ts b/src/test/format/extension.sort.test.ts index 44586d53c081..e9c5b94feb88 100644 --- a/src/test/format/extension.sort.test.ts +++ b/src/test/format/extension.sort.test.ts @@ -130,7 +130,7 @@ suite('Sorting', () => { await window.showTextDocument(textDocument); await commands.executeCommand(Commands.Sort_Imports); assert.notEqual(originalContent, textDocument.getText(), 'Contents have not changed'); - }); + }).timeout(TEST_TIMEOUT * 3); test('With Changes and Config in Args', async () => { await updateSetting( @@ -164,7 +164,7 @@ suite('Sorting', () => { const originalContent = textDocument.getText(); await commands.executeCommand(Commands.Sort_Imports); assert.notEqual(originalContent, textDocument.getText(), 'Contents have not changed'); - }).timeout(TEST_TIMEOUT * 2); + }).timeout(TEST_TIMEOUT * 3); test('With Changes and Config implicit from cwd', async () => { const textDocument = await workspace.openTextDocument(fileToFormatWithConfig); From 2c4d9d4178c65640c87ed9e3f9b235bab7f37734 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 7 Dec 2021 17:47:36 -0800 Subject: [PATCH 15/41] Fix test wothout config --- src/test/format/extension.sort.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/format/extension.sort.test.ts b/src/test/format/extension.sort.test.ts index e9c5b94feb88..0b51dd1e5cec 100644 --- a/src/test/format/extension.sort.test.ts +++ b/src/test/format/extension.sort.test.ts @@ -107,7 +107,7 @@ suite('Sorting', () => { await window.showTextDocument(textDocument); await commands.executeCommand(Commands.Sort_Imports); assert.notEqual(originalContent, textDocument.getText(), 'Contents have not changed'); - }).timeout(TEST_TIMEOUT * 3); + }).timeout(TEST_TIMEOUT * 2); test('With Config', async () => { const textDocument = await workspace.openTextDocument(fileToFormatWithConfig); From 2fdcb6a03b423ed0373195b96b178c56000676cc Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 8 Dec 2021 16:27:52 -0800 Subject: [PATCH 16/41] Add more time to timeout in sorting tests --- src/test/format/extension.sort.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/format/extension.sort.test.ts b/src/test/format/extension.sort.test.ts index 0b51dd1e5cec..e9c5b94feb88 100644 --- a/src/test/format/extension.sort.test.ts +++ b/src/test/format/extension.sort.test.ts @@ -107,7 +107,7 @@ suite('Sorting', () => { await window.showTextDocument(textDocument); await commands.executeCommand(Commands.Sort_Imports); assert.notEqual(originalContent, textDocument.getText(), 'Contents have not changed'); - }).timeout(TEST_TIMEOUT * 2); + }).timeout(TEST_TIMEOUT * 3); test('With Config', async () => { const textDocument = await workspace.openTextDocument(fileToFormatWithConfig); From 355179c7bd61b978706d0cee06b8c016fd4a4033 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 28 Sep 2021 15:43:29 -0700 Subject: [PATCH 17/41] Add conda run command --- .../common/process/pythonEnvironment.ts | 4 +- .../common/process/pythonExecutionFactory.ts | 19 ++++++- .../pythonExecutionFactory.unit.test.ts | 53 +++++++++++++++---- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/src/client/common/process/pythonEnvironment.ts b/src/client/common/process/pythonEnvironment.ts index 0c4a54cc5fd5..fab6b3583cae 100644 --- a/src/client/common/process/pythonEnvironment.ts +++ b/src/client/common/process/pythonEnvironment.ts @@ -139,7 +139,7 @@ export function createCondaEnv( procs: IProcessService, fs: IFileSystem, ): PythonEnvironment { - const runArgs = ['run']; + const runArgs = ['run', '--no-capture—output']; if (condaInfo.name === '') { runArgs.push('-p', condaInfo.path); } else { @@ -153,7 +153,7 @@ export function createCondaEnv( // TODO: Use pythonArgv here once 'conda run' can be // run without buffering output. // See https://github.com/microsoft/vscode-python/issues/8473. - undefined, + pythonArgv, (file, args, opts) => procs.exec(file, args, opts), (command, opts) => procs.shellExec(command, opts), ); diff --git a/src/client/common/process/pythonExecutionFactory.ts b/src/client/common/process/pythonExecutionFactory.ts index f48a526c23bb..82c64bb03895 100644 --- a/src/client/common/process/pythonExecutionFactory.ts +++ b/src/client/common/process/pythonExecutionFactory.ts @@ -5,7 +5,7 @@ import { gte } from 'semver'; import { Uri } from 'vscode'; import { IEnvironmentActivationService } from '../../interpreter/activation/types'; -import { IComponentAdapter, ICondaService } from '../../interpreter/contracts'; +import { IComponentAdapter, ICondaService, IInterpreterService } from '../../interpreter/contracts'; import { IServiceContainer } from '../../ioc/types'; import { CondaEnvironmentInfo } from '../../pythonEnvironments/common/environmentManagers/conda'; import { sendTelemetryEvent } from '../../telemetry'; @@ -83,6 +83,15 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { } const processService: IProcessService = await this.processServiceFactory.create(options.resource); + const interpreterService = this.serviceContainer.get(IInterpreterService); + const { hasInterpreters } = interpreterService; + if (hasInterpreters()) { + const condaExecutionService = await this.createCondaExecutionService(pythonPath, processService); + if (condaExecutionService) { + return condaExecutionService; + } + } + const windowsStoreInterpreterCheck = this.pyenvs.isWindowsStoreInterpreter.bind(this.pyenvs); return createPythonService( @@ -117,6 +126,14 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { processService.on('exec', this.logger.logProcess.bind(this.logger)); this.disposables.push(processService); + // Allow parts of the code to ignore conda run. + if (!options.bypassCondaExecution) { + const condaExecutionService = await this.createCondaExecutionService(pythonPath, processService); + if (condaExecutionService) { + return condaExecutionService; + } + } + return createPythonService(pythonPath, processService, this.fileSystem); } diff --git a/src/test/common/process/pythonExecutionFactory.unit.test.ts b/src/test/common/process/pythonExecutionFactory.unit.test.ts index 4177bbc5837c..c7f9241df1fb 100644 --- a/src/test/common/process/pythonExecutionFactory.unit.test.ts +++ b/src/test/common/process/pythonExecutionFactory.unit.test.ts @@ -257,9 +257,46 @@ suite('Process - PythonExecutionFactory', () => { assert.strictEqual(createInvoked, false); }); - test('Ensure `create` returns a CondaExecutionService instance if createCondaExecutionService() returns a valid object', async function () { - return this.skip(); + test("Ensure `create` returns a WindowsStorePythonProcess instance if it's a windows store intepreter path and we're in the discovery experiment", async () => { + const pythonPath = 'path/to/python'; + const pythonSettings = mock(PythonSettings); + + when(processFactory.create(resource)).thenResolve(processService.object); + when(pythonSettings.pythonPath).thenReturn(pythonPath); + when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); + inDiscoveryExperimentStub.resolves(true); + + const service = await factory.create({ resource }); + + expect(service).to.not.equal(undefined); + verify(processFactory.create(resource)).once(); + verify(pythonSettings.pythonPath).once(); + verify(pyenvs.isWindowsStoreInterpreter(pythonPath)).once(); + sinon.assert.calledOnce(inDiscoveryExperimentStub); + sinon.assert.notCalled(isWindowsStoreInterpreterStub); + }); + + test("Ensure `create` returns a WindowsStorePythonProcess instance if it's a windows store intepreter path and we're not in the discovery experiment", async () => { + const pythonPath = 'path/to/python'; + const pythonSettings = mock(PythonSettings); + + when(processFactory.create(resource)).thenResolve(processService.object); + when(pythonSettings.pythonPath).thenReturn(pythonPath); + when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); + inDiscoveryExperimentStub.resolves(false); + + const service = await factory.create({ resource }); + expect(service).to.not.equal(undefined); + verify(processFactory.create(resource)).once(); + verify(pythonSettings.pythonPath).once(); + verify(pyenvs.isWindowsStoreInterpreter(pythonPath)).never(); + sinon.assert.calledOnce(inDiscoveryExperimentStub); + sinon.assert.calledOnce(isWindowsStoreInterpreterStub); + sinon.assert.calledWith(isWindowsStoreInterpreterStub, pythonPath); + }); + + test('Ensure `create` returns a CondaExecutionService instance if createCondaExecutionService() returns a valid object', async () => { const pythonPath = 'path/to/python'; const pythonSettings = mock(PythonSettings); @@ -284,9 +321,7 @@ suite('Process - PythonExecutionFactory', () => { verify(condaService.getCondaFile()).once(); }); - test('Ensure `create` returns a PythonExecutionService instance if createCondaExecutionService() returns undefined', async function () { - return this.skip(); - + test('Ensure `create` returns a PythonExecutionService instance if createCondaExecutionService() returns undefined', async () => { const pythonPath = 'path/to/python'; const pythonSettings = mock(PythonSettings); when(processFactory.create(resource)).thenResolve(processService.object); @@ -305,9 +340,7 @@ suite('Process - PythonExecutionFactory', () => { verify(condaService.getCondaFile()).once(); }); - test('Ensure `createActivatedEnvironment` returns a CondaExecutionService instance if createCondaExecutionService() returns a valid object', async function () { - return this.skip(); - + test('Ensure `createActivatedEnvironment` returns a CondaExecutionService instance if createCondaExecutionService() returns a valid object', async () => { const pythonPath = 'path/to/python'; const pythonSettings = mock(PythonSettings); @@ -336,9 +369,7 @@ suite('Process - PythonExecutionFactory', () => { } }); - test('Ensure `createActivatedEnvironment` returns a PythonExecutionService instance if createCondaExecutionService() returns undefined', async function () { - return this.skip(); - + test('Ensure `createActivatedEnvironment` returns a PythonExecutionService instance if createCondaExecutionService() returns undefined', async () => { let createInvoked = false; const pythonPath = 'path/to/python'; const mockExecService = 'mockService'; From caf5ada24b67a88e520e71a911af8a8cf9a01262 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 20 Oct 2021 17:03:37 -0700 Subject: [PATCH 18/41] Fix code run --- src/client/common/process/pythonEnvironment.ts | 4 ++-- src/client/common/process/pythonExecutionFactory.ts | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/client/common/process/pythonEnvironment.ts b/src/client/common/process/pythonEnvironment.ts index fab6b3583cae..3cbd5e82c876 100644 --- a/src/client/common/process/pythonEnvironment.ts +++ b/src/client/common/process/pythonEnvironment.ts @@ -139,13 +139,13 @@ export function createCondaEnv( procs: IProcessService, fs: IFileSystem, ): PythonEnvironment { - const runArgs = ['run', '--no-capture—output']; + const runArgs = ['run']; if (condaInfo.name === '') { runArgs.push('-p', condaInfo.path); } else { runArgs.push('-n', condaInfo.name); } - const pythonArgv = [condaFile, ...runArgs, 'python']; + const pythonArgv = [condaFile, ...runArgs, '--no-capture-output', 'python']; const deps = createDeps( async (filename) => fs.pathExists(filename), pythonArgv, diff --git a/src/client/common/process/pythonExecutionFactory.ts b/src/client/common/process/pythonExecutionFactory.ts index 82c64bb03895..92fb5116428b 100644 --- a/src/client/common/process/pythonExecutionFactory.ts +++ b/src/client/common/process/pythonExecutionFactory.ts @@ -84,8 +84,8 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { const processService: IProcessService = await this.processServiceFactory.create(options.resource); const interpreterService = this.serviceContainer.get(IInterpreterService); - const { hasInterpreters } = interpreterService; - if (hasInterpreters()) { + const hasInterpreters = await interpreterService.hasInterpreters(); + if (hasInterpreters) { const condaExecutionService = await this.createCondaExecutionService(pythonPath, processService); if (condaExecutionService) { return condaExecutionService; @@ -161,6 +161,7 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { procService.on('exec', this.logger.logProcess.bind(this.logger)); this.disposables.push(procService); } + return createPythonService( pythonPath, procService, From c666e09fe2c14a7ac00cf142bac278de79ee432d Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 3 Nov 2021 15:30:34 -0500 Subject: [PATCH 19/41] Fix linting --- src/client/linters/flake8.ts | 2 +- src/client/linters/pycodestyle.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/linters/flake8.ts b/src/client/linters/flake8.ts index 3ad39fd1faf4..8faa7aeef36f 100644 --- a/src/client/linters/flake8.ts +++ b/src/client/linters/flake8.ts @@ -14,7 +14,7 @@ export class Flake8 extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ['--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', document.uri.fsPath], + ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", document.uri.fsPath], document, cancellation, ); diff --git a/src/client/linters/pycodestyle.ts b/src/client/linters/pycodestyle.ts index 6ef61b0ccdbe..4ffe143ab5ab 100644 --- a/src/client/linters/pycodestyle.ts +++ b/src/client/linters/pycodestyle.ts @@ -14,7 +14,7 @@ export class Pycodestyle extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ['--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', document.uri.fsPath], + ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", document.uri.fsPath], document, cancellation, ); From 2a7b34358893b4cbfa038ac75396ba2b93962222 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 9 Nov 2021 12:47:37 -0500 Subject: [PATCH 20/41] Fix tests --- .../pythonExecutionFactory.unit.test.ts | 39 ------------------- 1 file changed, 39 deletions(-) diff --git a/src/test/common/process/pythonExecutionFactory.unit.test.ts b/src/test/common/process/pythonExecutionFactory.unit.test.ts index c7f9241df1fb..d9db9b03abbb 100644 --- a/src/test/common/process/pythonExecutionFactory.unit.test.ts +++ b/src/test/common/process/pythonExecutionFactory.unit.test.ts @@ -257,45 +257,6 @@ suite('Process - PythonExecutionFactory', () => { assert.strictEqual(createInvoked, false); }); - test("Ensure `create` returns a WindowsStorePythonProcess instance if it's a windows store intepreter path and we're in the discovery experiment", async () => { - const pythonPath = 'path/to/python'; - const pythonSettings = mock(PythonSettings); - - when(processFactory.create(resource)).thenResolve(processService.object); - when(pythonSettings.pythonPath).thenReturn(pythonPath); - when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); - inDiscoveryExperimentStub.resolves(true); - - const service = await factory.create({ resource }); - - expect(service).to.not.equal(undefined); - verify(processFactory.create(resource)).once(); - verify(pythonSettings.pythonPath).once(); - verify(pyenvs.isWindowsStoreInterpreter(pythonPath)).once(); - sinon.assert.calledOnce(inDiscoveryExperimentStub); - sinon.assert.notCalled(isWindowsStoreInterpreterStub); - }); - - test("Ensure `create` returns a WindowsStorePythonProcess instance if it's a windows store intepreter path and we're not in the discovery experiment", async () => { - const pythonPath = 'path/to/python'; - const pythonSettings = mock(PythonSettings); - - when(processFactory.create(resource)).thenResolve(processService.object); - when(pythonSettings.pythonPath).thenReturn(pythonPath); - when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); - inDiscoveryExperimentStub.resolves(false); - - const service = await factory.create({ resource }); - - expect(service).to.not.equal(undefined); - verify(processFactory.create(resource)).once(); - verify(pythonSettings.pythonPath).once(); - verify(pyenvs.isWindowsStoreInterpreter(pythonPath)).never(); - sinon.assert.calledOnce(inDiscoveryExperimentStub); - sinon.assert.calledOnce(isWindowsStoreInterpreterStub); - sinon.assert.calledWith(isWindowsStoreInterpreterStub, pythonPath); - }); - test('Ensure `create` returns a CondaExecutionService instance if createCondaExecutionService() returns a valid object', async () => { const pythonPath = 'path/to/python'; const pythonSettings = mock(PythonSettings); From df16208fc410861573fa3dad4fd33f9bc269271d Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 9 Nov 2021 12:58:01 -0500 Subject: [PATCH 21/41] Add news --- news/1 Enhancements/7696.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 news/1 Enhancements/7696.md diff --git a/news/1 Enhancements/7696.md b/news/1 Enhancements/7696.md new file mode 100644 index 000000000000..0d556b80c7cb --- /dev/null +++ b/news/1 Enhancements/7696.md @@ -0,0 +1 @@ +Add suport for conda run withput output, using --no-capture-output. From 0ba12cbeddf93de230249d34ee02714473caad89 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 10 Nov 2021 13:06:02 -0500 Subject: [PATCH 22/41] Fix tests in linter --- src/test/linters/lint.args.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/linters/lint.args.test.ts b/src/test/linters/lint.args.test.ts index b9908900d449..cf2a000720d0 100644 --- a/src/test/linters/lint.args.test.ts +++ b/src/test/linters/lint.args.test.ts @@ -142,12 +142,12 @@ suite('Linting - Arguments', () => { } test('Flake8', async () => { const linter = new Flake8(serviceContainer); - const expectedArgs = ['--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; + const expectedArgs = ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; await testLinter(linter, expectedArgs); }); test('Pycodestyle', async () => { const linter = new Pycodestyle(serviceContainer); - const expectedArgs = ['--format=%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; + const expectedArgs = ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; await testLinter(linter, expectedArgs); }); test('Prospector', async () => { From fee7cbdbfcae0c8489fcf873bd8df18ffaba1b24 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Mon, 22 Nov 2021 15:58:26 -0800 Subject: [PATCH 23/41] Fix strings --- src/client/common/process/pythonEnvironment.ts | 4 ---- src/client/linters/flake8.ts | 2 +- src/client/linters/pycodestyle.ts | 2 +- src/client/linters/pylint.ts | 9 +++++++-- src/test/linters/pylint.unit.test.ts | 7 ++++++- 5 files changed, 15 insertions(+), 9 deletions(-) diff --git a/src/client/common/process/pythonEnvironment.ts b/src/client/common/process/pythonEnvironment.ts index 3cbd5e82c876..14828b9fd120 100644 --- a/src/client/common/process/pythonEnvironment.ts +++ b/src/client/common/process/pythonEnvironment.ts @@ -149,10 +149,6 @@ export function createCondaEnv( const deps = createDeps( async (filename) => fs.pathExists(filename), pythonArgv, - - // TODO: Use pythonArgv here once 'conda run' can be - // run without buffering output. - // See https://github.com/microsoft/vscode-python/issues/8473. pythonArgv, (file, args, opts) => procs.exec(file, args, opts), (command, opts) => procs.shellExec(command, opts), diff --git a/src/client/linters/flake8.ts b/src/client/linters/flake8.ts index 8faa7aeef36f..7afce91ddd2a 100644 --- a/src/client/linters/flake8.ts +++ b/src/client/linters/flake8.ts @@ -14,7 +14,7 @@ export class Flake8 extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", document.uri.fsPath], + ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", document.uri.fsPath], document, cancellation, ); diff --git a/src/client/linters/pycodestyle.ts b/src/client/linters/pycodestyle.ts index 4ffe143ab5ab..d7ee9874a511 100644 --- a/src/client/linters/pycodestyle.ts +++ b/src/client/linters/pycodestyle.ts @@ -14,7 +14,7 @@ export class Pycodestyle extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s'", document.uri.fsPath], + ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", document.uri.fsPath], document, cancellation, ); diff --git a/src/client/linters/pylint.ts b/src/client/linters/pylint.ts index e1b9662f530d..0a9d5467bd57 100644 --- a/src/client/linters/pylint.ts +++ b/src/client/linters/pylint.ts @@ -27,8 +27,13 @@ export class Pylint extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const { uri } = document; const settings = this.configService.getSettings(uri); - const args = ['--reports=n', '--output-format=json', uri.fsPath]; - const messages = await this.run(args, document, cancellation); + const args = [ + "--msg-template='{line},{column},{category},{symbol}:{msg}''", + '--reports=n', + '--output-format=text', + uri.fsPath, + ]; + const messages = await this.run(args, document, cancellation, REGEX); messages.forEach((msg) => { msg.severity = this.parseMessagesSeverity(msg.type, settings.linting.pylintCategorySeverity); }); diff --git a/src/test/linters/pylint.unit.test.ts b/src/test/linters/pylint.unit.test.ts index 2648dacd9ab5..671ea552d4e4 100644 --- a/src/test/linters/pylint.unit.test.ts +++ b/src/test/linters/pylint.unit.test.ts @@ -26,7 +26,12 @@ suite('Pylint - Function runLinter()', () => { const doc = { uri: vscode.Uri.file('path/to/doc'), }; - const args = ['--reports=n', '--output-format=json', doc.uri.fsPath]; + const args = [ + "--msg-template='{line},{column},{category},{symbol}:{msg}''", + '--reports=n', + '--output-format=text', + doc.uri.fsPath, + ]; class PylintTest extends Pylint { // eslint-disable-next-line class-methods-use-this public async run( From 51ce1e4acdc080d45bf8662b0bd1bef5ec681313 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Mon, 22 Nov 2021 17:49:14 -0800 Subject: [PATCH 24/41] Fix linters --- src/client/linters/flake8.ts | 2 +- src/client/linters/pycodestyle.ts | 2 +- src/client/linters/pylint.ts | 2 +- src/test/linters/lint.args.test.ts | 4 ++-- src/test/linters/pylint.unit.test.ts | 2 +- 5 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/client/linters/flake8.ts b/src/client/linters/flake8.ts index 7afce91ddd2a..c034cfb60639 100644 --- a/src/client/linters/flake8.ts +++ b/src/client/linters/flake8.ts @@ -14,7 +14,7 @@ export class Flake8 extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", document.uri.fsPath], + ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', document.uri.fsPath], document, cancellation, ); diff --git a/src/client/linters/pycodestyle.ts b/src/client/linters/pycodestyle.ts index d7ee9874a511..c7f83a8ab974 100644 --- a/src/client/linters/pycodestyle.ts +++ b/src/client/linters/pycodestyle.ts @@ -14,7 +14,7 @@ export class Pycodestyle extends BaseLinter { protected async runLinter(document: TextDocument, cancellation: CancellationToken): Promise { const messages = await this.run( - ["--format='%(row)d,%(col)d,%(code).1s,%(code)s:%(text)s''", document.uri.fsPath], + ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', document.uri.fsPath], document, cancellation, ); diff --git a/src/client/linters/pylint.ts b/src/client/linters/pylint.ts index 0a9d5467bd57..2bf31f7c189d 100644 --- a/src/client/linters/pylint.ts +++ b/src/client/linters/pylint.ts @@ -28,7 +28,7 @@ export class Pylint extends BaseLinter { const { uri } = document; const settings = this.configService.getSettings(uri); const args = [ - "--msg-template='{line},{column},{category},{symbol}:{msg}''", + '--msg-template={line},{column},{category},{symbol}:{msg}', '--reports=n', '--output-format=text', uri.fsPath, diff --git a/src/test/linters/lint.args.test.ts b/src/test/linters/lint.args.test.ts index cf2a000720d0..c936318c92bd 100644 --- a/src/test/linters/lint.args.test.ts +++ b/src/test/linters/lint.args.test.ts @@ -141,12 +141,12 @@ suite('Linting - Arguments', () => { expect(invoked).to.be.equal(true, 'method not invoked'); } test('Flake8', async () => { - const linter = new Flake8(serviceContainer); + const linter = new Flake8(outputChannel.object, serviceContainer); const expectedArgs = ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; await testLinter(linter, expectedArgs); }); test('Pycodestyle', async () => { - const linter = new Pycodestyle(serviceContainer); + const linter = new Pycodestyle(outputChannel.object, serviceContainer); const expectedArgs = ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; await testLinter(linter, expectedArgs); }); diff --git a/src/test/linters/pylint.unit.test.ts b/src/test/linters/pylint.unit.test.ts index 671ea552d4e4..2f601779d5c1 100644 --- a/src/test/linters/pylint.unit.test.ts +++ b/src/test/linters/pylint.unit.test.ts @@ -27,7 +27,7 @@ suite('Pylint - Function runLinter()', () => { uri: vscode.Uri.file('path/to/doc'), }; const args = [ - "--msg-template='{line},{column},{category},{symbol}:{msg}''", + '--msg-template={line},{column},{category},{symbol}:{msg}', '--reports=n', '--output-format=text', doc.uri.fsPath, From a3a067a0df6687fe602dff2a62aaaf5b0c2a9460 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Mon, 22 Nov 2021 20:11:04 -0800 Subject: [PATCH 25/41] Fix conda run unit test --- .../process/pythonEnvironment.unit.test.ts | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/test/common/process/pythonEnvironment.unit.test.ts b/src/test/common/process/pythonEnvironment.unit.test.ts index c446e44e368e..a0ed2c2cde2d 100644 --- a/src/test/common/process/pythonEnvironment.unit.test.ts +++ b/src/test/common/process/pythonEnvironment.unit.test.ts @@ -295,8 +295,8 @@ suite('CondaEnvironment', () => { expect(result).to.deep.equal({ command: condaFile, - args: ['run', '-n', condaInfo.name, 'python', ...args], - python: [condaFile, 'run', '-n', condaInfo.name, 'python'], + args: ['run', '-n', condaInfo.name, '--no-capture-output', 'python', ...args], + python: [condaFile, 'run', '-n', condaInfo.name, '--no-capture-output', 'python'], pythonExecutable: 'python', }); }); @@ -309,15 +309,20 @@ suite('CondaEnvironment', () => { expect(result).to.deep.equal({ command: condaFile, - args: ['run', '-p', condaInfo.path, 'python', ...args], - python: [condaFile, 'run', '-p', condaInfo.path, 'python'], + args: ['run', '-p', condaInfo.path, '--no-capture-output', 'python', ...args], + python: [condaFile, 'run', '-p', condaInfo.path, '--no-capture-output', 'python'], pythonExecutable: 'python', }); }); - test('getExecutionObservableInfo with a named environment should return execution info using pythonPath only', () => { - const expected = { command: pythonPath, args, python: [pythonPath], pythonExecutable: pythonPath }; + test('getExecutionObservableInfo with a named environment should return execution info using conda full path with the name', () => { const condaInfo = { name: 'foo', path: 'bar' }; + const expected = { + command: condaFile, + args: ['run', '-n', condaInfo.name, '--no-capture-output', 'python', ...args], + python: [condaFile, 'run', '-n', condaInfo.name, '--no-capture-output', 'python'], + pythonExecutable: 'python', + }; const env = createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); const result = env.getExecutionObservableInfo(args); @@ -325,9 +330,14 @@ suite('CondaEnvironment', () => { expect(result).to.deep.equal(expected); }); - test('getExecutionObservableInfo with a non-named environment should return execution info using pythonPath only', () => { - const expected = { command: pythonPath, args, python: [pythonPath], pythonExecutable: pythonPath }; + test('getExecutionObservableInfo with a non-named environment should return execution info using conda full path', () => { const condaInfo = { name: '', path: 'bar' }; + const expected = { + command: condaFile, + args: ['run', '-p', condaInfo.path, '--no-capture-output', 'python', ...args], + python: [condaFile, 'run', '-p', condaInfo.path, '--no-capture-output', 'python'], + pythonExecutable: 'python', + }; const env = createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); const result = env.getExecutionObservableInfo(args); From cf146a294365dcab484867f4723522db6f5ad9f8 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 24 Nov 2021 17:35:32 -0800 Subject: [PATCH 26/41] Fix funtional tests --- src/test/linters/lint.functional.test.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/test/linters/lint.functional.test.ts b/src/test/linters/lint.functional.test.ts index e0fc71aafa89..b029773c0d40 100644 --- a/src/test/linters/lint.functional.test.ts +++ b/src/test/linters/lint.functional.test.ts @@ -625,6 +625,11 @@ class TestFixture extends BaseTestFixture { const serviceContainer = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); const configService = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); const processLogger = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); + const componentAdapter = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); + componentAdapter + .setup((c) => c.getCondaEnvironment(TypeMoq.It.isAny())) + .returns(() => Promise.resolve(undefined)); + const filesystem = new FileSystem(); processLogger .setup((p) => p.logProcess(TypeMoq.It.isAnyString(), TypeMoq.It.isAny(), TypeMoq.It.isAny())) @@ -637,6 +642,9 @@ class TestFixture extends BaseTestFixture { serviceContainer .setup((s) => s.get(TypeMoq.It.isValue(IFileSystem), TypeMoq.It.isAny())) .returns(() => filesystem); + serviceContainer + .setup((s) => s.get(TypeMoq.It.isValue(IComponentAdapter), TypeMoq.It.isAny())) + .returns(() => componentAdapter.object); const platformService = new PlatformService(); From 9a1052c334e72a89a0428a37fbbe36424f098b08 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Mon, 29 Nov 2021 12:37:11 -0800 Subject: [PATCH 27/41] Fix single workspace tests --- src/client/pythonEnvironments/legacyIOC.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/client/pythonEnvironments/legacyIOC.ts b/src/client/pythonEnvironments/legacyIOC.ts index 7c2e774b4740..538366cfff38 100644 --- a/src/client/pythonEnvironments/legacyIOC.ts +++ b/src/client/pythonEnvironments/legacyIOC.ts @@ -227,14 +227,14 @@ class ComponentAdapter implements IComponentAdapter { } } }); - const initialEnvs = this.api.getEnvs(); + const initialEnvs = this.api.getEnvs() || []; if (initialEnvs.length > 0) { return true; } // We should already have initiated discovery. Wait for an env to be added // to the collection until the refresh has finished. await Promise.race([onAddedToCollection.promise, this.api.refreshPromise]); - const envs = await asyncFilter(this.api.getEnvs(), (e) => filter(convertEnvInfo(e))); + const envs = await asyncFilter(this.api.getEnvs() || [], (e) => filter(convertEnvInfo(e))); return envs.length > 0; } From 8c5d1c051088201243c1732a1ebf620112ff0106 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 7 Dec 2021 12:18:52 -0800 Subject: [PATCH 28/41] update minimum conda versionvalue --- src/client/common/process/pythonExecutionFactory.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/client/common/process/pythonExecutionFactory.ts b/src/client/common/process/pythonExecutionFactory.ts index 92fb5116428b..dd63e3387280 100644 --- a/src/client/common/process/pythonExecutionFactory.ts +++ b/src/client/common/process/pythonExecutionFactory.ts @@ -29,8 +29,8 @@ import { IInterpreterAutoSelectionService } from '../../interpreter/autoSelectio import { sleep } from '../utils/async'; import { traceError } from '../../logging'; -// Minimum version number of conda required to be able to use 'conda run' -export const CONDA_RUN_VERSION = '4.6.0'; +// Minimum version number of conda required to be able to use 'conda run' and '--no-capture--output' option +export const CONDA_RUN_VERSION = '4.9.0'; @injectable() export class PythonExecutionFactory implements IPythonExecutionFactory { @@ -137,8 +137,6 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { return createPythonService(pythonPath, processService, this.fileSystem); } - // Not using this function for now because there are breaking issues with conda run (conda 4.8, PVSC 2020.1). - // See https://github.com/microsoft/vscode-python/issues/9490 public async createCondaExecutionService( pythonPath: string, processService?: IProcessService, From bbb37009676958dda4615054ae76672656c19d15 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 7 Dec 2021 13:54:21 -0800 Subject: [PATCH 29/41] Change sorting timeput --- src/test/format/extension.sort.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/format/extension.sort.test.ts b/src/test/format/extension.sort.test.ts index 14cfb501a8f8..fcde1e5ebbc7 100644 --- a/src/test/format/extension.sort.test.ts +++ b/src/test/format/extension.sort.test.ts @@ -107,7 +107,7 @@ suite('Sorting', () => { await window.showTextDocument(textDocument); await commands.executeCommand(Commands.Sort_Imports); assert.notStrictEqual(originalContent, textDocument.getText(), 'Contents have not changed'); - }); + }).timeout(TEST_TIMEOUT * 3); test('With Config', async () => { const textDocument = await workspace.openTextDocument(fileToFormatWithConfig); From efeef0751a68c05e3ca870377523fc2a0aa59bc6 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 7 Dec 2021 15:10:27 -0800 Subject: [PATCH 30/41] Add timeout time in sorting test --- src/test/format/extension.sort.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/format/extension.sort.test.ts b/src/test/format/extension.sort.test.ts index fcde1e5ebbc7..e8d5601c92d0 100644 --- a/src/test/format/extension.sort.test.ts +++ b/src/test/format/extension.sort.test.ts @@ -130,7 +130,7 @@ suite('Sorting', () => { await window.showTextDocument(textDocument); await commands.executeCommand(Commands.Sort_Imports); assert.notStrictEqual(originalContent, textDocument.getText(), 'Contents have not changed'); - }); + }).timeout(TEST_TIMEOUT * 3); test('With Changes and Config in Args', async () => { await updateSetting( @@ -164,7 +164,7 @@ suite('Sorting', () => { const originalContent = textDocument.getText(); await commands.executeCommand(Commands.Sort_Imports); assert.notStrictEqual(originalContent, textDocument.getText(), 'Contents have not changed'); - }).timeout(TEST_TIMEOUT * 2); + }).timeout(TEST_TIMEOUT * 3); test('With Changes and Config implicit from cwd', async () => { const textDocument = await workspace.openTextDocument(fileToFormatWithConfig); From 90a8349c5819473e9feff918620b81d039111249 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 8 Dec 2021 16:27:52 -0800 Subject: [PATCH 31/41] Add more time to timeout in sorting tests --- src/test/format/extension.sort.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/format/extension.sort.test.ts b/src/test/format/extension.sort.test.ts index e8d5601c92d0..6852d6aafa48 100644 --- a/src/test/format/extension.sort.test.ts +++ b/src/test/format/extension.sort.test.ts @@ -106,7 +106,7 @@ suite('Sorting', () => { const originalContent = textDocument.getText(); await window.showTextDocument(textDocument); await commands.executeCommand(Commands.Sort_Imports); - assert.notStrictEqual(originalContent, textDocument.getText(), 'Contents have not changed'); + assert.notEqual(originalContent, textDocument.getText(), 'Contents have not changed'); }).timeout(TEST_TIMEOUT * 3); test('With Config', async () => { From 96d5d3c467473f43b54e41a7cfbeb2c69d6546a4 Mon Sep 17 00:00:00 2001 From: paulacamargo25 Date: Wed, 15 Dec 2021 12:00:24 -0500 Subject: [PATCH 32/41] Update news/1 Enhancements/7696.md Co-authored-by: Kartik Raj --- news/1 Enhancements/7696.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/news/1 Enhancements/7696.md b/news/1 Enhancements/7696.md index 0d556b80c7cb..ce5bf882046c 100644 --- a/news/1 Enhancements/7696.md +++ b/news/1 Enhancements/7696.md @@ -1 +1 @@ -Add suport for conda run withput output, using --no-capture-output. +Add support for conda run without output, using `--no-capture-output` flag. From 7a36818d701a631670f17cb42c5d92eed2f5272b Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 15 Dec 2021 12:17:15 -0500 Subject: [PATCH 33/41] Rix pylint test --- src/test/linters/pylint.unit.test.ts | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/test/linters/pylint.unit.test.ts b/src/test/linters/pylint.unit.test.ts index 2f601779d5c1..2648dacd9ab5 100644 --- a/src/test/linters/pylint.unit.test.ts +++ b/src/test/linters/pylint.unit.test.ts @@ -26,12 +26,7 @@ suite('Pylint - Function runLinter()', () => { const doc = { uri: vscode.Uri.file('path/to/doc'), }; - const args = [ - '--msg-template={line},{column},{category},{symbol}:{msg}', - '--reports=n', - '--output-format=text', - doc.uri.fsPath, - ]; + const args = ['--reports=n', '--output-format=json', doc.uri.fsPath]; class PylintTest extends Pylint { // eslint-disable-next-line class-methods-use-this public async run( From d11654b7d6f446e4395217dfa7183edbf6cf7525 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 15 Dec 2021 12:25:40 -0500 Subject: [PATCH 34/41] Fix lint test --- src/test/linters/lint.args.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/linters/lint.args.test.ts b/src/test/linters/lint.args.test.ts index c936318c92bd..cf2a000720d0 100644 --- a/src/test/linters/lint.args.test.ts +++ b/src/test/linters/lint.args.test.ts @@ -141,12 +141,12 @@ suite('Linting - Arguments', () => { expect(invoked).to.be.equal(true, 'method not invoked'); } test('Flake8', async () => { - const linter = new Flake8(outputChannel.object, serviceContainer); + const linter = new Flake8(serviceContainer); const expectedArgs = ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; await testLinter(linter, expectedArgs); }); test('Pycodestyle', async () => { - const linter = new Pycodestyle(outputChannel.object, serviceContainer); + const linter = new Pycodestyle(serviceContainer); const expectedArgs = ['--format= %(row)d,%(col)d,%(code).1s,%(code)s:%(text)s', fileUri.fsPath]; await testLinter(linter, expectedArgs); }); From ac7c626a6c2a15c8f2c5bc04515e375b7bbf0134 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Thu, 16 Dec 2021 11:53:10 -0500 Subject: [PATCH 35/41] Remove unnecessary interpreter check --- src/client/common/process/pythonExecutionFactory.ts | 12 ++++-------- src/client/pythonEnvironments/legacyIOC.ts | 4 ++-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/client/common/process/pythonExecutionFactory.ts b/src/client/common/process/pythonExecutionFactory.ts index dd63e3387280..a82336aa9faa 100644 --- a/src/client/common/process/pythonExecutionFactory.ts +++ b/src/client/common/process/pythonExecutionFactory.ts @@ -5,7 +5,7 @@ import { gte } from 'semver'; import { Uri } from 'vscode'; import { IEnvironmentActivationService } from '../../interpreter/activation/types'; -import { IComponentAdapter, ICondaService, IInterpreterService } from '../../interpreter/contracts'; +import { IComponentAdapter, ICondaService } from '../../interpreter/contracts'; import { IServiceContainer } from '../../ioc/types'; import { CondaEnvironmentInfo } from '../../pythonEnvironments/common/environmentManagers/conda'; import { sendTelemetryEvent } from '../../telemetry'; @@ -83,13 +83,9 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { } const processService: IProcessService = await this.processServiceFactory.create(options.resource); - const interpreterService = this.serviceContainer.get(IInterpreterService); - const hasInterpreters = await interpreterService.hasInterpreters(); - if (hasInterpreters) { - const condaExecutionService = await this.createCondaExecutionService(pythonPath, processService); - if (condaExecutionService) { - return condaExecutionService; - } + const condaExecutionService = await this.createCondaExecutionService(pythonPath, processService); + if (condaExecutionService) { + return condaExecutionService; } const windowsStoreInterpreterCheck = this.pyenvs.isWindowsStoreInterpreter.bind(this.pyenvs); diff --git a/src/client/pythonEnvironments/legacyIOC.ts b/src/client/pythonEnvironments/legacyIOC.ts index 538366cfff38..7c2e774b4740 100644 --- a/src/client/pythonEnvironments/legacyIOC.ts +++ b/src/client/pythonEnvironments/legacyIOC.ts @@ -227,14 +227,14 @@ class ComponentAdapter implements IComponentAdapter { } } }); - const initialEnvs = this.api.getEnvs() || []; + const initialEnvs = this.api.getEnvs(); if (initialEnvs.length > 0) { return true; } // We should already have initiated discovery. Wait for an env to be added // to the collection until the refresh has finished. await Promise.race([onAddedToCollection.promise, this.api.refreshPromise]); - const envs = await asyncFilter(this.api.getEnvs() || [], (e) => filter(convertEnvInfo(e))); + const envs = await asyncFilter(this.api.getEnvs(), (e) => filter(convertEnvInfo(e))); return envs.length > 0; } From a4b5660f223eca43afddf9b25a730ff9c81d99ae Mon Sep 17 00:00:00 2001 From: Kartik Raj Date: Wed, 8 Dec 2021 15:12:53 +0530 Subject: [PATCH 36/41] Use conda.ts --- .../common/process/pythonEnvironment.ts | 20 +++-- .../common/process/pythonExecutionFactory.ts | 78 +++++-------------- src/client/common/process/types.ts | 3 +- .../process/pythonEnvironment.unit.test.ts | 10 +-- .../pythonExecutionFactory.unit.test.ts | 3 +- 5 files changed, 36 insertions(+), 78 deletions(-) diff --git a/src/client/common/process/pythonEnvironment.ts b/src/client/common/process/pythonEnvironment.ts index 14828b9fd120..d3bc23d2e64d 100644 --- a/src/client/common/process/pythonEnvironment.ts +++ b/src/client/common/process/pythonEnvironment.ts @@ -2,7 +2,7 @@ // Licensed under the MIT License. import { traceError, traceInfo } from '../../logging'; -import { CondaEnvironmentInfo } from '../../pythonEnvironments/common/environmentManagers/conda'; +import { Conda, CondaEnvironmentInfo } from '../../pythonEnvironments/common/environmentManagers/conda'; import { buildPythonExecInfo, PythonExecInfo } from '../../pythonEnvironments/exec'; import { InterpreterInformation } from '../../pythonEnvironments/info'; import { getExecutablePath } from '../../pythonEnvironments/info/executable'; @@ -11,7 +11,7 @@ import { IFileSystem } from '../platform/types'; import * as internalPython from './internal/python'; import { ExecutionResult, IProcessService, ShellOptions, SpawnOptions } from './types'; -class PythonEnvironment { +export class PythonEnvironment { private cachedExecutablePath: Map> = new Map>(); private cachedInterpreterInformation: InterpreterInformation | undefined | null = null; @@ -131,21 +131,19 @@ export function createPythonEnv( return new PythonEnvironment(pythonPath, deps); } -export function createCondaEnv( - condaFile: string, +export async function createCondaEnv( condaInfo: CondaEnvironmentInfo, pythonPath: string, // These are used to generate the deps. procs: IProcessService, fs: IFileSystem, -): PythonEnvironment { - const runArgs = ['run']; - if (condaInfo.name === '') { - runArgs.push('-p', condaInfo.path); - } else { - runArgs.push('-n', condaInfo.name); +): Promise { + const conda = await Conda.getConda(); + const runArgs = await conda?.getRunArgs({ name: condaInfo.name, prefix: condaInfo.path }); + if (!runArgs) { + return undefined; } - const pythonArgv = [condaFile, ...runArgs, '--no-capture-output', 'python']; + const pythonArgv = [...runArgs, 'python']; const deps = createDeps( async (filename) => fs.pathExists(filename), pythonArgv, diff --git a/src/client/common/process/pythonExecutionFactory.ts b/src/client/common/process/pythonExecutionFactory.ts index a82336aa9faa..ed4d11bad924 100644 --- a/src/client/common/process/pythonExecutionFactory.ts +++ b/src/client/common/process/pythonExecutionFactory.ts @@ -1,19 +1,16 @@ // Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT License. import { inject, injectable } from 'inversify'; -import { gte } from 'semver'; -import { Uri } from 'vscode'; import { IEnvironmentActivationService } from '../../interpreter/activation/types'; -import { IComponentAdapter, ICondaService } from '../../interpreter/contracts'; +import { IComponentAdapter, IInterpreterService } from '../../interpreter/contracts'; import { IServiceContainer } from '../../ioc/types'; -import { CondaEnvironmentInfo } from '../../pythonEnvironments/common/environmentManagers/conda'; import { sendTelemetryEvent } from '../../telemetry'; import { EventName } from '../../telemetry/constants'; import { IFileSystem } from '../platform/types'; import { IConfigurationService, IDisposableRegistry, IInterpreterPathProxyService } from '../types'; import { ProcessService } from './proc'; -import { createCondaEnv, createPythonEnv, createWindowsStoreEnv } from './pythonEnvironment'; +import { createCondaEnv, createPythonEnv, createWindowsStoreEnv, PythonEnvironment } from './pythonEnvironment'; import { createPythonProcessService } from './pythonProcess'; import { ExecutionFactoryCreateWithEnvironmentOptions, @@ -29,9 +26,6 @@ import { IInterpreterAutoSelectionService } from '../../interpreter/autoSelectio import { sleep } from '../utils/async'; import { traceError } from '../../logging'; -// Minimum version number of conda required to be able to use 'conda run' and '--no-capture--output' option -export const CONDA_RUN_VERSION = '4.9.0'; - @injectable() export class PythonExecutionFactory implements IPythonExecutionFactory { private readonly disposables: IDisposableRegistry; @@ -45,7 +39,6 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { @inject(IEnvironmentActivationService) private readonly activationHelper: IEnvironmentActivationService, @inject(IProcessServiceFactory) private readonly processServiceFactory: IProcessServiceFactory, @inject(IConfigurationService) private readonly configService: IConfigurationService, - @inject(ICondaService) private readonly condaService: ICondaService, @inject(IBufferDecoder) private readonly decoder: IBufferDecoder, @inject(IComponentAdapter) private readonly pyenvs: IComponentAdapter, @inject(IInterpreterAutoSelectionService) private readonly autoSelection: IInterpreterAutoSelectionService, @@ -90,13 +83,11 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { const windowsStoreInterpreterCheck = this.pyenvs.isWindowsStoreInterpreter.bind(this.pyenvs); - return createPythonService( - pythonPath, - processService, - this.fileSystem, - undefined, - await windowsStoreInterpreterCheck(pythonPath), - ); + const env = (await windowsStoreInterpreterCheck(pythonPath)) + ? createWindowsStoreEnv(pythonPath, processService) + : createPythonEnv(pythonPath, processService, this.fileSystem); + + return createPythonService(processService, env); } public async createActivatedEnvironment( @@ -130,59 +121,28 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { } } - return createPythonService(pythonPath, processService, this.fileSystem); + const env = createPythonEnv(pythonPath, processService, this.fileSystem); + return createPythonService(processService, env); } public async createCondaExecutionService( pythonPath: string, - processService?: IProcessService, - resource?: Uri, + processService: IProcessService, ): Promise { - const processServicePromise = processService - ? Promise.resolve(processService) - : this.processServiceFactory.create(resource); const condaLocatorService = this.serviceContainer.get(IComponentAdapter); - const [condaVersion, condaEnvironment, condaFile, procService] = await Promise.all([ - this.condaService.getCondaVersion(), - condaLocatorService.getCondaEnvironment(pythonPath), - this.condaService.getCondaFile(), - processServicePromise, - ]); - - if (condaVersion && gte(condaVersion, CONDA_RUN_VERSION) && condaEnvironment && condaFile && procService) { - // Add logging to the newly created process service - if (!processService) { - procService.on('exec', this.logger.logProcess.bind(this.logger)); - this.disposables.push(procService); - } - - return createPythonService( - pythonPath, - procService, - this.fileSystem, - // This is what causes a CondaEnvironment to be returned: - [condaFile, condaEnvironment], - ); + const [condaEnvironment] = await Promise.all([condaLocatorService.getCondaEnvironment(pythonPath)]); + if (!condaEnvironment) { + return undefined; } - - return Promise.resolve(undefined); + const env = await createCondaEnv(condaEnvironment, pythonPath, processService, this.fileSystem); + if (!env) { + return undefined; + } + return createPythonService(processService, env); } } -function createPythonService( - pythonPath: string, - procService: IProcessService, - fs: IFileSystem, - conda?: [string, CondaEnvironmentInfo], - isWindowsStore?: boolean, -): IPythonExecutionService { - let env = createPythonEnv(pythonPath, procService, fs); - if (conda) { - const [condaPath, condaInfo] = conda; - env = createCondaEnv(condaPath, condaInfo, pythonPath, procService, fs); - } else if (isWindowsStore) { - env = createWindowsStoreEnv(pythonPath, procService); - } +function createPythonService(procService: IProcessService, env: PythonEnvironment): IPythonExecutionService { const procs = createPythonProcessService(procService, env); return { getInterpreterInformation: () => env.getInterpreterInformation(), diff --git a/src/client/common/process/types.ts b/src/client/common/process/types.ts index 2f22ea013261..215ed94fb4a4 100644 --- a/src/client/common/process/types.ts +++ b/src/client/common/process/types.ts @@ -83,8 +83,7 @@ export interface IPythonExecutionFactory { createActivatedEnvironment(options: ExecutionFactoryCreateWithEnvironmentOptions): Promise; createCondaExecutionService( pythonPath: string, - processService?: IProcessService, - resource?: Uri, + processService: IProcessService, ): Promise; } export const IPythonExecutionService = Symbol('IPythonExecutionService'); diff --git a/src/test/common/process/pythonEnvironment.unit.test.ts b/src/test/common/process/pythonEnvironment.unit.test.ts index a0ed2c2cde2d..f3a7deda6d34 100644 --- a/src/test/common/process/pythonEnvironment.unit.test.ts +++ b/src/test/common/process/pythonEnvironment.unit.test.ts @@ -287,9 +287,9 @@ suite('CondaEnvironment', () => { fileSystem = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); }); - test('getExecutionInfo with a named environment should return execution info using the environment name', () => { + test('getExecutionInfo with a named environment should return execution info using the environment name', async () => { const condaInfo = { name: 'foo', path: 'bar' }; - const env = createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); + const env = await createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); const result = env.getExecutionInfo(args); @@ -303,7 +303,7 @@ suite('CondaEnvironment', () => { test('getExecutionInfo with a non-named environment should return execution info using the environment path', () => { const condaInfo = { name: '', path: 'bar' }; - const env = createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); + const env = await createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); const result = env.getExecutionInfo(args); @@ -323,7 +323,7 @@ suite('CondaEnvironment', () => { python: [condaFile, 'run', '-n', condaInfo.name, '--no-capture-output', 'python'], pythonExecutable: 'python', }; - const env = createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); + const env = await createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); const result = env.getExecutionObservableInfo(args); @@ -338,7 +338,7 @@ suite('CondaEnvironment', () => { python: [condaFile, 'run', '-p', condaInfo.path, '--no-capture-output', 'python'], pythonExecutable: 'python', }; - const env = createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); + const env = await createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); const result = env.getExecutionObservableInfo(args); diff --git a/src/test/common/process/pythonExecutionFactory.unit.test.ts b/src/test/common/process/pythonExecutionFactory.unit.test.ts index d9db9b03abbb..5a2d32c15294 100644 --- a/src/test/common/process/pythonExecutionFactory.unit.test.ts +++ b/src/test/common/process/pythonExecutionFactory.unit.test.ts @@ -16,7 +16,7 @@ import { ConfigurationService } from '../../../client/common/configuration/servi import { BufferDecoder } from '../../../client/common/process/decoder'; import { ProcessLogger } from '../../../client/common/process/logger'; import { ProcessServiceFactory } from '../../../client/common/process/processFactory'; -import { CONDA_RUN_VERSION, PythonExecutionFactory } from '../../../client/common/process/pythonExecutionFactory'; +import { PythonExecutionFactory } from '../../../client/common/process/pythonExecutionFactory'; import { IBufferDecoder, IProcessLogger, @@ -34,6 +34,7 @@ import { ServiceContainer } from '../../../client/ioc/container'; import { CondaService } from '../../../client/pythonEnvironments/common/environmentManagers/condaService'; import { EnvironmentType, PythonEnvironment } from '../../../client/pythonEnvironments/info'; import { IInterpreterAutoSelectionService } from '../../../client/interpreter/autoSelection/types'; +import { CONDA_RUN_VERSION } from '../../../client/pythonEnvironments/common/environmentManagers/conda'; const pythonInterpreter: PythonEnvironment = { path: '/foo/bar/python.exe', From 49bf259dcc85e8a7b9e21251e5fa16a5c2378ca1 Mon Sep 17 00:00:00 2001 From: Kartik Raj Date: Wed, 8 Dec 2021 18:02:07 +0530 Subject: [PATCH 37/41] Fix tests --- .../process/pythonEnvironment.unit.test.ts | 27 +++++---- .../pythonExecutionFactory.unit.test.ts | 60 ++++--------------- src/test/linters/lint.functional.test.ts | 9 ++- .../djangoShellCodeExect.unit.test.ts | 14 ++++- .../terminalCodeExec.unit.test.ts | 36 ++++++----- 5 files changed, 64 insertions(+), 82 deletions(-) diff --git a/src/test/common/process/pythonEnvironment.unit.test.ts b/src/test/common/process/pythonEnvironment.unit.test.ts index f3a7deda6d34..dbc0720fdf94 100644 --- a/src/test/common/process/pythonEnvironment.unit.test.ts +++ b/src/test/common/process/pythonEnvironment.unit.test.ts @@ -3,6 +3,7 @@ import { expect, use } from 'chai'; import * as chaiAsPromised from 'chai-as-promised'; +import * as sinon from 'sinon'; import { SemVer } from 'semver'; import * as TypeMoq from 'typemoq'; import { IFileSystem } from '../../../client/common/platform/types'; @@ -13,6 +14,7 @@ import { } from '../../../client/common/process/pythonEnvironment'; import { IProcessService, StdErrError } from '../../../client/common/process/types'; import { Architecture } from '../../../client/common/utils/platform'; +import { Conda } from '../../../client/pythonEnvironments/common/environmentManagers/conda'; use(chaiAsPromised); @@ -283,15 +285,18 @@ suite('CondaEnvironment', () => { const condaFile = 'path/to/conda'; setup(() => { + sinon.stub(Conda, 'getConda').resolves(new Conda(condaFile)); processService = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); fileSystem = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); }); + teardown(() => sinon.restore()); + test('getExecutionInfo with a named environment should return execution info using the environment name', async () => { const condaInfo = { name: 'foo', path: 'bar' }; - const env = await createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); + const env = await createCondaEnv(condaInfo, pythonPath, processService.object, fileSystem.object); - const result = env.getExecutionInfo(args); + const result = env?.getExecutionInfo(args); expect(result).to.deep.equal({ command: condaFile, @@ -301,11 +306,11 @@ suite('CondaEnvironment', () => { }); }); - test('getExecutionInfo with a non-named environment should return execution info using the environment path', () => { + test('getExecutionInfo with a non-named environment should return execution info using the environment path', async () => { const condaInfo = { name: '', path: 'bar' }; - const env = await createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); + const env = await createCondaEnv(condaInfo, pythonPath, processService.object, fileSystem.object); - const result = env.getExecutionInfo(args); + const result = env?.getExecutionInfo(args); expect(result).to.deep.equal({ command: condaFile, @@ -315,7 +320,7 @@ suite('CondaEnvironment', () => { }); }); - test('getExecutionObservableInfo with a named environment should return execution info using conda full path with the name', () => { + test('getExecutionObservableInfo with a named environment should return execution info using conda full path with the name', async () => { const condaInfo = { name: 'foo', path: 'bar' }; const expected = { command: condaFile, @@ -323,14 +328,14 @@ suite('CondaEnvironment', () => { python: [condaFile, 'run', '-n', condaInfo.name, '--no-capture-output', 'python'], pythonExecutable: 'python', }; - const env = await createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); + const env = await createCondaEnv(condaInfo, pythonPath, processService.object, fileSystem.object); - const result = env.getExecutionObservableInfo(args); + const result = env?.getExecutionObservableInfo(args); expect(result).to.deep.equal(expected); }); - test('getExecutionObservableInfo with a non-named environment should return execution info using conda full path', () => { + test('getExecutionObservableInfo with a non-named environment should return execution info using conda full path', async () => { const condaInfo = { name: '', path: 'bar' }; const expected = { command: condaFile, @@ -338,9 +343,9 @@ suite('CondaEnvironment', () => { python: [condaFile, 'run', '-p', condaInfo.path, '--no-capture-output', 'python'], pythonExecutable: 'python', }; - const env = await createCondaEnv(condaFile, condaInfo, pythonPath, processService.object, fileSystem.object); + const env = await createCondaEnv(condaInfo, pythonPath, processService.object, fileSystem.object); - const result = env.getExecutionObservableInfo(args); + const result = env?.getExecutionObservableInfo(args); expect(result).to.deep.equal(expected); }); diff --git a/src/test/common/process/pythonExecutionFactory.unit.test.ts b/src/test/common/process/pythonExecutionFactory.unit.test.ts index 5a2d32c15294..1e4eda3f25e7 100644 --- a/src/test/common/process/pythonExecutionFactory.unit.test.ts +++ b/src/test/common/process/pythonExecutionFactory.unit.test.ts @@ -28,13 +28,12 @@ import { IConfigurationService, IDisposableRegistry, IInterpreterPathProxyServic import { Architecture } from '../../../client/common/utils/platform'; import { EnvironmentActivationService } from '../../../client/interpreter/activation/service'; import { IEnvironmentActivationService } from '../../../client/interpreter/activation/types'; -import { IComponentAdapter, ICondaService, IInterpreterService } from '../../../client/interpreter/contracts'; +import { IComponentAdapter, IInterpreterService } from '../../../client/interpreter/contracts'; import { InterpreterService } from '../../../client/interpreter/interpreterService'; import { ServiceContainer } from '../../../client/ioc/container'; -import { CondaService } from '../../../client/pythonEnvironments/common/environmentManagers/condaService'; import { EnvironmentType, PythonEnvironment } from '../../../client/pythonEnvironments/info'; import { IInterpreterAutoSelectionService } from '../../../client/interpreter/autoSelection/types'; -import { CONDA_RUN_VERSION } from '../../../client/pythonEnvironments/common/environmentManagers/conda'; +import { Conda, CONDA_RUN_VERSION } from '../../../client/pythonEnvironments/common/environmentManagers/conda'; const pythonInterpreter: PythonEnvironment = { path: '/foo/bar/python.exe', @@ -79,7 +78,6 @@ suite('Process - PythonExecutionFactory', () => { let bufferDecoder: IBufferDecoder; let processFactory: IProcessServiceFactory; let configService: IConfigurationService; - let condaService: ICondaService; let processLogger: IProcessLogger; let processService: typemoq.IMock; let interpreterService: IInterpreterService; @@ -88,11 +86,11 @@ suite('Process - PythonExecutionFactory', () => { let autoSelection: IInterpreterAutoSelectionService; let interpreterPathExpHelper: IInterpreterPathProxyService; setup(() => { + sinon.stub(Conda, 'getConda').resolves(new Conda('conda')); bufferDecoder = mock(BufferDecoder); activationHelper = mock(EnvironmentActivationService); processFactory = mock(ProcessServiceFactory); configService = mock(ConfigurationService); - condaService = mock(CondaService); processLogger = mock(ProcessLogger); autoSelection = mock(); interpreterPathExpHelper = mock(); @@ -135,7 +133,6 @@ suite('Process - PythonExecutionFactory', () => { instance(activationHelper), instance(processFactory), instance(configService), - instance(condaService), instance(bufferDecoder), instance(pyenvs), instance(autoSelection), @@ -266,21 +263,18 @@ suite('Process - PythonExecutionFactory', () => { when(processFactory.create(resource)).thenResolve(processService.object); when(pythonSettings.pythonPath).thenReturn(pythonPath); when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); - when(condaService.getCondaVersion()).thenResolve(new SemVer(CONDA_RUN_VERSION)); + sinon.stub(Conda.prototype, 'getCondaVersion').resolves(new SemVer(CONDA_RUN_VERSION)); when(pyenvs.getCondaEnvironment(pythonPath)).thenResolve({ name: 'foo', path: 'path/to/foo/env', }); - when(condaService.getCondaFile()).thenResolve('conda'); const service = await factory.create({ resource }); expect(service).to.not.equal(undefined); verify(processFactory.create(resource)).once(); verify(pythonSettings.pythonPath).once(); - verify(condaService.getCondaVersion()).once(); verify(pyenvs.getCondaEnvironment(pythonPath)).once(); - verify(condaService.getCondaFile()).once(); }); test('Ensure `create` returns a PythonExecutionService instance if createCondaExecutionService() returns undefined', async () => { @@ -289,7 +283,7 @@ suite('Process - PythonExecutionFactory', () => { when(processFactory.create(resource)).thenResolve(processService.object); when(pythonSettings.pythonPath).thenReturn(pythonPath); when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); - when(condaService.getCondaVersion()).thenResolve(new SemVer('1.0.0')); + sinon.stub(Conda.prototype, 'getCondaVersion').resolves(new SemVer('1.0.0')); when(interpreterService.hasInterpreters()).thenResolve(true); const service = await factory.create({ resource }); @@ -297,9 +291,7 @@ suite('Process - PythonExecutionFactory', () => { expect(service).to.not.equal(undefined); verify(processFactory.create(resource)).once(); verify(pythonSettings.pythonPath).once(); - verify(condaService.getCondaVersion()).once(); verify(pyenvs.getCondaEnvironment(pythonPath)).once(); - verify(condaService.getCondaFile()).once(); }); test('Ensure `createActivatedEnvironment` returns a CondaExecutionService instance if createCondaExecutionService() returns a valid object', async () => { @@ -312,17 +304,15 @@ suite('Process - PythonExecutionFactory', () => { x: '1', }); when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); - when(condaService.getCondaVersion()).thenResolve(new SemVer(CONDA_RUN_VERSION)); + sinon.stub(Conda.prototype, 'getCondaVersion').resolves(new SemVer(CONDA_RUN_VERSION)); when(pyenvs.getCondaEnvironment(anyString())).thenResolve({ name: 'foo', path: 'path/to/foo/env', }); - when(condaService.getCondaFile()).thenResolve('conda'); const service = await factory.createActivatedEnvironment({ resource, interpreter }); expect(service).to.not.equal(undefined); - verify(condaService.getCondaFile()).once(); if (!interpreter) { verify(pythonSettings.pythonPath).once(); verify(pyenvs.getCondaEnvironment(pythonPath)).once(); @@ -347,14 +337,12 @@ suite('Process - PythonExecutionFactory', () => { }); when(pythonSettings.pythonPath).thenReturn(pythonPath); when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); - when(condaService.getCondaVersion()).thenResolve(new SemVer('1.0.0')); + sinon.stub(Conda.prototype, 'getCondaVersion').resolves(new SemVer('1.0.0')); const service = await factory.createActivatedEnvironment({ resource, interpreter }); expect(service).to.not.equal(undefined); - verify(condaService.getCondaFile()).once(); verify(activationHelper.getActivatedEnvironmentVariables(resource, anything(), anything())).once(); - verify(condaService.getCondaVersion()).once(); if (!interpreter) { verify(pythonSettings.pythonPath).once(); } @@ -368,40 +356,18 @@ suite('Process - PythonExecutionFactory', () => { name: 'foo', path: 'path/to/foo/env', }); - when(condaService.getCondaVersion()).thenResolve(new SemVer(CONDA_RUN_VERSION)); - when(condaService.getCondaFile()).thenResolve('conda'); + sinon.stub(Conda.prototype, 'getCondaVersion').resolves(new SemVer(CONDA_RUN_VERSION)); - const result = await factory.createCondaExecutionService(pythonPath, processService.object, resource); - - expect(result).to.not.equal(undefined); - verify(condaService.getCondaVersion()).once(); - verify(pyenvs.getCondaEnvironment(pythonPath)).once(); - verify(condaService.getCondaFile()).once(); - }); - - test('Ensure `createCondaExecutionService` instantiates a ProcessService instance if the process argument is undefined', async () => { - const pythonPath = 'path/to/python'; - when(processFactory.create(resource)).thenResolve(processService.object); - when(pyenvs.getCondaEnvironment(pythonPath)).thenResolve({ - name: 'foo', - path: 'path/to/foo/env', - }); - when(condaService.getCondaVersion()).thenResolve(new SemVer(CONDA_RUN_VERSION)); - when(condaService.getCondaFile()).thenResolve('conda'); - - const result = await factory.createCondaExecutionService(pythonPath, undefined, resource); + const result = await factory.createCondaExecutionService(pythonPath, processService.object); expect(result).to.not.equal(undefined); - verify(processFactory.create(resource)).once(); - verify(condaService.getCondaVersion()).once(); verify(pyenvs.getCondaEnvironment(pythonPath)).once(); - verify(condaService.getCondaFile()).once(); }); test('Ensure `createCondaExecutionService` returns undefined if there is no conda environment', async () => { const pythonPath = 'path/to/python'; when(pyenvs.getCondaEnvironment(pythonPath)).thenResolve(undefined); - when(condaService.getCondaVersion()).thenResolve(new SemVer(CONDA_RUN_VERSION)); + sinon.stub(Conda.prototype, 'getCondaVersion').resolves(new SemVer(CONDA_RUN_VERSION)); const result = await factory.createCondaExecutionService(pythonPath, processService.object); @@ -409,14 +375,12 @@ suite('Process - PythonExecutionFactory', () => { undefined, 'createCondaExecutionService should return undefined if not in a conda environment', ); - verify(condaService.getCondaVersion()).once(); verify(pyenvs.getCondaEnvironment(pythonPath)).once(); - verify(condaService.getCondaFile()).once(); }); test('Ensure `createCondaExecutionService` returns undefined if the conda version does not support conda run', async () => { const pythonPath = 'path/to/python'; - when(condaService.getCondaVersion()).thenResolve(new SemVer('1.0.0')); + sinon.stub(Conda.prototype, 'getCondaVersion').resolves(new SemVer('1.0.0')); const result = await factory.createCondaExecutionService(pythonPath, processService.object); @@ -424,9 +388,7 @@ suite('Process - PythonExecutionFactory', () => { undefined, 'createCondaExecutionService should return undefined if not in a conda environment', ); - verify(condaService.getCondaVersion()).once(); verify(pyenvs.getCondaEnvironment(pythonPath)).once(); - verify(condaService.getCondaFile()).once(); }); }); }); diff --git a/src/test/linters/lint.functional.test.ts b/src/test/linters/lint.functional.test.ts index b029773c0d40..82bbf35abb10 100644 --- a/src/test/linters/lint.functional.test.ts +++ b/src/test/linters/lint.functional.test.ts @@ -29,13 +29,14 @@ import { import { IConfigurationService, IDisposableRegistry, IInterpreterPathProxyService } from '../../client/common/types'; import { IEnvironmentVariablesProvider } from '../../client/common/variables/types'; import { IEnvironmentActivationService } from '../../client/interpreter/activation/types'; -import { IComponentAdapter, ICondaService, IInterpreterService } from '../../client/interpreter/contracts'; +import { IComponentAdapter, IInterpreterService } from '../../client/interpreter/contracts'; import { IServiceContainer } from '../../client/ioc/types'; import { LINTERID_BY_PRODUCT } from '../../client/linters/constants'; import { ILintMessage, LinterId, LintMessageSeverity } from '../../client/linters/types'; import { deleteFile, PYTHON_PATH } from '../common'; import { BaseTestFixture, getLinterID, getProductName, newMockDocument, throwUnknownProduct } from './common'; import { IInterpreterAutoSelectionService } from '../../client/interpreter/autoSelection/types'; +import { Conda } from '../../client/pythonEnvironments/common/environmentManagers/conda'; const workspaceDir = path.join(__dirname, '..', '..', '..', 'src', 'test'); const workspaceUri = Uri.file(workspaceDir); @@ -704,9 +705,8 @@ class TestFixture extends BaseTestFixture { .setup((c) => c.get(TypeMoq.It.isValue(IInterpreterService), TypeMoq.It.isAny())) .returns(() => interpreterService.object); - const condaService = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); - condaService.setup((c) => c.getCondaVersion()).returns(() => Promise.resolve(undefined)); - condaService.setup((c) => c.getCondaFile()).returns(() => Promise.resolve('conda')); + sinon.stub(Conda, 'getConda').resolves(new Conda('conda')); + sinon.stub(Conda.prototype, 'getCondaVersion').resolves(undefined); const processLogger = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); processLogger @@ -731,7 +731,6 @@ class TestFixture extends BaseTestFixture { envActivationService.object, procServiceFactory, configService, - condaService.object, decoder, instance(pyenvs), instance(autoSelection), diff --git a/src/test/terminals/codeExecution/djangoShellCodeExect.unit.test.ts b/src/test/terminals/codeExecution/djangoShellCodeExect.unit.test.ts index 65ba2a27f35f..c8705e59f7cf 100644 --- a/src/test/terminals/codeExecution/djangoShellCodeExect.unit.test.ts +++ b/src/test/terminals/codeExecution/djangoShellCodeExect.unit.test.ts @@ -4,6 +4,7 @@ import { expect } from 'chai'; import * as path from 'path'; import * as TypeMoq from 'typemoq'; +import * as sinon from 'sinon'; import { Disposable, Uri, WorkspaceFolder } from 'vscode'; import { ICommandManager, IDocumentManager, IWorkspaceService } from '../../../client/common/application/types'; import { IFileSystem, IPlatformService } from '../../../client/common/platform/types'; @@ -15,6 +16,9 @@ import { IConfigurationService, IPythonSettings, ITerminalSettings } from '../.. import { DjangoShellCodeExecutionProvider } from '../../../client/terminals/codeExecution/djangoShellCodeExecution'; import { ICodeExecutionService } from '../../../client/terminals/types'; import { PYTHON_PATH } from '../../common'; +import { Conda, CONDA_RUN_VERSION } from '../../../client/pythonEnvironments/common/environmentManagers/conda'; +import { SemVer } from 'semver'; +import assert from 'assert'; suite('Terminal - Django Shell Code Execution', () => { let executor: ICodeExecutionService; @@ -69,6 +73,7 @@ suite('Terminal - Django Shell Code Execution', () => { }); disposables = []; + sinon.restore(); }); async function testReplCommandArguments( @@ -204,7 +209,12 @@ suite('Terminal - Django Shell Code Execution', () => { const condaFile = 'conda'; const processService = TypeMoq.Mock.ofType(); - const env = createCondaEnv(condaFile, condaEnv, pythonPath, processService.object, fileSystem.object); + sinon.stub(Conda, 'getConda').resolves(new Conda(condaFile)); + const env = await createCondaEnv(condaEnv, pythonPath, processService.object, fileSystem.object); + sinon.stub(Conda.prototype, 'getCondaVersion').resolves(new SemVer(CONDA_RUN_VERSION)); + if (!env) { + assert(false, 'Should not be undefined for conda version 4.9.0'); + } const procs = createPythonProcessService(processService.object, env); const condaExecutionService = { getInterpreterInformation: env.getInterpreterInformation, @@ -219,7 +229,7 @@ suite('Terminal - Django Shell Code Execution', () => { }; const expectedTerminalArgs = [...terminalArgs, 'manage.py', 'shell']; pythonExecutionFactory - .setup((p) => p.createCondaExecutionService(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny())) + .setup((p) => p.createCondaExecutionService(TypeMoq.It.isAny(), TypeMoq.It.isAny())) .returns(() => Promise.resolve(condaExecutionService)); const replCommandArgs = await (executor as DjangoShellCodeExecutionProvider).getExecutableInfo(resource); diff --git a/src/test/terminals/codeExecution/terminalCodeExec.unit.test.ts b/src/test/terminals/codeExecution/terminalCodeExec.unit.test.ts index 8fcc308d99e8..ba2ab27f6a6c 100644 --- a/src/test/terminals/codeExecution/terminalCodeExec.unit.test.ts +++ b/src/test/terminals/codeExecution/terminalCodeExec.unit.test.ts @@ -3,6 +3,7 @@ import { expect } from 'chai'; import * as path from 'path'; +import { SemVer } from 'semver'; import * as TypeMoq from 'typemoq'; import { Disposable, Uri, WorkspaceFolder } from 'vscode'; import { ICommandManager, IDocumentManager, IWorkspaceService } from '../../../client/common/application/types'; @@ -17,11 +18,14 @@ import { } from '../../../client/common/terminal/types'; import { IConfigurationService, IPythonSettings, ITerminalSettings } from '../../../client/common/types'; import { noop } from '../../../client/common/utils/misc'; +import { Conda, CONDA_RUN_VERSION } from '../../../client/pythonEnvironments/common/environmentManagers/conda'; import { DjangoShellCodeExecutionProvider } from '../../../client/terminals/codeExecution/djangoShellCodeExecution'; import { ReplProvider } from '../../../client/terminals/codeExecution/repl'; import { TerminalCodeExecutionProvider } from '../../../client/terminals/codeExecution/terminalCodeExecution'; import { ICodeExecutionService } from '../../../client/terminals/types'; import { PYTHON_PATH } from '../../common'; +import * as sinon from 'sinon'; +import assert from 'assert'; suite('Terminal - Code Execution', () => { ['Terminal Execution', 'Repl Execution', 'Django Execution'].forEach((testSuiteName) => { @@ -47,7 +51,7 @@ suite('Terminal - Code Execution', () => { disposable.dispose(); } }); - + sinon.restore(); disposables = []; }); @@ -307,9 +311,7 @@ suite('Terminal - Code Execution', () => { terminalSettings.setup((t) => t.executeInFileDir).returns(() => false); workspace.setup((w) => w.getWorkspaceFolder(TypeMoq.It.isAny())).returns(() => undefined); pythonExecutionFactory - .setup((p) => - p.createCondaExecutionService(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), - ) + .setup((p) => p.createCondaExecutionService(TypeMoq.It.isAny(), TypeMoq.It.isAny())) .returns(() => Promise.resolve(undefined)); await executor.executeFile(file); @@ -355,7 +357,12 @@ suite('Terminal - Code Execution', () => { const condaFile = 'conda'; const procService = TypeMoq.Mock.ofType(); - const env = createCondaEnv(condaFile, condaEnv, pythonPath, procService.object, fileSystem.object); + sinon.stub(Conda, 'getConda').resolves(new Conda(condaFile)); + sinon.stub(Conda.prototype, 'getCondaVersion').resolves(new SemVer(CONDA_RUN_VERSION)); + const env = await createCondaEnv(condaEnv, pythonPath, procService.object, fileSystem.object); + if (!env) { + assert(false, 'Should not be undefined for conda version 4.9.0'); + } const procs = createPythonProcessService(procService.object, env); const condaExecutionService = { getInterpreterInformation: env.getInterpreterInformation, @@ -369,9 +376,7 @@ suite('Terminal - Code Execution', () => { execModule: procs.execModule, }; pythonExecutionFactory - .setup((p) => - p.createCondaExecutionService(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), - ) + .setup((p) => p.createCondaExecutionService(TypeMoq.It.isAny(), TypeMoq.It.isAny())) .returns(() => Promise.resolve(condaExecutionService)); await executor.executeFile(file); @@ -407,9 +412,7 @@ suite('Terminal - Code Execution', () => { terminalArgs: string[], ) { pythonExecutionFactory - .setup((p) => - p.createCondaExecutionService(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), - ) + .setup((p) => p.createCondaExecutionService(TypeMoq.It.isAny(), TypeMoq.It.isAny())) .returns(() => Promise.resolve(undefined)); platform.setup((p) => p.isWindows).returns(() => isWindows); settings.setup((s) => s.pythonPath).returns(() => pythonPath); @@ -467,7 +470,12 @@ suite('Terminal - Code Execution', () => { const condaFile = 'conda'; const procService = TypeMoq.Mock.ofType(); - const env = createCondaEnv(condaFile, condaEnv, pythonPath, procService.object, fileSystem.object); + sinon.stub(Conda, 'getConda').resolves(new Conda(condaFile)); + sinon.stub(Conda.prototype, 'getCondaVersion').resolves(new SemVer(CONDA_RUN_VERSION)); + const env = await createCondaEnv(condaEnv, pythonPath, procService.object, fileSystem.object); + if (!env) { + assert(false, 'Should not be undefined for conda version 4.9.0'); + } const procs = createPythonProcessService(procService.object, env); const condaExecutionService = { getInterpreterInformation: env.getInterpreterInformation, @@ -481,9 +489,7 @@ suite('Terminal - Code Execution', () => { execModule: procs.execModule, }; pythonExecutionFactory - .setup((p) => - p.createCondaExecutionService(TypeMoq.It.isAny(), TypeMoq.It.isAny(), TypeMoq.It.isAny()), - ) + .setup((p) => p.createCondaExecutionService(TypeMoq.It.isAny(), TypeMoq.It.isAny())) .returns(() => Promise.resolve(condaExecutionService)); const djangoArgs = isDjangoRepl ? ['manage.py', 'shell'] : []; From ee806ed9be96ee7d603a77b62848ecc1499a6c20 Mon Sep 17 00:00:00 2001 From: Kartik Raj Date: Wed, 8 Dec 2021 18:05:27 +0530 Subject: [PATCH 38/41] Remove unnecessary export --- src/client/common/process/pythonEnvironment.ts | 4 ++-- src/client/common/process/pythonExecutionFactory.ts | 5 +++-- src/client/common/process/pythonProcess.ts | 8 ++------ src/client/common/process/types.ts | 9 +++++++++ 4 files changed, 16 insertions(+), 10 deletions(-) diff --git a/src/client/common/process/pythonEnvironment.ts b/src/client/common/process/pythonEnvironment.ts index d3bc23d2e64d..a7db9d4feb28 100644 --- a/src/client/common/process/pythonEnvironment.ts +++ b/src/client/common/process/pythonEnvironment.ts @@ -9,9 +9,9 @@ import { getExecutablePath } from '../../pythonEnvironments/info/executable'; import { getInterpreterInfo } from '../../pythonEnvironments/info/interpreter'; import { IFileSystem } from '../platform/types'; import * as internalPython from './internal/python'; -import { ExecutionResult, IProcessService, ShellOptions, SpawnOptions } from './types'; +import { ExecutionResult, IProcessService, IPythonEnvironment, ShellOptions, SpawnOptions } from './types'; -export class PythonEnvironment { +class PythonEnvironment implements IPythonEnvironment { private cachedExecutablePath: Map> = new Map>(); private cachedInterpreterInformation: InterpreterInformation | undefined | null = null; diff --git a/src/client/common/process/pythonExecutionFactory.ts b/src/client/common/process/pythonExecutionFactory.ts index ed4d11bad924..ec476b3f03e1 100644 --- a/src/client/common/process/pythonExecutionFactory.ts +++ b/src/client/common/process/pythonExecutionFactory.ts @@ -10,7 +10,7 @@ import { EventName } from '../../telemetry/constants'; import { IFileSystem } from '../platform/types'; import { IConfigurationService, IDisposableRegistry, IInterpreterPathProxyService } from '../types'; import { ProcessService } from './proc'; -import { createCondaEnv, createPythonEnv, createWindowsStoreEnv, PythonEnvironment } from './pythonEnvironment'; +import { createCondaEnv, createPythonEnv, createWindowsStoreEnv } from './pythonEnvironment'; import { createPythonProcessService } from './pythonProcess'; import { ExecutionFactoryCreateWithEnvironmentOptions, @@ -19,6 +19,7 @@ import { IProcessLogger, IProcessService, IProcessServiceFactory, + IPythonEnvironment, IPythonExecutionFactory, IPythonExecutionService, } from './types'; @@ -142,7 +143,7 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { } } -function createPythonService(procService: IProcessService, env: PythonEnvironment): IPythonExecutionService { +function createPythonService(procService: IProcessService, env: IPythonEnvironment): IPythonExecutionService { const procs = createPythonProcessService(procService, env); return { getInterpreterInformation: () => env.getInterpreterInformation(), diff --git a/src/client/common/process/pythonProcess.ts b/src/client/common/process/pythonProcess.ts index 6536019e10f7..28a11bdb5718 100644 --- a/src/client/common/process/pythonProcess.ts +++ b/src/client/common/process/pythonProcess.ts @@ -5,7 +5,7 @@ import { PythonExecInfo } from '../../pythonEnvironments/exec'; import { ErrorUtils } from '../errors/errorUtils'; import { ModuleNotInstalledError } from '../errors/moduleNotInstalledError'; import * as internalPython from './internal/python'; -import { ExecutionResult, IProcessService, ObservableExecutionResult, SpawnOptions } from './types'; +import { ExecutionResult, IProcessService, IPythonEnvironment, ObservableExecutionResult, SpawnOptions } from './types'; class PythonProcessService { constructor( @@ -69,11 +69,7 @@ class PythonProcessService { export function createPythonProcessService( procs: IProcessService, // from PythonEnvironment: - env: { - getExecutionInfo(pythonArgs?: string[]): PythonExecInfo; - getExecutionObservableInfo(pythonArgs?: string[]): PythonExecInfo; - isModuleInstalled(moduleName: string): Promise; - }, + env: IPythonEnvironment, ) { const deps = { // from PythonService: diff --git a/src/client/common/process/types.ts b/src/client/common/process/types.ts index 215ed94fb4a4..426a4cc176d8 100644 --- a/src/client/common/process/types.ts +++ b/src/client/common/process/types.ts @@ -102,6 +102,15 @@ export interface IPythonExecutionService { execModule(moduleName: string, args: string[], options: SpawnOptions): Promise>; } +export interface IPythonEnvironment { + getInterpreterInformation(): Promise; + getExecutionObservableInfo(pythonArgs?: string[]): PythonExecInfo; + getExecutablePath(): Promise; + isModuleInstalled(moduleName: string): Promise; + getModuleVersion(moduleName: string): Promise; + getExecutionInfo(pythonArgs?: string[]): PythonExecInfo; +} + export class StdErrError extends Error { constructor(message: string) { super(message); From 62f5516ce19970b32ceea5712e6a6247cc52a888 Mon Sep 17 00:00:00 2001 From: Kartik Raj Date: Tue, 21 Dec 2021 17:33:09 +0530 Subject: [PATCH 39/41] Rebase --- src/client/common/process/pythonExecutionFactory.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/common/process/pythonExecutionFactory.ts b/src/client/common/process/pythonExecutionFactory.ts index ec476b3f03e1..1dcdf70d7966 100644 --- a/src/client/common/process/pythonExecutionFactory.ts +++ b/src/client/common/process/pythonExecutionFactory.ts @@ -3,7 +3,7 @@ import { inject, injectable } from 'inversify'; import { IEnvironmentActivationService } from '../../interpreter/activation/types'; -import { IComponentAdapter, IInterpreterService } from '../../interpreter/contracts'; +import { IComponentAdapter } from '../../interpreter/contracts'; import { IServiceContainer } from '../../ioc/types'; import { sendTelemetryEvent } from '../../telemetry'; import { EventName } from '../../telemetry/constants'; From a9db7078ff263dad670eccf1d718cf1268b2e3a4 Mon Sep 17 00:00:00 2001 From: Kartik Raj Date: Tue, 21 Dec 2021 17:37:10 +0530 Subject: [PATCH 40/41] Mege --- src/client/common/process/pythonEnvironment.ts | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/client/common/process/pythonEnvironment.ts b/src/client/common/process/pythonEnvironment.ts index a7db9d4feb28..3fe5e97cffbc 100644 --- a/src/client/common/process/pythonEnvironment.ts +++ b/src/client/common/process/pythonEnvironment.ts @@ -139,11 +139,10 @@ export async function createCondaEnv( fs: IFileSystem, ): Promise { const conda = await Conda.getConda(); - const runArgs = await conda?.getRunArgs({ name: condaInfo.name, prefix: condaInfo.path }); - if (!runArgs) { + const pythonArgv = await conda?.getRunPythonArgs({ name: condaInfo.name, prefix: condaInfo.path }); + if (!pythonArgv) { return undefined; } - const pythonArgv = [...runArgs, 'python']; const deps = createDeps( async (filename) => fs.pathExists(filename), pythonArgv, From 91dfba0c277d3b0ffdf62f4af41dff9576c1663f Mon Sep 17 00:00:00 2001 From: Kartik Raj Date: Wed, 26 Jan 2022 18:20:52 +0530 Subject: [PATCH 41/41] Fix tests --- .../common/process/pythonEnvironment.ts | 8 ++--- src/client/common/process/types.ts | 4 +-- .../process/pythonEnvironment.unit.test.ts | 33 ++++++++++--------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/src/client/common/process/pythonEnvironment.ts b/src/client/common/process/pythonEnvironment.ts index 3fe5e97cffbc..90465c68ee0c 100644 --- a/src/client/common/process/pythonEnvironment.ts +++ b/src/client/common/process/pythonEnvironment.ts @@ -28,13 +28,13 @@ class PythonEnvironment implements IPythonEnvironment { }, ) {} - public getExecutionInfo(pythonArgs: string[] = []): PythonExecInfo { + public getExecutionInfo(pythonArgs: string[] = [], pythonExecutable?: string): PythonExecInfo { const python = this.deps.getPythonArgv(this.pythonPath); - return buildPythonExecInfo(python, pythonArgs); + return buildPythonExecInfo(python, pythonArgs, pythonExecutable); } - public getExecutionObservableInfo(pythonArgs: string[] = []): PythonExecInfo { + public getExecutionObservableInfo(pythonArgs: string[] = [], pythonExecutable?: string): PythonExecInfo { const python = this.deps.getObservablePythonArgv(this.pythonPath); - return buildPythonExecInfo(python, pythonArgs); + return buildPythonExecInfo(python, pythonArgs, pythonExecutable); } public async getInterpreterInformation(): Promise { diff --git a/src/client/common/process/types.ts b/src/client/common/process/types.ts index d197da8ac5f2..5134b63e8425 100644 --- a/src/client/common/process/types.ts +++ b/src/client/common/process/types.ts @@ -103,11 +103,11 @@ export interface IPythonExecutionService { export interface IPythonEnvironment { getInterpreterInformation(): Promise; - getExecutionObservableInfo(pythonArgs?: string[]): PythonExecInfo; + getExecutionObservableInfo(pythonArgs?: string[], pythonExecutable?: string): PythonExecInfo; getExecutablePath(): Promise; isModuleInstalled(moduleName: string): Promise; getModuleVersion(moduleName: string): Promise; - getExecutionInfo(pythonArgs?: string[]): PythonExecInfo; + getExecutionInfo(pythonArgs?: string[], pythonExecutable?: string): PythonExecInfo; } export class StdErrError extends Error { diff --git a/src/test/common/process/pythonEnvironment.unit.test.ts b/src/test/common/process/pythonEnvironment.unit.test.ts index 3182db7a139c..4babf9e6013b 100644 --- a/src/test/common/process/pythonEnvironment.unit.test.ts +++ b/src/test/common/process/pythonEnvironment.unit.test.ts @@ -15,6 +15,7 @@ import { import { IProcessService, StdErrError } from '../../../client/common/process/types'; import { Architecture } from '../../../client/common/utils/platform'; import { Conda } from '../../../client/pythonEnvironments/common/environmentManagers/conda'; +import { OUTPUT_MARKER_SCRIPT } from '../../../client/common/process/internal/scripts'; use(chaiAsPromised); @@ -288,13 +289,13 @@ suite('CondaEnvironment', () => { const condaInfo = { name: 'foo', path: 'bar' }; const env = await createCondaEnv(condaInfo, pythonPath, processService.object, fileSystem.object); - const result = env?.getExecutionInfo(args); + const result = env?.getExecutionInfo(args, pythonPath); expect(result).to.deep.equal({ command: condaFile, - args: ['run', '-n', condaInfo.name, '--no-capture-output', 'python', ...args], - python: [condaFile, 'run', '-n', condaInfo.name, '--no-capture-output', 'python'], - pythonExecutable: 'python', + args: ['run', '-n', condaInfo.name, '--no-capture-output', 'python', OUTPUT_MARKER_SCRIPT, ...args], + python: [condaFile, 'run', '-n', condaInfo.name, '--no-capture-output', 'python', OUTPUT_MARKER_SCRIPT], + pythonExecutable: pythonPath, }); }); @@ -302,13 +303,13 @@ suite('CondaEnvironment', () => { const condaInfo = { name: '', path: 'bar' }; const env = await createCondaEnv(condaInfo, pythonPath, processService.object, fileSystem.object); - const result = env?.getExecutionInfo(args); + const result = env?.getExecutionInfo(args, pythonPath); expect(result).to.deep.equal({ command: condaFile, - args: ['run', '-p', condaInfo.path, '--no-capture-output', 'python', ...args], - python: [condaFile, 'run', '-p', condaInfo.path, '--no-capture-output', 'python'], - pythonExecutable: 'python', + args: ['run', '-p', condaInfo.path, '--no-capture-output', 'python', OUTPUT_MARKER_SCRIPT, ...args], + python: [condaFile, 'run', '-p', condaInfo.path, '--no-capture-output', 'python', OUTPUT_MARKER_SCRIPT], + pythonExecutable: pythonPath, }); }); @@ -316,13 +317,13 @@ suite('CondaEnvironment', () => { const condaInfo = { name: 'foo', path: 'bar' }; const expected = { command: condaFile, - args: ['run', '-n', condaInfo.name, '--no-capture-output', 'python', ...args], - python: [condaFile, 'run', '-n', condaInfo.name, '--no-capture-output', 'python'], - pythonExecutable: 'python', + args: ['run', '-n', condaInfo.name, '--no-capture-output', 'python', OUTPUT_MARKER_SCRIPT, ...args], + python: [condaFile, 'run', '-n', condaInfo.name, '--no-capture-output', 'python', OUTPUT_MARKER_SCRIPT], + pythonExecutable: pythonPath, }; const env = await createCondaEnv(condaInfo, pythonPath, processService.object, fileSystem.object); - const result = env?.getExecutionObservableInfo(args); + const result = env?.getExecutionObservableInfo(args, pythonPath); expect(result).to.deep.equal(expected); }); @@ -331,13 +332,13 @@ suite('CondaEnvironment', () => { const condaInfo = { name: '', path: 'bar' }; const expected = { command: condaFile, - args: ['run', '-p', condaInfo.path, '--no-capture-output', 'python', ...args], - python: [condaFile, 'run', '-p', condaInfo.path, '--no-capture-output', 'python'], - pythonExecutable: 'python', + args: ['run', '-p', condaInfo.path, '--no-capture-output', 'python', OUTPUT_MARKER_SCRIPT, ...args], + python: [condaFile, 'run', '-p', condaInfo.path, '--no-capture-output', 'python', OUTPUT_MARKER_SCRIPT], + pythonExecutable: pythonPath, }; const env = await createCondaEnv(condaInfo, pythonPath, processService.object, fileSystem.object); - const result = env?.getExecutionObservableInfo(args); + const result = env?.getExecutionObservableInfo(args, pythonPath); expect(result).to.deep.equal(expected); });