Improve interpreter discovery logging (#1909)

We had several cases where interpreter discovery fails. This PR improves
the verbose output to ensure interpreter discovery is debuggable for a
user.

In the process, i removed the custom gourgeist logic for the
uv_interpreter logic.

**venv creation**

```
$ uv venv -v -p 3.10
 uv_interpreter::python_query::find_requested_python request=3.10
      0.002389s   0ms DEBUG uv_interpreter::python_query Starting interpreter discovery for Python 3.10
   uv_interpreter::python_query::windows::py_list_paths
      0.016288s  14ms DEBUG uv_interpreter::interpreter Probing interpreter info for: C:\Users\Ferris\AppData\Local\Programs\Python\Python312\python.exe
      0.072860s  70ms DEBUG uv_interpreter::interpreter Found Python 3.12.1 for: C:\Users\Ferris\AppData\Local\Programs\Python\Python312\python.exe
      0.074303s  72ms DEBUG uv_interpreter::interpreter Probing interpreter info for: C:\Users\Ferris\AppData\Local\Programs\Python\Python38\python.exe
      0.134311s 132ms DEBUG uv_interpreter::interpreter Found Python 3.8.10 for: C:\Users\Ferris\AppData\Local\Programs\Python\Python38\python.exe
  x No Python 3.10 found through `py --list-paths` or in `PATH`. Is Python 3.10 installed?
error: process didn't exit successfully: `target\debug\uv.exe venv -v -p 3.10` (exit code: 1)
```

```
$ uv venv -v -p 3.10
 uv_interpreter::python_query::find_requested_python request=3.10
      0.001889s   0ms DEBUG uv_interpreter::python_query Starting interpreter discovery for Python 3.10
   uv_interpreter::python_query::windows::py_list_paths
      0.021488s  19ms DEBUG uv_interpreter::interpreter Cached interpreter info for Python 3.12.1, skipping probing: C:\Users\Ferris\AppData\Local\Programs\Python\Python312\python.exe
      0.021945s  20ms DEBUG uv_interpreter::interpreter Cached interpreter info for Python 3.8.10, skipping probing: C:\Users\Ferris\AppData\Local\Programs\Python\Python38\python.exe
  x No Python 3.10 found through `py --list-paths` or in `PATH`. Is Python 3.10 installed?
error: process didn't exit successfully: `target\debug\uv.exe venv -v -p 3.10` (exit code: 1)
```

```
$ uv venv -v -p 3.8
 uv_interpreter::python_query::find_requested_python request=3.8
      0.001896s   0ms DEBUG uv_interpreter::python_query Starting interpreter discovery for Python 3.8
   uv_interpreter::python_query::windows::py_list_paths
      0.013541s  11ms DEBUG uv_interpreter::interpreter Cached interpreter info for Python 3.8.10, skipping probing: C:\Users\Ferris\AppData\Local\Programs\Python\Python38\python.exe
Using Python 3.8.10 interpreter at C:\Users\Ferris\AppData\Local\Programs\Python\Python38\python.exe
Creating virtualenv at: .venv
Activate with: .venv\Scripts\activate
```

```
$ uv venv -v -p 3.12
 uv_interpreter::python_query::find_requested_python request=3.12
      0.001741s   0ms DEBUG uv_interpreter::python_query Starting interpreter discovery for Python 3.12
   uv_interpreter::python_query::windows::py_list_paths
      0.012807s  11ms DEBUG uv_interpreter::interpreter Cached interpreter info for Python 3.12.1, skipping probing: C:\Users\Ferris\AppData\Local\Programs\Python\Python312\python.exe
Using Python 3.12.1 interpreter at C:\Users\Ferris\AppData\Local\Programs\Python\Python312\python.exe
Creating virtualenv at: .venv
Activate with: .venv\Scripts\activate
```

**pip compile**

```
$ uv pip compile -v .\scripts\requirements\black.in
   uv::requirements::from_source source=.\scripts\requirements\black.in
   uv_interpreter::interpreter::find_best python_version=None
        0.002071s   0ms DEBUG uv_interpreter::interpreter Starting interpreter discovery for active Python
        0.002220s   0ms DEBUG uv_interpreter::virtual_env Found a virtualenv named .venv at: C:\Users\Ferris\projects\uv\.venv
        0.002483s   0ms DEBUG uv_interpreter::interpreter Cached interpreter info for Python 3.12.1, skipping probing: C:\Users\Ferris\projects\uv\.venv\Scripts\python.exe
      0.002581s DEBUG uv::commands::pip_compile Using Python 3.12.1 interpreter at C:\Users\Ferris\projects\uv\.venv\Scripts\python.exe for builds
```

```
$ uv pip compile -p 3.8 -v .\scripts\requirements\black.in
   uv::requirements::from_source source=.\scripts\requirements\black.in
   uv_interpreter::interpreter::find_best python_version=Some(PythonVersion(StringVersion { string: "3.8", version: "3.8" }))
        0.002001s   0ms DEBUG uv_interpreter::interpreter Starting interpreter discovery for Python 3.8
        0.002146s   0ms DEBUG uv_interpreter::virtual_env Found a virtualenv named .venv at: C:\Users\Ferris\projects\uv\.venv
        0.002378s   0ms DEBUG uv_interpreter::interpreter Cached interpreter info for Python 3.12.1, skipping probing: C:\Users\Ferris\projects\uv\.venv\Scripts\python.exe
     uv_interpreter::python_query::find_requested_python request=3.8
          0.002509s   0ms DEBUG uv_interpreter::python_query Starting interpreter discovery for Python 3.8
       uv_interpreter::python_query::windows::py_list_paths
          0.015989s  13ms DEBUG uv_interpreter::interpreter Cached interpreter info for Python 3.8.10, skipping probing: C:\Users\Ferris\AppData\Local\Programs\Python\Python38\python.exe
      0.016144s DEBUG uv::commands::pip_compile Using Python 3.8.10 interpreter at C:\Users\Ferris\AppData\Local\Programs\Python\Python38\python.exe for builds

```

```
$ uv pip compile -p 3.10 -v .\scripts\requirements\black.in
   uv::requirements::from_source source=.\scripts\requirements\black.in
   uv_interpreter::interpreter::find_best python_version=Some(PythonVersion(StringVersion { string: "3.10", version: "3.10" }))
        0.002086s   0ms DEBUG uv_interpreter::interpreter Starting interpreter discovery for Python 3.10
        0.002234s   0ms DEBUG uv_interpreter::virtual_env Found a virtualenv named .venv at: C:\Users\Ferris\projects\uv\.venv
        0.002462s   0ms DEBUG uv_interpreter::interpreter Cached interpreter info for Python 3.12.1, skipping probing: C:\Users\Ferris\projects\uv\.venv\Scripts\python.exe
     uv_interpreter::python_query::find_requested_python request=3.10
          0.002589s   0ms DEBUG uv_interpreter::python_query Starting interpreter discovery for Python 3.10
       uv_interpreter::python_query::windows::py_list_paths
          0.017299s  14ms DEBUG uv_interpreter::interpreter Cached interpreter info for Python 3.12.1, skipping probing: C:\Users\Ferris\AppData\Local\Programs\Python\Python312\python.exe
          0.018135s  15ms DEBUG uv_interpreter::interpreter Cached interpreter info for Python 3.8.10, skipping probing: C:\Users\Ferris\AppData\Local\Programs\Python\Python38\python.exe
        0.020176s  18ms DEBUG uv_interpreter::virtual_env Found a virtualenv named .venv at: C:\Users\Ferris\projects\uv\.venv
        0.020873s  18ms DEBUG uv_interpreter::interpreter Cached interpreter info for Python 3.12.1, skipping probing: C:\Users\Ferris\projects\uv\.venv\Scripts\python.exe
      0.021116s DEBUG uv::commands::pip_compile Using Python 3.12.1 interpreter at C:\Users\Ferris\projects\uv\.venv\Scripts\python.exe for builds
  warning: The requested Python version 3.10 is not available; 3.12.1 will be used to build dependencies instead.
```
This commit is contained in:
konsti 2024-02-23 19:43:46 +01:00 committed by GitHub
parent 11ed4f7183
commit 9cf7d113bc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 64 additions and 69 deletions

View file

@ -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;
@ -35,7 +35,11 @@ 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!(
@ -77,7 +81,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
@ -94,11 +98,21 @@ 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);
@ -139,7 +153,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,
@ -184,7 +198,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") {
@ -403,7 +417,11 @@ 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);
}
@ -424,8 +442,13 @@ 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.

View file

@ -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;
@ -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> {
debug!("Starting interpreter discovery for Python {}", request);
let versions = request
.splitn(3, '.')
.map(str::parse::<u8>)
@ -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) {
@ -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,

View file

@ -1,5 +1,6 @@
use pep440_rs::Version;
use pep508_rs::{MarkerEnvironment, StringVersion};
use std::fmt::{Display, Formatter};
use std::ops::Deref;
use std::str::FromStr;
@ -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`].