From 8c4dee44782cf11685bc043f91dd7b08a3616429 Mon Sep 17 00:00:00 2001 From: Anthony Kim <62267334+anthonykim1@users.noreply.github.com> Date: Fri, 4 Oct 2024 13:00:44 -0700 Subject: [PATCH] Allow pytest to use correct interpreter from getActiveInterpreter (#24250) Resolves: https://github.com/microsoft/vscode-python/issues/24122 Related: https://github.com/microsoft/vscode-python/issues/24190, https://github.com/microsoft/vscode-python/issues/24127 I think the culprit was we were not passing in interpreter when we call createActivatedEnvironment. --- src/client/testing/testController/common/types.ts | 8 +++++++- src/client/testing/testController/controller.ts | 4 ++++ .../testController/pytest/pytestDiscoveryAdapter.ts | 11 +++++++++-- .../testController/pytest/pytestExecutionAdapter.ts | 5 +++++ .../testing/testController/workspaceTestAdapter.ts | 6 +++++- 5 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/client/testing/testController/common/types.ts b/src/client/testing/testController/common/types.ts index 0de3ff8ad0c0..58132a83484a 100644 --- a/src/client/testing/testController/common/types.ts +++ b/src/client/testing/testController/common/types.ts @@ -16,6 +16,7 @@ import { import { ITestDebugLauncher, TestDiscoveryOptions } from '../../common/types'; import { IPythonExecutionFactory } from '../../../common/process/types'; import { EnvironmentVariables } from '../../../common/variables/types'; +import { PythonEnvironment } from '../../../pythonEnvironments/info'; export type TestRunInstanceOptions = TestRunOptions & { exclude?: readonly TestItem[]; @@ -206,7 +207,11 @@ export interface ITestResultResolver { export interface ITestDiscoveryAdapter { // ** first line old method signature, second line new method signature discoverTests(uri: Uri): Promise; - discoverTests(uri: Uri, executionFactory: IPythonExecutionFactory): Promise; + discoverTests( + uri: Uri, + executionFactory: IPythonExecutionFactory, + interpreter?: PythonEnvironment, + ): Promise; } // interface for execution/runner adapter @@ -220,6 +225,7 @@ export interface ITestExecutionAdapter { runInstance?: TestRun, executionFactory?: IPythonExecutionFactory, debugLauncher?: ITestDebugLauncher, + interpreter?: PythonEnvironment, ): Promise; } diff --git a/src/client/testing/testController/controller.ts b/src/client/testing/testController/controller.ts index dd624078a534..12d0fec23134 100644 --- a/src/client/testing/testController/controller.ts +++ b/src/client/testing/testController/controller.ts @@ -276,6 +276,7 @@ export class PythonTestController implements ITestController, IExtensionSingleAc this.testController, this.refreshCancellation.token, this.pythonExecFactory, + await this.interpreterService.getActiveInterpreter(workspace.uri), ); } else { traceError('Unable to find test adapter for workspace.'); @@ -297,6 +298,7 @@ export class PythonTestController implements ITestController, IExtensionSingleAc this.testController, this.refreshCancellation.token, this.pythonExecFactory, + await this.interpreterService.getActiveInterpreter(workspace.uri), ); } else { traceError('Unable to find test adapter for workspace.'); @@ -455,6 +457,7 @@ export class PythonTestController implements ITestController, IExtensionSingleAc request.profile?.kind, this.pythonExecFactory, this.debugLauncher, + await this.interpreterService.getActiveInterpreter(workspace.uri), ); } return this.pytest.runTests( @@ -483,6 +486,7 @@ export class PythonTestController implements ITestController, IExtensionSingleAc request.profile?.kind, this.pythonExecFactory, this.debugLauncher, + await this.interpreterService.getActiveInterpreter(workspace.uri), ); } // below is old way of running unittest execution diff --git a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts index 2162c1fe6e71..e62bd02dd3de 100644 --- a/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts +++ b/src/client/testing/testController/pytest/pytestDiscoveryAdapter.ts @@ -23,6 +23,7 @@ import { hasSymlinkParent, } from '../common/utils'; import { IEnvironmentVariablesProvider } from '../../../common/variables/types'; +import { PythonEnvironment } from '../../../pythonEnvironments/info'; /** * Wrapper class for unittest test discovery. This is where we call `runTestCommand`. #this seems incorrectly copied @@ -35,13 +36,17 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { private readonly envVarsService?: IEnvironmentVariablesProvider, ) {} - async discoverTests(uri: Uri, executionFactory?: IPythonExecutionFactory): Promise { + async discoverTests( + uri: Uri, + executionFactory?: IPythonExecutionFactory, + interpreter?: PythonEnvironment, + ): Promise { const { name, dispose } = await startDiscoveryNamedPipe((data: DiscoveredTestPayload) => { this.resultResolver?.resolveDiscovery(data); }); try { - await this.runPytestDiscovery(uri, name, executionFactory); + await this.runPytestDiscovery(uri, name, executionFactory, interpreter); } finally { dispose(); } @@ -54,6 +59,7 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { uri: Uri, discoveryPipeName: string, executionFactory?: IPythonExecutionFactory, + interpreter?: PythonEnvironment, ): Promise { const relativePathToPytest = 'python_files'; const fullPluginPath = path.join(EXTENSION_ROOT_DIR, relativePathToPytest); @@ -100,6 +106,7 @@ export class PytestTestDiscoveryAdapter implements ITestDiscoveryAdapter { const creationOptions: ExecutionFactoryCreateWithEnvironmentOptions = { allowEnvironmentFetchExceptions: false, resource: uri, + interpreter, }; const execService = await executionFactory?.createActivatedEnvironment(creationOptions); // delete UUID following entire discovery finishing. diff --git a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts index bcd97f450b58..fadec7f73488 100644 --- a/src/client/testing/testController/pytest/pytestExecutionAdapter.ts +++ b/src/client/testing/testController/pytest/pytestExecutionAdapter.ts @@ -19,6 +19,7 @@ import { PYTEST_PROVIDER } from '../../common/constants'; import { EXTENSION_ROOT_DIR } from '../../../common/constants'; import * as utils from '../common/utils'; import { IEnvironmentVariablesProvider } from '../../../common/variables/types'; +import { PythonEnvironment } from '../../../pythonEnvironments/info'; export class PytestTestExecutionAdapter implements ITestExecutionAdapter { constructor( @@ -35,6 +36,7 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { runInstance?: TestRun, executionFactory?: IPythonExecutionFactory, debugLauncher?: ITestDebugLauncher, + interpreter?: PythonEnvironment, ): Promise { const deferredTillServerClose: Deferred = utils.createTestingDeferred(); @@ -74,6 +76,7 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { profileKind, executionFactory, debugLauncher, + interpreter, ); } finally { await deferredTillServerClose.promise; @@ -98,6 +101,7 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { profileKind?: TestRunProfileKind, executionFactory?: IPythonExecutionFactory, debugLauncher?: ITestDebugLauncher, + interpreter?: PythonEnvironment, ): Promise { const relativePathToPytest = 'python_files'; const fullPluginPath = path.join(EXTENSION_ROOT_DIR, relativePathToPytest); @@ -122,6 +126,7 @@ export class PytestTestExecutionAdapter implements ITestExecutionAdapter { const creationOptions: ExecutionFactoryCreateWithEnvironmentOptions = { allowEnvironmentFetchExceptions: false, resource: uri, + interpreter, }; // need to check what will happen in the exec service is NOT defined and is null const execService = await executionFactory?.createActivatedEnvironment(creationOptions); diff --git a/src/client/testing/testController/workspaceTestAdapter.ts b/src/client/testing/testController/workspaceTestAdapter.ts index a0e65cfb5061..81641ee5125c 100644 --- a/src/client/testing/testController/workspaceTestAdapter.ts +++ b/src/client/testing/testController/workspaceTestAdapter.ts @@ -14,6 +14,7 @@ import { ITestDiscoveryAdapter, ITestExecutionAdapter, ITestResultResolver } fro import { IPythonExecutionFactory } from '../../common/process/types'; import { ITestDebugLauncher } from '../common/types'; import { buildErrorNodeOptions } from './common/utils'; +import { PythonEnvironment } from '../../pythonEnvironments/info'; /** * This class exposes a test-provider-agnostic way of discovering tests. @@ -45,6 +46,7 @@ export class WorkspaceTestAdapter { profileKind?: boolean | TestRunProfileKind, executionFactory?: IPythonExecutionFactory, debugLauncher?: ITestDebugLauncher, + interpreter?: PythonEnvironment, ): Promise { if (this.executing) { traceError('Test execution already in progress, not starting a new one.'); @@ -80,6 +82,7 @@ export class WorkspaceTestAdapter { runInstance, executionFactory, debugLauncher, + interpreter, ); } else { await this.executionAdapter.runTests(this.workspaceUri, testCaseIds, profileKind); @@ -115,6 +118,7 @@ export class WorkspaceTestAdapter { testController: TestController, token?: CancellationToken, executionFactory?: IPythonExecutionFactory, + interpreter?: PythonEnvironment, ): Promise { sendTelemetryEvent(EventName.UNITTEST_DISCOVERING, undefined, { tool: this.testProvider }); @@ -130,7 +134,7 @@ export class WorkspaceTestAdapter { try { // ** execution factory only defined for new rewrite way if (executionFactory !== undefined) { - await this.discoveryAdapter.discoverTests(this.workspaceUri, executionFactory); + await this.discoveryAdapter.discoverTests(this.workspaceUri, executionFactory, interpreter); } else { await this.discoveryAdapter.discoverTests(this.workspaceUri); }