You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
feat: confirm inline-script env setup with a short-lived CodeLens (#1790)
## 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`.
---------
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copy file name to clipboardExpand all lines: docs/managing-python-projects.md
+2Lines changed: 2 additions & 0 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -99,6 +99,8 @@ When you create a script, the extension generates a single `.py` file with PEP 7
99
99
100
100
An inline-script environment is built from the script's `# /// script` block and stored in the extension's cache, where it is shared by every script with the same dependencies and base interpreter. Because editing one would silently change the others, these environments are not user-managed: the Python Environments views do not offer install, uninstall, or version-change actions for them. Their package list remains visible.
101
101
102
+
A CodeLens above the `# /// script` block offers **Set up environment for this script**, and the same action is available as a quick fix on an unresolved import. For a few seconds after setup succeeds it is replaced by a **Script environment ready (Python X.Y.Z)** confirmation naming the Python that was selected — useful when `requires-python` matches several installed versions, or when one was installed on demand. The confirmation is plain text rather than a clickable action, and it expires on its own; at every other time the setup CodeLens behaves exactly as before.
103
+
102
104
Setup records which distributions it installed. If that record and the environment's contents later disagree — for example after installing a package into it from a terminal — every script sharing the environment needs setup again. Saving or reopening a script does not repair it; use the script's setup action to rebuild from its declared dependencies.
103
105
104
106
Once a mismatch is confirmed during an environment lookup, the affected scripts' setup actions return without requiring a save.
0 commit comments