mirror of
https://github.com/astral-sh/uv.git
synced 2025-10-03 15:24:36 +00:00
Add InterpreterRequest::Any
instead of using VersionRequest::Any
(#3789)
A follow-up to #3266 addressing some awkwardness where there was no "empty" or default interpreter request kind.
This commit is contained in:
parent
91ed1c6c7c
commit
ddfbee1cb6
4 changed files with 49 additions and 24 deletions
|
@ -26,8 +26,11 @@ use std::{path::Path, path::PathBuf, str::FromStr};
|
||||||
/// A request to find a Python interpreter.
|
/// A request to find a Python interpreter.
|
||||||
///
|
///
|
||||||
/// See [`InterpreterRequest::from_str`].
|
/// See [`InterpreterRequest::from_str`].
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||||
pub enum InterpreterRequest {
|
pub enum InterpreterRequest {
|
||||||
|
/// Use any discovered Python interpreter
|
||||||
|
#[default]
|
||||||
|
Any,
|
||||||
/// A Python version without an implementation name e.g. `3.10`
|
/// A Python version without an implementation name e.g. `3.10`
|
||||||
Version(VersionRequest),
|
Version(VersionRequest),
|
||||||
/// A path to a directory containing a Python installation, e.g. `.venv`
|
/// A path to a directory containing a Python installation, e.g. `.venv`
|
||||||
|
@ -60,7 +63,7 @@ pub enum SourceSelector {
|
||||||
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Copy, Clone, Debug, Default, PartialEq, Eq)]
|
||||||
pub enum VersionRequest {
|
pub enum VersionRequest {
|
||||||
#[default]
|
#[default]
|
||||||
Default,
|
Any,
|
||||||
Major(u8),
|
Major(u8),
|
||||||
MajorMinor(u8, u8),
|
MajorMinor(u8, u8),
|
||||||
MajorMinorPatch(u8, u8, u8),
|
MajorMinorPatch(u8, u8, u8),
|
||||||
|
@ -297,7 +300,7 @@ fn python_executables_from_search_path<'a>(
|
||||||
env::var_os("UV_TEST_PYTHON_PATH").unwrap_or(env::var_os("PATH").unwrap_or_default());
|
env::var_os("UV_TEST_PYTHON_PATH").unwrap_or(env::var_os("PATH").unwrap_or_default());
|
||||||
|
|
||||||
let possible_names: Vec<_> = version
|
let possible_names: Vec<_> = version
|
||||||
.unwrap_or(&VersionRequest::Default)
|
.unwrap_or(&VersionRequest::Any)
|
||||||
.possible_names(implementation)
|
.possible_names(implementation)
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
@ -565,6 +568,27 @@ pub fn find_interpreter(
|
||||||
interpreter,
|
interpreter,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InterpreterRequest::Any => {
|
||||||
|
let Some((source, interpreter)) =
|
||||||
|
python_interpreters(None, None, system, sources, cache)
|
||||||
|
.find(|result| {
|
||||||
|
match result {
|
||||||
|
// Return the first critical error or interpreter
|
||||||
|
Err(err) => should_stop_discovery(err),
|
||||||
|
Ok(_) => true,
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.transpose()?
|
||||||
|
else {
|
||||||
|
return Ok(InterpreterResult::Err(
|
||||||
|
InterpreterNotFound::NoPythonInstallation(sources.clone(), None),
|
||||||
|
));
|
||||||
|
};
|
||||||
|
DiscoveredInterpreter {
|
||||||
|
source,
|
||||||
|
interpreter,
|
||||||
|
}
|
||||||
|
}
|
||||||
InterpreterRequest::Version(version) => {
|
InterpreterRequest::Version(version) => {
|
||||||
let Some((source, interpreter)) =
|
let Some((source, interpreter)) =
|
||||||
python_interpreters(Some(version), None, system, sources, cache)
|
python_interpreters(Some(version), None, system, sources, cache)
|
||||||
|
@ -577,7 +601,7 @@ pub fn find_interpreter(
|
||||||
})
|
})
|
||||||
.transpose()?
|
.transpose()?
|
||||||
else {
|
else {
|
||||||
let err = if matches!(version, VersionRequest::Default) {
|
let err = if matches!(version, VersionRequest::Any) {
|
||||||
InterpreterNotFound::NoPythonInstallation(sources.clone(), Some(*version))
|
InterpreterNotFound::NoPythonInstallation(sources.clone(), Some(*version))
|
||||||
} else {
|
} else {
|
||||||
InterpreterNotFound::NoMatchingVersion(sources.clone(), *version)
|
InterpreterNotFound::NoMatchingVersion(sources.clone(), *version)
|
||||||
|
@ -600,7 +624,7 @@ pub fn find_interpreter(
|
||||||
///
|
///
|
||||||
/// See [`find_interpreter`] for more details on interpreter discovery.
|
/// See [`find_interpreter`] for more details on interpreter discovery.
|
||||||
pub fn find_default_interpreter(cache: &Cache) -> Result<InterpreterResult, Error> {
|
pub fn find_default_interpreter(cache: &Cache) -> Result<InterpreterResult, Error> {
|
||||||
let request = InterpreterRequest::Version(VersionRequest::Default);
|
let request = InterpreterRequest::default();
|
||||||
let sources = SourceSelector::System;
|
let sources = SourceSelector::System;
|
||||||
|
|
||||||
let result = find_interpreter(&request, SystemPython::Required, &sources, cache)?;
|
let result = find_interpreter(&request, SystemPython::Required, &sources, cache)?;
|
||||||
|
@ -665,7 +689,7 @@ pub fn find_best_interpreter(
|
||||||
|
|
||||||
// If a Python version was requested but cannot be fulfilled, just take any version
|
// If a Python version was requested but cannot be fulfilled, just take any version
|
||||||
debug!("Looking for Python interpreter with any version");
|
debug!("Looking for Python interpreter with any version");
|
||||||
let request = InterpreterRequest::Version(VersionRequest::Default);
|
let request = InterpreterRequest::Any;
|
||||||
Ok(find_interpreter(
|
Ok(find_interpreter(
|
||||||
// TODO(zanieb): Add a dedicated `Default` variant to `InterpreterRequest`
|
// TODO(zanieb): Add a dedicated `Default` variant to `InterpreterRequest`
|
||||||
&request, system, &sources, cache,
|
&request, system, &sources, cache,
|
||||||
|
@ -917,7 +941,7 @@ impl VersionRequest {
|
||||||
};
|
};
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::Default => [Some(python3), Some(python), None, None],
|
Self::Any => [Some(python3), Some(python), None, None],
|
||||||
Self::Major(major) => [
|
Self::Major(major) => [
|
||||||
Some(Cow::Owned(format!("python{major}{extension}"))),
|
Some(Cow::Owned(format!("python{major}{extension}"))),
|
||||||
Some(python),
|
Some(python),
|
||||||
|
@ -960,7 +984,7 @@ impl VersionRequest {
|
||||||
};
|
};
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
Self::Default => [Some(python3), Some(python), None, None],
|
Self::Any => [Some(python3), Some(python), None, None],
|
||||||
Self::Major(major) => [
|
Self::Major(major) => [
|
||||||
Some(Cow::Owned(format!("{name}{major}{extension}"))),
|
Some(Cow::Owned(format!("{name}{major}{extension}"))),
|
||||||
Some(python),
|
Some(python),
|
||||||
|
@ -990,7 +1014,7 @@ impl VersionRequest {
|
||||||
/// Check if a interpreter matches the requested Python version.
|
/// Check if a interpreter matches the requested Python version.
|
||||||
fn matches_interpreter(self, interpreter: &Interpreter) -> bool {
|
fn matches_interpreter(self, interpreter: &Interpreter) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Default => true,
|
Self::Any => true,
|
||||||
Self::Major(major) => interpreter.python_major() == major,
|
Self::Major(major) => interpreter.python_major() == major,
|
||||||
Self::MajorMinor(major, minor) => {
|
Self::MajorMinor(major, minor) => {
|
||||||
(interpreter.python_major(), interpreter.python_minor()) == (major, minor)
|
(interpreter.python_major(), interpreter.python_minor()) == (major, minor)
|
||||||
|
@ -1007,7 +1031,7 @@ impl VersionRequest {
|
||||||
|
|
||||||
fn matches_version(self, version: &PythonVersion) -> bool {
|
fn matches_version(self, version: &PythonVersion) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Default => true,
|
Self::Any => true,
|
||||||
Self::Major(major) => version.major() == major,
|
Self::Major(major) => version.major() == major,
|
||||||
Self::MajorMinor(major, minor) => (version.major(), version.minor()) == (major, minor),
|
Self::MajorMinor(major, minor) => (version.major(), version.minor()) == (major, minor),
|
||||||
Self::MajorMinorPatch(major, minor, patch) => {
|
Self::MajorMinorPatch(major, minor, patch) => {
|
||||||
|
@ -1018,7 +1042,7 @@ impl VersionRequest {
|
||||||
|
|
||||||
fn matches_major_minor(self, major: u8, minor: u8) -> bool {
|
fn matches_major_minor(self, major: u8, minor: u8) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Default => true,
|
Self::Any => true,
|
||||||
Self::Major(self_major) => self_major == major,
|
Self::Major(self_major) => self_major == major,
|
||||||
Self::MajorMinor(self_major, self_minor) => (self_major, self_minor) == (major, minor),
|
Self::MajorMinor(self_major, self_minor) => (self_major, self_minor) == (major, minor),
|
||||||
Self::MajorMinorPatch(self_major, self_minor, _) => {
|
Self::MajorMinorPatch(self_major, self_minor, _) => {
|
||||||
|
@ -1030,7 +1054,7 @@ impl VersionRequest {
|
||||||
/// Return true if a patch version is present in the request.
|
/// Return true if a patch version is present in the request.
|
||||||
fn has_patch(self) -> bool {
|
fn has_patch(self) -> bool {
|
||||||
match self {
|
match self {
|
||||||
Self::Default => false,
|
Self::Any => false,
|
||||||
Self::Major(..) => false,
|
Self::Major(..) => false,
|
||||||
Self::MajorMinor(..) => false,
|
Self::MajorMinor(..) => false,
|
||||||
Self::MajorMinorPatch(..) => true,
|
Self::MajorMinorPatch(..) => true,
|
||||||
|
@ -1041,7 +1065,7 @@ impl VersionRequest {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn without_patch(self) -> Self {
|
fn without_patch(self) -> Self {
|
||||||
match self {
|
match self {
|
||||||
Self::Default => Self::Default,
|
Self::Any => Self::Any,
|
||||||
Self::Major(major) => Self::Major(major),
|
Self::Major(major) => Self::Major(major),
|
||||||
Self::MajorMinor(major, minor) => Self::MajorMinor(major, minor),
|
Self::MajorMinor(major, minor) => Self::MajorMinor(major, minor),
|
||||||
Self::MajorMinorPatch(major, minor, _) => Self::MajorMinor(major, minor),
|
Self::MajorMinorPatch(major, minor, _) => Self::MajorMinor(major, minor),
|
||||||
|
@ -1082,7 +1106,7 @@ impl From<&PythonVersion> for VersionRequest {
|
||||||
impl fmt::Display for VersionRequest {
|
impl fmt::Display for VersionRequest {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Default => f.write_str("default"),
|
Self::Any => f.write_str("default"),
|
||||||
Self::Major(major) => write!(f, "{major}"),
|
Self::Major(major) => write!(f, "{major}"),
|
||||||
Self::MajorMinor(major, minor) => write!(f, "{major}.{minor}"),
|
Self::MajorMinor(major, minor) => write!(f, "{major}.{minor}"),
|
||||||
Self::MajorMinorPatch(major, minor, patch) => {
|
Self::MajorMinorPatch(major, minor, patch) => {
|
||||||
|
@ -1161,6 +1185,7 @@ impl SystemPython {
|
||||||
impl fmt::Display for InterpreterRequest {
|
impl fmt::Display for InterpreterRequest {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
Self::Any => write!(f, "any Python"),
|
||||||
Self::Version(version) => write!(f, "Python @ {version}"),
|
Self::Version(version) => write!(f, "Python @ {version}"),
|
||||||
Self::Directory(path) => write!(f, "directory {}", path.user_display()),
|
Self::Directory(path) => write!(f, "directory {}", path.user_display()),
|
||||||
Self::File(path) => write!(f, "file {}", path.user_display()),
|
Self::File(path) => write!(f, "file {}", path.user_display()),
|
||||||
|
@ -1193,13 +1218,13 @@ impl fmt::Display for InterpreterSource {
|
||||||
impl fmt::Display for InterpreterNotFound {
|
impl fmt::Display for InterpreterNotFound {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::NoPythonInstallation(sources, None | Some(VersionRequest::Default)) => {
|
Self::NoPythonInstallation(sources, None | Some(VersionRequest::Any)) => {
|
||||||
write!(f, "No Python interpreters found in {sources}")
|
write!(f, "No Python interpreters found in {sources}")
|
||||||
}
|
}
|
||||||
Self::NoPythonInstallation(sources, Some(version)) => {
|
Self::NoPythonInstallation(sources, Some(version)) => {
|
||||||
write!(f, "No Python {version} interpreters found in {sources}")
|
write!(f, "No Python {version} interpreters found in {sources}")
|
||||||
}
|
}
|
||||||
Self::NoMatchingVersion(sources, VersionRequest::Default) => {
|
Self::NoMatchingVersion(sources, VersionRequest::Any) => {
|
||||||
write!(f, "No Python interpreter found in {sources}")
|
write!(f, "No Python interpreter found in {sources}")
|
||||||
}
|
}
|
||||||
Self::NoMatchingVersion(sources, version) => {
|
Self::NoMatchingVersion(sources, version) => {
|
||||||
|
|
|
@ -8,7 +8,7 @@ use same_file::is_same_file;
|
||||||
use uv_cache::Cache;
|
use uv_cache::Cache;
|
||||||
use uv_fs::{LockedFile, Simplified};
|
use uv_fs::{LockedFile, Simplified};
|
||||||
|
|
||||||
use crate::discovery::{InterpreterRequest, SourceSelector, SystemPython, VersionRequest};
|
use crate::discovery::{InterpreterRequest, SourceSelector, SystemPython};
|
||||||
use crate::virtualenv::{virtualenv_python_executable, PyVenvConfiguration};
|
use crate::virtualenv::{virtualenv_python_executable, PyVenvConfiguration};
|
||||||
use crate::{
|
use crate::{
|
||||||
find_default_interpreter, find_interpreter, Error, Interpreter, InterpreterSource, Target,
|
find_default_interpreter, find_interpreter, Error, Interpreter, InterpreterSource, Target,
|
||||||
|
@ -54,7 +54,7 @@ impl PythonEnvironment {
|
||||||
/// Allows Conda environments (via `CONDA_PREFIX`) though they are not technically virtual environments.
|
/// Allows Conda environments (via `CONDA_PREFIX`) though they are not technically virtual environments.
|
||||||
pub fn from_virtualenv(cache: &Cache) -> Result<Self, Error> {
|
pub fn from_virtualenv(cache: &Cache) -> Result<Self, Error> {
|
||||||
let sources = SourceSelector::VirtualEnv;
|
let sources = SourceSelector::VirtualEnv;
|
||||||
let request = InterpreterRequest::Version(VersionRequest::Default);
|
let request = InterpreterRequest::Any;
|
||||||
let found = find_interpreter(&request, SystemPython::Disallowed, &sources, cache)??;
|
let found = find_interpreter(&request, SystemPython::Disallowed, &sources, cache)??;
|
||||||
|
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
|
@ -74,7 +74,7 @@ impl PythonEnvironment {
|
||||||
/// Create a [`PythonEnvironment`] for the parent interpreter i.e. the executable in `python -m uv ...`
|
/// Create a [`PythonEnvironment`] for the parent interpreter i.e. the executable in `python -m uv ...`
|
||||||
pub fn from_parent_interpreter(system: SystemPython, cache: &Cache) -> Result<Self, Error> {
|
pub fn from_parent_interpreter(system: SystemPython, cache: &Cache) -> Result<Self, Error> {
|
||||||
let sources = SourceSelector::from_sources([InterpreterSource::ParentInterpreter]);
|
let sources = SourceSelector::from_sources([InterpreterSource::ParentInterpreter]);
|
||||||
let request = InterpreterRequest::Version(VersionRequest::Default);
|
let request = InterpreterRequest::Any;
|
||||||
let found = find_interpreter(&request, system, &sources, cache)??;
|
let found = find_interpreter(&request, system, &sources, cache)??;
|
||||||
|
|
||||||
Ok(Self(Arc::new(PythonEnvironmentShared {
|
Ok(Self(Arc::new(PythonEnvironmentShared {
|
||||||
|
|
|
@ -586,7 +586,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
|| {
|
|| {
|
||||||
let result = find_interpreter(
|
let result = find_interpreter(
|
||||||
&InterpreterRequest::Version(VersionRequest::Default),
|
&InterpreterRequest::Any,
|
||||||
SystemPython::Allowed,
|
SystemPython::Allowed,
|
||||||
&SourceSelector::All,
|
&SourceSelector::All,
|
||||||
&cache,
|
&cache,
|
||||||
|
@ -620,7 +620,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
|| {
|
|| {
|
||||||
let result = find_interpreter(
|
let result = find_interpreter(
|
||||||
&InterpreterRequest::Version(VersionRequest::Default),
|
&InterpreterRequest::Any,
|
||||||
SystemPython::Allowed,
|
SystemPython::Allowed,
|
||||||
&SourceSelector::All,
|
&SourceSelector::All,
|
||||||
&cache,
|
&cache,
|
||||||
|
@ -661,7 +661,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
|| {
|
|| {
|
||||||
let result = find_interpreter(
|
let result = find_interpreter(
|
||||||
&InterpreterRequest::Version(VersionRequest::Default),
|
&InterpreterRequest::Any,
|
||||||
SystemPython::Required,
|
SystemPython::Required,
|
||||||
&SourceSelector::All,
|
&SourceSelector::All,
|
||||||
&cache,
|
&cache,
|
||||||
|
@ -701,7 +701,7 @@ mod tests {
|
||||||
],
|
],
|
||||||
|| {
|
|| {
|
||||||
let result = find_interpreter(
|
let result = find_interpreter(
|
||||||
&InterpreterRequest::Version(VersionRequest::Default),
|
&InterpreterRequest::Any,
|
||||||
SystemPython::Disallowed,
|
SystemPython::Disallowed,
|
||||||
&SourceSelector::All,
|
&SourceSelector::All,
|
||||||
&cache,
|
&cache,
|
||||||
|
|
|
@ -178,7 +178,7 @@ pub(crate) async fn pip_compile(
|
||||||
// TODO(zanieb): We should consolidate `VersionRequest` and `PythonVersion`
|
// TODO(zanieb): We should consolidate `VersionRequest` and `PythonVersion`
|
||||||
InterpreterRequest::Version(VersionRequest::from(version))
|
InterpreterRequest::Version(VersionRequest::from(version))
|
||||||
} else {
|
} else {
|
||||||
InterpreterRequest::Version(VersionRequest::Default)
|
InterpreterRequest::default()
|
||||||
};
|
};
|
||||||
find_best_interpreter(&request, system, &cache)??
|
find_best_interpreter(&request, system, &cache)??
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue