Skip to content

[Do not merge] PEP 723 inline script env support design doc#1601

Draft
StellaHuang95 wants to merge 5 commits into
microsoft:mainfrom
StellaHuang95:pep723-design
Draft

[Do not merge] PEP 723 inline script env support design doc#1601
StellaHuang95 wants to merge 5 commits into
microsoft:mainfrom
StellaHuang95:pep723-design

Conversation

@StellaHuang95

Copy link
Copy Markdown
Contributor

⚠️ Not for merge. This PR exists to gather feedback on the design before any implementation is going too far.

Context

PEP 723 defines inline script metadata — a # /// script# /// block at the top of a single-file Python script that declares requires-python and dependencies inline, so the script is self-contained without a pyproject.toml or requirements.txt. Tools like uv and pipx already honor it; users opening these scripts in VS Code today get no automatic environment support.

This doc talks about how the extension should build, manage, and dispose of environments for those scripts.

What's in this doc

Eleven design questions, each with a proposed decision and the reasoning. The interesting / contentious ones:

  • Q2 — Disk location. Proposal: <globalStorageUri>/script-envs-v1/<hash>/. Never inside the workspace.
  • Q4 — Script-to-directory mapping. Proposal: pipx-style, deps-keyed hash (adapted to honor requires-python). The "no in-place sync" argument is the load-bearing one here.
  • Q5 — Reuse vs build fresh. Only two outcomes, no "sync" path. Table of every interesting transition.
  • Q6 — Persistence. Proposal: reuse the existing setEnvironment(scriptUri, env, /*persist*/ true) pipeline rather than inventing a new layer.
  • Q7 — Cleanup. Proposal: explicit command + opportunistic 14-day TTL (matches pipx).
  • Q9 / Q10 — Pylance & Run/F5. Essentially solved by Q6's setEnvironment call, with source pointers into Pylance and the Python extension to back the claim.

Any feedback is welcome, thanks!

@StellaHuang95

Copy link
Copy Markdown
Contributor Author

@brettcannon Still can't assign you as a reviewer so tagging you here, any feedback is welcome, thank you!

- **Lazy on open + save** — parse only when the file enters an editor or
is saved.
- **Opt-in bulk command** — user runs `Python Envs: Set Up Environments for Inline Script Files` from the command palette to discover all of them, list every detected inline-script files in a multi-select quick-pick.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

What about a third option (requires pylance's help), whenever the script header is detected by the Pylance parser.

This might happen if somebody opens a script that is referenced by another script with a header (imported by would be set in Pylance).

Example:

main_script.py (has the PEP 723 script)
tools.py (is referenced by PEP 723 script)

User edits tools.py

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I was mostly thinking to actually run or edit main_script.py, the user almost always opens it at some point. And once they open it once, the current mechanism captures it, so the inline env stays set up across sessions.

Are you thinking about the case where the user opens tools.py first, and is seeing squiggles on the imports? I agree that could be annoying. The tricky part for us is that the inline env is intentionally tied to the file with the PEP 723 header. For a file like tools.py to also pick up that env as its active one, we'd need to either register it as its own "project" pointing at someone else's env, or follow the import graph and pick a "best" inline env.

So my lean is probably not do this for v1 unless we can think of a good way to solve the problem above. Detect-on-open + persistence covers most real workflows, and the bulk command addresses the same underlying frustration in a simpler way:

A user exploring a new repo can set up every inline env in one shot without needing Pylance to drive discovery. Are you seeing lots of Pylance users complaining about that? If we hear that this still isn't enough I am happy to make some improvements.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

No sounds reasonable. I was just trying to think of other situations that could cause the env to be created. My idea was more about what background things could cause the env to automatically be created, and not necessarily about Pylance behaving correctly with respect to imports in the tools.py.


**Decision.**

Reuse the existing venv persistence mechanism.Do not invent a new

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

This is going to require changes to Pylance outside of the work to support Python Environments sub environments because the environment in this case is tied to a file and not an entire folder.

Not sure if that will work correctly or not.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

yeah that's a good point, I think it requires changes on Pylance side to make it to work. I wonder how pylance work for notebook files, maybe we can do the same thing to look up env for files with inline script.

Comment thread pep723_design_questions.md Outdated

## 8. UX flows

**Question:** How does the user create envs — for a single script, and

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Personally, I think the user should never have to create environments for the script. It should just happen automatically. What do they gain by having this command?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Right now the envs extension runs on one shared extension host process, unlike pylance which has its own process and can do the heave-lifting in its own background thread without any architecture changes.

So for the bulk command I would rather keep it user triggered. A full workspace scan + per-file parse on a large repo is too much work and may block other. For single file case, I can probably add a codeLens that looks like this so that one click setup is obvious to user.

📦 Set up environment for this script
 # /// script
 # dependencies = ["requests"]
 # ///

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants