diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d23f9c780094..27f67a681e7c 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -252,6 +252,7 @@ jobs: } & $condaPythonPath ./build/ci/addEnvPath.py ${{env.PYTHON_VIRTUAL_ENVS_LOCATION}} condaExecPath $condaExecPath & $condaPythonPath ./build/ci/addEnvPath.py ${{env.PYTHON_VIRTUAL_ENVS_LOCATION}} condaPath + & $condaExecPath init --all # 2. For `interpreterLocatorService.testvirtualenvs.ts` diff --git a/.github/workflows/nightly-coverage.yml b/.github/workflows/nightly-coverage.yml index 18f97ad6354d..48c228b81d1c 100644 --- a/.github/workflows/nightly-coverage.yml +++ b/.github/workflows/nightly-coverage.yml @@ -119,6 +119,7 @@ jobs: } & $condaPythonPath ./build/ci/addEnvPath.py ${{env.PYTHON_VIRTUAL_ENVS_LOCATION}} condaExecPath $condaExecPath & $condaPythonPath ./build/ci/addEnvPath.py ${{env.PYTHON_VIRTUAL_ENVS_LOCATION}} condaPath + & $condaExecPath init --all # 2. For `interpreterLocatorService.testvirtualenvs.ts` diff --git a/.github/workflows/pr-check.yml b/.github/workflows/pr-check.yml index 9bfa4831cb73..de4d06c5f05b 100644 --- a/.github/workflows/pr-check.yml +++ b/.github/workflows/pr-check.yml @@ -231,6 +231,7 @@ jobs: } & $condaPythonPath ./build/ci/addEnvPath.py ${{env.PYTHON_VIRTUAL_ENVS_LOCATION}} condaExecPath $condaExecPath & $condaPythonPath ./build/ci/addEnvPath.py ${{env.PYTHON_VIRTUAL_ENVS_LOCATION}} condaPath + & $condaExecPath init --all # 2. For `interpreterLocatorService.testvirtualenvs.ts` @@ -545,6 +546,7 @@ jobs: } & $condaPythonPath ./build/ci/addEnvPath.py ${{env.PYTHON_VIRTUAL_ENVS_LOCATION}} condaExecPath $condaExecPath & $condaPythonPath ./build/ci/addEnvPath.py ${{env.PYTHON_VIRTUAL_ENVS_LOCATION}} condaPath + & $condaExecPath init --all # 2. For `interpreterLocatorService.testvirtualenvs.ts` diff --git a/src/client/pythonEnvironments/common/environmentManagers/conda.ts b/src/client/pythonEnvironments/common/environmentManagers/conda.ts index 1eb577ee1b1f..30359a06fda7 100644 --- a/src/client/pythonEnvironments/common/environmentManagers/conda.ts +++ b/src/client/pythonEnvironments/common/environmentManagers/conda.ts @@ -2,7 +2,7 @@ import * as fsapi from 'fs-extra'; import * as path from 'path'; import { traceVerbose } from '../../../common/logger'; import { getEnvironmentVariable, getOSType, getUserHomeDir, OSType } from '../../../common/utils/platform'; -import { exec, pathExists, readFile } from '../externalDependencies'; +import { exec, getPythonSetting, pathExists, readFile } from '../externalDependencies'; import { PythonVersion, UNKNOWN_PYTHON_VERSION } from '../../base/info'; import { parseVersion } from '../../base/info/pythonVersion'; @@ -238,6 +238,11 @@ export class Conda { // Produce a list of candidate binaries to be probed by exec'ing them. async function* getCandidates() { + const customCondaPath = getPythonSetting('condaPath'); + if (customCondaPath && customCondaPath !== 'conda') { + // If user has specified a custom conda path, use it first. + yield customCondaPath; + } // Check unqualified filename first, in case it's on PATH. yield 'conda'; if (getOSType() === OSType.Windows) { diff --git a/src/test/common/terminals/environmentActivationProviders/terminalActivation.testvirtualenvs.ts b/src/test/common/terminals/environmentActivationProviders/terminalActivation.testvirtualenvs.ts index 8a3d7c44208d..dc2324ac9900 100644 --- a/src/test/common/terminals/environmentActivationProviders/terminalActivation.testvirtualenvs.ts +++ b/src/test/common/terminals/environmentActivationProviders/terminalActivation.testvirtualenvs.ts @@ -24,9 +24,8 @@ import { import { EXTENSION_ROOT_DIR_FOR_TESTS, TEST_TIMEOUT } from '../../../constants'; import { sleep } from '../../../core'; import { initialize, initializeTest } from '../../../initialize'; -import * as ExperimentHelpers from '../../../../client/common/experiments/helpers'; -suite.skip('Activation of Environments in Terminal', () => { +suite('Activation of Environments in Terminal', () => { const file = path.join( EXTENSION_ROOT_DIR_FOR_TESTS, 'src', @@ -61,13 +60,12 @@ suite.skip('Activation of Environments in Terminal', () => { let experiments: IExperimentService; const sandbox = sinon.createSandbox(); suiteSetup(async () => { - sandbox.stub(ExperimentHelpers, 'inDiscoveryExperiment').resolves(false); envPaths = await fs.readJson(envsLocation); terminalSettings = vscode.workspace.getConfiguration('terminal', vscode.workspace.workspaceFolders![0].uri); pythonSettings = vscode.workspace.getConfiguration('python', vscode.workspace.workspaceFolders![0].uri); - defaultShell.Windows = terminalSettings.inspect('integrated.shell.windows').globalValue; - defaultShell.Linux = terminalSettings.inspect('integrated.shell.linux').globalValue; - await terminalSettings.update('integrated.shell.linux', '/bin/bash', vscode.ConfigurationTarget.Global); + defaultShell.Windows = terminalSettings.inspect('integrated.defaultProfile.windows').globalValue; + defaultShell.Linux = terminalSettings.inspect('integrated.defaultProfile.linux').globalValue; + await terminalSettings.update('integrated.defaultProfile.linux', 'bash', vscode.ConfigurationTarget.Global); experiments = (await initialize()).serviceContainer.get(IExperimentService); }); @@ -105,11 +103,15 @@ suite.skip('Activation of Environments in Terminal', () => { vscode.ConfigurationTarget.WorkspaceFolder, ); await terminalSettings.update( - 'integrated.shell.windows', + 'integrated.defaultProfile.windows', defaultShell.Windows, vscode.ConfigurationTarget.Global, ); - await terminalSettings.update('integrated.shell.linux', defaultShell.Linux, vscode.ConfigurationTarget.Global); + await terminalSettings.update( + 'integrated.defaultProfile.linux', + defaultShell.Linux, + vscode.ConfigurationTarget.Global, + ); await pythonSettings.update('condaPath', undefined, vscode.ConfigurationTarget.Workspace); if (experiments.inExperimentSync(DeprecatePythonPath.experiment)) { await resetGlobalInterpreterPathSetting(); @@ -189,9 +191,10 @@ suite.skip('Activation of Environments in Terminal', () => { await testActivation(envPaths.virtualEnvPath); }); test('Should activate with conda', async () => { + // Powershell does not work with conda by default, hence use cmd. await terminalSettings.update( - 'integrated.shell.windows', - 'C:\\Windows\\System32\\cmd.exe', + 'integrated.defaultProfile.windows', + 'Command Prompt', vscode.ConfigurationTarget.Global, ); await pythonSettings.update('condaPath', envPaths.condaExecPath, vscode.ConfigurationTarget.Workspace); diff --git a/src/test/pythonEnvironments/base/locators/composite/resolverUtils.unit.test.ts b/src/test/pythonEnvironments/base/locators/composite/resolverUtils.unit.test.ts index 0574685ffeca..c5de00c3072a 100644 --- a/src/test/pythonEnvironments/base/locators/composite/resolverUtils.unit.test.ts +++ b/src/test/pythonEnvironments/base/locators/composite/resolverUtils.unit.test.ts @@ -27,11 +27,21 @@ import { import { resolveBasicEnv } from '../../../../../client/pythonEnvironments/base/locators/composite/resolverUtils'; suite('Resolver Utils', () => { + let getWorkspaceFolders: sinon.SinonStub; + setup(() => { + sinon.stub(externalDependencies, 'getPythonSetting').withArgs('condaPath').returns('conda'); + getWorkspaceFolders = sinon.stub(externalDependencies, 'getWorkspaceFolders'); + getWorkspaceFolders.returns([]); + }); + + teardown(() => { + sinon.restore(); + }); + suite('Pyenv', () => { const testPyenvRoot = path.join(TEST_LAYOUT_ROOT, 'pyenvhome', '.pyenv'); const testPyenvVersionsDir = path.join(testPyenvRoot, 'versions'); setup(() => { - sinon.stub(externalDependencies, 'getWorkspaceFolders').returns([]); sinon.stub(platformApis, 'getEnvironmentVariable').withArgs('PYENV_ROOT').returns(testPyenvRoot); }); @@ -68,7 +78,6 @@ suite('Resolver Utils', () => { const testStoreAppRoot = path.join(testLocalAppData, 'Microsoft', 'WindowsApps'); setup(() => { - sinon.stub(externalDependencies, 'getWorkspaceFolders').returns([]); sinon.stub(platformApis, 'getEnvironmentVariable').withArgs('LOCALAPPDATA').returns(testLocalAppData); }); @@ -199,10 +208,6 @@ suite('Resolver Utils', () => { }; } - setup(() => { - sinon.stub(externalDependencies, 'getWorkspaceFolders').returns([]); - }); - teardown(() => { sinon.restore(); }); @@ -265,7 +270,7 @@ suite('Resolver Utils', () => { suite('Simple envs', () => { const testVirtualHomeDir = path.join(TEST_LAYOUT_ROOT, 'virtualhome'); setup(() => { - sinon.stub(externalDependencies, 'getWorkspaceFolders').returns([testVirtualHomeDir]); + getWorkspaceFolders.returns([testVirtualHomeDir]); }); teardown(() => { @@ -318,7 +323,6 @@ suite('Resolver Utils', () => { const testPosixKnownPathsRoot = path.join(TEST_LAYOUT_ROOT, 'posixroot'); const testLocation3 = path.join(testPosixKnownPathsRoot, 'location3'); setup(() => { - sinon.stub(externalDependencies, 'getWorkspaceFolders').returns([]); sinon.stub(platformApis, 'getOSType').callsFake(() => platformApis.OSType.Linux); }); @@ -514,7 +518,6 @@ suite('Resolver Utils', () => { setup(async () => { sinon.stub(winreg, 'readRegistryValues').callsFake(fakeRegistryValues); sinon.stub(winreg, 'readRegistryKeys').callsFake(fakeRegistryKeys); - sinon.stub(externalDependencies, 'getWorkspaceFolders').returns([]); sinon.stub(platformApis, 'getOSType').callsFake(() => platformApis.OSType.Windows); }); diff --git a/src/test/pythonEnvironments/common/environmentManagers/conda.unit.test.ts b/src/test/pythonEnvironments/common/environmentManagers/conda.unit.test.ts index 7bcb4b54d05b..369c65b3629f 100644 --- a/src/test/pythonEnvironments/common/environmentManagers/conda.unit.test.ts +++ b/src/test/pythonEnvironments/common/environmentManagers/conda.unit.test.ts @@ -85,8 +85,12 @@ suite('Conda and its environments are located correctly', () => { }; } + let getPythonSetting: sinon.SinonStub; + setup(() => { osType = platform.OSType.Unknown; + getPythonSetting = sinon.stub(externalDependencies, 'getPythonSetting'); + getPythonSetting.withArgs('condaPath').returns('conda'); homeDir = undefined; execPath = []; files = {}; @@ -189,6 +193,17 @@ suite('Conda and its environments are located correctly', () => { expect(conda).to.equal(undefined, 'conda should be missing'); }); + test('Must find conda using `python.condaPath` setting and prefer it', async () => { + getPythonSetting.withArgs('condaPath').returns('condaPath/conda'); + + files = { + condaPath: { + conda: JSON.stringify(condaInfo('4.8.0')), + }, + }; + await expectConda('/condaPath/conda'); + }); + test('Must find conda on PATH, and prefer it', async () => { osType = platform.OSType.Linux; execPath = ['/bin'];