Skip to content

Implement PythonVersion in managers - #1751

Open
Eduardo Villalpando Mello (edvilme) wants to merge 4 commits into
mainfrom
python-versions-implement
Open

Implement PythonVersion in managers#1751
Eduardo Villalpando Mello (edvilme) wants to merge 4 commits into
mainfrom
python-versions-implement

Conversation

@edvilme

Copy link
Copy Markdown
Contributor

This pull request refactors Python version handling in the inline script interpreter and metadata logic to use the new PythonVersion and PythonVersionSpecifier classes, resulting in more robust and maintainable version parsing and comparison. It removes custom parsing and comparison logic, centralizes version logic, and improves the accuracy of version specifier matching.

Python version parsing and comparison improvements:

  • Replaced custom version parsing and comparison functions in interpreter.ts with the new PythonVersion class for all version handling, including sorting interpreters and extracting lower bounds. [1] [2] [3] [4] [5]
  • Updated the PythonVersion class to provide precise parsing, normalization, comparison, and matching logic, including support for release levels and precision tracking. [1] [2] [3] [4] [5]

Version specifier handling:

  • Replaced ad-hoc specifier parsing in matchesPythonVersion with the new PythonVersionSpecifier class, ensuring accurate and maintainable specifier matching. [1] [2]
  • Updated lower bound extraction and specifier splitting to use splitClause and PythonVersionSpecifier, improving PEP 440 compliance. [1] [2]

Code cleanup and simplification:

  • Removed redundant parsing and comparison utilities, consolidating all version logic into the PythonVersion class. [1] [2]

These changes make version handling more reliable, easier to maintain, and better aligned with PEP 440 standards.

@rchiodo

Rich Chiodo (rchiodo) commented Sep 1, 2026

Copy link
Copy Markdown
Contributor

🔒 Automated review in progress — Rich Chiodo (@rchiodo) is auto-reviewing this PR.

@edvilme Eduardo Villalpando Mello (edvilme) added the debt Code quality issues label Sep 1, 2026
@rchiodo

Copy link
Copy Markdown
Contributor

Result: 🔴 could-not-verify

Verification details

Verification: Isolated verification observed failures that were not classified as caused by this PR: Dependency and test discovery probe, Offline dependency bootstrap, Git reference discovery. The relevant tests could not be fully run in the isolated environment; this review is not fully verified.

Summary: No tests could run because the disposable verifier lacked `npm`; the locked offline bootstrap failed with `npm: not found`. Targeted version, inline-script, installer, pip, and conda suites are therefore recorded as not-run. The PR adds 19 test cases, but execution could not be verified.

Test runs: 3 failed, 4 not run

  • ⚠️ Not run | Python version and specifier unit tests | npm run compile-tests && npm run unittest -- --grep "PythonVersion|PythonVersionSpecifier"
  • ⚠️ Not run | Inline script interpreter and metadata unit tests | npm run compile-tests && npm run unittest -- --grep "inlineScriptInterpreter|inlineScriptMetadata"
  • ⚠️ Not run | UV installer and pip package manager unit tests | npm run compile-tests && npm run unittest -- --grep "uvPythonInstaller - getUvPythonPath|PipPackageManager"
  • ⚠️ Not run | Conda version creation and shortening unit tests | npm run compile-tests && npm run unittest -- --grep "getPythonVersionsForCreation|shortenVersionString"
  • Failed | unrelated to this PR | Dependency and test discovery probe | git status --short && git branch --show-current && git merge-base HEAD upstream/main && git diff --name-status upstream/main...HEAD && if exist node_modules (echo NODE_MODULES_PRESENT) else (echo NODE_MODULES_MISSING)
  • Failed | unrelated to this PR | Offline dependency bootstrap | npm ci --offline
  • Failed | unrelated to this PR | Git reference discovery | git --no-pager log --oneline --decorate -5; git branch -a; git remote -v
⚠️ Python version and specifier unit tests diagnostic output
Dependency bootstrap failed: /bin/sh: npm: not found
⚠️ Inline script interpreter and metadata unit tests diagnostic output
Dependency bootstrap failed: /bin/sh: npm: not found
⚠️ UV installer and pip package manager unit tests diagnostic output
Dependency bootstrap failed: /bin/sh: npm: not found
⚠️ Conda version creation and shortening unit tests diagnostic output
Dependency bootstrap failed: /bin/sh: npm: not found
Dependency and test discovery probe diagnostic output
/bin/sh: 1: Syntax error: "(" unexpected (expecting "then")
Offline dependency bootstrap diagnostic output
/bin/sh: 1: npm: not found
Git reference discovery diagnostic output
fatal: not a git repository (or any parent up to mount point /)

@rchiodo Rich Chiodo (rchiodo) left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Approved via Review Center.

