mirror of
				https://github.com/astral-sh/uv.git
				synced 2025-10-31 12:06:13 +00:00 
			
		
		
		
	Avoid Windows Store shims in --python python3-like invocations (#2212)
				
					
				
			## Summary We have logic in `python_query.rs` to filter out Windows Store shims when you use invocations like `-p 3.10`, but not `--python python3`, which is uncommon but allowed on Windows. Closes #2211.
This commit is contained in:
		
							parent
							
								
									cf94df7cb9
								
							
						
					
					
						commit
						01ebaef4e7
					
				
					 2 changed files with 37 additions and 21 deletions
				
			
		|  | @ -1,4 +1,3 @@ | ||||||
| use std::ffi::{OsStr, OsString}; |  | ||||||
| use std::io::Write; | use std::io::Write; | ||||||
| use std::path::{Path, PathBuf}; | use std::path::{Path, PathBuf}; | ||||||
| use std::process::Command; | use std::process::Command; | ||||||
|  | @ -200,25 +199,6 @@ impl Interpreter { | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     /// Find the Python interpreter in `PATH`, respecting `UV_PYTHON_PATH`.
 |  | ||||||
|     ///
 |  | ||||||
|     /// Returns `Ok(None)` if not found.
 |  | ||||||
|     pub(crate) fn find_executable<R: AsRef<OsStr> + Into<OsString> + Copy>( |  | ||||||
|         requested: R, |  | ||||||
|     ) -> Result<Option<PathBuf>, Error> { |  | ||||||
|         let result = if let Some(isolated) = std::env::var_os("UV_TEST_PYTHON_PATH") { |  | ||||||
|             which::which_in(requested, Some(isolated), std::env::current_dir()?) |  | ||||||
|         } else { |  | ||||||
|             which::which(requested) |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         match result { |  | ||||||
|             Err(which::Error::CannotFindBinaryPath) => Ok(None), |  | ||||||
|             Err(err) => Err(Error::WhichError(requested.into(), err)), |  | ||||||
|             Ok(path) => Ok(Some(path)), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     /// Returns the path to the Python virtual environment.
 |     /// Returns the path to the Python virtual environment.
 | ||||||
|     #[inline] |     #[inline] | ||||||
|     pub fn platform(&self) -> &Platform { |     pub fn platform(&self) -> &Platform { | ||||||
|  |  | ||||||
|  | @ -2,6 +2,7 @@ | ||||||
| 
 | 
 | ||||||
| use std::borrow::Cow; | use std::borrow::Cow; | ||||||
| use std::env; | use std::env; | ||||||
|  | use std::ffi::{OsStr, OsString}; | ||||||
| use std::path::PathBuf; | use std::path::PathBuf; | ||||||
| 
 | 
 | ||||||
| use tracing::{debug, instrument}; | use tracing::{debug, instrument}; | ||||||
|  | @ -58,7 +59,7 @@ pub fn find_requested_python( | ||||||
|         } |         } | ||||||
|     } else if !request.contains(std::path::MAIN_SEPARATOR) { |     } else if !request.contains(std::path::MAIN_SEPARATOR) { | ||||||
|         // `-p python3.10`; Generally not used on windows because all Python are `python.exe`.
 |         // `-p python3.10`; Generally not used on windows because all Python are `python.exe`.
 | ||||||
|         let Some(executable) = Interpreter::find_executable(request)? else { |         let Some(executable) = find_executable(request)? else { | ||||||
|             return Ok(None); |             return Ok(None); | ||||||
|         }; |         }; | ||||||
|         Interpreter::query(&executable, platform.clone(), cache).map(Some) |         Interpreter::query(&executable, platform.clone(), cache).map(Some) | ||||||
|  | @ -198,6 +199,41 @@ fn find_python( | ||||||
|     Ok(None) |     Ok(None) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// Find the Python interpreter in `PATH` matching the given name (e.g., `python3`, respecting
 | ||||||
|  | /// `UV_PYTHON_PATH`.
 | ||||||
|  | ///
 | ||||||
|  | /// Returns `Ok(None)` if not found.
 | ||||||
|  | fn find_executable<R: AsRef<OsStr> + Into<OsString> + Copy>( | ||||||
|  |     requested: R, | ||||||
|  | ) -> Result<Option<PathBuf>, Error> { | ||||||
|  |     #[allow(non_snake_case)] | ||||||
|  |     let UV_TEST_PYTHON_PATH = env::var_os("UV_TEST_PYTHON_PATH"); | ||||||
|  | 
 | ||||||
|  |     #[allow(non_snake_case)] | ||||||
|  |     let PATH = UV_TEST_PYTHON_PATH | ||||||
|  |         .or(env::var_os("PATH")) | ||||||
|  |         .unwrap_or_default(); | ||||||
|  | 
 | ||||||
|  |     // We use `which` here instead of joining the paths ourselves because `which` checks for us if the python
 | ||||||
|  |     // binary is executable and exists. It also has some extra logic that handles inconsistent casing on Windows
 | ||||||
|  |     // and expands `~`.
 | ||||||
|  |     for path in env::split_paths(&PATH) { | ||||||
|  |         let paths = match which::which_in_global(requested, Some(&path)) { | ||||||
|  |             Ok(paths) => paths, | ||||||
|  |             Err(which::Error::CannotFindBinaryPath) => continue, | ||||||
|  |             Err(err) => return Err(Error::WhichError(requested.into(), err)), | ||||||
|  |         }; | ||||||
|  |         for path in paths { | ||||||
|  |             if cfg!(windows) && windows::is_windows_store_shim(&path) { | ||||||
|  |                 continue; | ||||||
|  |             } | ||||||
|  |             return Ok(Some(path)); | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     Ok(None) | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Debug, Clone)] | #[derive(Debug, Clone)] | ||||||
| enum PythonInstallation { | enum PythonInstallation { | ||||||
|     PyListPath { |     PyListPath { | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Charlie Marsh
						Charlie Marsh