Skip to content

Commit

Permalink
Replace DiscoveredToolchain with dedicated Toolchain type
Browse files Browse the repository at this point in the history
# Conflicts:
#	crates/uv/src/commands/pip/sync.rs
#	crates/uv/src/commands/pip/uninstall.rs
#	crates/uv/src/commands/project/lock.rs
  • Loading branch information
zanieb committed Jun 7, 2024
1 parent e91d46d commit 142868b
Show file tree
Hide file tree
Showing 3 changed files with 141 additions and 47 deletions.
49 changes: 13 additions & 36 deletions crates/uv-toolchain/src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::implementation::{ImplementationName, LenientImplementationName};
use crate::interpreter::Error as InterpreterError;
use crate::managed::InstalledToolchains;
use crate::py_launcher::py_list_paths;
use crate::toolchain::Toolchain;
use crate::virtualenv::{
conda_prefix_from_env, virtualenv_from_env, virtualenv_from_working_dir,
virtualenv_python_executable,
Expand Down Expand Up @@ -83,12 +84,12 @@ pub enum SystemPython {
Required,
}

/// The result of an interpreter search.
/// The result of an toolchain search.
///
/// Returned by [`find_interpreter`].
type ToolchainResult = Result<DiscoveredToolchain, ToolchainNotFound>;
/// Returned by [`find_toolchain`].
type ToolchainResult = Result<Toolchain, ToolchainNotFound>;

/// The result of failed interpreter discovery.
/// The result of failed toolchain discovery.
///
/// See [`InterpreterResult`].
#[derive(Clone, Debug, Error)]
Expand All @@ -113,16 +114,7 @@ pub enum ToolchainNotFound {
FileNotExecutable(PathBuf),
}

/// The result of successful toolchain discovery.
///
/// See [`ToolchainResult`].
#[derive(Clone, Debug)]
pub struct DiscoveredToolchain {
pub(crate) source: ToolchainSource,
pub(crate) interpreter: Interpreter,
}

/// The source of a discovered Python interpreter.
/// The source of a discovered Python toolchain.
#[derive(Debug, Clone, PartialEq, Eq, Copy, Hash, PartialOrd, Ord)]
pub enum ToolchainSource {
/// The toolchain path was provided directly
Expand Down Expand Up @@ -474,7 +466,7 @@ pub fn find_toolchain(
path.clone(),
)));
}
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::ProvidedPath,
interpreter: Interpreter::query(path, cache)?,
}
Expand All @@ -499,7 +491,7 @@ pub fn find_toolchain(
ToolchainNotFound::ExecutableNotFoundInDirectory(path.clone(), executable),
));
}
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::ProvidedPath,
interpreter: Interpreter::query(executable, cache)?,
}
Expand All @@ -518,7 +510,7 @@ pub fn find_toolchain(
ToolchainNotFound::ExecutableNotFoundInSearchPath(name.clone()),
));
};
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::SearchPath,
interpreter: Interpreter::query(executable, cache)?,
}
Expand All @@ -542,7 +534,7 @@ pub fn find_toolchain(
ToolchainNotFound::NoMatchingImplementation(sources.clone(), *implementation),
));
};
DiscoveredToolchain {
Toolchain {
source,
interpreter,
}
Expand Down Expand Up @@ -573,7 +565,7 @@ pub fn find_toolchain(
),
));
};
DiscoveredToolchain {
Toolchain {
source,
interpreter,
}
Expand All @@ -595,7 +587,7 @@ pub fn find_toolchain(
ToolchainNotFound::NoPythonInstallation(sources.clone(), None),
));
};
DiscoveredToolchain {
Toolchain {
source,
interpreter,
}
Expand All @@ -620,7 +612,7 @@ pub fn find_toolchain(
};
return Ok(ToolchainResult::Err(err));
};
DiscoveredToolchain {
Toolchain {
source,
interpreter,
}
Expand Down Expand Up @@ -1348,21 +1340,6 @@ impl fmt::Display for ToolchainSources {
}
}

impl DiscoveredToolchain {
#[allow(dead_code)]
pub fn source(&self) -> &ToolchainSource {
&self.source
}

pub fn interpreter(&self) -> &Interpreter {
&self.interpreter
}

pub fn into_interpreter(self) -> Interpreter {
self.interpreter
}
}

#[cfg(test)]
mod tests {

Expand Down
23 changes: 12 additions & 11 deletions crates/uv-toolchain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ mod prefix;
mod py_launcher;
mod python_version;
mod target;
mod toolchain;
mod virtualenv;

#[cfg(not(test))]
Expand Down Expand Up @@ -80,8 +81,8 @@ mod tests {
use uv_configuration::PreviewMode;

use crate::{
discovery::DiscoveredToolchain, find_best_toolchain, find_default_toolchain,
find_toolchain, implementation::ImplementationName, managed::InstalledToolchains,
find_best_toolchain, find_default_toolchain, find_toolchain,
implementation::ImplementationName, managed::InstalledToolchains, toolchain::Toolchain,
virtualenv::virtualenv_python_executable, Error, PythonEnvironment, PythonVersion,
SystemPython, ToolchainNotFound, ToolchainRequest, ToolchainSource, ToolchainSources,
VersionRequest,
Expand Down Expand Up @@ -430,7 +431,7 @@ mod tests {
assert!(
matches!(
interpreter,
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::SearchPath,
interpreter: _
}
Expand Down Expand Up @@ -484,7 +485,7 @@ mod tests {
assert!(
matches!(
toolchain,
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::SearchPath,
interpreter: _
}
Expand Down Expand Up @@ -540,7 +541,7 @@ mod tests {
assert!(
matches!(
toolchain,
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::SearchPath,
interpreter: _
}
Expand Down Expand Up @@ -665,7 +666,7 @@ mod tests {
assert!(
matches!(
toolchain,
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::SearchPath,
interpreter: _
}
Expand Down Expand Up @@ -698,7 +699,7 @@ mod tests {
assert!(
matches!(
toolchain,
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::SearchPath,
interpreter: _
}
Expand Down Expand Up @@ -785,7 +786,7 @@ mod tests {
assert!(
matches!(
toolchain,
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::SearchPath,
interpreter: _
}
Expand Down Expand Up @@ -818,7 +819,7 @@ mod tests {
assert!(
matches!(
toolchain,
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::SearchPath,
interpreter: _
}
Expand Down Expand Up @@ -853,7 +854,7 @@ mod tests {
assert!(
matches!(
toolchain,
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::SearchPath,
interpreter: _
}
Expand Down Expand Up @@ -883,7 +884,7 @@ mod tests {
assert!(
matches!(
toolchain,
DiscoveredToolchain {
Toolchain {
source: ToolchainSource::ActiveEnvironment,
interpreter: _
}
Expand Down
116 changes: 116 additions & 0 deletions crates/uv-toolchain/src/toolchain.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
use uv_configuration::PreviewMode;

use uv_cache::Cache;

use crate::discovery::{SystemPython, ToolchainRequest, ToolchainSources};
use crate::{find_default_toolchain, find_toolchain, Error, Interpreter, ToolchainSource};

#[derive(Clone, Debug)]
pub struct Toolchain {
// Public in the crate for test assertions
pub(crate) source: ToolchainSource,
pub(crate) interpreter: Interpreter,
}

impl Toolchain {
/// Find an installed [`Toolchain`].
///
/// This is the standard interface for discovering a Python toolchain for use with uv.
pub fn find(
python: Option<&str>,
system: SystemPython,
preview: PreviewMode,
cache: &Cache,
) -> Result<Self, Error> {
if let Some(python) = python {
Self::from_requested_python(python, system, preview, cache)
} else if system.is_preferred() {
Self::from_default_python(preview, cache)
} else {
// First check for a parent intepreter
// We gate this check to avoid an extra log message when it is not set
if std::env::var_os("UV_INTERNAL__PARENT_INTERPRETER").is_some() {
match Self::from_parent_interpreter(system, cache) {
Ok(env) => return Ok(env),
Err(Error::NotFound(_)) => {}
Err(err) => return Err(err),
}
}

// Then a virtual environment
match Self::from_virtualenv(cache) {
Ok(venv) => Ok(venv),
Err(Error::NotFound(_)) if system.is_allowed() => {
Self::from_default_python(preview, cache)
}
Err(err) => Err(err),
}
}
}

/// Find an installed [`Toolchain`] in an existing virtual environment.
///
/// Allows Conda environments (via `CONDA_PREFIX`) though they are not technically virtual environments.
pub fn from_virtualenv(cache: &Cache) -> Result<Self, Error> {
let sources = ToolchainSources::VirtualEnv;
let request = ToolchainRequest::Any;
let toolchain = find_toolchain(&request, SystemPython::Disallowed, &sources, cache)??;

debug_assert!(
toolchain.interpreter().is_virtualenv()
|| matches!(toolchain.source(), ToolchainSource::CondaPrefix),
"Not a virtualenv (source: {}, prefix: {})",
toolchain.source(),
toolchain.interpreter().sys_base_prefix().display()
);

Ok(toolchain)
}

/// Find an installed [`Toolchain`] belonging to the parent interpreter i.e. the executable in `python -m uv ...`
pub fn from_parent_interpreter(system: SystemPython, cache: &Cache) -> Result<Self, Error> {
let sources = ToolchainSources::from_sources([ToolchainSource::ParentInterpreter]);
let request = ToolchainRequest::Any;
let toolchain = find_toolchain(&request, system, &sources, cache)??;
Ok(toolchain)
}

/// Find an installed [`Toolchain`] that satisfies a request.
pub fn from_requested_python(
request: &str,
system: SystemPython,
preview: PreviewMode,
cache: &Cache,
) -> Result<Self, Error> {
let sources = ToolchainSources::from_settings(system, preview);
let request = ToolchainRequest::parse(request);
let toolchain = find_toolchain(&request, system, &sources, cache)??;
Ok(toolchain)
}

/// Find an installed [`Toolchain`] for the default Python interpreter.
pub fn from_default_python(preview: PreviewMode, cache: &Cache) -> Result<Self, Error> {
let toolchain = find_default_toolchain(preview, cache)??;
Ok(toolchain)
}

/// Find an installed [`Toolchain`] from an existing [`Interpreter`].
pub fn from_interpreter(interpreter: Interpreter) -> Self {
Self {
source: ToolchainSource::ProvidedPath,
interpreter,
}
}

pub fn source(&self) -> &ToolchainSource {
&self.source
}

pub fn interpreter(&self) -> &Interpreter {
&self.interpreter
}

pub fn into_interpreter(self) -> Interpreter {
self.interpreter
}
}

0 comments on commit 142868b

Please sign in to comment.