diff --git a/src/client/pythonEnvironments/base/info/interpreter.ts b/src/client/pythonEnvironments/base/info/interpreter.ts index 4acb15f5ee003..f6daa31ee03bf 100644 --- a/src/client/pythonEnvironments/base/info/interpreter.ts +++ b/src/client/pythonEnvironments/base/info/interpreter.ts @@ -7,7 +7,7 @@ import { Architecture } from '../../../common/utils/platform'; import { copyPythonExecInfo, PythonExecInfo } from '../../exec'; import { parseVersion } from './pythonVersion'; -type PythonEnvInformation = { +export type InterpreterInformation = { arch: Architecture; executable: { filename: string; @@ -26,7 +26,7 @@ type PythonEnvInformation = { * @param python - the path to the Python executable * @param raw - the information returned by the `interpreterInfo.py` script */ -export function extractPythonEnvInfo(python: string, raw: PythonEnvInfo): PythonEnvInformation { +export function extractPythonEnvInfo(python: string, raw: PythonEnvInfo): InterpreterInformation { const rawVersion = `${raw.versionInfo.slice(0, 3).join('.')}-${raw.versionInfo[3]}`; const version = parseVersion(rawVersion); version.sysVersion = raw.sysVersion; @@ -64,7 +64,7 @@ export async function getInterpreterInfo( python: PythonExecInfo, shellExec: ShellExecFunc, logger?: Logger, -): Promise { +): Promise { const [args, parse] = getInterpreterInfoCommand(); const info = copyPythonExecInfo(python, args); const argv = [info.command, ...info.args]; diff --git a/src/client/pythonEnvironments/info/environmentInfoService.ts b/src/client/pythonEnvironments/info/environmentInfoService.ts index 30ff146ce0480..f4b91b215539e 100644 --- a/src/client/pythonEnvironments/info/environmentInfoService.ts +++ b/src/client/pythonEnvironments/info/environmentInfoService.ts @@ -4,8 +4,7 @@ import { injectable } from 'inversify'; import { createDeferred, Deferred } from '../../common/utils/async'; import { createWorkerPool, IWorkerPool, QueuePosition } from '../../common/utils/workerPool'; -import { PythonEnvInfo } from '../base/info'; -import { getInterpreterInfo } from '../base/info/interpreter'; +import { getInterpreterInfo, InterpreterInformation } from '../base/info/interpreter'; import { shellExecute } from '../common/externalDependencies'; import { buildPythonExecInfo } from '../exec'; @@ -17,26 +16,17 @@ export enum EnvironmentInfoServiceQueuePriority { export const IEnvironmentInfoService = Symbol('IEnvironmentInfoService'); export interface IEnvironmentInfoService { getEnvironmentInfo( - environment: PythonEnvInfo, + interpreterPath: string, priority?: EnvironmentInfoServiceQueuePriority - ): Promise; + ): Promise; } -async function buildEnvironmentInfo(environment: PythonEnvInfo): Promise { - const interpreterInfo = await getInterpreterInfo( - buildPythonExecInfo(environment.executable.filename), - shellExecute, - ); +async function buildEnvironmentInfo(interpreterPath: string): Promise { + const interpreterInfo = await getInterpreterInfo(buildPythonExecInfo(interpreterPath), shellExecute); if (interpreterInfo === undefined || interpreterInfo.version === undefined) { return undefined; } - // Deep copy into a new object - const resolvedEnv = JSON.parse(JSON.stringify(environment)) as PythonEnvInfo; - resolvedEnv.version = interpreterInfo.version; - resolvedEnv.executable.filename = interpreterInfo.executable.filename; - resolvedEnv.executable.sysPrefix = interpreterInfo.executable.sysPrefix; - resolvedEnv.arch = interpreterInfo.arch; - return resolvedEnv; + return interpreterInfo; } @injectable() @@ -45,29 +35,31 @@ export class EnvironmentInfoService implements IEnvironmentInfoService { // path again and again in a given session. This information will likely not change in a given // session. There are definitely cases where this will change. But a simple reload should address // those. - private readonly cache: Map> = new Map>(); + private readonly cache: Map> = new Map< + string, + Deferred + >(); - private readonly workerPool: IWorkerPool; + private readonly workerPool: IWorkerPool; public constructor() { - this.workerPool = createWorkerPool(buildEnvironmentInfo); + this.workerPool = createWorkerPool(buildEnvironmentInfo); } public async getEnvironmentInfo( - environment: PythonEnvInfo, + interpreterPath: string, priority?: EnvironmentInfoServiceQueuePriority, - ): Promise { - const interpreterPath = environment.executable.filename; + ): Promise { const result = this.cache.get(interpreterPath); if (result !== undefined) { // Another call for this environment has already been made, return its result return result.promise; } - const deferred = createDeferred(); + const deferred = createDeferred(); this.cache.set(interpreterPath, deferred); return (priority === EnvironmentInfoServiceQueuePriority.High - ? this.workerPool.addToQueue(environment, QueuePosition.Front) - : this.workerPool.addToQueue(environment, QueuePosition.Back) + ? this.workerPool.addToQueue(interpreterPath, QueuePosition.Front) + : this.workerPool.addToQueue(interpreterPath, QueuePosition.Back) ).then((r) => { if (r !== undefined) { deferred.resolve(r); diff --git a/src/test/pythonEnvironments/info/environmentInfoService.functional.test.ts b/src/test/pythonEnvironments/info/environmentInfoService.functional.test.ts index b0803ba064d23..ac3660c1b5e70 100644 --- a/src/test/pythonEnvironments/info/environmentInfoService.functional.test.ts +++ b/src/test/pythonEnvironments/info/environmentInfoService.functional.test.ts @@ -8,7 +8,7 @@ import * as sinon from 'sinon'; import { ImportMock } from 'ts-mock-imports'; import { ExecutionResult } from '../../../client/common/process/types'; import { Architecture } from '../../../client/common/utils/platform'; -import { PythonEnvInfo, PythonEnvKind } from '../../../client/pythonEnvironments/base/info'; +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 { @@ -19,13 +19,9 @@ import { suite('Environment Info Service', () => { let stubShellExec: sinon.SinonStub; - function createEnvInfo(executable: string): PythonEnvInfo { + function createExpectedEnvInfo(executable: string): InterpreterInformation { return { - id: '', - kind: PythonEnvKind.Unknown, version: parseVersion('0.0.0'), - name: '', - location: '', arch: Architecture.x64, executable: { filename: executable, @@ -33,25 +29,6 @@ suite('Environment Info Service', () => { mtime: -1, ctime: -1, }, - distro: { org: '' }, - }; - } - - function createExpectedEnvInfo(executable: string): PythonEnvInfo { - return { - id: '', - kind: PythonEnvKind.Unknown, - version: parseVersion('3.8.3-final'), - name: '', - location: '', - arch: Architecture.x64, - executable: { - filename: executable, - sysPrefix: 'path', - mtime: -1, - ctime: -1, - }, - distro: { org: '' }, }; } @@ -72,16 +49,14 @@ suite('Environment Info Service', () => { }); test('Add items to queue and get results', async () => { const envService = new EnvironmentInfoService(); - const promises: Promise[] = []; - const expected: PythonEnvInfo[] = []; + const promises: Promise[] = []; + const expected: InterpreterInformation[] = []; for (let i = 0; i < 10; i = i + 1) { const path = `any-path${i}`; if (i < 5) { - promises.push(envService.getEnvironmentInfo(createEnvInfo(path))); + promises.push(envService.getEnvironmentInfo(path)); } else { - promises.push( - envService.getEnvironmentInfo(createEnvInfo(path), EnvironmentInfoServiceQueuePriority.High), - ); + promises.push(envService.getEnvironmentInfo(path, EnvironmentInfoServiceQueuePriority.High)); } expected.push(createExpectedEnvInfo(path)); } @@ -97,17 +72,17 @@ suite('Environment Info Service', () => { test('Add same item to queue', async () => { const envService = new EnvironmentInfoService(); - const promises: Promise[] = []; - const expected: PythonEnvInfo[] = []; + const promises: Promise[] = []; + const expected: InterpreterInformation[] = []; const path = 'any-path'; // Clear call counts stubShellExec.resetHistory(); // Evaluate once so the result is cached. - await envService.getEnvironmentInfo(createEnvInfo(path)); + await envService.getEnvironmentInfo(path); for (let i = 0; i < 10; i = i + 1) { - promises.push(envService.getEnvironmentInfo(createEnvInfo(path))); + promises.push(envService.getEnvironmentInfo(path)); expected.push(createExpectedEnvInfo(path)); }