Repository navigation
Fix pytest discovery using workspace-root interpreter after missed startup environment events - #26195
Conversation
…d startup environment events Subscribe to Python Environments extension project/environment changes before the initial test project discovery, and queue re-discovery for workspaces whose initial project registration is still in flight when an environment is assigned. Previously, environment assignments raised while initial discovery was running were missed entirely, leaving the workspace stuck on the fallback default project that discovers tests with the workspace-root (e.g. system) interpreter instead of the project's environment. Fixes microsoft#25718
|
🔒 Automated review in progress — Heejae Chang (@heejaechang) is auto-reviewing this PR. |
|
Result: Verification detailsVerification: The relevant tests could not be fully run in the isolated environment; this review is not fully verified. Summary: Offline dependency installation and TypeScript compilation passed. All 13 controller tests passed, including both new startup regressions and the updated legacy-mode case; the broader testController run passed 262 tests, including the controller tests again. No test failures occurred. Verification is partial because the reporter’s monorepo reload scenario was not exercised in a real VS Code extension host. Test runs: 5 passed, 1 not run
|
Heejae Chang (heejaechang)
left a comment
There was a problem hiding this comment.
Approved via Review Center.
Summary
Fixes #25718.
In a monorepo where a Python sub-project has its own environment (e.g.
apps/example-py/.venv), pytest test discovery can run with the workspace-root interpreter (system Python, without pytest) instead of the project's environment, failing withNo module named pytest. The reporter suspected a race between the Python Environments extension and the Python extension; this PR closes that race in the project-based test discovery flow ([test-by-project]).Root cause
Project-based discovery intentionally falls back to a "default project" bound to the workspace-root interpreter when a project's environment has not been assigned yet, and relies on the environments extension's
onDidChangeEnvironment/onDidChangePythonProjectsevents to re-discover once environments resolve. Two startup holes made that self-healing unreliable:Events raised before subscription were dropped.
activate()awaited the initialdiscoverAndRegisterProjects()for every workspace before callingsubscribeToProjectChanges()/subscribeToEnvironmentChanges(). Acquiring the environments API during that initial discovery is what activates the environments extension and kicks off its initial refresh, so the environment assignments produced by that refresh could fire into a window where nobody was listening. The workspace then stayed on the fallback default project (workspace-root interpreter) until a manual refresh or file save.Events arriving during initial registration were ignored.
handleEnvironmentChangeonly queued workspaces for whichprojectRegistry.hasProjects()was already true. An environment assignment raised while a workspace's initial project discovery was still in flight (nothing registered yet) was dropped, with the same stuck-on-wrong-interpreter result.Changes (
src/client/testing/testController/controller.ts)activate(): subscribe to project and environment changes before the initial project discovery, so no assignments are missed during startup.handleEnvironmentChange(): queue re-discovery for any workspace that is not in legacy mode (i.e. has no legacyWorkspaceTestAdapterregistered), instead of only workspaces with already-registered projects. Legacy-mode workspaces are still skipped; workspaces mid-registration are now covered.No changes to the fallback default-project behavior itself, to discovery/execution adapters, or to interpreter resolution.
Tests
compile:npx tsc -p ./passes.npm run test:unittestsmocha config): allPythonTestControllerand testing-controller suites pass (13/13 controller tests; 108/108 across the testController-related suites).ignores workspaces that are not in project-based modeto explicitly cover legacy mode (legacy adapter registered).queues workspaces whose initial project registration is still in flight.activate() subscribes to project and environment changes before initial project discovery(asserts call ordering).Terminal Environment Variable Collection Serviceconda-shell mocks,Native Python Finderbinary tests); verified identical failures on a pristineupstream/mainworktree.Test plan / manual verification
I could not run the VS Code integration host here, so end-to-end verification with the reporter's monorepo example is still needed:
apps/example-pywith its.venv).No module named pytestdiscovery error from the system Python; once the environments extension assigns the project environment, the workspace re-discovers automatically and the test tree is rooted at the project with its venv.