diff --git a/news/2 Fixes/16355.md b/news/2 Fixes/16355.md new file mode 100644 index 000000000000..32cd40cd4690 --- /dev/null +++ b/news/2 Fixes/16355.md @@ -0,0 +1 @@ +Fix issue with sys.prefix when getting environment details. diff --git a/src/client/pythonEnvironments/index.ts b/src/client/pythonEnvironments/index.ts index 36e829c95465..d526a79a7471 100644 --- a/src/client/pythonEnvironments/index.ts +++ b/src/client/pythonEnvironments/index.ts @@ -25,7 +25,7 @@ import { PosixKnownPathsLocator } from './discovery/locators/services/posixKnown import { PyenvLocator } from './discovery/locators/services/pyenvLocator'; import { WindowsRegistryLocator } from './discovery/locators/services/windowsRegistryLocator'; import { WindowsStoreLocator } from './discovery/locators/services/windowsStoreLocator'; -import { EnvironmentInfoService } from './info/environmentInfoService'; +import { getEnvironmentInfoService } from './info/environmentInfoService'; import { isComponentEnabled, registerLegacyDiscoveryForIOC, registerNewDiscoveryForIOC } from './legacyIOC'; import { EnvironmentsSecurity, IEnvironmentsSecurity } from './security'; import { PoetryLocator } from './discovery/locators/services/poetryLocator'; @@ -37,7 +37,7 @@ export async function initialize(ext: ExtensionState): Promise createLocators(ext, environmentsSecurity), - // Other sub-commonents (e.g. config, "current" env) will go here. + // Other sub-components (e.g. config, "current" env) will go here. ); ext.disposables.push(api); @@ -94,8 +94,7 @@ async function createLocators( ); // Create the env info service used by ResolvingLocator and CachingLocator. - const envInfoService = new EnvironmentInfoService(); - ext.disposables.push(envInfoService); + const envInfoService = getEnvironmentInfoService(ext.disposables); // Build the stack of composite locators. locators = new PythonEnvsReducer(locators); diff --git a/src/client/pythonEnvironments/info/environmentInfoService.ts b/src/client/pythonEnvironments/info/environmentInfoService.ts index a13e80affd58..ad793f4ecaa7 100644 --- a/src/client/pythonEnvironments/info/environmentInfoService.ts +++ b/src/client/pythonEnvironments/info/environmentInfoService.ts @@ -2,6 +2,7 @@ // Licensed under the MIT License. import { traceVerbose } from '../../common/logger'; +import { IDisposableRegistry } from '../../common/types'; import { createDeferred, Deferred } from '../../common/utils/async'; import { createRunningWorkerPool, IWorkerPool, QueuePosition } from '../../common/utils/workerPool'; import { getInterpreterInfo, InterpreterInformation } from '../base/info/interpreter'; @@ -32,7 +33,7 @@ async function buildEnvironmentInfo(interpreterPath: string): Promise { + service.dispose(); + envInfoService = undefined; + }, + }); + envInfoService = service; + } + return envInfoService; +} diff --git a/src/client/pythonEnvironments/legacyIOC.ts b/src/client/pythonEnvironments/legacyIOC.ts index da71a24eca34..2e5c9f9536bd 100644 --- a/src/client/pythonEnvironments/legacyIOC.ts +++ b/src/client/pythonEnvironments/legacyIOC.ts @@ -69,6 +69,7 @@ import { EnvironmentsSecurity, IEnvironmentsSecurity } from './security'; import { toSemverLikeVersion } from './base/info/pythonVersion'; import { PythonVersion } from './info/pythonVersion'; import { IExtensionSingleActivationService } from '../activation/types'; +import { EnvironmentInfoServiceQueuePriority, getEnvironmentInfoService } from './info/environmentInfoService'; const convertedKinds = new Map( Object.entries({ @@ -195,14 +196,23 @@ class ComponentAdapter implements IComponentAdapter { // We use the same getInterpreters() here as for IInterpreterLocatorService. public async getInterpreterDetails(pythonPath: string, resource?: vscode.Uri): Promise { - const info = buildEnvInfo({ executable: pythonPath }); + const envInfo = buildEnvInfo({ executable: pythonPath }); if (resource !== undefined) { const wsFolder = vscode.workspace.getWorkspaceFolder(resource); if (wsFolder !== undefined) { - info.searchLocation = wsFolder.uri; + envInfo.searchLocation = wsFolder.uri; + } + } + + const env = (await this.api.resolveEnv(envInfo)) ?? envInfo; + if (env.executable.sysPrefix) { + const execInfoService = getEnvironmentInfoService(); + const info = await execInfoService.getEnvironmentInfo(pythonPath, EnvironmentInfoServiceQueuePriority.High); + if (info) { + env.executable.sysPrefix = info.executable.sysPrefix; + env.version = info.version; } } - const env = await this.api.resolveEnv(info); return convertEnvInfo(env ?? buildEnvInfo({ executable: pythonPath })); } diff --git a/src/test/pythonEnvironments/base/locators/composite/environmentsResolver.unit.test.ts b/src/test/pythonEnvironments/base/locators/composite/environmentsResolver.unit.test.ts index ff4256849284..24a3dea5ceb9 100644 --- a/src/test/pythonEnvironments/base/locators/composite/environmentsResolver.unit.test.ts +++ b/src/test/pythonEnvironments/base/locators/composite/environmentsResolver.unit.test.ts @@ -8,6 +8,7 @@ import * as sinon from 'sinon'; import { ImportMock } from 'ts-mock-imports'; import { EventEmitter } from 'vscode'; import { ExecutionResult } from '../../../../../client/common/process/types'; +import { IDisposableRegistry } from '../../../../../client/common/types'; import { createDeferred } from '../../../../../client/common/utils/async'; import { Architecture } from '../../../../../client/common/utils/platform'; import { PythonEnvInfo, PythonEnvKind } from '../../../../../client/pythonEnvironments/base/info'; @@ -17,19 +18,24 @@ import { PythonEnvsResolver } from '../../../../../client/pythonEnvironments/bas import { getEnvs as getEnvsWithUpdates } from '../../../../../client/pythonEnvironments/base/locatorUtils'; import { PythonEnvsChangedEvent } from '../../../../../client/pythonEnvironments/base/watcher'; import * as ExternalDep from '../../../../../client/pythonEnvironments/common/externalDependencies'; -import { EnvironmentInfoService } from '../../../../../client/pythonEnvironments/info/environmentInfoService'; +import { + getEnvironmentInfoService, + IEnvironmentInfoService, +} from '../../../../../client/pythonEnvironments/info/environmentInfoService'; import { sleep } from '../../../../core'; import { createNamedEnv, getEnvs, SimpleLocator } from '../../common'; suite('Python envs locator - Environments Resolver', () => { - let envInfoService: EnvironmentInfoService; + let envInfoService: IEnvironmentInfoService; + let disposables: IDisposableRegistry; setup(() => { - envInfoService = new EnvironmentInfoService(); + disposables = []; + envInfoService = getEnvironmentInfoService(disposables); }); teardown(() => { sinon.restore(); - envInfoService.dispose(); + disposables.forEach((d) => d.dispose()); }); /** diff --git a/src/test/pythonEnvironments/info/environmentInfoService.functional.test.ts b/src/test/pythonEnvironments/info/environmentInfoService.functional.test.ts index 1afbb21a8b80..fc8e2482978f 100644 --- a/src/test/pythonEnvironments/info/environmentInfoService.functional.test.ts +++ b/src/test/pythonEnvironments/info/environmentInfoService.functional.test.ts @@ -7,17 +7,19 @@ import * as assert from 'assert'; import * as sinon from 'sinon'; import { ImportMock } from 'ts-mock-imports'; import { ExecutionResult } from '../../../client/common/process/types'; +import { IDisposableRegistry } from '../../../client/common/types'; import { Architecture } from '../../../client/common/utils/platform'; import { InterpreterInformation } from '../../../client/pythonEnvironments/base/info/interpreter'; import { parseVersion } from '../../../client/pythonEnvironments/base/info/pythonVersion'; import * as ExternalDep from '../../../client/pythonEnvironments/common/externalDependencies'; import { - EnvironmentInfoService, EnvironmentInfoServiceQueuePriority, + getEnvironmentInfoService, } from '../../../client/pythonEnvironments/info/environmentInfoService'; suite('Environment Info Service', () => { let stubShellExec: sinon.SinonStub; + let disposables: IDisposableRegistry; function createExpectedEnvInfo(executable: string): InterpreterInformation { return { @@ -36,6 +38,7 @@ suite('Environment Info Service', () => { } setup(() => { + disposables = []; stubShellExec = ImportMock.mockFunction( ExternalDep, 'shellExecute', @@ -49,9 +52,10 @@ suite('Environment Info Service', () => { }); teardown(() => { stubShellExec.restore(); + disposables.forEach((d) => d.dispose()); }); test('Add items to queue and get results', async () => { - const envService = new EnvironmentInfoService(); + const envService = getEnvironmentInfoService(disposables); const promises: Promise[] = []; const expected: InterpreterInformation[] = []; for (let i = 0; i < 10; i = i + 1) { @@ -74,7 +78,7 @@ suite('Environment Info Service', () => { }); test('Add same item to queue', async () => { - const envService = new EnvironmentInfoService(); + const envService = getEnvironmentInfoService(disposables); const promises: Promise[] = []; const expected: InterpreterInformation[] = []; @@ -96,7 +100,7 @@ suite('Environment Info Service', () => { }); test('isInfoProvided() returns true for items already processed', async () => { - const envService = new EnvironmentInfoService(); + const envService = getEnvironmentInfoService(disposables); let result: boolean; const promises: Promise[] = []; const path1 = 'any-path1'; @@ -113,7 +117,7 @@ suite('Environment Info Service', () => { }); test('isInfoProvided() returns false otherwise', async () => { - const envService = new EnvironmentInfoService(); + const envService = getEnvironmentInfoService(disposables); const promises: Promise[] = []; const path1 = 'any-path1'; const path2 = 'any-path2';