Use exact per-file environments for Python files (PEP 723 PR 19) - #26129
Conversation
Resolve debugger programs and Pylance Python-file configuration against the exact file resource without publishing false workspace interpreter changes. Preserve workspace fallback and activate differing program environments. Part of microsoft/vscode-python-environments#1602. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2ea8f5e to
e413c74
Compare
|
🔒 Automated review in progress — Bill Schnurr (@bschnurr) is auto-reviewing this PR. |
|
Verification: The relevant tests could not be fully run in the isolated environment; this review is not fully verified. Result: Summary: Verification could not execute because no trusted sandbox image is configured for `microsoft/vscode-python`, and local execution was not authorized. The PR adds eight focused unit tests covering exact interpreter lookup, debugger selection, activation, and Pylance configuration. None could be run, so no pass/fail confidence is available. Two newly introduced debugger resolution paths appear uncovered. Test runs: 1 not run
|
Bill Schnurr (bschnurr)
left a comment
There was a problem hiding this comment.
Approved via Review Center.
|
Verification: The relevant tests could not be fully run in the isolated environment; this review is not fully verified. Result: Summary: Verification was blocked because no trusted sandbox image is configured for `microsoft/vscode-python`, and local execution was not authorized. No tests meaningfully ran. The PR adds eight focused unit tests, but `${file}` debugger program resolution lacks explicit coverage. Test runs: 1 not run
|
|
Verification: The relevant tests could not be fully run in the isolated environment; this review is not fully verified. Result: Summary: Verification could not run because no trusted sandbox image is configured for `microsoft/vscode-python`, and local execution was not authorized. The PR adds nine focused unit tests covering exact interpreter lookup, debugger selection/fallback, named workspaces, and activation. One documented path, `${file}` debugger program resolution, has no test coverage I could find. Test runs: 1 not run
|
Clarify why the workspace/configuration handler resolves the interpreter for the exact .py file (exactResource) rather than its folder: it honors a per-file environment such as a PEP 723 inline-script env for the language client this extension hosts, and only diverges from folder resolution when the Python Environments extension is in use. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The debug resolver now resolves \/\ to a program URI and looks up the interpreter for that file. To avoid changing behavior for users who are not using the environments extension (e.g. multi-root debugging of a file that lives in a different folder than the launch config), only take the program-scoped path when useEnvExtension() is true; otherwise fall back to the historical workspace-folder resolution. Environments-extension users still get per-file (inline-script) resolution. Stub useEnvExtension() in the existing program-scoped resolver tests and add a test covering the gated fallback. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
2d58111 to
67eef40
Compare
|
Verification: The relevant tests could not be fully run in the isolated environment; this review is not fully verified. Result: Summary: No tests could run because the verification container lacked a trusted `microsoft/vscode-python` sandbox image, and local execution was not authorized. The PR adds nine focused unit-test cases covering exact interpreter lookup, debugger resolution, activation, and Pylance configuration. `${file}`-based debugger interpreter selection remains without direct coverage. Test runs: 1 not run
|
7c12038
into
microsoft:main
Rich Chiodo (rchiodo)
left a comment
There was a problem hiding this comment.
Approved via Review Center.
> Part of #1602 (PEP 723 inline script env support). Design doc: #1601. ### Roadmap context This is **PR 10 of 16** in the PEP 723 inline-script roadmap. PRs 7-9 persist, discover, validate, and route per-script environments; this PR gives each configured script an exact project identity that survives restart and can be consumed by per-file integrations. | Phase 3 / integration | PR | Status | |---|---|---| | | PR 7: per-script persistence | merged (#1697) | | | PR 8: activation-time discovery | merged (#1722) | | | PR 9: automatic per-script routing | merged (#1729) | | | **PR 10: exact script project registration** | **this PR** | | | PRs 11-12: CodeLens and bulk setup UX | follow-up | | | PR 17: Pylance per-file Python path | [microsoft/pyrx#9265](microsoft/pyrx#9265) | | | PR 19: Python extension per-file lookup | [microsoft/vscode-python#26129](microsoft/vscode-python#26129) | ### Why this PR PR 9 can route a saved script to a validated inline environment, but the project manager still identifies the script through its containing workspace project. That prevents the per-file identity from surviving restart consistently and leaves downstream configuration and environment-change consumers without an exact script scope. The registration also needs an ownership boundary: clearing inline environments must remove entries created by the extension without deleting user-authored project settings. ### What this PR does - Registers an exact `pythonProjects` entry before binding an inline environment. - Stores the normal environment and package manager as the script's fallback rather than replacing them with the inline manager. - Marks extension-managed entries as either: - `created`: remove the entry during inline cleanup; - `adopted`: remove only the marker and preserve the user's entry. - Ignores the managed fallback entry while a validated inline association is routeable. - Uses that entry normally when the feature is disabled or the association becomes stale. - Rolls back a newly prepared registration if inline association binding fails. - Supports single and batch script selection. - Converts a managed entry into an ordinary user-owned entry when the user explicitly selects a non-inline manager. - Coordinates explicit managed selections with the dedicated clear-cache operation. - Resolves and updates same-named scripts correctly in multi-root workspaces. ### Registration and cleanup semantics | Condition | Behavior | |---|---| | No exact project entry exists | Create a marked entry containing the ordinary fallback managers | | An exact user entry exists | Temporarily mark it without changing its manager choices | | Inline binding fails | Roll back the marker/created entry and any newly added in-memory project | | Validated association exists | Route through the inline manager | | Association is stale or unavailable | Use the stored fallback manager | | User selects a non-inline manager | Update the owning setting and remove the managed marker | | Clear Script Environment Cache | Remove created entries; restore adopted entries | | Two roots contain the same relative script path | Match using the `workspace` discriminator | ### Performance and safety - No workspace scan is introduced. - Configuration writes occur only during explicit persisted selection, rollback, manager changes, or dedicated cache cleanup. - Serialization is limited to managed inline-script project mutations; unrelated environment routing and refresh operations are not queued. - User-owned project settings are never deleted by inline cleanup. ### User impact The feature remains behind `python-envs.inlineScripts.enabled`. Existing users and projects without a managed inline-script entry retain their current manager-selection behavior. After setup, a script has a stable exact project scope across reloads; when inline routing is unavailable, its previous project/workspace environment remains the fallback. ### Tests - `npm run compile-tests` - `npm run compile` - `npm run lint` - Focused command, environment-manager, and settings tests: **92 passing** - The full unit suite was also run. Six unchanged timing-sensitive inline-manager tests failed only under full-suite load and passed together in an isolated rerun. ### Scope and follow-up This PR does not add the setup CodeLens, bulk setup command, TTL eviction, or public feature enablement. Those remain in PRs 11, 12, and 14. Per-file language-service and debugger integration are handled by the companion cross-repository PRs above. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Roadmap context
This is cross-repository PR 19 in the PEP 723 roadmap. It closes the Python extension's per-file lookup gaps for debugging and Pylance configuration.
Why this PR
IInterpreterService.getActiveInterpreter(resource)normally shares in-flight, timeout, and last-known state by workspace folder. A file URI can therefore receive the workspace interpreter when a workspace lookup is already running or when exact environment resolution exceeds the timeout.That breaks two per-file consumers:
workspace/configurationrequest can receive a cached workspace interpreter.The exact lookup must also avoid publishing a file interpreter as a workspace-wide interpreter change.
What this PR does
exactResourceoption toIInterpreterService.${file};${workspaceFolder};${workspaceFolder:name}.pythonPathand command-valuedpython..py-scoped Pylance configuration requests; workspace-level requests retain the existing cached fast path.Lookup semantics
pythonconfig for a.pyURIPerformance and safety
.pyconfiguration scopes.User impact
Users without a per-file environment retain the same interpreter and debugger behavior. When a Python file has a distinct environment, Pylance configuration and debugger launch consistently use that file's interpreter rather than a workspace-cached value.
Tests
TelemetryReporterimport errors in untouched files.Scope and follow-up
This PR does not implement Pylance's open-file rerouting notification. Live movement and reanalysis after a per-file environment change remain in PR 18.