mirror of
https://github.com/astral-sh/uv.git
synced 2025-09-26 12:09:12 +00:00
Use base executable to set virtualenv Python path (#8481)
See extensive discussion in https://github.com/astral-sh/uv/pull/8433#issuecomment-2430472849. This PR brings us into alignment with the standard library by using `sys._base_executable` rather than canonicalizing the executable path. The benefits are primarily for Homebrew, where we'll now resolve to paths like `/opt/homebrew/opt/python@3.12/bin` instead of the undesirable `/opt/homebrew/Cellar/python@3.9/3.9.19_1/Frameworks/Python.framework/Versions/3.9/bin`. Most other users should see no change, though in some cases, nested virtual environments now have slightly different behavior -- namely, they _sometimes_ resolve to the virtual environment Python (at least for Homebrew; not for rtx or uv Pythons though). See [here](https://docs.google.com/spreadsheets/d/1Vw5ClYEjgrBJJhQiwa3cCenIA1GbcRyudYN9NwQaEcM/edit?gid=0#gid=0) for a breakdown. Closes https://github.com/astral-sh/uv/issues/1640. Closes https://github.com/astral-sh/uv/issues/1795.
This commit is contained in:
parent
b6c531f4dd
commit
633467576b
3 changed files with 34 additions and 23 deletions
|
@ -57,31 +57,20 @@ pub(crate) fn create(
|
|||
// considered the "base" for the virtual environment. This is typically the Python executable
|
||||
// from the [`Interpreter`]; however, if the interpreter is a virtual environment itself, then
|
||||
// the base Python executable is the Python executable of the interpreter's base interpreter.
|
||||
let base_python = if cfg!(unix) {
|
||||
// On Unix, follow symlinks to resolve the base interpreter, since the Python executable in
|
||||
// a virtual environment is a symlink to the base interpreter.
|
||||
uv_fs::canonicalize_executable(interpreter.sys_executable())?
|
||||
} else if cfg!(windows) {
|
||||
// On Windows, follow `virtualenv`. If we're in a virtual environment, use
|
||||
// `sys._base_executable` if it exists; if not, use `sys.base_prefix`. For example, with
|
||||
// Python installed from the Windows Store, `sys.base_prefix` is slightly "incorrect".
|
||||
let base_python = if cfg!(unix) && interpreter.is_standalone() {
|
||||
// In `python-build-standalone`, a symlinked interpreter will return its own executable path
|
||||
// as `sys._base_executable`. Using the symlinked path as the base Python executable is
|
||||
// incorrect, since it will cause `home` to point to something that is _not_ a Python
|
||||
// installation.
|
||||
//
|
||||
// If we're _not_ in a virtual environment, use the interpreter's executable, since it's
|
||||
// already a "system Python". We canonicalize the path to ensure that it's real and
|
||||
// consistent, though we don't expect any symlinks on Windows.
|
||||
if interpreter.is_virtualenv() {
|
||||
if let Some(base_executable) = interpreter.sys_base_executable() {
|
||||
base_executable.to_path_buf()
|
||||
} else {
|
||||
// Assume `python.exe`, though the exact executable name is never used (below) on
|
||||
// Windows, only its parent directory.
|
||||
interpreter.sys_base_prefix().join("python.exe")
|
||||
}
|
||||
} else {
|
||||
interpreter.sys_executable().to_path_buf()
|
||||
}
|
||||
// Instead, we want to fully resolve the symlink to the actual Python executable.
|
||||
uv_fs::canonicalize_executable(interpreter.sys_executable())?
|
||||
} else {
|
||||
unimplemented!("Only Windows and Unix are supported")
|
||||
std::path::absolute(
|
||||
interpreter
|
||||
.sys_base_executable()
|
||||
.unwrap_or(interpreter.sys_executable()),
|
||||
)?
|
||||
};
|
||||
|
||||
// Validate the existing location.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue