Skip to content

Commit 83f7380

Browse files
authored
Allow use of free-threaded variants in Python 3.14+ without explicit opt-in (#16142)
Closes #15739 Closes #12445
1 parent 7d63ef1 commit 83f7380

2 files changed

Lines changed: 92 additions & 3 deletions

File tree

crates/uv-python/src/discovery.rs

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1668,9 +1668,19 @@ fn is_windows_store_shim(_path: &Path) -> bool {
16681668
impl PythonVariant {
16691669
fn matches_interpreter(self, interpreter: &Interpreter) -> bool {
16701670
match self {
1671-
// TODO(zanieb): Right now, we allow debug interpreters to be selected by default for
1672-
// backwards compatibility, but we may want to change this in the future.
1673-
Self::Default => !interpreter.gil_disabled(),
1671+
Self::Default => {
1672+
// TODO(zanieb): Right now, we allow debug interpreters to be selected by default for
1673+
// backwards compatibility, but we may want to change this in the future.
1674+
if (interpreter.python_major(), interpreter.python_minor()) >= (3, 14) {
1675+
// For Python 3.14+, the free-threaded build is not considered experimental
1676+
// and can satisfy the default variant without opt-in
1677+
true
1678+
} else {
1679+
// In Python 3.13 and earlier, the free-threaded build is considered
1680+
// experimental and requires explicit opt-in
1681+
!interpreter.gil_disabled()
1682+
}
1683+
}
16741684
Self::Debug => interpreter.debug_enabled(),
16751685
Self::Freethreaded => interpreter.gil_disabled(),
16761686
Self::FreethreadedDebug => interpreter.gil_disabled() && interpreter.debug_enabled(),

crates/uv/tests/it/python_find.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use assert_cmd::assert::OutputAssertExt;
12
use assert_fs::prelude::{FileTouch, PathChild};
23
use assert_fs::{fixture::FileWriteStr, prelude::PathCreateDir};
34
use indoc::indoc;
@@ -1256,3 +1257,81 @@ fn python_find_path() {
12561257
error: No interpreter found at path `foobar`
12571258
");
12581259
}
1260+
1261+
#[test]
1262+
fn python_find_freethreaded_313() {
1263+
let context: TestContext = TestContext::new_with_versions(&[])
1264+
.with_filtered_python_keys()
1265+
.with_filtered_python_sources()
1266+
.with_managed_python_dirs()
1267+
.with_python_download_cache()
1268+
.with_filtered_python_install_bin()
1269+
.with_filtered_python_names()
1270+
.with_filtered_exe_suffix();
1271+
1272+
context
1273+
.python_install()
1274+
.arg("--preview")
1275+
.arg("3.13t")
1276+
.assert()
1277+
.success();
1278+
1279+
// Request Python 3.13 (without opt-in)
1280+
uv_snapshot!(context.filters(), context.python_find().arg("3.13"), @r"
1281+
success: false
1282+
exit_code: 2
1283+
----- stdout -----
1284+
1285+
----- stderr -----
1286+
error: No interpreter found for Python 3.13 in [PYTHON SOURCES]
1287+
");
1288+
1289+
// Request Python 3.13t (with explicit opt-in)
1290+
uv_snapshot!(context.filters(), context.python_find().arg("3.13t"), @r"
1291+
success: true
1292+
exit_code: 0
1293+
----- stdout -----
1294+
[TEMP_DIR]/managed/cpython-3.13+freethreaded-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
1295+
1296+
----- stderr -----
1297+
");
1298+
}
1299+
1300+
#[test]
1301+
fn python_find_freethreaded_314() {
1302+
let context: TestContext = TestContext::new_with_versions(&[])
1303+
.with_filtered_python_keys()
1304+
.with_filtered_python_sources()
1305+
.with_managed_python_dirs()
1306+
.with_python_download_cache()
1307+
.with_filtered_python_install_bin()
1308+
.with_filtered_python_names()
1309+
.with_filtered_exe_suffix();
1310+
1311+
context
1312+
.python_install()
1313+
.arg("--preview")
1314+
.arg("3.14t")
1315+
.assert()
1316+
.success();
1317+
1318+
// Request Python 3.14 (without opt-in)
1319+
uv_snapshot!(context.filters(), context.python_find().arg("3.14"), @r"
1320+
success: true
1321+
exit_code: 0
1322+
----- stdout -----
1323+
[TEMP_DIR]/managed/cpython-3.14+freethreaded-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
1324+
1325+
----- stderr -----
1326+
");
1327+
1328+
// Request Python 3.14t (with explicit opt-in)
1329+
uv_snapshot!(context.filters(), context.python_find().arg("3.14t"), @r"
1330+
success: true
1331+
exit_code: 0
1332+
----- stdout -----
1333+
[TEMP_DIR]/managed/cpython-3.14+freethreaded-[PLATFORM]/[INSTALL-BIN]/[PYTHON]
1334+
1335+
----- stderr -----
1336+
");
1337+
}

0 commit comments

Comments
 (0)