feat: confirm inline-script env setup with a short-lived CodeLens - #1790
Conversation
Setting up a PEP 723 inline-script environment previously signalled success only by the setup CodeLens disappearing, which is indistinguishable from the lens never having been offered. It also left the chosen base interpreter invisible, which matters when `requires-python` matches several installed Pythons or when one was installed on demand. For five seconds after setup succeeds the hidden setup lens is replaced by a passive "Script environment ready (Python X.Y.Z)" confirmation anchored at the `# /// script` block, which then expires on its own. That line is already occupied by the setup lens at that point, so this adds no extra reflow. Every other CodeLens path is unchanged: the dirty guard, the metadata check, shouldRoute semantics, and the setup lens title, command and anchor are all byte-identical. Both setup surfaces (the CodeLens and the unresolved-import quick fix) show the confirmation; the bulk command does not, since it already reports its own summary. Confirmations are in-memory and per-window, and their timers are cleared on disposal. Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
🔒 Automated review in progress — Bill Schnurr (@bschnurr) is auto-reviewing this PR. |
|
Result: 🔴 Verification detailsVerification: Isolated verification observed failures that were not classified as caused by this PR: Sandbox dependency and test-artifact preflight, Offline npm dependency restoration, TypeScript test compilation. The relevant tests could not be fully run in the isolated environment; this review is not fully verified. Summary: Targeted inline-script unit tests could not run because offline dependency restoration lacked `brace-expansion@2.1.4`. Consequently, `npm run compile-tests` failed with `tsc: not found`, leaving both changed suites uncompiled. Inspection confirmed nine newly added tests, but none executed. Overall verification is blocked by the sandbox dependency cache. Test runs: 3 failed, 1 not run
|
The two CodeLens confirmation tests used partial assertions: `includes('3.12.4')`
and `!includes('(')`. Both are weak -- the first passes on any message that merely
contains the version, and the second only asserts the absence of a character, so it
verified nothing about the versionless text at all.
Both now assert the complete localized title with assert.strictEqual. Confirmed
load-bearing by mutation: renaming the message to "Script env ready" leaves both
old assertions green while both new ones fail.
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
|
Result: 🔴 Verification detailsVerification: Isolated verification observed failures that were not classified as caused by this PR: TypeScript test compilation, Offline dependency bootstrap. The relevant tests could not be fully run in the isolated environment; this review is not fully verified. Summary: Verification was blocked by unavailable offline dependencies. `npm ci --offline` failed because `brace-expansion-2.1.4.tgz` was not cached, and test compilation then failed because `tsc` was unavailable. Consequently, neither targeted inline-script unit suite could run, so confidence is low. Test runs: 1 passed, 2 failed, 2 not run
❌
|
Bill Schnurr (bschnurr)
left a comment
There was a problem hiding this comment.
Approved via Review Center.
33bf91f
into
microsoft:main
Problem
Setting up a PEP 723 inline-script environment signals success only by the setup CodeLens disappearing — which is indistinguishable from the lens never having been offered in the first place. It also leaves the chosen base interpreter invisible, which matters when
requires-pythonmatches several installed Pythons, or when one was installed on demand viauv python install.Change
For five seconds after setup succeeds, the (now hidden) setup lens is replaced by a passive confirmation anchored at the
# /// scriptblock:then it expires on its own. The version comes from
shortenVersionString(environment.version)— the same helpergetPythonInfouses forscript env (3.12.4)— so the lens and the environment's own name cannot disagree.An empty command id renders the title as plain, non-clickable text: this is a statement, not an action.
No extra reflow
The line is already occupied by the setup lens at that moment, so the confirmation does not add a shift — it delays the single existing one by five seconds. This was the main objection to an earlier draft, and it turned out not to apply.
Scope
The entire behavioural change is one new row in
provideCodeLenses:isDirtyshouldRoute[][][][][][][]Everything else is byte-identical: the dirty guard, the metadata check,
shouldRoutesemantics, and the setup lens title, command, arguments and anchor.routingRegistry.ts,envManager.ts,window.apis.ts, settings andpackage.jsonare untouched.Both setup surfaces — the CodeLens and the unresolved-import quick fix from #1788 — show the confirmation, since both route through
python-envs.setupInlineScriptEnv. The bulk command deliberately does not: it already ends with its ownSet up {0} of {1} ...summary and can process scripts that are not open.Implementation notes
noteEnvironmentReadycancels any existing timer for the script first, so re-running setup restarts the window rather than inheriting a nearly-expired one.getInlineScriptRoutingKey, so on WindowsC:\App.pyandc:\app.pyshare one entry.dispose()clears every pending timer; a test asserts nothing fires afterwards.Known limitation
If the file is edited while the environment builds,
getSavedMetadataForPersistencereturns{}for the dirty document, soupdateValidatedStateForSelectionleavesshouldRoutefalse and the confirmation is unreachable until the next save — and lost entirely if that takes longer than five seconds. Showing it anyway would mean confirming an association that is not validated, so the miss is preferable to the lie.Expiry also depends on VS Code re-querying after
onDidChangeCodeLenses. That is normally immediate, but the lens can outlast five seconds slightly under load. It always clears.Tests
Six new provider tests on
sinon.useFakeTimers()(no wall-clock dependency): shows with version, omits version when unresolved, expires and fires exactly one refresh, routed-but-not-just-set-up shows nothing, hidden while dirty, and no timer leak pastdispose(). Three handler tests cover the callback firing on success and staying silent when creation returns nothing or throws.The five pre-existing CodeLens tests are unmodified and still pass — including "hides the CodeLens once a validated association makes the script routeable", which is the proof that the default routed path is unchanged.
npm run lintOK,npm run compile-testsOK,npm run unittestOK (2331 passing, 6 pending, 0 failing)Nothing here is user-visible by default: the whole surface stays behind the undeclared internal flag
python-envs.inlineScripts.enabled, which defaults tofalse.