Add uv fallback for inline script environments (PEP 723 PR 6/16) - #1696
Add uv fallback for inline script environments (PEP 723 PR 6/16)#1696Stella Huang (StellaHuang95) wants to merge 1 commit into
Conversation
Add consent-gated uv installation when no installed interpreter satisfies a script. Coalesce matching installs, skip prompts for quick create, and directly resolve a successful installation when discovery is stale or unavailable. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 1a9f6ba1-9bd3-4664-bc25-a0d34d7a2e91
|
🔒 Automated review in progress — Stella Huang (@StellaHuang95) is auto-reviewing this PR. |
| private matchesInstallConstraint(requiresPython: string, version: string): boolean { | ||
| try { | ||
| return satisfiesPep440(version, requiresPython, { | ||
| prereleases: /(?:(?:a|alpha|b|beta|c|rc|pre|preview)[._-]?\d+|dev[._-]?\d+)/i.test( | ||
| requiresPython, | ||
| ), | ||
| }); | ||
| } catch (error) { | ||
| this.log.warn(`Unable to evaluate requires-python '${requiresPython}': ${getErrorMessage(error)}`); | ||
| return false; | ||
| } | ||
| } |
There was a problem hiding this comment.
I would probably extract this function off the class since it is not bound to an instance and can be reused elsewhere
| ...[...this.directlyResolvedBaseInterpreters.values()].filter( | ||
| (environment) => | ||
| !metadata.requiresPython || | ||
| this.matchesInstallConstraint(metadata.requiresPython, environment.version), | ||
| ), |
There was a problem hiding this comment.
| ...[...this.directlyResolvedBaseInterpreters.values()].filter( | |
| (environment) => | |
| !metadata.requiresPython || | |
| this.matchesInstallConstraint(metadata.requiresPython, environment.version), | |
| ), | |
| ...this.directlyResolvedBaseInterpreters.values().filter( | |
| (environment) => | |
| !metadata.requiresPython || | |
| this.matchesInstallConstraint(metadata.requiresPython, environment.version), | |
| ), |
| let candidates = derivedChecks | ||
| .filter((candidate) => !candidate.derived) | ||
| .map((candidate) => candidate.environment); | ||
| .map((candidate) => candidate.environment) | ||
| .filter( | ||
| (candidate) => | ||
| !metadata.requiresPython || | ||
| this.matchesInstallConstraint(metadata.requiresPython, candidate.version), | ||
| ); |
There was a problem hiding this comment.
Maybe thes can be combined into something like
let candidates = derivedChecks
.filter((candidate) =>
!candidate.derived
&& (!metadata.requiresPython || this.matchesInstallConstraint(metadata.requiresPython, candidate.version)
)
.map((candidate) => candidate.environment)|
|
||
| while (candidates.length > 0) { | ||
| const environment = pickCompatibleInterpreter(candidates, metadata.requiresPython); | ||
| const environment = pickCompatibleInterpreter(candidates, undefined); |
There was a problem hiding this comment.
| const environment = pickCompatibleInterpreter(candidates, undefined); | |
| const environment = pickCompatibleInterpreter(candidates); |
| this.baseInterpreterInstallationQueue = run.then( | ||
| () => undefined, | ||
| () => undefined, | ||
| ); |
There was a problem hiding this comment.
I am not entirely sure what does this mean
|
|
||
| const installedPath = await this.installPythonAndRefresh(requiresPython, version); | ||
| if (!installedPath) { | ||
| return undefined; |
There was a problem hiding this comment.
Maybe we can try catching this?
| return selected; | ||
| } | ||
|
|
||
| private async selectInstallablePythonVersion( |
There was a problem hiding this comment.
Maybe this is a followup PR, but I think we could create a PythonVersion class that can handle extracting lower/upper bounds, testing regexes, comparing, ensuring versions match constraints, etc.
Roadmap context
This is PR 6 of 16 in the PEP 723 inline-script roadmap. It extends the PR 5
create()happy path with the missing-compatible-interpreter fallback.InlineScriptEnvManagerskeletoncreate()happy pathcreate()uv-install fallbackget/set+ Memento)Why this PR
PR 5 can create or reuse an inline-script environment when an installed base interpreter already satisfies the script's
requires-python. It deliberately stops when no compatible interpreter exists.This PR adds the consent-gated fallback for that case:
What this PR does
Adds the inline-script fallback to
InlineScriptEnvManager.create()Selects a safe uv target from
requires-python>=3.13→3.13and==3.13.1→3.13.1.>=3.13.2,!=3.13.2without installing the excluded floor.c1→rc1) before passing a version to uv.Extends the uv installer's consent flow
Handles stale discovery after installation
requires-python, and canonicalizes its path before creating the cached environment.Examples
requires-python>=3.133.13selector==3.13.13.13.1without requiring a catalog lookup>=3.11,<3.123.11.xrelease>=3.13.2,!=3.13.23.13.2and choose a compatible advertised release>=3.15.0a1,<3.16>=3.14,<3.16Safety and concurrency
Tests
Coverage includes:
npm run compile-tests,npm run lint, the full unit suite, and the focused inline-script/uv suites are clean.User impact
No default-path user impact yet. This completes an internal Phase 2 manager capability. Automatic routing and user-facing entry points arrive in later roadmap PRs.
When those entry points are wired, users whose scripts require an unavailable Python will be able to approve installing a compatible interpreter rather than having environment creation stop.