Skip to content

feat: confirm inline-script env setup with a short-lived CodeLens - #1790

Merged
Stella Huang (StellaHuang95) merged 2 commits into
microsoft:mainfrom
StellaHuang95:stellahuang-microsoft-pep723-inline-script-research-ef8
Sep 16, 2026
Merged

Stella Huang (StellaHuang95) merged 2 commits into
microsoft:mainfrom
StellaHuang95:stellahuang-microsoft-pep723-inline-script-research-ef8

Conversation

@StellaHuang95

Copy link
Copy Markdown
Contributor

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-python matches several installed Pythons, or when one was installed on demand via uv python install.

Change

For five seconds after setup succeeds, the (now hidden) setup lens is replaced by a passive confirmation anchored at the # /// script block:

Script environment ready (Python 3.12.4)

then it expires on its own. The version comes from shortenVersionString(environment.version) — the same helper getPythonInfo uses for script 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:

isDirty metadata shouldRoute confirmation live Before After
yes [] []
no none [] []
no yes yes yes [] confirmation
no yes yes no [] []
no yes no setup lens setup lens

Everything else is byte-identical: the dirty guard, the metadata check, shouldRoute semantics, and the setup lens title, command, arguments and anchor. routingRegistry.ts, envManager.ts, window.apis.ts, settings and package.json are 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 own Set up {0} of {1} ... summary and can process scripts that are not open.

Implementation notes

  • noteEnvironmentReady cancels any existing timer for the script first, so re-running setup restarts the window rather than inheriting a nearly-expired one.
  • Entries are keyed by getInlineScriptRoutingKey, so on Windows C:\App.py and c:\app.py share one entry.
  • dispose() clears every pending timer; a test asserts nothing fires afterwards.
  • Confirmations are in-memory and per-window, deliberately not persisted — a confirmation is about an action you just took.

Known limitation

If the file is edited while the environment builds, getSavedMetadataForPersistence returns {} for the dirty document, so updateValidatedStateForSelection leaves shouldRoute false 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 past dispose(). 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 lint OK, npm run compile-tests OK, npm run unittest OK (2331 passing, 6 pending, 0 failing)

discovers a build that completes after the short retry window is a pre-existing flake unrelated to this change — verified by stashing these changes and running it on a clean tree, where it failed 2 of 4 runs.

Nothing here is user-visible by default: the whole surface stays behind the undeclared internal flag python-envs.inlineScripts.enabled, which defaults to false.

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>
@StellaHuang95 Stella Huang (StellaHuang95) added the feature-request Request for new features or functionality label Sep 15, 2026
@bschnurr

Copy link
Copy Markdown
Member

🔒 Automated review in progress — Bill Schnurr (@bschnurr) is auto-reviewing this PR.

Comment thread src/test/features/inlineScript/codeLens.unit.test.ts
@bschnurr

Copy link
Copy Markdown
Member

Result: 🔴 could-not-verify

Verification details

Verification: 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

  • ⚠️ Not run | Inline-script CodeLens and setup-handler unit tests | node ./node_modules/mocha/bin/mocha.js --require source-map-support/register --require out/test/unittests.js --ui tdd --timeout 180000 out/test/features/inlineScript/codeLens.unit.test.js out/test/features/inlineScript/setupEnvironment.unit.test.js
  • Failed | unrelated to this PR | Sandbox dependency and test-artifact preflight | printf 'profile=%s\n' "${AUTOMATION_SANDBOX_PROFILE:-}"; printf 'node=%s npm=%s\n' "$(node --version 2>/dev/null || echo missing)" "$(npm --version 2>/dev/null || echo missing)"; if [ -d node_modules ]; then echo 'node_modules=present'; else echo 'node_modules=missing'; fi; if [ -f out/test/features/inlineScript/codeLens.unit.test.js ] && [ -f out/test/features/inlineScript/setupEnvironment.unit.test.js ]; then echo 'compiled_target_tests=present'; else echo 'compiled_target_tests=missing'; fi; git diff --name-status HEAD^...HEAD; git status --short
  • Failed | unrelated to this PR | Offline npm dependency restoration | npm ci --offline
  • Failed | unrelated to this PR | TypeScript test compilation | npm run compile-tests
