From 2037cd76e1bdafda741216a24ccbc062ed73635e Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 28 Sep 2021 15:43:29 -0700 Subject: [PATCH 01/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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/38] 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 e167a03b9451c9f6ab69fc495f99a3069ad58a04 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 21 Dec 2021 15:29:28 -0500 Subject: [PATCH 36/38] Fix timeout test errors --- src/client/common/installer/pipInstaller.ts | 2 +- .../common/installer/productInstaller.ts | 21 +++++++++++++++---- .../common/process/pythonExecutionFactory.ts | 10 ++++++--- src/client/common/process/types.ts | 1 + src/client/common/types.ts | 2 +- src/test/common/installer.test.ts | 2 +- 6 files changed, 28 insertions(+), 10 deletions(-) diff --git a/src/client/common/installer/pipInstaller.ts b/src/client/common/installer/pipInstaller.ts index ec8dcf6bcc45..855ab00b188c 100644 --- a/src/client/common/installer/pipInstaller.ts +++ b/src/client/common/installer/pipInstaller.ts @@ -107,7 +107,7 @@ export class PipInstaller extends ModuleInstaller { const resource = isResource(info) ? info : undefined; const pythonPath = isResource(info) ? undefined : info.path; return pythonExecutionFactory - .create({ resource, pythonPath }) + .create({ resource, pythonPath, bypassCondaExecution: true }) .then((proc) => proc.isModuleInstalled('pip')) .catch(() => false); } diff --git a/src/client/common/installer/productInstaller.ts b/src/client/common/installer/productInstaller.ts index 9364f1d90d8c..783e06471b59 100644 --- a/src/client/common/installer/productInstaller.ts +++ b/src/client/common/installer/productInstaller.ts @@ -178,7 +178,11 @@ abstract class BaseInstaller { } } - public async isInstalled(product: Product, resource?: InterpreterUri): Promise { + public async isInstalled( + product: Product, + resource?: InterpreterUri, + bypassCondaExecution?: boolean, + ): Promise { if (product === Product.unittest) { return true; } @@ -191,7 +195,12 @@ abstract class BaseInstaller { if (isModule) { const pythonProcess = await this.serviceContainer .get(IPythonExecutionFactory) - .createActivatedEnvironment({ resource: uri, interpreter, allowEnvironmentFetchExceptions: true }); + .createActivatedEnvironment({ + resource: uri, + interpreter, + allowEnvironmentFetchExceptions: true, + bypassCondaExecution, + }); return pythonProcess.isModuleInstalled(executableName); } const process = await this.serviceContainer.get(IProcessServiceFactory).create(uri); @@ -599,8 +608,12 @@ export class ProductInstaller implements IInstaller { return this.createInstaller(product).install(product, resource, cancel, flags); } - public async isInstalled(product: Product, resource?: InterpreterUri): Promise { - return this.createInstaller(product).isInstalled(product, resource); + public async isInstalled( + product: Product, + resource?: InterpreterUri, + bypassCondaExecution?: boolean, + ): Promise { + return this.createInstaller(product).isInstalled(product, resource, bypassCondaExecution); } // eslint-disable-next-line class-methods-use-this diff --git a/src/client/common/process/pythonExecutionFactory.ts b/src/client/common/process/pythonExecutionFactory.ts index a82336aa9faa..d89ef9f14b26 100644 --- a/src/client/common/process/pythonExecutionFactory.ts +++ b/src/client/common/process/pythonExecutionFactory.ts @@ -83,9 +83,12 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { } const processService: IProcessService = await this.processServiceFactory.create(options.resource); - const condaExecutionService = await this.createCondaExecutionService(pythonPath, processService); - if (condaExecutionService) { - return condaExecutionService; + // Allow parts of the code to ignore conda run. + if (!options.bypassCondaExecution) { + const condaExecutionService = await this.createCondaExecutionService(pythonPath, processService); + if (condaExecutionService) { + return condaExecutionService; + } } const windowsStoreInterpreterCheck = this.pyenvs.isWindowsStoreInterpreter.bind(this.pyenvs); @@ -113,6 +116,7 @@ export class PythonExecutionFactory implements IPythonExecutionFactory { return this.create({ resource: options.resource, pythonPath: options.interpreter ? options.interpreter.path : undefined, + bypassCondaExecution: options.bypassCondaExecution, }); } const pythonPath = options.interpreter diff --git a/src/client/common/process/types.ts b/src/client/common/process/types.ts index 2f22ea013261..13e7911e3ac3 100644 --- a/src/client/common/process/types.ts +++ b/src/client/common/process/types.ts @@ -65,6 +65,7 @@ export const IPythonExecutionFactory = Symbol('IPythonExecutionFactory'); export type ExecutionFactoryCreationOptions = { resource?: Uri; pythonPath?: string; + bypassCondaExecution?: boolean; }; export type ExecutionFactoryCreateWithEnvironmentOptions = { resource?: Uri; diff --git a/src/client/common/types.ts b/src/client/common/types.ts index f71ebf890645..9b4a689c2b43 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -122,7 +122,7 @@ export interface IInstaller { cancel?: CancellationToken, flags?: ModuleInstallFlags, ): Promise; - isInstalled(product: Product, resource?: InterpreterUri): Promise; + isInstalled(product: Product, resource?: InterpreterUri, bypassCondaExecution?: boolean): Promise; isProductVersionCompatible( product: Product, semVerRequirement: string, diff --git a/src/test/common/installer.test.ts b/src/test/common/installer.test.ts index 0309b0df7bf7..327326ddc365 100644 --- a/src/test/common/installer.test.ts +++ b/src/test/common/installer.test.ts @@ -296,7 +296,7 @@ suite('Installer', () => { } callback({ stdout: '' }); }); - await installer.isInstalled(product, resource); + await installer.isInstalled(product, resource, true); await checkInstalledDef.promise; } getNamesAndValues(Product).forEach((prod) => { From d767c26cf0e198529ae00202769ad7b53e3005e9 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Tue, 21 Dec 2021 16:23:50 -0500 Subject: [PATCH 37/38] Fix unit test pip installer --- src/client/common/installer/pipInstaller.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/common/installer/pipInstaller.ts b/src/client/common/installer/pipInstaller.ts index 855ab00b188c..ec8dcf6bcc45 100644 --- a/src/client/common/installer/pipInstaller.ts +++ b/src/client/common/installer/pipInstaller.ts @@ -107,7 +107,7 @@ export class PipInstaller extends ModuleInstaller { const resource = isResource(info) ? info : undefined; const pythonPath = isResource(info) ? undefined : info.path; return pythonExecutionFactory - .create({ resource, pythonPath, bypassCondaExecution: true }) + .create({ resource, pythonPath }) .then((proc) => proc.isModuleInstalled('pip')) .catch(() => false); } From 7fb6003621f08d9bd3c7a49cc2d166ae69868674 Mon Sep 17 00:00:00 2001 From: Paula Camargo Date: Wed, 22 Dec 2021 13:28:39 -0500 Subject: [PATCH 38/38] Fix IModuleInstaller test --- src/client/common/installer/productInstaller.ts | 6 ++++-- src/client/common/types.ts | 1 + src/test/common/installer.test.ts | 2 +- 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/client/common/installer/productInstaller.ts b/src/client/common/installer/productInstaller.ts index 783e06471b59..786adb5bc0c5 100644 --- a/src/client/common/installer/productInstaller.ts +++ b/src/client/common/installer/productInstaller.ts @@ -94,6 +94,7 @@ abstract class BaseInstaller { resource?: InterpreterUri, cancel?: CancellationToken, flags?: ModuleInstallFlags, + bypassCondaExecution?: boolean, ): Promise { if (product === Product.unittest) { return InstallerResponse.Installed; @@ -113,7 +114,7 @@ abstract class BaseInstaller { .installModule(product, resource, cancel, flags) .catch((ex) => traceError(`Error in installing the product '${ProductNames.get(product)}', ${ex}`)); - return this.isInstalled(product, resource).then((isInstalled) => { + return this.isInstalled(product, resource, bypassCondaExecution).then((isInstalled) => { sendTelemetryEvent(EventName.PYTHON_INSTALL_PACKAGE, undefined, { installer: installer.displayName, productName: ProductNames.get(product), @@ -604,8 +605,9 @@ export class ProductInstaller implements IInstaller { resource?: InterpreterUri, cancel?: CancellationToken, flags?: ModuleInstallFlags, + bypassCondaExecution?: boolean, ): Promise { - return this.createInstaller(product).install(product, resource, cancel, flags); + return this.createInstaller(product).install(product, resource, cancel, flags, bypassCondaExecution); } public async isInstalled( diff --git a/src/client/common/types.ts b/src/client/common/types.ts index 9b4a689c2b43..e0826c433f41 100644 --- a/src/client/common/types.ts +++ b/src/client/common/types.ts @@ -121,6 +121,7 @@ export interface IInstaller { resource?: InterpreterUri, cancel?: CancellationToken, flags?: ModuleInstallFlags, + bypassCondaExecution?: boolean, ): Promise; isInstalled(product: Product, resource?: InterpreterUri, bypassCondaExecution?: boolean): Promise; isProductVersionCompatible( diff --git a/src/test/common/installer.test.ts b/src/test/common/installer.test.ts index 327326ddc365..880e7d486b5d 100644 --- a/src/test/common/installer.test.ts +++ b/src/test/common/installer.test.ts @@ -333,7 +333,7 @@ suite('Installer', () => { checkInstalledDef.resolve(); } }); - await installer.install(product); + await installer.install(product, undefined, undefined, undefined, true); await checkInstalledDef.promise; } getNamesAndValues(Product).forEach((prod) => {