mirror of
				https://github.com/astral-sh/uv.git
				synced 2025-10-30 19:48:11 +00:00 
			
		
		
		
	Skip Python 2 versions when locating Python (#3476)
## Summary Unfortunately, the `-I` flag was added in Python 3.4. So if we query a Python version prior to 3.4 (e.g., Python 2.7), we can't run our script at all, and lose the ability to match against our structured error. This PR adds an additional check against the stderr output for these cases. Closes https://github.com/astral-sh/uv/issues/3474. ## Test Plan Installed Python 2.7, and verified that it was skipped (and that we instead found my `python3`).
This commit is contained in:
		
							parent
							
								
									bc963d13cb
								
							
						
					
					
						commit
						5ad373b2ec
					
				
					 2 changed files with 70 additions and 19 deletions
				
			
		|  | @ -150,19 +150,77 @@ fn find_python( | ||||||
| 
 | 
 | ||||||
|                     let interpreter = match Interpreter::query(&path, cache) { |                     let interpreter = match Interpreter::query(&path, cache) { | ||||||
|                         Ok(interpreter) => interpreter, |                         Ok(interpreter) => interpreter, | ||||||
|                         Err( | 
 | ||||||
|                             err @ Error::QueryScript { |                         // If the Python version is < 3.4, the `-I` flag is not supported, so
 | ||||||
|                                 err: InterpreterInfoError::UnsupportedPythonVersion { .. }, |                         // we can't run the script at all, and need to sniff it from the output.
 | ||||||
|                                 .. |                         Err(Error::PythonSubcommandOutput { stderr, .. }) | ||||||
|                             }, |                             if stderr.contains("Unknown option: -I") | ||||||
|                         ) => { |                                 && stderr.contains("usage: python [option]") => | ||||||
|                             if selector.major() <= Some(2) { |                         { | ||||||
|                                 return Err(err); |                             // If the user _requested_ a version prior to 3.4, raise an error, as
 | ||||||
|  |                             // 3.4 is the minimum supported version for invoking the interpreter
 | ||||||
|  |                             // query script at all.
 | ||||||
|  |                             match selector { | ||||||
|  |                                 PythonVersionSelector::Major(major) if major < 3 => { | ||||||
|  |                                     return Err(Error::UnsupportedPython(major.to_string())); | ||||||
|  |                                 } | ||||||
|  |                                 PythonVersionSelector::MajorMinor(major, minor) | ||||||
|  |                                     if (major, minor) < (3, 4) => | ||||||
|  |                                 { | ||||||
|  |                                     return Err(Error::UnsupportedPython(format!( | ||||||
|  |                                         "{major}.{minor}" | ||||||
|  |                                     ))); | ||||||
|  |                                 } | ||||||
|  |                                 PythonVersionSelector::MajorMinorPatch(major, minor, patch) | ||||||
|  |                                     if (major, minor) < (3, 4) => | ||||||
|  |                                 { | ||||||
|  |                                     return Err(Error::UnsupportedPython(format!( | ||||||
|  |                                         "{major}.{minor}.{patch}" | ||||||
|  |                                     ))); | ||||||
|  |                                 } | ||||||
|  |                                 _ => {} | ||||||
|                             } |                             } | ||||||
|                             // Skip over Python 2 or older installation when querying for a recent python installation.
 | 
 | ||||||
|                             debug!("Found a Python 2 installation that isn't supported by uv, skipping."); |                             debug!( | ||||||
|  |                                 "Found a Python installation that isn't supported by uv, skipping." | ||||||
|  |                             ); | ||||||
|                             continue; |                             continue; | ||||||
|                         } |                         } | ||||||
|  | 
 | ||||||
|  |                         Err(Error::QueryScript { | ||||||
|  |                             err: InterpreterInfoError::UnsupportedPythonVersion { .. }, | ||||||
|  |                             .. | ||||||
|  |                         }) => { | ||||||
|  |                             // If the user _requested_ a version prior to 3.7, raise an error, as
 | ||||||
|  |                             // 3.7 is the minimum supported version for running the interpreter
 | ||||||
|  |                             // query script.
 | ||||||
|  |                             match selector { | ||||||
|  |                                 PythonVersionSelector::Major(major) if major < 3 => { | ||||||
|  |                                     return Err(Error::UnsupportedPython(major.to_string())); | ||||||
|  |                                 } | ||||||
|  |                                 PythonVersionSelector::MajorMinor(major, minor) | ||||||
|  |                                     if (major, minor) < (3, 7) => | ||||||
|  |                                 { | ||||||
|  |                                     return Err(Error::UnsupportedPython(format!( | ||||||
|  |                                         "{major}.{minor}" | ||||||
|  |                                     ))); | ||||||
|  |                                 } | ||||||
|  |                                 PythonVersionSelector::MajorMinorPatch(major, minor, patch) | ||||||
|  |                                     if (major, minor) < (3, 7) => | ||||||
|  |                                 { | ||||||
|  |                                     return Err(Error::UnsupportedPython(format!( | ||||||
|  |                                         "{major}.{minor}.{patch}" | ||||||
|  |                                     ))); | ||||||
|  |                                 } | ||||||
|  |                                 _ => {} | ||||||
|  |                             } | ||||||
|  | 
 | ||||||
|  |                             debug!( | ||||||
|  |                                 "Found a Python installation that isn't supported by uv, skipping." | ||||||
|  |                             ); | ||||||
|  |                             continue; | ||||||
|  |                         } | ||||||
|  | 
 | ||||||
|                         Err(error) => return Err(error), |                         Err(error) => return Err(error), | ||||||
|                     }; |                     }; | ||||||
| 
 | 
 | ||||||
|  | @ -400,15 +458,6 @@ impl PythonVersionSelector { | ||||||
|             ], |             ], | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 |  | ||||||
|     fn major(self) -> Option<u8> { |  | ||||||
|         match self { |  | ||||||
|             Self::Default => None, |  | ||||||
|             Self::Major(major) => Some(major), |  | ||||||
|             Self::MajorMinor(major, _) => Some(major), |  | ||||||
|             Self::MajorMinorPatch(major, _, _) => Some(major), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn warn_on_unsupported_python(interpreter: &Interpreter) { | fn warn_on_unsupported_python(interpreter: &Interpreter) { | ||||||
|  |  | ||||||
|  | @ -74,6 +74,8 @@ pub enum Error { | ||||||
|         stdout: String, |         stdout: String, | ||||||
|         stderr: String, |         stderr: String, | ||||||
|     }, |     }, | ||||||
|  |     #[error("Requested Python version ({0}) is unsupported")] | ||||||
|  |     UnsupportedPython(String), | ||||||
|     #[error("Failed to write to cache")] |     #[error("Failed to write to cache")] | ||||||
|     Encode(#[from] rmp_serde::encode::Error), |     Encode(#[from] rmp_serde::encode::Error), | ||||||
|     #[error("Broken virtualenv: Failed to parse pyvenv.cfg")] |     #[error("Broken virtualenv: Failed to parse pyvenv.cfg")] | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Charlie Marsh
						Charlie Marsh