mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-19 11:15:01 +00:00
Require opt-in to use alternative Python implementations (#7650)
Closes #7118 This only really affects managed interpreters, as we exclude alternative Python implementations from the search path during the `VersionRequest::executable_names` part of discovery.
This commit is contained in:
parent
da328379c1
commit
a53ddaa24a
6 changed files with 100 additions and 14 deletions
|
@ -934,21 +934,44 @@ pub(crate) fn find_python_installation(
|
|||
return result;
|
||||
};
|
||||
|
||||
// If it's a pre-release, and pre-releases aren't allowed skip it but store it for later
|
||||
// Check if we need to skip the interpreter because it is "not allowed", e.g., if it is a
|
||||
// pre-release version or an alternative implementation, using it requires opt-in.
|
||||
|
||||
// If the interpreter has a default executable name, e.g. `python`, and was found on the
|
||||
// search path, we consider this opt-in to use it.
|
||||
let has_default_executable_name = installation.interpreter.has_default_executable_name()
|
||||
&& installation.source == PythonSource::SearchPath;
|
||||
|
||||
// If it's a pre-release and pre-releases aren't allowed, skip it — but store it for later
|
||||
// since we'll use a pre-release if no other versions are available.
|
||||
if installation.python_version().pre().is_some()
|
||||
&& !request.allows_prereleases()
|
||||
&& !installation.source.allows_prereleases()
|
||||
&& !has_default_executable_name
|
||||
{
|
||||
debug!("Skipping pre-release {}", installation.key());
|
||||
first_prerelease = Some(installation.clone());
|
||||
continue;
|
||||
}
|
||||
|
||||
// If it's an alternative implementation and alternative implementations aren't allowed,
|
||||
// skip it. Note we avoid querying these interpreters at all if they're on the search path
|
||||
// and are not requested, but other sources such as the managed installations will include
|
||||
// them.
|
||||
if installation.is_alternative_implementation()
|
||||
&& !request.allows_alternative_implementations()
|
||||
&& !installation.source.allows_alternative_implementations()
|
||||
&& !has_default_executable_name
|
||||
{
|
||||
debug!("Skipping alternative implementation {}", installation.key());
|
||||
continue;
|
||||
}
|
||||
|
||||
// If we didn't skip it, this is the installation to use
|
||||
return result;
|
||||
}
|
||||
|
||||
// If we only found pre-releases, they're implicitly allowed and we should return the first one
|
||||
// If we only found pre-releases, they're implicitly allowed and we should return the first one.
|
||||
if let Some(installation) = first_prerelease {
|
||||
return Ok(Ok(installation));
|
||||
}
|
||||
|
@ -1205,10 +1228,7 @@ impl PythonRequest {
|
|||
for implementation in
|
||||
ImplementationName::long_names().chain(ImplementationName::short_names())
|
||||
{
|
||||
if let Some(remainder) = value
|
||||
.to_ascii_lowercase()
|
||||
.strip_prefix(Into::<&str>::into(implementation))
|
||||
{
|
||||
if let Some(remainder) = value.to_ascii_lowercase().strip_prefix(implementation) {
|
||||
// e.g. `pypy`
|
||||
if remainder.is_empty() {
|
||||
return Self::Implementation(
|
||||
|
@ -1369,6 +1389,7 @@ impl PythonRequest {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether this request opts-in to a pre-release Python version.
|
||||
pub(crate) fn allows_prereleases(&self) -> bool {
|
||||
match self {
|
||||
Self::Default => false,
|
||||
|
@ -1381,6 +1402,19 @@ impl PythonRequest {
|
|||
}
|
||||
}
|
||||
|
||||
/// Whether this request opts-in to an alternative Python implementation, e.g., PyPy.
|
||||
pub(crate) fn allows_alternative_implementations(&self) -> bool {
|
||||
match self {
|
||||
Self::Default => false,
|
||||
Self::Any => true,
|
||||
Self::Version(_) => false,
|
||||
Self::Directory(_) | Self::File(_) | Self::ExecutableName(_) => true,
|
||||
Self::Implementation(_) => true,
|
||||
Self::ImplementationVersion(_, _) => true,
|
||||
Self::Key(request) => request.allows_alternative_implementations(),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_explicit_system(&self) -> bool {
|
||||
matches!(self, Self::File(_) | Self::Directory(_))
|
||||
}
|
||||
|
@ -1410,7 +1444,7 @@ impl PythonSource {
|
|||
matches!(self, Self::Managed)
|
||||
}
|
||||
|
||||
/// Whether a pre-release Python installation from the source should be used without opt-in.
|
||||
/// Whether a pre-release Python installation from this source can be used without opt-in.
|
||||
pub(crate) fn allows_prereleases(self) -> bool {
|
||||
match self {
|
||||
Self::Managed | Self::Registry | Self::MicrosoftStore => false,
|
||||
|
@ -1422,6 +1456,18 @@ impl PythonSource {
|
|||
| Self::DiscoveredEnvironment => true,
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether an alternative Python implementation from this source can be used without opt-in.
|
||||
pub(crate) fn allows_alternative_implementations(self) -> bool {
|
||||
match self {
|
||||
Self::Managed | Self::Registry | Self::SearchPath | Self::MicrosoftStore => false,
|
||||
Self::CondaPrefix
|
||||
| Self::ProvidedPath
|
||||
| Self::ParentInterpreter
|
||||
| Self::ActiveEnvironment
|
||||
| Self::DiscoveredEnvironment => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PythonPreference {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue