From 4e656f6d8c7ba36054fb8cec3415fc8acfc014bf Mon Sep 17 00:00:00 2001 From: messense Date: Wed, 25 Dec 2024 14:57:04 +0800 Subject: [PATCH] Encode free-threaded Python support in bridge model --- src/bridge.rs | 23 ++++++++++++++++++++ src/python_interpreter/mod.rs | 41 ++++++++++++++++++++++++++++++++--- 2 files changed, 61 insertions(+), 3 deletions(-) diff --git a/src/bridge.rs b/src/bridge.rs index fe8f5b1e2..3825fa81b 100644 --- a/src/bridge.rs +++ b/src/bridge.rs @@ -49,6 +49,18 @@ impl Bindings { _ => MINIMUM_PYPY_MINOR, } } + + /// free-threaded Python support + fn supports_free_threaded(&self) -> bool { + match self.name.as_str() { + "pyo3" | "pyo3-ffi" => { + let major_version = self.version.major; + let minor_version = self.version.minor; + (major_version, minor_version) >= (0, 23) + } + _ => false, + } + } } /// The way the rust code is used in the wheel @@ -108,6 +120,17 @@ impl BridgeModel { pub fn is_bin(&self) -> bool { matches!(self, BridgeModel::Bin(_)) } + + /// free-threaded Python support + pub fn supports_free_threaded(&self) -> bool { + match self { + BridgeModel::Bin(Some(bindings)) + | BridgeModel::Bindings(bindings) + | BridgeModel::BindingsAbi3 { bindings, .. } => bindings.supports_free_threaded(), + BridgeModel::Bin(None) => true, + BridgeModel::Cffi | BridgeModel::UniFfi => false, + } + } } impl Display for BridgeModel { diff --git a/src/python_interpreter/mod.rs b/src/python_interpreter/mod.rs index ec7f3fe10..20e3afbc8 100644 --- a/src/python_interpreter/mod.rs +++ b/src/python_interpreter/mod.rs @@ -739,6 +739,9 @@ impl PythonInterpreter { let min_pypy_minor = bindings .map(|bindings| bindings.minimal_pypy_minor_version()) .unwrap_or(MINIMUM_PYPY_MINOR); + let supports_free_threaded = bridge + .map(|bridge| bridge.supports_free_threaded()) + .unwrap_or(false); InterpreterConfig::lookup_target(target) .into_iter() .filter_map(|config| match requires_python { @@ -770,6 +773,13 @@ impl PythonInterpreter { } InterpreterKind::GraalPy => Some(config), }) + .filter_map(|config| { + if config.gil_disabled && !supports_free_threaded { + None + } else { + Some(config) + } + }) .collect() } @@ -1047,7 +1057,6 @@ mod tests { "CPython 3.11", "CPython 3.12", "CPython 3.13", - "CPython 3.13t", "PyPy 3.8", "PyPy 3.9", "PyPy 3.10", @@ -1055,16 +1064,21 @@ mod tests { "#]]; expected.assert_debug_eq(&pythons); + // pyo3 0.23+ should find CPython 3.13t let pythons = PythonInterpreter::find_by_target( &target, - Some(&VersionSpecifiers::from_str(">=3.8").unwrap()), None, + Some(&BridgeModel::Bindings(Bindings { + name: "pyo3".to_string(), + version: semver::Version::new(0, 23, 0), + })), ) .iter() .map(ToString::to_string) .collect::>(); let expected = expect![[r#" [ + "CPython 3.7m", "CPython 3.8", "CPython 3.9", "CPython 3.10", @@ -1072,6 +1086,28 @@ mod tests { "CPython 3.12", "CPython 3.13", "CPython 3.13t", + "PyPy 3.9", + "PyPy 3.10", + ] + "#]]; + expected.assert_debug_eq(&pythons); + + let pythons = PythonInterpreter::find_by_target( + &target, + Some(&VersionSpecifiers::from_str(">=3.8").unwrap()), + None, + ) + .iter() + .map(ToString::to_string) + .collect::>(); + let expected = expect![[r#" + [ + "CPython 3.8", + "CPython 3.9", + "CPython 3.10", + "CPython 3.11", + "CPython 3.12", + "CPython 3.13", "PyPy 3.8", "PyPy 3.9", "PyPy 3.10", @@ -1093,7 +1129,6 @@ mod tests { "CPython 3.11", "CPython 3.12", "CPython 3.13", - "CPython 3.13t", "PyPy 3.10", ] "#]];