diff --git a/CHANGELOG.md b/CHANGELOG.md index 8b01726136c0..ff82fa2ccd57 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ ### Fixes +1. Double-check for interpreters when running diagnostics before displaying the "Python is not installed" message. + ([#11870](https://github.com/Microsoft/vscode-python/issues/11870)) 1. Ensure user cannot belong to all experiments in an experiment group. ([#11943](https://github.com/Microsoft/vscode-python/issues/11943)) 1. Ensure extension features are started when in `Deprecate PythonPath` experiment and opening a file without any folder opened. diff --git a/src/client/application/diagnostics/checks/pythonInterpreter.ts b/src/client/application/diagnostics/checks/pythonInterpreter.ts index f4219f0c8c4b..6040234f7f2a 100644 --- a/src/client/application/diagnostics/checks/pythonInterpreter.ts +++ b/src/client/application/diagnostics/checks/pythonInterpreter.ts @@ -67,7 +67,14 @@ export class InvalidPythonInterpreterService extends BaseDiagnosticsService { } const interpreterService = this.serviceContainer.get(IInterpreterService); - const hasInterpreters = await interpreterService.hasInterpreters; + // 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; if (!hasInterpreters) { return [new InvalidPythonInterpreterDiagnostic(DiagnosticCodes.NoPythonInterpretersDiagnostic, resource)]; diff --git a/src/test/application/diagnostics/checks/pythonInterpreter.unit.test.ts b/src/test/application/diagnostics/checks/pythonInterpreter.unit.test.ts index baf7696dd849..19148e6d7e5d 100644 --- a/src/test/application/diagnostics/checks/pythonInterpreter.unit.test.ts +++ b/src/test/application/diagnostics/checks/pythonInterpreter.unit.test.ts @@ -29,7 +29,12 @@ import { CommandsWithoutArgs } from '../../../../client/common/application/comma import { IPlatformService } from '../../../../client/common/platform/types'; import { IConfigurationService, IDisposableRegistry, IPythonSettings } from '../../../../client/common/types'; import { noop } from '../../../../client/common/utils/misc'; -import { IInterpreterHelper, IInterpreterService, InterpreterType } from '../../../../client/interpreter/contracts'; +import { + IInterpreterHelper, + IInterpreterService, + InterpreterType, + PythonInterpreter +} from '../../../../client/interpreter/contracts'; import { IServiceContainer } from '../../../../client/ioc/types'; suite('Application Diagnostics - Checks Python Interpreter', () => { @@ -129,7 +134,7 @@ suite('Application Diagnostics - Checks Python Interpreter', () => { expect(diagnostics).to.be.deep.equal([]); settings.verifyAll(); }); - test('Should return diagnostics if there are no interpreters', async () => { + test('Should return diagnostics if there are no interpreters after double-checking', async () => { settings .setup((s) => s.disableInstallationChecks) .returns(() => false) @@ -138,6 +143,10 @@ suite('Application Diagnostics - Checks Python Interpreter', () => { .setup((i) => i.hasInterpreters) .returns(() => Promise.resolve(false)) .verifiable(typemoq.Times.once()); + interpreterService + .setup((i) => i.getInterpreters(undefined)) + .returns(() => Promise.resolve([])) + .verifiable(typemoq.Times.once()); const diagnostics = await diagnosticService.diagnose(undefined); expect(diagnostics).to.be.deep.equal( @@ -147,6 +156,34 @@ suite('Application Diagnostics - Checks Python Interpreter', () => { settings.verifyAll(); interpreterService.verifyAll(); }); + test('Should return empty diagnostics if there are interpreters after double-checking', async () => { + const interpreter: PythonInterpreter = { type: InterpreterType.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 .setup((s) => s.disableInstallationChecks)