Expand Windows shim detection to include python3.12.exe (#2209)

## Summary

Our Windows shim detection wasn't catching shims like `python3.12.exe`.

Closes #2208.

## Test Plan

Installed Python 3.12 via the Windows Store; verified that `cargo run
venv --python 3.12` failed before but passes after this change.
This commit is contained in:
Charlie Marsh 2024-03-05 10:25:05 -08:00 committed by GitHub
parent 8620b5a52f
commit cf94df7cb9
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -330,7 +330,7 @@ impl PythonVersionSelector {
}
mod windows {
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::process::Command;
use once_cell::sync::Lazy;
@ -412,17 +412,56 @@ mod windows {
/// does not want us to do this as the format is unstable. So this is a best effort way.
/// we just hope that the reparse point has the python redirector in it, when it's not
/// pointing to a valid Python.
pub(super) fn is_windows_store_shim(path: &std::path::Path) -> bool {
///
/// Matches against paths like:
/// `C:\Users\crmar\AppData\Local\Microsoft\WindowsApps\python.exe`
pub(super) fn is_windows_store_shim(path: &Path) -> bool {
// Rye uses a more sophisticated test to identify the windows store shim.
// Unfortunately, it only works with the `python.exe` shim but not `python3.exe`.
// What we do here is a very naive implementation but probably sufficient for all we need.
// There's the risk of false positives but I consider it rare, considering how specific
// the path is.
// Rye Shim detection: https://github.com/mitsuhiko/rye/blob/78bf4d010d5e2e88ebce1ba636c7acec97fd454d/rye/src/cli/shim.rs#L100-L172
path.to_str().map_or(false, |path| {
path.ends_with("Local\\Microsoft\\WindowsApps\\python.exe")
|| path.ends_with("Local\\Microsoft\\WindowsApps\\python3.exe")
})
if !path.is_absolute() {
return false;
}
let mut components = path.components().rev();
// Ex) `python.exe` or `python3.exe` or `python3.12.exe`
if !components
.next()
.and_then(|component| component.as_os_str().to_str())
.and_then(|component| component.rsplit_once('.'))
.is_some_and(|(name, extension)| name.starts_with("python") && extension == "exe")
{
return false;
}
// Ex) `WindowsApps`
if !components
.next()
.is_some_and(|component| component.as_os_str() == "WindowsApps")
{
return false;
}
// Ex) `Microsoft`
if !components
.next()
.is_some_and(|component| component.as_os_str() == "Microsoft")
{
return false;
}
// Ex) `Local`
if !components
.next()
.is_some_and(|component| component.as_os_str() == "Local")
{
return false;
}
true
}
#[cfg(test)]
@ -464,6 +503,22 @@ mod windows {
"###);
});
}
#[test]
fn detect_shim() {
assert!(super::is_windows_store_shim(
r"C:\Users\crmar\AppData\Local\Microsoft\WindowsApps\python.exe".as_ref()
));
assert!(super::is_windows_store_shim(
r"C:\Users\crmar\AppData\Local\Microsoft\WindowsApps\python3.exe".as_ref()
));
assert!(super::is_windows_store_shim(
r"C:\Users\crmar\AppData\Local\Microsoft\WindowsApps\python3.12.exe".as_ref()
));
assert!(!super::is_windows_store_shim(
r"C:\Users\crmar\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.11_qbs5n2kfra8p0\python.exe".as_ref()
));
}
}
}