From 9b1071f11dcf80f05e88274865127a70b868908b Mon Sep 17 00:00:00 2001 From: Stella Huang Date: Tue, 14 Apr 2026 13:43:18 -0700 Subject: [PATCH] fix conda global --- src/managers/conda/condaEnvManager.ts | 1 + .../condaEnvManager.setGlobal.unit.test.ts | 110 ++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 src/test/managers/conda/condaEnvManager.setGlobal.unit.test.ts diff --git a/src/managers/conda/condaEnvManager.ts b/src/managers/conda/condaEnvManager.ts index 1db198b4..73e76232 100644 --- a/src/managers/conda/condaEnvManager.ts +++ b/src/managers/conda/condaEnvManager.ts @@ -311,6 +311,7 @@ export class CondaEnvManager implements EnvironmentManager, Disposable { : undefined; if (scope === undefined) { + this.globalEnv = checkedEnv; await setCondaForGlobal(checkedEnv?.environmentPath?.fsPath); } else if (scope instanceof Uri) { const folder = this.api.getPythonProject(scope); diff --git a/src/test/managers/conda/condaEnvManager.setGlobal.unit.test.ts b/src/test/managers/conda/condaEnvManager.setGlobal.unit.test.ts new file mode 100644 index 00000000..ebd31b2d --- /dev/null +++ b/src/test/managers/conda/condaEnvManager.setGlobal.unit.test.ts @@ -0,0 +1,110 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import assert from 'assert'; +import * as sinon from 'sinon'; +import { Uri } from 'vscode'; +import { PythonEnvironment, PythonEnvironmentApi } from '../../../api'; +import { PythonEnvironmentImpl } from '../../../internal.api'; +import { CondaEnvManager } from '../../../managers/conda/condaEnvManager'; +import * as condaUtils from '../../../managers/conda/condaUtils'; +import { NativePythonFinder } from '../../../managers/common/nativePythonFinder'; + +function makeEnv(name: string, envPath: string, version: string = '3.12.0'): PythonEnvironment { + return new PythonEnvironmentImpl( + { id: `${name}-test`, managerId: 'ms-python.python:conda' }, + { + name, + displayName: `${name} (${version})`, + displayPath: envPath, + version, + environmentPath: Uri.file(envPath), + sysPrefix: envPath, + execInfo: { + run: { executable: 'python' }, + }, + }, + ); +} + +function createManager(): CondaEnvManager { + const manager = new CondaEnvManager( + {} as NativePythonFinder, + {} as PythonEnvironmentApi, + { info: sinon.stub(), error: sinon.stub(), warn: sinon.stub() } as any, + ); + // Bypass initialization + (manager as any)._initialized = { completed: true, promise: Promise.resolve() }; + (manager as any).collection = []; + return manager; +} + +suite('CondaEnvManager.set - globalEnv update', () => { + let setCondaForGlobalStub: sinon.SinonStub; + let checkNoPythonStub: sinon.SinonStub; + + setup(() => { + setCondaForGlobalStub = sinon.stub(condaUtils, 'setCondaForGlobal').resolves(); + checkNoPythonStub = sinon.stub(condaUtils, 'checkForNoPythonCondaEnvironment'); + }); + + teardown(() => { + sinon.restore(); + }); + + test('set(undefined, env) updates globalEnv in memory', async () => { + const manager = createManager(); + const oldEnv = makeEnv('base', '/miniconda3', '3.11.0'); + const newEnv = makeEnv('myenv', '/miniconda3/envs/myenv', '3.12.0'); + (manager as any).globalEnv = oldEnv; + + // checkForNoPythonCondaEnvironment returns the env as-is (has Python) + checkNoPythonStub.resolves(newEnv); + + await manager.set(undefined, newEnv); + + // globalEnv should now be updated in memory + const result = await manager.get(undefined); + assert.strictEqual(result, newEnv, 'get(undefined) should return the newly set environment'); + assert.notStrictEqual(result, oldEnv, 'get(undefined) should NOT return the old environment'); + }); + + test('set(undefined, env) persists to disk', async () => { + const manager = createManager(); + const newEnv = makeEnv('myenv', '/miniconda3/envs/myenv', '3.12.0'); + checkNoPythonStub.resolves(newEnv); + + await manager.set(undefined, newEnv); + + assert.ok(setCondaForGlobalStub.calledOnce, 'setCondaForGlobal should be called'); + assert.strictEqual( + setCondaForGlobalStub.firstCall.args[0], + newEnv.environmentPath.fsPath, + 'should persist the correct path', + ); + }); + + test('set(undefined, undefined) clears globalEnv', async () => { + const manager = createManager(); + const oldEnv = makeEnv('base', '/miniconda3', '3.11.0'); + (manager as any).globalEnv = oldEnv; + + await manager.set(undefined, undefined); + + const result = await manager.get(undefined); + assert.strictEqual(result, undefined, 'get(undefined) should return undefined after clearing'); + }); + + test('set(undefined, noPythonEnv) where user declines install clears globalEnv', async () => { + const manager = createManager(); + const oldEnv = makeEnv('base', '/miniconda3', '3.11.0'); + const noPythonEnv = makeEnv('nopy', '/miniconda3/envs/nopy', 'no-python'); + (manager as any).globalEnv = oldEnv; + + // User declined to install Python + checkNoPythonStub.resolves(undefined); + + await manager.set(undefined, noPythonEnv); + + const result = await manager.get(undefined); + assert.strictEqual(result, undefined, 'globalEnv should be cleared when checkedEnv is undefined'); + }); +});