fix(python): exclude freethreaded builds from precompiled selection#8672
fix(python): exclude freethreaded builds from precompiled selection#8672
Conversation
Freethreaded Python builds (e.g. cpython-3.14.3-freethreaded-install_only_stripped) use a different lib directory layout (python3.14t vs python3.14), causing "missing lib directory" errors during installation. Filter them out by default unless the user explicitly sets python.precompiled_flavor. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Summary of ChangesHello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request addresses an issue where freethreaded Python builds were being incorrectly selected and causing installation failures due to incompatible library paths. The changes modify the precompiled Python build selection logic to prioritize standard builds by default, ensuring a smoother installation experience for most users. Users who specifically require freethreaded builds can still opt into them via a configuration setting. Highlights
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. Footnotes
|
Greptile SummaryThis PR fixes a regression where
The approach is minimal and well-targeted. One concern: the static Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[mise up --bump python] --> B[fetch_precompiled_remote_versions / fetch_precompiled_for_target]
B --> C{precompiled_flavor set?}
C -- Yes --> D[Pass all lines incl. freethreaded\nthrough platform filter]
C -- No --> E[Filter out lines containing 'freethreaded']
D --> F[Select best tarball via rank / min_by_key]
E --> F
F --> G[Download & extract tarball]
G --> H[install_precompiled: call update_sysconfig]
H --> I[find_sysconfigdata]
I --> J{lib/pythonM.mt exists?}
J -- Yes freethreaded --> K[Use lib/pythonM.Mt/]
J -- No --> L{lib/pythonM.m exists?}
L -- Yes --> M[Use lib/pythonM.m/]
L -- No --> N[Error: MissingLib]
K --> O[Patch _sysconfigdata_ file]
M --> O
|
There was a problem hiding this comment.
Code Review
This pull request addresses an issue where freethreaded Python builds were being incorrectly selected due to the install_only_stripped ranking and alphabetical sorting. The changes filter out freethreaded tarballs by default unless python.precompiled_flavor is explicitly set. The code changes involve adding a filter to exclude freethreaded versions in src/plugins/core/python.rs. The review focuses on the correctness of the added filter and its impact on the intended functionality.
| let versions = raw | ||
| .lines() | ||
| .filter(|v| v.contains(&platform)) | ||
| .filter(|v| flavor.is_some() || !v.contains("freethreaded")) |
There was a problem hiding this comment.
This filter excludes freethreaded versions unless flavor is set. It's crucial to ensure this logic doesn't inadvertently exclude desired versions when flavor is explicitly set to a non-freethreaded value. Consider adding a test case to verify this scenario.
.filter(|v| flavor.is_some() || !v.contains("freethreaded"))
// When flavor is set, we want to include freethreaded builds, so don't filter them out.| let result = raw | ||
| .lines() | ||
| .filter(|v| v.contains(&platform)) | ||
| .filter(|v| flavor.is_some() || !v.contains("freethreaded")) |
There was a problem hiding this comment.
Similar to the previous comment, ensure this filter doesn't exclude desired versions when flavor is explicitly set to a non-freethreaded value. A test case would be beneficial here as well.
.filter(|v| flavor.is_some() || !v.contains("freethreaded"))
// When flavor is set, we want to include freethreaded builds, so don't filter them out.
Hyperfine Performance
|
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.9 x -- echo |
25.5 ± 0.7 | 24.0 | 30.4 | 1.02 ± 0.04 |
mise x -- echo |
24.9 ± 0.6 | 23.8 | 29.8 | 1.00 |
mise env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.9 env |
24.0 ± 0.7 | 23.1 | 29.3 | 1.00 |
mise env |
24.1 ± 0.4 | 23.2 | 27.4 | 1.00 ± 0.03 |
mise hook-env
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.9 hook-env |
25.2 ± 0.7 | 23.8 | 28.5 | 1.00 ± 0.04 |
mise hook-env |
25.1 ± 0.7 | 24.2 | 28.3 | 1.00 |
mise ls
| Command | Mean [ms] | Min [ms] | Max [ms] | Relative |
|---|---|---|---|---|
mise-2026.3.9 ls |
23.7 ± 0.5 | 22.8 | 29.2 | 1.00 |
mise ls |
24.5 ± 0.4 | 23.4 | 26.6 | 1.03 ± 0.03 |
xtasks/test/perf
| Command | mise-2026.3.9 | mise | Variance |
|---|---|---|---|
| install (cached) | 153ms | 153ms | +0% |
| ls (cached) | 85ms | 85ms | +0% |
| bin-paths (cached) | 90ms | 90ms | +0% |
| task-ls (cached) | 858ms | 823ms | +4% |
Free-threaded Python uses `lib/python3.14t/` (note the `t` suffix). Probe for this variant in `find_sysconfigdata` so that freethreaded builds work when explicitly requested via `python.precompiled_flavor`. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
mise v2026.3.10 excludes freethreaded Python builds by default, fixing "Python installation is missing a lib directory" errors. See: https://github.com/jdx/mise/releases/tag/v2026.3.10 Fix: jdx/mise#8672 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
mise v2026.3.10 excludes freethreaded Python builds by default, fixing "Python installation is missing a lib directory" errors. See: https://github.com/jdx/mise/releases/tag/v2026.3.10 Fix: jdx/mise#8672 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
mise v2026.3.10 excludes freethreaded Python builds by default, fixing "Python installation is missing a lib directory" errors. See: https://github.com/jdx/mise/releases/tag/v2026.3.10 Fix: jdx/mise#8672 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Summary
cpython-3.14.3+20260320-x86_64-unknown-linux-gnu-freethreaded-install_only_stripped.tar.gz) uselib/python3.14t/instead oflib/python3.14/, causing"Python installation is missing a lib directory"errors during installationinstall_only_strippedranking treated freethreaded and non-freethreaded builds equally, and the freethreaded variant won alphabetically viamin_by_keypython.precompiled_flavoris explicitly setTest plan
backend/test_pipx_deep_dependencies_slowshould pass (previously failing onmise up --bump pythonselecting freethreaded 3.14.3)python.precompiled_flavorset to a freethreaded variant should still get freethreaded builds🤖 Generated with Claude Code
Note
Medium Risk
Changes precompiled Python artifact selection and sysconfig patching path resolution, which can affect which binaries users install and whether installs succeed on newer Python versions. Risk is moderate due to platform/version variability, but logic is narrowly scoped and gated by
python.precompiled_flavor.Overview
Precompiled Python selection now filters out
freethreadedartifacts by default (unlesssettings.python.precompiled_flavoris explicitly set), preventing freethreaded tarballs from winning tie-breaks during version ranking.Sysconfig patching now searches
lib/pythonX.Ytin addition to the existing suffix/no-suffix locations, avoiding "missinglibdirectory" failures for free-threaded installs that use thetlib directory convention.Written by Cursor Bugbot for commit d29ecc7. This will update automatically on new commits. Configure here.