Skip to content

Commit

Permalink
Move implementations next to definitions (#10131)
Browse files Browse the repository at this point in the history
  • Loading branch information
charliermarsh authored Dec 24, 2024
1 parent b24fb77 commit 6ed7302
Showing 1 changed file with 159 additions and 159 deletions.
318 changes: 159 additions & 159 deletions crates/uv/src/commands/project/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -448,6 +448,165 @@ pub(crate) enum ProjectInterpreter {
Environment(PythonEnvironment),
}

impl ProjectInterpreter {
/// Discover the interpreter to use in the current [`Workspace`].
pub(crate) async fn discover(
workspace: &Workspace,
project_dir: &Path,
python_request: Option<PythonRequest>,
python_preference: PythonPreference,
python_downloads: PythonDownloads,
connectivity: Connectivity,
native_tls: bool,
allow_insecure_host: &[TrustedHost],
install_mirrors: PythonInstallMirrors,
no_config: bool,
cache: &Cache,
printer: Printer,
) -> Result<Self, ProjectError> {
// Resolve the Python request and requirement for the workspace.
let WorkspacePython {
source,
python_request,
requires_python,
} = WorkspacePython::from_request(python_request, Some(workspace), project_dir, no_config)
.await?;

// Read from the virtual environment first.
let venv = workspace.venv();
match PythonEnvironment::from_root(&venv, cache) {
Ok(venv) => {
if python_request.as_ref().map_or(true, |request| {
if request.satisfied(venv.interpreter(), cache) {
debug!(
"The virtual environment's Python version satisfies `{}`",
request.to_canonical_string()
);
true
} else {
debug!(
"The virtual environment's Python version does not satisfy `{}`",
request.to_canonical_string()
);
false
}
}) {
if let Some(requires_python) = requires_python.as_ref() {
if requires_python.contains(venv.interpreter().python_version()) {
return Ok(Self::Environment(venv));
}
debug!(
"The virtual environment's Python version does not meet the project's Python requirement: `{requires_python}`"
);
} else {
return Ok(Self::Environment(venv));
}
}
}
Err(uv_python::Error::MissingEnvironment(_)) => {}
Err(uv_python::Error::InvalidEnvironment(inner)) => {
// If there's an invalid environment with existing content, we error instead of
// deleting it later on
match inner.kind {
InvalidEnvironmentKind::NotDirectory => {
return Err(ProjectError::InvalidProjectEnvironmentDir(
venv,
inner.kind.to_string(),
))
}
InvalidEnvironmentKind::MissingExecutable(_) => {
if fs_err::read_dir(&venv).is_ok_and(|mut dir| dir.next().is_some()) {
return Err(ProjectError::InvalidProjectEnvironmentDir(
venv,
"it is not a valid Python environment (no Python executable was found)"
.to_string(),
));
}
}
// If the environment is an empty directory, it's fine to use
InvalidEnvironmentKind::Empty => {}
};
}
Err(uv_python::Error::Query(uv_python::InterpreterError::NotFound(path))) => {
if path.is_symlink() {
let target_path = fs_err::read_link(&path)?;
warn_user!(
"Ignoring existing virtual environment linked to non-existent Python interpreter: {} -> {}",
path.user_display().cyan(),
target_path.user_display().cyan(),
);
}
}
Err(err) => return Err(err.into()),
};

let client_builder = BaseClientBuilder::default()
.connectivity(connectivity)
.native_tls(native_tls)
.allow_insecure_host(allow_insecure_host.to_vec());

let reporter = PythonDownloadReporter::single(printer);

// Locate the Python interpreter to use in the environment
let python = PythonInstallation::find_or_download(
python_request.as_ref(),
EnvironmentPreference::OnlySystem,
python_preference,
python_downloads,
&client_builder,
cache,
Some(&reporter),
install_mirrors.python_install_mirror.as_deref(),
install_mirrors.pypy_install_mirror.as_deref(),
)
.await?;

let managed = python.source().is_managed();
let implementation = python.implementation();
let interpreter = python.into_interpreter();

if managed {
writeln!(
printer.stderr(),
"Using {} {}",
implementation.pretty(),
interpreter.python_version().cyan()
)?;
} else {
writeln!(
printer.stderr(),
"Using {} {} interpreter at: {}",
implementation.pretty(),
interpreter.python_version(),
interpreter.sys_executable().user_display().cyan()
)?;
}

if let Some(requires_python) = requires_python.as_ref() {
validate_requires_python(&interpreter, Some(workspace), requires_python, &source)?;
}

Ok(Self::Interpreter(interpreter))
}

/// Convert the [`ProjectInterpreter`] into an [`Interpreter`].
pub(crate) fn into_interpreter(self) -> Interpreter {
match self {
ProjectInterpreter::Interpreter(interpreter) => interpreter,
ProjectInterpreter::Environment(venv) => venv.into_interpreter(),
}
}
}

/// The source of a `Requires-Python` specifier.
#[derive(Debug, Clone)]
pub(crate) enum RequiresPythonSource {
/// From the PEP 723 inline script metadata.
Script,
/// From a `pyproject.toml` in a workspace.
Project,
}

#[derive(Debug, Clone)]
pub(crate) enum PythonRequestSource {
/// The request was provided by the user.
Expand Down Expand Up @@ -543,15 +702,6 @@ impl WorkspacePython {
}
}

/// The source of a `Requires-Python` specifier.
#[derive(Debug, Clone)]
pub(crate) enum RequiresPythonSource {
/// From the PEP 723 inline script metadata.
Script,
/// From a `pyproject.toml` in a workspace.
Project,
}

/// The resolved Python request and requirement for a [`Pep723Script`]
#[derive(Debug, Clone)]
pub(crate) struct ScriptPython {
Expand Down Expand Up @@ -617,156 +767,6 @@ impl ScriptPython {
}
}

impl ProjectInterpreter {
/// Discover the interpreter to use in the current [`Workspace`].
pub(crate) async fn discover(
workspace: &Workspace,
project_dir: &Path,
python_request: Option<PythonRequest>,
python_preference: PythonPreference,
python_downloads: PythonDownloads,
connectivity: Connectivity,
native_tls: bool,
allow_insecure_host: &[TrustedHost],
install_mirrors: PythonInstallMirrors,
no_config: bool,
cache: &Cache,
printer: Printer,
) -> Result<Self, ProjectError> {
// Resolve the Python request and requirement for the workspace.
let WorkspacePython {
source,
python_request,
requires_python,
} = WorkspacePython::from_request(python_request, Some(workspace), project_dir, no_config)
.await?;

// Read from the virtual environment first.
let venv = workspace.venv();
match PythonEnvironment::from_root(&venv, cache) {
Ok(venv) => {
if python_request.as_ref().map_or(true, |request| {
if request.satisfied(venv.interpreter(), cache) {
debug!(
"The virtual environment's Python version satisfies `{}`",
request.to_canonical_string()
);
true
} else {
debug!(
"The virtual environment's Python version does not satisfy `{}`",
request.to_canonical_string()
);
false
}
}) {
if let Some(requires_python) = requires_python.as_ref() {
if requires_python.contains(venv.interpreter().python_version()) {
return Ok(Self::Environment(venv));
}
debug!(
"The virtual environment's Python version does not meet the project's Python requirement: `{requires_python}`"
);
} else {
return Ok(Self::Environment(venv));
}
}
}
Err(uv_python::Error::MissingEnvironment(_)) => {}
Err(uv_python::Error::InvalidEnvironment(inner)) => {
// If there's an invalid environment with existing content, we error instead of
// deleting it later on
match inner.kind {
InvalidEnvironmentKind::NotDirectory => {
return Err(ProjectError::InvalidProjectEnvironmentDir(
venv,
inner.kind.to_string(),
))
}
InvalidEnvironmentKind::MissingExecutable(_) => {
if fs_err::read_dir(&venv).is_ok_and(|mut dir| dir.next().is_some()) {
return Err(ProjectError::InvalidProjectEnvironmentDir(
venv,
"it is not a valid Python environment (no Python executable was found)"
.to_string(),
));
}
}
// If the environment is an empty directory, it's fine to use
InvalidEnvironmentKind::Empty => {}
};
}
Err(uv_python::Error::Query(uv_python::InterpreterError::NotFound(path))) => {
if path.is_symlink() {
let target_path = fs_err::read_link(&path)?;
warn_user!(
"Ignoring existing virtual environment linked to non-existent Python interpreter: {} -> {}",
path.user_display().cyan(),
target_path.user_display().cyan(),
);
}
}
Err(err) => return Err(err.into()),
};

let client_builder = BaseClientBuilder::default()
.connectivity(connectivity)
.native_tls(native_tls)
.allow_insecure_host(allow_insecure_host.to_vec());

let reporter = PythonDownloadReporter::single(printer);

// Locate the Python interpreter to use in the environment
let python = PythonInstallation::find_or_download(
python_request.as_ref(),
EnvironmentPreference::OnlySystem,
python_preference,
python_downloads,
&client_builder,
cache,
Some(&reporter),
install_mirrors.python_install_mirror.as_deref(),
install_mirrors.pypy_install_mirror.as_deref(),
)
.await?;

let managed = python.source().is_managed();
let implementation = python.implementation();
let interpreter = python.into_interpreter();

if managed {
writeln!(
printer.stderr(),
"Using {} {}",
implementation.pretty(),
interpreter.python_version().cyan()
)?;
} else {
writeln!(
printer.stderr(),
"Using {} {} interpreter at: {}",
implementation.pretty(),
interpreter.python_version(),
interpreter.sys_executable().user_display().cyan()
)?;
}

if let Some(requires_python) = requires_python.as_ref() {
validate_requires_python(&interpreter, Some(workspace), requires_python, &source)?;
}

Ok(Self::Interpreter(interpreter))
}

/// Convert the [`ProjectInterpreter`] into an [`Interpreter`].
pub(crate) fn into_interpreter(self) -> Interpreter {
match self {
ProjectInterpreter::Interpreter(interpreter) => interpreter,
ProjectInterpreter::Environment(venv) => venv.into_interpreter(),
}
}
}

/// Initialize a virtual environment for the current project.
pub(crate) async fn get_or_init_environment(
workspace: &Workspace,
Expand Down

0 comments on commit 6ed7302

Please sign in to comment.