diff --git a/news/1 Enhancements/17030.md b/news/1 Enhancements/17030.md new file mode 100644 index 000000000000..95c673c68db6 --- /dev/null +++ b/news/1 Enhancements/17030.md @@ -0,0 +1 @@ +Do not query to get all interpreters where it's not needed in the extension code. diff --git a/src/client/application/diagnostics/checks/macPythonInterpreter.ts b/src/client/application/diagnostics/checks/macPythonInterpreter.ts index 000600d34e2d..f18a58df594f 100644 --- a/src/client/application/diagnostics/checks/macPythonInterpreter.ts +++ b/src/client/application/diagnostics/checks/macPythonInterpreter.ts @@ -87,7 +87,7 @@ export class InvalidMacPythonInterpreterService extends BaseDiagnosticsService { return []; } - const hasInterpreters = await this.interpreterService.hasInterpreters; + const hasInterpreters = await this.interpreterService.hasInterpreters(); if (!hasInterpreters) { return []; } @@ -104,17 +104,20 @@ export class InvalidMacPythonInterpreterService extends BaseDiagnosticsService { return []; } - const interpreters = await this.interpreterService.getInterpreters(resource); - for (const info of interpreters) { - if (!(await this.helper.isMacDefaultPythonPath(info.path))) { - return [ - new InvalidMacPythonInterpreterDiagnostic( - DiagnosticCodes.MacInterpreterSelectedAndHaveOtherInterpretersDiagnostic, - resource, - ), - ]; - } + if ( + await this.interpreterService.hasInterpreters((e) => + this.helper.isMacDefaultPythonPath(e.path).then((x) => !x), + ) + ) { + // If non-mac default interpreters exist. + return [ + new InvalidMacPythonInterpreterDiagnostic( + DiagnosticCodes.MacInterpreterSelectedAndHaveOtherInterpretersDiagnostic, + resource, + ), + ]; } + return [ new InvalidMacPythonInterpreterDiagnostic( DiagnosticCodes.MacInterpreterSelectedAndNoOtherInterpretersDiagnostic, diff --git a/src/client/application/diagnostics/checks/pythonInterpreter.ts b/src/client/application/diagnostics/checks/pythonInterpreter.ts index cc5194d7b59a..f46d5247a24f 100644 --- a/src/client/application/diagnostics/checks/pythonInterpreter.ts +++ b/src/client/application/diagnostics/checks/pythonInterpreter.ts @@ -67,14 +67,7 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService { } const interpreterService = this.serviceContainer.get(IInterpreterService); - // hasInterpreters being false can mean one of 2 things: - // 1. getInterpreters hasn't returned any interpreters; - // 2. getInterpreters hasn't run yet. - // We want to make sure that false comes from 1, so we're adding this fix until we refactor interpreter discovery. - // Also see https://github.com/microsoft/vscode-python/issues/3023. - const hasInterpreters = - (await interpreterService.hasInterpreters) || - (await interpreterService.getInterpreters(resource)).length > 0; + const hasInterpreters = await interpreterService.hasInterpreters(); if (!hasInterpreters) { return [new InvalidPythonInterpreterDiagnostic(DiagnosticCodes.NoPythonInterpretersDiagnostic, resource)]; diff --git a/src/client/debugger/extension/adapter/factory.ts b/src/client/debugger/extension/adapter/factory.ts index e63cc9ae535c..c54d3c8d44dd 100644 --- a/src/client/debugger/extension/adapter/factory.ts +++ b/src/client/debugger/extension/adapter/factory.ts @@ -114,6 +114,7 @@ export class DebugAdapterDescriptorFactory implements IDebugAdapterDescriptorFac return interpreter.path; } + await this.interpreterService.hasInterpreters(); // Wait until we know whether we have an interpreter const interpreters = await this.interpreterService.getInterpreters(resourceUri); if (interpreters.length === 0) { this.notifySelectInterpreter().ignoreErrors(); diff --git a/src/client/interpreter/autoSelection/index.ts b/src/client/interpreter/autoSelection/index.ts index 9d6af2b303e2..c6191189d9e7 100644 --- a/src/client/interpreter/autoSelection/index.ts +++ b/src/client/interpreter/autoSelection/index.ts @@ -196,7 +196,7 @@ export class InterpreterAutoSelectionService implements IInterpreterAutoSelectio private async autoselectInterpreterWithLocators(resource: Resource): Promise { // Do not perform a full interpreter search if we already have cached interpreters for this workspace. const queriedState = this.getAutoSelectionInterpretersQueryState(resource); - const interpreters = await this.interpreterService.getInterpreters(resource, { + const interpreters = await this.interpreterService.getAllInterpreters(resource, { ignoreCache: queriedState.value !== true, }); const workspaceUri = this.interpreterHelper.getActiveWorkspaceUri(resource); diff --git a/src/client/interpreter/configuration/interpreterSelector/interpreterSelector.ts b/src/client/interpreter/configuration/interpreterSelector/interpreterSelector.ts index f6766e52d8fa..3b60e25169fc 100644 --- a/src/client/interpreter/configuration/interpreterSelector/interpreterSelector.ts +++ b/src/client/interpreter/configuration/interpreterSelector/interpreterSelector.ts @@ -25,11 +25,10 @@ export class InterpreterSelector implements IInterpreterSelector { } public async getSuggestions(resource: Resource, ignoreCache?: boolean): Promise { - const interpreters = await this.interpreterManager.getInterpreters(resource, { + const interpreters = await this.interpreterManager.getAllInterpreters(resource, { onSuggestion: true, ignoreCache, }); - interpreters.sort(this.envTypeComparer.compare.bind(this.envTypeComparer)); return Promise.all(interpreters.map((item) => this.suggestionToQuickPickItem(item, resource))); diff --git a/src/client/interpreter/contracts.ts b/src/client/interpreter/contracts.ts index af4ea3f1e6d3..cba1f53297aa 100644 --- a/src/client/interpreter/contracts.ts +++ b/src/client/interpreter/contracts.ts @@ -1,8 +1,10 @@ import { SemVer } from 'semver'; import { CodeLensProvider, ConfigurationTarget, Disposable, Event, TextDocument, Uri } from 'vscode'; import { IExtensionSingleActivationService } from '../activation/types'; +import { FileChangeType } from '../common/platform/fileSystemWatcher'; import { Resource } from '../common/types'; import { PythonEnvSource } from '../pythonEnvironments/base/info'; +import { PythonLocatorQuery } from '../pythonEnvironments/base/locator'; import { CondaEnvironmentInfo, CondaInfo } from '../pythonEnvironments/common/environmentManagers/conda'; import { EnvironmentType, PythonEnvironment } from '../pythonEnvironments/info'; @@ -30,20 +32,26 @@ export interface IVirtualEnvironmentsSearchPathProvider { getSearchPaths(resource?: Uri): Promise; } +export type PythonEnvironmentsChangedEvent = { + type?: FileChangeType; + resource?: Uri; + old?: PythonEnvironment; + update?: PythonEnvironment | undefined; +}; + export const IComponentAdapter = Symbol('IComponentAdapter'); export interface IComponentAdapter { + triggerRefresh(query?: PythonLocatorQuery): Promise; + readonly refreshPromise: Promise; + readonly onChanged: Event; // InterpreterLocatorProgressStatubarHandler readonly onRefreshing: Event; readonly onRefreshed: Event; // VirtualEnvPrompt onDidCreate(resource: Resource, callback: () => void): Disposable; // IInterpreterLocatorService - hasInterpreters: Promise; - getInterpreters( - resource?: Uri, - options?: GetInterpreterOptions, - source?: PythonEnvSource[], - ): Promise; + hasInterpreters(filter?: (e: PythonEnvironment) => Promise): Promise; + getInterpreters(resource?: Uri, source?: PythonEnvSource[]): PythonEnvironment[]; // WorkspaceVirtualEnvInterpretersAutoSelectionRule getWorkspaceVirtualEnvInterpreters( @@ -104,11 +112,15 @@ export interface ICondaLocatorService { export const IInterpreterService = Symbol('IInterpreterService'); export interface IInterpreterService { + triggerRefresh(query?: PythonLocatorQuery): Promise; + readonly refreshPromise: Promise; + readonly onDidChangeInterpreters: Event; onDidChangeInterpreterConfiguration: Event; onDidChangeInterpreter: Event; onDidChangeInterpreterInformation: Event; - hasInterpreters: Promise; + hasInterpreters(filter?: (e: PythonEnvironment) => Promise): Promise; getInterpreters(resource?: Uri, options?: GetInterpreterOptions): Promise; + getAllInterpreters(resource?: Uri, options?: GetInterpreterOptions): Promise; getActiveInterpreter(resource?: Uri): Promise; getInterpreterDetails(pythonPath: string, resoure?: Uri): Promise; refresh(resource: Resource): Promise; diff --git a/src/client/interpreter/interpreterService.ts b/src/client/interpreter/interpreterService.ts index 726192de2cd5..f48eacff3511 100644 --- a/src/client/interpreter/interpreterService.ts +++ b/src/client/interpreter/interpreterService.ts @@ -20,8 +20,6 @@ import { import { sleep } from '../common/utils/async'; import { IServiceContainer } from '../ioc/types'; import { EnvironmentType, PythonEnvironment } from '../pythonEnvironments/info'; -import { sendTelemetryEvent } from '../telemetry'; -import { EventName } from '../telemetry/constants'; import { GetInterpreterOptions, IComponentAdapter, @@ -30,12 +28,13 @@ import { IInterpreterLocatorService, IInterpreterService, INTERPRETER_LOCATOR_SERVICE, + PythonEnvironmentsChangedEvent, } from './contracts'; import { IVirtualEnvironmentManager } from './virtualEnvs/types'; import { getInterpreterHash } from '../pythonEnvironments/discovery/locators/services/hashProvider'; import { inDiscoveryExperiment, inDiscoveryExperimentSync } from '../common/experiments/helpers'; -import { StopWatch } from '../common/utils/stopWatch'; import { PythonVersion } from '../pythonEnvironments/info/pythonVersion'; +import { PythonLocatorQuery } from '../pythonEnvironments/base/locator'; const EXPIRY_DURATION = 24 * 60 * 60 * 1000; @@ -43,10 +42,12 @@ type StoredPythonEnvironment = PythonEnvironment & { store?: boolean }; @injectable() export class InterpreterService implements Disposable, IInterpreterService { - public get hasInterpreters(): Promise { + public async hasInterpreters( + filter: (e: PythonEnvironment) => Promise = async () => true, + ): Promise { return inDiscoveryExperiment(this.experimentService).then((inExp) => { if (inExp) { - return this.pyenvs.hasInterpreters; + return this.pyenvs.hasInterpreters(filter); } const locator = this.serviceContainer.get( IInterpreterLocatorService, @@ -56,10 +57,22 @@ export class InterpreterService implements Disposable, IInterpreterService { }); } + public triggerRefresh(query?: PythonLocatorQuery): Promise { + return inDiscoveryExperimentSync(this.experimentService) + ? this.pyenvs.triggerRefresh(query) + : Promise.resolve(); + } + + public get refreshPromise(): Promise { + return inDiscoveryExperimentSync(this.experimentService) ? this.pyenvs.refreshPromise : Promise.resolve(); + } + public get onDidChangeInterpreter(): Event { return this.didChangeInterpreterEmitter.event; } + public onDidChangeInterpreters: Event; + public get onDidChangeInterpreterInformation(): Event { return this.didChangeInterpreterInformation.event; } @@ -97,6 +110,7 @@ export class InterpreterService implements Disposable, IInterpreterService { this.configService = this.serviceContainer.get(IConfigurationService); this.interpreterPathService = this.serviceContainer.get(IInterpreterPathService); this.experimentsManager = this.serviceContainer.get(IExperimentService); + this.onDidChangeInterpreters = pyenvs.onChanged; } public async refresh(resource?: Uri): Promise { @@ -138,9 +152,8 @@ export class InterpreterService implements Disposable, IInterpreterService { public async getInterpreters(resource?: Uri, options?: GetInterpreterOptions): Promise { let environments: PythonEnvironment[] = []; - const stopWatch = new StopWatch(); if (inDiscoveryExperimentSync(this.experimentService)) { - environments = await this.pyenvs.getInterpreters(resource, options); + environments = this.pyenvs.getInterpreters(resource); } else { const locator = this.serviceContainer.get( IInterpreterLocatorService, @@ -149,10 +162,6 @@ export class InterpreterService implements Disposable, IInterpreterService { environments = await locator.getInterpreters(resource, options); } - sendTelemetryEvent(EventName.PYTHON_INTERPRETER_DISCOVERY, stopWatch.elapsedTime, { - interpreters: environments?.length ?? 0, - }); - await Promise.all( environments .filter((item) => !item.displayName) @@ -167,6 +176,14 @@ export class InterpreterService implements Disposable, IInterpreterService { return environments; } + public async getAllInterpreters(resource?: Uri, options?: GetInterpreterOptions): Promise { + if (options?.ignoreCache) { + this.triggerRefresh().ignoreErrors(); + } + await this.refreshPromise; + return this.getInterpreters(resource, options); + } + public dispose(): void { inDiscoveryExperiment(this.experimentService).then((inExp) => { if (!inExp) { @@ -243,6 +260,7 @@ export class InterpreterService implements Disposable, IInterpreterService { // This is the preferred approach, hence the delay in option 1. const option2 = (async () => { + await this.refreshPromise; const interpreters = await this.getInterpreters(resource); const found = interpreters.find((i) => fs.arePathsSame(i.path, pythonPath)); if (found) { diff --git a/src/client/jupyter/jupyterIntegration.ts b/src/client/jupyter/jupyterIntegration.ts index 2ff2c800f404..7cdaca6b4293 100644 --- a/src/client/jupyter/jupyterIntegration.ts +++ b/src/client/jupyter/jupyterIntegration.ts @@ -170,7 +170,7 @@ export class JupyterExtensionIntegration { getActiveInterpreter: async (resource?: Uri) => this.interpreterService.getActiveInterpreter(resource), getInterpreterDetails: async (pythonPath: string) => this.interpreterService.getInterpreterDetails(pythonPath), - getInterpreters: async (resource: Uri | undefined) => this.interpreterService.getInterpreters(resource), + getInterpreters: async (resource: Uri | undefined) => this.interpreterService.getAllInterpreters(resource), getActivatedEnvironmentVariables: async ( resource: Resource, interpreter?: PythonEnvironment, diff --git a/src/client/pythonEnvironments/legacyIOC.ts b/src/client/pythonEnvironments/legacyIOC.ts index 66c0154cec57..25ea840d8976 100644 --- a/src/client/pythonEnvironments/legacyIOC.ts +++ b/src/client/pythonEnvironments/legacyIOC.ts @@ -12,7 +12,6 @@ import { CONDA_ENV_FILE_SERVICE, CONDA_ENV_SERVICE, CURRENT_PATH_SERVICE, - GetInterpreterOptions, GLOBAL_VIRTUAL_ENV_SERVICE, IComponentAdapter, ICondaService, @@ -29,6 +28,7 @@ import { PIPENV_SERVICE, WINDOWS_REGISTRY_SERVICE, WORKSPACE_VIRTUAL_ENV_SERVICE, + PythonEnvironmentsChangedEvent, } from '../interpreter/contracts'; import { IPipEnvServiceHelper, IPythonInPathCommandProvider } from '../interpreter/locators/types'; import { VirtualEnvironmentManager } from '../interpreter/virtualEnvs'; @@ -69,6 +69,7 @@ import { IExtensionSingleActivationService } from '../activation/types'; import { EnvironmentInfoServiceQueuePriority, getEnvironmentInfoService } from './base/info/environmentInfoService'; import { createDeferred } from '../common/utils/async'; import { PythonEnvCollectionChangedEvent } from './base/watcher'; +import { asyncFilter } from '../common/utils/arrayUtils'; const convertedKinds = new Map( Object.entries({ @@ -139,19 +140,34 @@ class ComponentAdapter implements IComponentAdapter { private readonly refreshed = new vscode.EventEmitter(); - private readonly onAddedToCollection = createDeferred(); + private readonly changed = new vscode.EventEmitter(); constructor( // The adapter only wraps one thing: the component API. private readonly api: IDiscoveryAPI, ) { - this.api.onChanged((e: PythonEnvCollectionChangedEvent) => { - if (e.update) { - this.onAddedToCollection.resolve(); - } + this.api.onChanged((event) => { + this.changed.fire({ + type: event.type, + update: event.update ? convertEnvInfo(event.update) : undefined, + old: event.old ? convertEnvInfo(event.old) : undefined, + resource: event.searchLocation, + }); }); } + public triggerRefresh(query?: PythonLocatorQuery): Promise { + return this.api.triggerRefresh(query); + } + + public get refreshPromise() { + return this.api.refreshPromise; + } + + public get onChanged() { + return this.changed.event; + } + // For use in VirtualEnvironmentPrompt.activate() // Call callback if an environment gets created within the resource provided. @@ -249,43 +265,33 @@ class ComponentAdapter implements IComponentAdapter { } // Implements IInterpreterLocatorService - public get hasInterpreters(): Promise { + public async hasInterpreters( + filter: (e: PythonEnvironment) => Promise = async () => true, + ): Promise { + const onAddedToCollection = createDeferred(); + // Watch for collection changed events. + this.api.onChanged(async (e: PythonEnvCollectionChangedEvent) => { + if (e.update) { + if (await filter(convertEnvInfo(e.update))) { + onAddedToCollection.resolve(); + } + } + }); const initialEnvs = this.api.getEnvs(); if (initialEnvs.length > 0) { - return Promise.resolve(true); + return true; } // We should already have initiated discovery. Wait for an env to be added // to the collection until the refresh has finished. - return Promise.race([this.onAddedToCollection.promise, this.api.refreshPromise]).then(() => { - const envs = this.api.getEnvs(); - return envs.length > 0; - }); + await Promise.race([onAddedToCollection.promise, this.api.refreshPromise]); + const envs = await asyncFilter(this.api.getEnvs(), (e) => filter(convertEnvInfo(e))); + return envs.length > 0; } - public async getInterpreters( - resource?: vscode.Uri, - options?: GetInterpreterOptions, - source?: PythonEnvSource[], - ): Promise { + public getInterpreters(resource?: vscode.Uri, source?: PythonEnvSource[]): PythonEnvironment[] { // Notify locators are locating. this.refreshing.fire(); - const legacyEnvs = await this.getInterpretersViaAPI(resource, options, source).catch((ex) => { - traceError('Fetching environments via the new API failed', ex); - return []; - }); - - // Notify all locators have completed locating. Note it's crucial to notify this even when getInterpretersViaAPI - // fails, to ensure "Python extension loading..." text disappears. - this.refreshed.fire(); - return legacyEnvs; - } - - private async getInterpretersViaAPI( - resource?: vscode.Uri, - options?: GetInterpreterOptions, - source?: PythonEnvSource[], - ): Promise { const query: PythonLocatorQuery = {}; if (resource !== undefined) { const wsFolder = vscode.workspace.getWorkspaceFolder(resource); @@ -297,16 +303,17 @@ class ComponentAdapter implements IComponentAdapter { } } - if (options?.ignoreCache) { - await this.api.triggerRefresh(query); - } - await this.api.refreshPromise; let envs = this.api.getEnvs(query); if (source) { envs = envs.filter((env) => intersection(source, env.source).length > 0); } - return envs.map(convertEnvInfo); + const legacyEnvs = envs.map(convertEnvInfo); + + // Notify all locators have completed locating. Note it's crucial to notify this even when getInterpretersViaAPI + // fails, to ensure "Python extension loading..." text disappears. + this.refreshed.fire(); + return legacyEnvs; } public async getWorkspaceVirtualEnvInterpreters( diff --git a/src/client/startupTelemetry.ts b/src/client/startupTelemetry.ts index c540fcaa82b6..bccc081fdb62 100644 --- a/src/client/startupTelemetry.ts +++ b/src/client/startupTelemetry.ts @@ -105,21 +105,19 @@ async function getActivationTelemetryProps(serviceContainer: IServiceContainer): ? workspaceService.workspaceFolders![0].uri : undefined; const settings = configurationService.getSettings(mainWorkspaceUri); - const [condaVersion, interpreter, interpreters] = await Promise.all([ + const [condaVersion, interpreter, hasPython3] = await Promise.all([ condaLocator .getCondaVersion() .then((ver) => (ver ? ver.raw : '')) .catch(() => ''), interpreterService.getActiveInterpreter().catch(() => undefined), - interpreterService.getInterpreters(mainWorkspaceUri).catch(() => []), + interpreterService.hasInterpreters(async (item) => item.version?.major === 3), ]); const workspaceFolderCount = workspaceService.hasWorkspaceFolders ? workspaceService.workspaceFolders!.length : 0; const pythonVersion = interpreter && interpreter.version ? interpreter.version.raw : undefined; const interpreterType = interpreter ? interpreter.envType : undefined; const usingUserDefinedInterpreter = hasUserDefinedPythonPath(mainWorkspaceUri, serviceContainer); const usingGlobalInterpreter = isUsingGlobalInterpreterInWorkspace(settings.pythonPath, serviceContainer); - const hasPython3 = - interpreters!.filter((item) => (item && item.version ? item.version.major === 3 : false)).length > 0; return { condaVersion, diff --git a/src/test/application/diagnostics/checks/macPythonInterpreter.unit.test.ts b/src/test/application/diagnostics/checks/macPythonInterpreter.unit.test.ts index 98d51eb027f2..f1ccba8f5af1 100644 --- a/src/test/application/diagnostics/checks/macPythonInterpreter.unit.test.ts +++ b/src/test/application/diagnostics/checks/macPythonInterpreter.unit.test.ts @@ -169,7 +169,7 @@ suite('Application Diagnostics - Checks Mac Python Interpreter', () => { .returns(() => false) .verifiable(typemoq.Times.once()); interpreterService - .setup((i) => i.hasInterpreters) + .setup((i) => i.hasInterpreters()) .returns(() => Promise.resolve(true)) .verifiable(typemoq.Times.once()); interpreterService @@ -199,7 +199,7 @@ suite('Application Diagnostics - Checks Mac Python Interpreter', () => { .returns(() => false) .verifiable(typemoq.Times.once()); interpreterService - .setup((i) => i.hasInterpreters) + .setup((i) => i.hasInterpreters()) .returns(() => Promise.resolve(true)) .verifiable(typemoq.Times.once()); interpreterService @@ -234,8 +234,12 @@ suite('Application Diagnostics - Checks Mac Python Interpreter', () => { .returns(() => false) .verifiable(typemoq.Times.once()); interpreterService - .setup((i) => i.getInterpreters(typemoq.It.isAny())) - .returns(() => Promise.resolve([{ path: pythonPath } as any, { path: pythonPath } as any])) + .setup((i) => i.hasInterpreters()) + .returns(() => Promise.resolve(true)) + .verifiable(typemoq.Times.once()); + interpreterService + .setup((i) => i.hasInterpreters(typemoq.It.isAny())) + .returns(() => Promise.resolve(false)) .verifiable(typemoq.Times.once()); interpreterService .setup((i) => i.getActiveInterpreter(typemoq.It.isAny())) @@ -262,10 +266,6 @@ suite('Application Diagnostics - Checks Mac Python Interpreter', () => { ], 'not the same', ); - settings.verifyAll(); - interpreterService.verifyAll(); - platformService.verifyAll(); - helper.verifyAll(); }); test('Should return diagnostic if there are other interpreters, platform is mac and selected interpreter is default mac interpreter', async () => { const nonMacStandardInterpreter = 'Non Mac Std Interpreter'; @@ -274,14 +274,12 @@ suite('Application Diagnostics - Checks Mac Python Interpreter', () => { .returns(() => false) .verifiable(typemoq.Times.once()); interpreterService - .setup((i) => i.getInterpreters(typemoq.It.isAny())) - .returns(() => - Promise.resolve([ - { path: pythonPath } as any, - { path: pythonPath } as any, - { path: nonMacStandardInterpreter } as any, - ]), - ) + .setup((i) => i.hasInterpreters()) + .returns(() => Promise.resolve(true)) + .verifiable(typemoq.Times.once()); + interpreterService + .setup((i) => i.hasInterpreters(typemoq.It.isAny())) + .returns(() => Promise.resolve(true)) .verifiable(typemoq.Times.once()); platformService .setup((i) => i.isMac) @@ -312,10 +310,6 @@ suite('Application Diagnostics - Checks Mac Python Interpreter', () => { ], 'not the same', ); - settings.verifyAll(); - interpreterService.verifyAll(); - platformService.verifyAll(); - helper.verifyAll(); }); test('Handling no interpreters diagnostic should return select interpreter cmd', async () => { const diagnostic = new InvalidMacPythonInterpreterDiagnostic( diff --git a/src/test/application/diagnostics/checks/pythonInterpreter.unit.test.ts b/src/test/application/diagnostics/checks/pythonInterpreter.unit.test.ts index d889417bc0a6..50609d565fa5 100644 --- a/src/test/application/diagnostics/checks/pythonInterpreter.unit.test.ts +++ b/src/test/application/diagnostics/checks/pythonInterpreter.unit.test.ts @@ -29,7 +29,7 @@ import { IConfigurationService, IDisposableRegistry, IPythonSettings } from '../ import { noop } from '../../../../client/common/utils/misc'; import { IInterpreterHelper, IInterpreterService } from '../../../../client/interpreter/contracts'; import { IServiceContainer } from '../../../../client/ioc/types'; -import { EnvironmentType, PythonEnvironment } from '../../../../client/pythonEnvironments/info'; +import { EnvironmentType } from '../../../../client/pythonEnvironments/info'; suite('Application Diagnostics - Checks Python Interpreter', () => { let diagnosticService: IDiagnosticsService; @@ -134,7 +134,7 @@ suite('Application Diagnostics - Checks Python Interpreter', () => { .returns(() => false) .verifiable(typemoq.Times.once()); interpreterService - .setup((i) => i.hasInterpreters) + .setup((i) => i.hasInterpreters()) .returns(() => Promise.resolve(false)) .verifiable(typemoq.Times.once()); interpreterService @@ -147,36 +147,6 @@ suite('Application Diagnostics - Checks Python Interpreter', () => { [new InvalidPythonInterpreterDiagnostic(DiagnosticCodes.NoPythonInterpretersDiagnostic, undefined)], 'not the same', ); - settings.verifyAll(); - interpreterService.verifyAll(); - }); - test('Should return empty diagnostics if there are interpreters after double-checking', async () => { - const interpreter: PythonEnvironment = { envType: EnvironmentType.Unknown } as any; - - settings - .setup((s) => s.disableInstallationChecks) - .returns(() => false) - .verifiable(typemoq.Times.once()); - interpreterService - .setup((i) => i.hasInterpreters) - .returns(() => Promise.resolve(false)) - .verifiable(typemoq.Times.once()); - interpreterService - .setup((i) => i.getInterpreters(undefined)) - .returns(() => Promise.resolve([interpreter])) - .verifiable(typemoq.Times.once()); - interpreterService - .setup((i) => i.getActiveInterpreter(typemoq.It.isAny())) - .returns(() => { - return Promise.resolve(interpreter); - }) - .verifiable(typemoq.Times.once()); - - const diagnostics = await diagnosticService.diagnose(undefined); - - expect(diagnostics).to.be.deep.equal([], 'not the same'); - settings.verifyAll(); - interpreterService.verifyAll(); }); test('Should return invalid diagnostics if there are interpreters but no current interpreter', async () => { settings @@ -184,7 +154,7 @@ suite('Application Diagnostics - Checks Python Interpreter', () => { .returns(() => false) .verifiable(typemoq.Times.once()); interpreterService - .setup((i) => i.hasInterpreters) + .setup((i) => i.hasInterpreters()) .returns(() => Promise.resolve(true)) .verifiable(typemoq.Times.once()); interpreterService @@ -213,7 +183,7 @@ suite('Application Diagnostics - Checks Python Interpreter', () => { .returns(() => false) .verifiable(typemoq.Times.once()); interpreterService - .setup((i) => i.hasInterpreters) + .setup((i) => i.hasInterpreters()) .returns(() => Promise.resolve(true)) .verifiable(typemoq.Times.once()); interpreterService diff --git a/src/test/common/process/pythonExecutionFactory.unit.test.ts b/src/test/common/process/pythonExecutionFactory.unit.test.ts index a2b559faaaac..cbf2a0dddbb2 100644 --- a/src/test/common/process/pythonExecutionFactory.unit.test.ts +++ b/src/test/common/process/pythonExecutionFactory.unit.test.ts @@ -285,7 +285,7 @@ suite('Process - PythonExecutionFactory', () => { const pythonPath = 'path/to/python'; const pythonSettings = mock(PythonSettings); - when(interpreterService.hasInterpreters).thenResolve(true); + when(interpreterService.hasInterpreters()).thenResolve(true); when(processFactory.create(resource)).thenResolve(processService.object); when(pythonSettings.pythonPath).thenReturn(pythonPath); when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); @@ -315,7 +315,7 @@ suite('Process - PythonExecutionFactory', () => { when(pythonSettings.pythonPath).thenReturn(pythonPath); when(configService.getSettings(resource)).thenReturn(instance(pythonSettings)); when(condaService.getCondaVersion()).thenResolve(new SemVer('1.0.0')); - when(interpreterService.hasInterpreters).thenResolve(true); + when(interpreterService.hasInterpreters()).thenResolve(true); const service = await factory.create({ resource }); diff --git a/src/test/configuration/interpreterSelector/interpreterSelector.unit.test.ts b/src/test/configuration/interpreterSelector/interpreterSelector.unit.test.ts index f6703bd03f5e..4d01bb5bd9e0 100644 --- a/src/test/configuration/interpreterSelector/interpreterSelector.unit.test.ts +++ b/src/test/configuration/interpreterSelector/interpreterSelector.unit.test.ts @@ -91,7 +91,7 @@ suite('Interpreters - selector', () => { { displayName: '4', path: 'c:/path4/path4', envType: EnvironmentType.Conda }, ].map((item) => ({ ...info, ...item })); interpreterService - .setup((x) => x.getInterpreters(TypeMoq.It.isAny(), { onSuggestion: true, ignoreCache })) + .setup((x) => x.getAllInterpreters(TypeMoq.It.isAny(), { onSuggestion: true, ignoreCache })) .returns(() => new Promise((resolve) => resolve(initial))); const actual = await selector.getSuggestions(undefined, ignoreCache); @@ -153,7 +153,7 @@ suite('Interpreters - selector', () => { ].map((item) => ({ ...info, ...item })); interpreterService - .setup((x) => x.getInterpreters(TypeMoq.It.isAny(), { onSuggestion: true, ignoreCache })) + .setup((x) => x.getAllInterpreters(TypeMoq.It.isAny(), { onSuggestion: true, ignoreCache })) .returns(() => new Promise((resolve) => resolve(environments))); const interpreterHelper = TypeMoq.Mock.ofType(); diff --git a/src/test/interpreters/autoSelection/index.unit.test.ts b/src/test/interpreters/autoSelection/index.unit.test.ts index 09ed1a4cccb4..a8d2d0d19fac 100644 --- a/src/test/interpreters/autoSelection/index.unit.test.ts +++ b/src/test/interpreters/autoSelection/index.unit.test.ts @@ -82,7 +82,7 @@ suite('Interpreters - Auto Selection', () => { instance(helper), ); - when(interpreterService.getInterpreters(anything(), anything())).thenCall((_, opts) => { + when(interpreterService.getAllInterpreters(anything(), anything())).thenCall((_, opts) => { options.push(opts); return Promise.resolve([ @@ -157,7 +157,7 @@ suite('Interpreters - Auto Selection', () => { version: { major: 3, minor: 10, patch: 0 }, } as PythonEnvironment; - when(interpreterService.getInterpreters(resource, anything())).thenCall((_, opts) => { + when(interpreterService.getAllInterpreters(resource, anything())).thenCall((_, opts) => { options.push(opts); return Promise.resolve([ { @@ -177,8 +177,8 @@ suite('Interpreters - Auto Selection', () => { await autoSelectionService.autoSelectInterpreter(resource); expect(eventFired).to.deep.equal(true, 'event not fired'); - expect(options).to.deep.equal([{ ignoreCache: true }], 'getInterpreters options are different'); - verify(interpreterService.getInterpreters(resource, anything())).once(); + expect(options).to.deep.equal([{ ignoreCache: true }], 'getAllInterpreters options are different'); + verify(interpreterService.getAllInterpreters(resource, anything())).once(); verify(state.updateValue(localEnv)).once(); }); @@ -189,7 +189,7 @@ suite('Interpreters - Auto Selection', () => { version: { major: 3, minor: 9, patch: 1 }, } as PythonEnvironment; - when(interpreterService.getInterpreters(resource, anything())).thenCall((_, opts) => { + when(interpreterService.getAllInterpreters(resource, anything())).thenCall((_, opts) => { options.push(opts); return Promise.resolve([ { @@ -209,12 +209,12 @@ suite('Interpreters - Auto Selection', () => { await autoSelectionService.autoSelectInterpreter(resource); expect(eventFired).to.deep.equal(true, 'event not fired'); - expect(options).to.deep.equal([{ ignoreCache: true }], 'getInterpreters options are different'); - verify(interpreterService.getInterpreters(resource, anything())).once(); + expect(options).to.deep.equal([{ ignoreCache: true }], 'getAllInterpreters options are different'); + verify(interpreterService.getAllInterpreters(resource, anything())).once(); verify(state.updateValue(systemEnv)).once(); }); - test('getInterpreters is called with ignoreCache at true if there is no value set in the workspace persistent state', async () => { + test('getAllInterpreters is called with ignoreCache at true if there is no value set in the workspace persistent state', async () => { const interpreterComparer = new EnvironmentTypeComparer(instance(helper)); const queryState = mock(PersistentState) as PersistentState; @@ -222,7 +222,7 @@ suite('Interpreters - Auto Selection', () => { when(stateFactory.createWorkspacePersistentState(anyString(), undefined)).thenReturn( instance(queryState), ); - when(interpreterService.getInterpreters(resource, anything())).thenCall((_, opts) => { + when(interpreterService.getAllInterpreters(resource, anything())).thenCall((_, opts) => { options.push(opts); return Promise.resolve([ @@ -253,11 +253,11 @@ suite('Interpreters - Auto Selection', () => { await autoSelectionService.autoSelectInterpreter(resource); - verify(interpreterService.getInterpreters(resource, anything())).once(); - expect(options).to.deep.equal([{ ignoreCache: true }], 'getInterpreters options are different'); + verify(interpreterService.getAllInterpreters(resource, anything())).once(); + expect(options).to.deep.equal([{ ignoreCache: true }], 'getAllInterpreters options are different'); }); - test('getInterpreters is called with ignoreCache at false if there is a value set in the workspace persistent state', async () => { + test('getAllInterpreters is called with ignoreCache at false if there is a value set in the workspace persistent state', async () => { const interpreterComparer = new EnvironmentTypeComparer(instance(helper)); const queryState = mock(PersistentState) as PersistentState; @@ -265,7 +265,7 @@ suite('Interpreters - Auto Selection', () => { when(stateFactory.createWorkspacePersistentState(anyString(), undefined)).thenReturn( instance(queryState), ); - when(interpreterService.getInterpreters(resource, anything())).thenCall((_, opts) => { + when(interpreterService.getAllInterpreters(resource, anything())).thenCall((_, opts) => { options.push(opts); return Promise.resolve([ @@ -296,14 +296,14 @@ suite('Interpreters - Auto Selection', () => { await autoSelectionService.autoSelectInterpreter(resource); - verify(interpreterService.getInterpreters(resource, anything())).once(); - expect(options).to.deep.equal([{ ignoreCache: false }], 'getInterpreters options are different'); + verify(interpreterService.getAllInterpreters(resource, anything())).once(); + expect(options).to.deep.equal([{ ignoreCache: false }], 'getAllInterpreters options are different'); }); test('Telemetry event is sent with useCachedInterpreter set to false if auto-selection has not been run before', async () => { const interpreterComparer = new EnvironmentTypeComparer(instance(helper)); - when(interpreterService.getInterpreters(resource, anything())).thenCall(() => + when(interpreterService.getAllInterpreters(resource, anything())).thenCall(() => Promise.resolve([ { envType: EnvironmentType.Conda, @@ -332,7 +332,7 @@ suite('Interpreters - Auto Selection', () => { await autoSelectionService.autoSelectInterpreter(resource); - verify(interpreterService.getInterpreters(resource, anything())).once(); + verify(interpreterService.getAllInterpreters(resource, anything())).once(); sinon.assert.calledOnce(sendTelemetryEventStub); expect(telemetryEvents).to.deep.equal( [ @@ -348,7 +348,7 @@ suite('Interpreters - Auto Selection', () => { test('Telemetry event is sent with useCachedInterpreter set to true if auto-selection has been run before', async () => { const interpreterComparer = new EnvironmentTypeComparer(instance(helper)); - when(interpreterService.getInterpreters(resource, anything())).thenCall(() => + when(interpreterService.getAllInterpreters(resource, anything())).thenCall(() => Promise.resolve([ { envType: EnvironmentType.Conda, @@ -379,7 +379,7 @@ suite('Interpreters - Auto Selection', () => { await autoSelectionService.autoSelectInterpreter(resource); - verify(interpreterService.getInterpreters(resource, anything())).once(); + verify(interpreterService.getAllInterpreters(resource, anything())).once(); sinon.assert.calledTwice(sendTelemetryEventStub); expect(telemetryEvents).to.deep.equal( [ diff --git a/src/test/linters/lint.functional.test.ts b/src/test/linters/lint.functional.test.ts index 37bf4330d31f..659a723d8662 100644 --- a/src/test/linters/lint.functional.test.ts +++ b/src/test/linters/lint.functional.test.ts @@ -697,7 +697,7 @@ class TestFixture extends BaseTestFixture { .returns(() => decoder); const interpreterService = TypeMoq.Mock.ofType(undefined, TypeMoq.MockBehavior.Strict); - interpreterService.setup((i) => i.hasInterpreters).returns(() => Promise.resolve(true)); + interpreterService.setup((i) => i.hasInterpreters()).returns(() => Promise.resolve(true)); serviceContainer .setup((c) => c.get(TypeMoq.It.isValue(IInterpreterService), TypeMoq.It.isAny())) .returns(() => interpreterService.object); diff --git a/src/test/refactor/rename.test.ts b/src/test/refactor/rename.test.ts index ebd74f965c9c..6599e0e36de9 100644 --- a/src/test/refactor/rename.test.ts +++ b/src/test/refactor/rename.test.ts @@ -63,7 +63,7 @@ suite('Refactor Rename', () => { .setup((p) => p.create(typeMoq.It.isAny())) .returns(() => Promise.resolve(new ProcessService(new BufferDecoder()))); const interpreterService = typeMoq.Mock.ofType(); - interpreterService.setup((i) => i.hasInterpreters).returns(() => Promise.resolve(true)); + interpreterService.setup((i) => i.hasInterpreters()).returns(() => Promise.resolve(true)); const envActivationService = typeMoq.Mock.ofType(); envActivationService .setup((e) => e.getActivatedEnvironmentVariables(typeMoq.It.isAny()))