⚠️ Inline-script CodeLens and setup-handler unit tests diagnostic output
Not run because dependency restoration and the required test compilation failed.
Sandbox dependency and test-artifact preflight diagnostic output
profile=typescript
node=v22.21.1 npm=10.9.4
node_modules=missing
compiled_target_tests=missing
fatal: not a git repository
Offline npm dependency restoration diagnostic output
npm error code ENOTCACHED
npm error request to https://packagefeedproxy.microsoft.io/npm/brace-expansion/-/brace-expansion-2.1.4.tgz failed: cache mode is 'only-if-cached' but no cached response is available.
TypeScript test compilation diagnostic output
> vscode-python-envs@1.37.0 compile-tests
> tsc -p . --outDir out

sh: 1: tsc: not found

@bschnurr Bill Schnurr (bschnurr) added the review-auto:changes-requested Automated review: posted blocking findings to address. label Sep 16, 2026
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>
@bschnurr

Copy link
Copy Markdown
Member

Result: 🔴 could-not-verify

Verification details

Verification: 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

  • Failed | unrelated to this PR | TypeScript test compilation | npm run compile-tests
  • ⚠️ Not run | Inline script CodeLens provider unit tests | node ./node_modules/mocha/bin/mocha.js --require source-map-support/register --require out/test/unittests.js --ui tdd --timeout 180000 out/test/features/inlineScript/codeLens.unit.test.js
  • ⚠️ Not run | Inline script setup environment unit tests | node ./node_modules/mocha/bin/mocha.js --require source-map-support/register --require out/test/unittests.js --ui tdd --timeout 180000 out/test/features/inlineScript/setupEnvironment.unit.test.js
  • Failed | unrelated to this PR | Offline dependency bootstrap | npm ci --offline
  • Passed | Dependency and test discovery | printf 'profile=%s\n' "${AUTOMATION_SANDBOX_PROFILE:-}"; printf '%s\n' '--- changed files ---'; git diff --name-status HEAD^ HEAD; printf '%s\n' '--- dependency state ---'; test -x node_modules/.bin/mocha && echo 'mocha=present' || echo 'mocha=missing'; test -x node_modules/.bin/tsc && echo 'tsc=present' || echo 'tsc=missing'; node --version; npm --version; printf '%s\n' '--- relevant scripts ---'; node -e "const p=require('./package.json'); for (const k of ['compile-tests','unittest','lint']) console.log(k+'='+p.scripts[k])"; printf '%s\n' '--- mocha config ---'; cat build/.mocha.unittests.json
TypeScript test compilation diagnostic output
> vscode-python-envs@1.37.0 compile-tests
> tsc -p . --outDir out

sh: 1: tsc: not found
⚠️ Inline script CodeLens provider unit tests diagnostic output
Not run because offline dependency restoration failed and test compilation could not proceed.
⚠️ Inline script setup environment unit tests diagnostic output
Not run because offline dependency restoration failed and test compilation could not proceed.
Offline dependency bootstrap diagnostic output
npm error code ENOTCACHED
npm error request to https://packagefeedproxy.microsoft.io/npm/brace-expansion/-/brace-expansion-2.1.4.tgz failed: cache mode is 'only-if-cached' but no cached response is available.

@bschnurr Bill Schnurr (bschnurr) left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approved via Review Center.

@bschnurr Bill Schnurr (bschnurr) added review-auto:approved Automated review: no blocking findings (approval posted). and removed review-auto:changes-requested Automated review: posted blocking findings to address. labels Sep 16, 2026
@StellaHuang95
Stella Huang (StellaHuang95) merged commit 33bf91f into microsoft:main Sep 16, 2026
48 checks passed
@StellaHuang95
Stella Huang (StellaHuang95) deleted the stellahuang-microsoft-pep723-inline-script-research-ef8 branch September 16, 2026 01:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

feature-request Request for new features or functionality review-auto:approved Automated review: no blocking findings (approval posted).

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants