Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve interpreter discovery logging #1909

Merged
merged 2 commits into from
Feb 23, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 0 additions & 46 deletions crates/gourgeist/src/interpreter.rs

This file was deleted.

4 changes: 1 addition & 3 deletions crates/gourgeist/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,19 @@ use std::path::Path;
use camino::{FromPathError, Utf8Path};
use thiserror::Error;

pub use interpreter::parse_python_cli;
use platform_host::PlatformError;
use uv_interpreter::{Interpreter, Virtualenv};

pub use crate::bare::create_bare_venv;

mod bare;
mod interpreter;

#[derive(Debug, Error)]
pub enum Error {
#[error(transparent)]
IO(#[from] io::Error),
#[error("Failed to determine python interpreter to use")]
InvalidPythonInterpreter(#[source] Box<dyn std::error::Error + Sync + Send>),
InterpreterError(#[from] uv_interpreter::Error),
#[error(transparent)]
Platform(#[from] PlatformError),
#[error("Reserved key used for pyvenv.cfg: {0}")]
Expand Down
16 changes: 10 additions & 6 deletions crates/gourgeist/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,32 +11,36 @@ use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::{fmt, EnvFilter};

use gourgeist::{create_bare_venv, parse_python_cli, Prompt};
use gourgeist::{create_bare_venv, Prompt};
use platform_host::Platform;
use uv_cache::Cache;
use uv_interpreter::Interpreter;
use uv_interpreter::{find_default_python, find_requested_python};

#[derive(Parser, Debug)]
struct Cli {
path: Option<Utf8PathBuf>,
#[clap(short, long)]
python: Option<Utf8PathBuf>,
python: Option<String>,
#[clap(long)]
prompt: Option<String>,
}

fn run() -> Result<(), gourgeist::Error> {
let cli = Cli::parse();
let location = cli.path.unwrap_or(Utf8PathBuf::from(".venv"));
let python = parse_python_cli(cli.python)?;
let platform = Platform::current()?;
let cache = if let Some(project_dirs) = ProjectDirs::from("", "", "gourgeist") {
Cache::from_path(project_dirs.cache_dir())?
} else {
Cache::from_path(".gourgeist_cache")?
};
let info = Interpreter::query(python.as_std_path(), &platform, &cache).unwrap();
create_bare_venv(&location, &info, Prompt::from_args(cli.prompt), Vec::new())?;
let interpreter = if let Some(python_request) = &cli.python {
find_requested_python(python_request, &platform, &cache)?
.ok_or(uv_interpreter::Error::NoSuchPython(python_request.to_string()))?
} else {
find_default_python(&platform, &cache)?
};
create_bare_venv(&location, &interpreter, Prompt::from_args(cli.prompt), Vec::new())?;
Ok(())
}

Expand Down
22 changes: 15 additions & 7 deletions crates/uv-interpreter/src/interpreter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::process::Command;
use fs_err as fs;
use once_cell::sync::OnceCell;
use serde::{Deserialize, Serialize};
use tracing::{debug, warn};
use tracing::{debug, instrument, warn};

use cache_key::digest;
use pep440_rs::Version;
Expand Down Expand Up @@ -35,7 +35,7 @@ pub struct Interpreter {

impl Interpreter {
/// Detect the interpreter info for the given Python executable.
pub fn query(executable: &Path, platform: &Platform, cache: &Cache) -> Result<Self, Error> {
pub(crate) fn query(executable: &Path, platform: &Platform, cache: &Cache) -> Result<Self, Error> {
let info = InterpreterInfo::query_cached(executable, cache)?;

debug_assert!(
Expand Down Expand Up @@ -77,7 +77,7 @@ impl Interpreter {

/// Return a new [`Interpreter`] with the given base prefix.
#[must_use]
pub fn with_base_prefix(self, base_prefix: PathBuf) -> Self {
pub(crate) fn with_base_prefix(self, base_prefix: PathBuf) -> Self {
Self {
base_prefix,
..self
Expand All @@ -94,11 +94,18 @@ impl Interpreter {
/// the first available version.
///
/// See [`Self::find_version`] for details on the precedence of Python lookup locations.
#[instrument(skip_all, fields(?python_version))]
pub fn find_best(
python_version: Option<&PythonVersion>,
platform: &Platform,
cache: &Cache,
) -> Result<Self, Error> {
if let Some(python_version) = python_version {
debug!("Starting interpreter discovery for Python {}", python_version);
} else {
debug!("Starting interpreter discovery for active Python");
}

// First, check for an exact match (or the first available version if no Python version was provided)
if let Some(interpreter) = Self::find_version(python_version, platform, cache)? {
return Ok(interpreter);
Expand Down Expand Up @@ -139,7 +146,7 @@ impl Interpreter {
///
/// If a version is provided and an interpreter cannot be found with the given version,
/// we will return [`None`].
pub fn find_version(
pub(crate) fn find_version(
python_version: Option<&PythonVersion>,
platform: &Platform,
cache: &Cache,
Expand Down Expand Up @@ -184,7 +191,7 @@ impl Interpreter {
/// Find the Python interpreter in `PATH`, respecting `UV_PYTHON_PATH`.
///
/// Returns `Ok(None)` if not found.
pub fn find_executable<R: AsRef<OsStr> + Into<OsString> + Copy>(
pub(crate) fn find_executable<R: AsRef<OsStr> + Into<OsString> + Copy>(
requested: R,
) -> Result<Option<PathBuf>, Error> {
let result = if let Some(isolated) = std::env::var_os("UV_TEST_PYTHON_PATH") {
Expand Down Expand Up @@ -403,7 +410,7 @@ impl InterpreterInfo {
match rmp_serde::from_slice::<CachedByTimestamp<Self>>(&data) {
Ok(cached) => {
if cached.timestamp == modified {
debug!("Using cached markers for: {}", executable.display());
debug!("Cached interpreter info for Python {}, skipping probing: {}", cached.data.markers.python_full_version, executable.display());
return Ok(cached.data);
}

Expand All @@ -424,8 +431,9 @@ impl InterpreterInfo {
}

// Otherwise, run the Python script.
debug!("Detecting markers for: {}", executable.display());
debug!("Probing interpreter info for: {}", executable.display());
let info = Self::query(executable)?;
debug!("Found Python {} for: {}", info.markers.python_full_version, executable.display());

// If `executable` is a pyenv shim, a bash script that redirects to the activated
// python executable at another path, we're not allowed to cache the interpreter info.
Expand Down
15 changes: 9 additions & 6 deletions crates/uv-interpreter/src/python_query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use std::borrow::Cow;
use std::env;
use std::path::PathBuf;

use tracing::instrument;
use tracing::{debug, instrument};

use platform_host::Platform;
use uv_cache::Cache;
Expand All @@ -23,11 +23,13 @@ use crate::{Error, Interpreter};
/// version (e.g. `python3.12` on unix) and error when the version mismatches, as a binary with the
/// patch version (e.g. `python3.12.1`) is often not in `PATH` and we make the simplifying
/// assumption that the user has only this one patch version installed.
#[instrument(skip_all, fields(%request))]
pub fn find_requested_python(
request: &str,
platform: &Platform,
cache: &Cache,
) -> Result<Option<Interpreter>, Error> {
) -> Result<Option<Interpreter>, Error> {
debug!("Starting interpreter discovery for Python {}", request);
let versions = request
.splitn(3, '.')
.map(str::parse::<u8>)
Expand Down Expand Up @@ -70,7 +72,9 @@ pub fn find_requested_python(
///
/// We prefer the test overwrite `UV_TEST_PYTHON_PATH` if it is set, otherwise `python3`/`python` or
/// `python.exe` respectively.
#[instrument(skip_all)]
pub fn find_default_python(platform: &Platform, cache: &Cache) -> Result<Interpreter, Error> {
debug!("Starting interpreter discovery for default Python");
try_find_default_python(platform, cache)?.ok_or(if cfg!(windows) {
Error::NoPythonInstalledWindows
} else if cfg!(unix) {
Expand Down Expand Up @@ -100,7 +104,6 @@ pub(crate) fn try_find_default_python(
/// * (windows): For each of the above, test for the existence of `python.bat` shim (pyenv-windows) last.
///
/// (Windows): Filter out the windows store shim (Enabled in Settings/Apps/Advanced app settings/App execution aliases).
#[instrument(skip_all, fields(? selector))]
fn find_python(
selector: PythonVersionSelector,
platform: &Platform,
Expand Down Expand Up @@ -339,8 +342,8 @@ mod windows {
use platform_host::Platform;
use uv_cache::Cache;

use crate::python_query::{PythonInstallation, PythonVersionSelector};
use crate::{Error, Interpreter};
use crate::python_query::{PythonInstallation, PythonVersionSelector};

/// ```text
/// -V:3.12 C:\Users\Ferris\AppData\Local\Programs\Python\Python312\python.exe
Expand Down Expand Up @@ -435,7 +438,7 @@ mod windows {
use platform_host::Platform;
use uv_cache::Cache;

use crate::{find_requested_python, Error};
use crate::{Error, find_requested_python};

fn format_err<T: Debug>(err: Result<T, Error>) -> String {
anyhow::Error::new(err.unwrap_err())
Expand Down Expand Up @@ -477,8 +480,8 @@ mod tests {
use platform_host::Platform;
use uv_cache::Cache;

use crate::python_query::find_requested_python;
use crate::Error;
use crate::python_query::find_requested_python;

fn format_err<T: std::fmt::Debug>(err: Result<T, Error>) -> String {
anyhow::Error::new(err.unwrap_err())
Expand Down
7 changes: 7 additions & 0 deletions crates/uv-interpreter/src/python_version.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use std::fmt::{Display, Formatter};
use pep440_rs::Version;
use pep508_rs::{MarkerEnvironment, StringVersion};
use std::ops::Deref;
Expand Down Expand Up @@ -41,6 +42,12 @@ impl FromStr for PythonVersion {
}
}

impl Display for PythonVersion {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
Display::fmt(&self.0, f)
}
}

impl PythonVersion {
/// Return a [`MarkerEnvironment`] compatible with the given [`PythonVersion`], based on
/// a base [`MarkerEnvironment`].
Expand Down
2 changes: 1 addition & 1 deletion crates/uv/src/confirm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use console::{style, Key, Term};

/// Prompt the user for confirmation in the given [`Term`].
///
/// This is a slimmed-down version of [`dialoguer::Confirm`], with the post-confirmation report
/// This is a slimmed-down version of `dialoguer::Confirm`, with the post-confirmation report
/// enabled.
pub(crate) fn confirm(message: &str, term: &Term, default: bool) -> Result<bool> {
ctrlc::set_handler(move || {
Expand Down
8 changes: 4 additions & 4 deletions crates/uv/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ struct PipCompileArgs {
#[clap(long)]
refresh_package: Vec<PackageName>,

/// The URL of the Python package index (by default: https://pypi.org/simple).
/// The URL of the Python package index (by default: <https://pypi.org/simple>).
#[clap(long, short, env = "UV_INDEX_URL")]
index_url: Option<IndexUrl>,

Expand Down Expand Up @@ -404,7 +404,7 @@ struct PipSyncArgs {
#[clap(long, value_enum, default_value_t = install_wheel_rs::linker::LinkMode::default())]
link_mode: install_wheel_rs::linker::LinkMode,

/// The URL of the Python package index (by default: https://pypi.org/simple).
/// The URL of the Python package index (by default: <https://pypi.org/simple>).
#[clap(long, short, env = "UV_INDEX_URL")]
index_url: Option<IndexUrl>,

Expand Down Expand Up @@ -573,7 +573,7 @@ struct PipInstallArgs {
#[clap(long, short)]
output_file: Option<PathBuf>,

/// The URL of the Python package index (by default: https://pypi.org/simple).
/// The URL of the Python package index (by default: <https://pypi.org/simple>).
#[clap(long, short, env = "UV_INDEX_URL")]
index_url: Option<IndexUrl>,

Expand Down Expand Up @@ -711,7 +711,7 @@ struct VenvArgs {
#[clap(long, verbatim_doc_comment)]
prompt: Option<String>,

/// The URL of the Python package index (by default: https://pypi.org/simple).
/// The URL of the Python package index (by default: <https://pypi.org/simple>).
#[clap(long, short, env = "UV_INDEX_URL")]
index_url: Option<IndexUrl>,

Expand Down
Loading