@rchiodo Rich Chiodo (rchiodo) added the review-auto:approved Automated review: no blocking findings (approval posted). label Sep 2, 2026
Follow-up to the rebase onto main. Removes the remaining hand-rolled
version handling around the centralized classes:

- Parse each uv catalog candidate once and sort on the parsed value,
  instead of re-parsing with the throwing constructor inside the sort
  comparator.
- Apply the same decorate-sort-undecorate shape to
  pickCompatibleInterpreter, so sorting no longer depends on a distant
  filter having already proven every version parses.
- Build the short display string with toReleaseString instead of
  reaching into major/minor/patch.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6444890d-5c9c-4e8e-82b3-37a157ead632
const VERSION_PATTERN =
/^(?<major>\d+)(?:\.(?<minor>\d+))?(?:\.(?<patch>\d+))?(?:(?:\.(?<longLevel>alpha|beta|candidate|final)\.(?<longSerial>\d+))|(?:(?<shortLevel>preview|pre|rc|a|b|c)[._-]?(?<shortSerial>\d+)))?$/i;

/**

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Issue · Please address or respond

The new parser accepts compact a/b/rc suffixes but rejects valid PEP 440 word aliases without the dotted sys.version_info form, such as 3.14.0alpha1. Those literals were accepted by the previous PEP 440-based installation constraint matching, so a normal requires-python constraint using one is now treated as invalid. Support the aliases and separator forms consistently, with coverage for alpha1.

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.

Fixed in 0afe955.

The parser had two separate branches: one for the dotted sys.version_info form (alpha|beta|candidate|final requiring . on both sides) and one for the compact form (a|b|rc|c|pre|preview). Word aliases without dots fell between them, so 3.14.0alpha1 was rejected.

Both branches are now a single alternation with optional ., -, or _ separators, so every spelling and separator combination is accepted uniformly (3.14.0alpha1, 3.14.0-alpha-1, 3.14.0.alpha.1, 3.14.0b1, 3.14.3.final.0). Longer spellings precede the abbreviations they start with so alpha wins over a. This also removed the duplicated level/serial capture groups and the ?? merge in the constructor.

Coverage added: normalizes every prerelease spelling and separator (includes alpha1, all three separators, and case-insensitivity) and treats every release-candidate alias as the same level (rc/c/pre/preview/candidate).

I kept an explicit serial required, and still reject epochs, post/dev releases, and local labels — those remain out of scope for an interpreter version.

/** Parses and validates a single clause such as `>=3.11` or `==3.12.*`. */
function parseClause(clause: string): VersionClause | undefined {
const parts = splitClause(clause);
if (!parts) {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Issue · Please address or respond

Prerelease admission is applied globally after all clauses match. Consequently, 3.14.0rc1 matches >=3.13.0rc1,<3.14, even though an exclusive final-release upper bound excludes prereleases of that bound under PEP 440. Encode this ordered-bound prerelease rule per clause and add the compound case to the specifier tests.

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.

Good catch, fixed in 0afe955.

Prerelease admission was decided once for the whole specifier (clauses.some(allowsPrereleases)), so a prerelease named in any clause admitted prereleases everywhere, including past an exclusive final upper bound.

The rule is now encoded on the clause that owns it: a < clause whose bound is a final release rejects any prerelease sharing that release, independent of what other clauses admit. A prerelease bound is unaffected, so <3.14.0rc2 still admits 3.14.0rc1.

Coverage added in excludes prereleases of an exclusive upper bound:

  • 3.14.0rc1 vs >=3.13.0rc1,<3.14 -> false (the reported case)
  • 3.13.5rc1 vs >=3.13.0rc1,<3.14 -> true (prereleases below the bound still admitted)
  • 3.14.0rc1 vs >=3.13.0rc1,<3.14.0rc2 -> true (prerelease bound unaffected)
  • 3.14.0rc1 vs >=3.13.0rc1,<=3.14 -> true (PEP 440 restricts only the exclusive form)

I left <= and > alone deliberately: PEP 440 restricts only <V for prereleases, and the >V restriction concerns post-releases, which this class does not model.

@rchiodo

Copy link
Copy Markdown
Contributor

Result: 🔴 could-not-verify

Verification details

Verification: Isolated verification observed failures that were not classified as caused by this PR: Repository test discovery probe. The relevant tests could not be fully run in the isolated environment; this review is not fully verified.

Summary: No tests could execute because the isolated container does not provide `npm`; the required locked offline bootstrap exited 127. Repository inspection confirmed substantial new coverage for version parsing, specifier matching, interpreter selection, uv lookup, and Conda sorting. Runtime confidence remains low without executable test results.

Test runs: 1 failed, 4 not run

  • ⚠️ Not run | Core Python version and inline-script unit tests | npm run compile-tests && npm run unittest -- --grep "^(PythonVersion|PythonVersionSpecifier|inlineScriptInterpreter|inlineScriptMetadata)"
  • ⚠️ Not run | InlineScriptEnvManager unit tests | npm run unittest -- --grep "^InlineScriptEnvManager"
  • ⚠️ Not run | Manager integration unit tests for version handling | npm run unittest -- --grep "^(PipPackageManager|uvPythonInstaller - getUvPythonPath|getPythonVersionsForCreation|pep440Version)"
  • Failed | unrelated to this PR | Repository test discovery probe | git status --short && git diff --name-status upstream/main...HEAD && node -e "const p=require('./package.json'); console.log(JSON.stringify(p.scripts,null,2))" && if exist node_modules (echo NODE_MODULES_PRESENT) else (echo NODE_MODULES_MISSING)
  • ⚠️ Not run | Locked offline dependency bootstrap | npm ci --offline
⚠️ Core Python version and inline-script unit tests diagnostic output
Blocked because npm is unavailable in the verification container.
⚠️ InlineScriptEnvManager unit tests diagnostic output
Blocked because npm is unavailable in the verification container.
⚠️ Manager integration unit tests for version handling diagnostic output
Blocked because npm is unavailable in the verification container.
Repository test discovery probe diagnostic output
/bin/sh: 1: Syntax error: "(" unexpected (expecting "then")
⚠️ Locked offline dependency bootstrap diagnostic output
/bin/sh: 1: npm: not found

@rchiodo Rich Chiodo (rchiodo) added review-auto:changes-requested Automated review: posted blocking findings to address. and removed review-auto:approved Automated review: no blocking findings (approval posted). labels Sep 2, 2026
Accept every prerelease spelling consistently. The parser had separate
branches for the dotted `sys.version_info` form and the compact form, so
word aliases without dots such as `3.14.0alpha1` were rejected even
though the previous PEP 440-based matching accepted them. One alternation
now covers all spellings with optional `.`, `-`, or `_` separators, which
also removes the duplicated level and serial capture groups.

Encode the exclusive upper bound prerelease rule per clause. Prerelease
admission was applied to the specifier as a whole, so `3.14.0rc1`
satisfied `>=3.13.0rc1,<3.14` because another clause named a prerelease.
An exclusive bound now rejects prereleases of its own release, while
`<3.14.0rc2` still admits them.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 6444890d-5c9c-4e8e-82b3-37a157ead632
@rchiodo

Copy link
Copy Markdown
Contributor

Result: 🔴 could-not-verify

Verification details

Verification: Isolated verification observed failures that were not classified as caused by this PR: Dependency and diff discovery, Offline dependency bootstrap. The relevant tests could not be fully run in the isolated environment; this review is not fully verified.

Summary: Verification could not run because the isolated environment lacks `npm`; the offline bootstrap failed with `npm: not found`. The PR adds or updates 23 targeted tests covering version parsing, specifiers, interpreter selection, uv lookup, and Conda sorting. No executable test completed, so runtime confidence is unavailable.

Test runs: 2 failed, 3 not run

  • ⚠️ Not run | Compile unit tests | npm run compile-tests
  • ⚠️ Not run | Core version and inline-script suites | npm run unittest -- --grep "PythonVersion|PythonVersionSpecifier|inlineScriptInterpreter|inlineScriptMetadata"
  • ⚠️ Not run | uv and Conda version-selection suites | npm run unittest -- --grep "uvPythonInstaller - getUvPythonPath|getPythonVersionsForCreation"
  • Failed | unrelated to this PR | Dependency and diff discovery | $base = git merge-base upstream/main HEAD; Write-Output "BASE=$base"; git status --short; git diff --name-status $base HEAD; if (Test-Path node_modules) { Write-Output 'NODE_MODULES=present' } else { Write-Output 'NODE_MODULES=missing' }; if (Test-Path out\client\extension.js) { Write-Output 'TEST_BUILD=present' } else { Write-Output 'TEST_BUILD=missing' }
  • Failed | unrelated to this PR | Offline dependency bootstrap | npm ci --offline
⚠️ Compile unit tests diagnostic output
Blocked because npm is unavailable in the verification environment.
⚠️ Core version and inline-script suites diagnostic output
Blocked because npm is unavailable and tests could not be compiled.
⚠️ uv and Conda version-selection suites diagnostic output
Blocked because npm is unavailable and tests could not be compiled.
Dependency and diff discovery diagnostic output
/bin/sh: 1: Syntax error: "{" unexpected (expecting "then")
Offline dependency bootstrap diagnostic output
/bin/sh: 1: npm: not found

@rchiodo Rich Chiodo (rchiodo) 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 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

debt Code quality issues 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