mirror of
https://github.com/astral-sh/uv.git
synced 2025-09-27 12:39:09 +00:00
Ignore virtual environments in parent directories when choosing Python version for new projects (#9075)
Some checks are pending
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86_64 (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | linux (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on linux (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | python3.10 on windows (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on linux (push) Blocked by required conditions
CI / check system | conda3.8 on linux (push) Blocked by required conditions
CI / check system | conda3.11 on macos (push) Blocked by required conditions
CI / check system | conda3.8 on macos (push) Blocked by required conditions
CI / check system | conda3.11 on windows (push) Blocked by required conditions
CI / check system | conda3.8 on windows (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
Some checks are pending
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86_64 (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | linux (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows (push) Blocked by required conditions
CI / cargo build (msrv) (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on linux (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | uv publish (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on opensuse (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | python3.10 on windows (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.11 on linux (push) Blocked by required conditions
CI / check system | conda3.8 on linux (push) Blocked by required conditions
CI / check system | conda3.11 on macos (push) Blocked by required conditions
CI / check system | conda3.8 on macos (push) Blocked by required conditions
CI / check system | conda3.11 on windows (push) Blocked by required conditions
CI / check system | conda3.8 on windows (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows (push) Blocked by required conditions
CI / benchmarks (push) Blocked by required conditions
`uv init` shouldn't have been using `EnvironmentPreference::Any` for discovery of a Python interpreter, it seems like an oversight that it was reading from virtual environments. I changed it to `EnvironmentPreference::OnlySystem` so we'll use the first Python on the `PATH` instead. However, I think we actually do want to respect a virtual environment's Python version if it's in the target project directory already, so I've implemented that as well. Closes https://github.com/astral-sh/uv/issues/9072 Closes https://github.com/astral-sh/uv/issues/8092
This commit is contained in:
parent
95e7d8702f
commit
cb430b8d44
2 changed files with 127 additions and 8 deletions
|
@ -17,8 +17,9 @@ use uv_git::GIT;
|
||||||
use uv_pep440::Version;
|
use uv_pep440::Version;
|
||||||
use uv_pep508::PackageName;
|
use uv_pep508::PackageName;
|
||||||
use uv_python::{
|
use uv_python::{
|
||||||
EnvironmentPreference, PythonDownloads, PythonInstallation, PythonPreference, PythonRequest,
|
EnvironmentPreference, PythonDownloads, PythonEnvironment, PythonInstallation,
|
||||||
PythonVariant, PythonVersionFile, VersionFileDiscoveryOptions, VersionRequest,
|
PythonPreference, PythonRequest, PythonVariant, PythonVersionFile, VersionFileDiscoveryOptions,
|
||||||
|
VersionRequest,
|
||||||
};
|
};
|
||||||
use uv_resolver::RequiresPython;
|
use uv_resolver::RequiresPython;
|
||||||
use uv_scripts::{Pep723Script, ScriptTag};
|
use uv_scripts::{Pep723Script, ScriptTag};
|
||||||
|
@ -409,7 +410,7 @@ async fn init_project(
|
||||||
} else {
|
} else {
|
||||||
let interpreter = PythonInstallation::find_or_download(
|
let interpreter = PythonInstallation::find_or_download(
|
||||||
Some(python_request),
|
Some(python_request),
|
||||||
EnvironmentPreference::Any,
|
EnvironmentPreference::OnlySystem,
|
||||||
python_preference,
|
python_preference,
|
||||||
python_downloads,
|
python_downloads,
|
||||||
&client_builder,
|
&client_builder,
|
||||||
|
@ -431,7 +432,7 @@ async fn init_project(
|
||||||
python_request => {
|
python_request => {
|
||||||
let interpreter = PythonInstallation::find_or_download(
|
let interpreter = PythonInstallation::find_or_download(
|
||||||
Some(&python_request),
|
Some(&python_request),
|
||||||
EnvironmentPreference::Any,
|
EnvironmentPreference::OnlySystem,
|
||||||
python_preference,
|
python_preference,
|
||||||
python_downloads,
|
python_downloads,
|
||||||
&client_builder,
|
&client_builder,
|
||||||
|
@ -457,8 +458,29 @@ async fn init_project(
|
||||||
(requires_python, python_request)
|
(requires_python, python_request)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else if let Ok(virtualenv) = PythonEnvironment::from_root(path.join(".venv"), cache) {
|
||||||
|
// (2) An existing Python environment in the target directory
|
||||||
|
debug!("Using Python version from existing virtual environment in project");
|
||||||
|
let interpreter = virtualenv.into_interpreter();
|
||||||
|
|
||||||
|
let requires_python =
|
||||||
|
RequiresPython::greater_than_equal_version(&interpreter.python_minor_version());
|
||||||
|
|
||||||
|
// Pin to the minor version.
|
||||||
|
let python_request = if no_pin_python {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(PythonRequest::Version(VersionRequest::MajorMinor(
|
||||||
|
interpreter.python_major(),
|
||||||
|
interpreter.python_minor(),
|
||||||
|
PythonVariant::Default,
|
||||||
|
)))
|
||||||
|
};
|
||||||
|
|
||||||
|
(requires_python, python_request)
|
||||||
} else if let Some(requires_python) = workspace.as_ref().and_then(find_requires_python) {
|
} else if let Some(requires_python) = workspace.as_ref().and_then(find_requires_python) {
|
||||||
// (2) `requires-python` from the workspace
|
// (3) `requires-python` from the workspace
|
||||||
|
debug!("Using Python version from project workspace");
|
||||||
let python_request = PythonRequest::Version(VersionRequest::Range(
|
let python_request = PythonRequest::Version(VersionRequest::Range(
|
||||||
requires_python.specifiers().clone(),
|
requires_python.specifiers().clone(),
|
||||||
PythonVariant::Default,
|
PythonVariant::Default,
|
||||||
|
@ -470,7 +492,7 @@ async fn init_project(
|
||||||
} else {
|
} else {
|
||||||
let interpreter = PythonInstallation::find_or_download(
|
let interpreter = PythonInstallation::find_or_download(
|
||||||
Some(&python_request),
|
Some(&python_request),
|
||||||
EnvironmentPreference::Any,
|
EnvironmentPreference::OnlySystem,
|
||||||
python_preference,
|
python_preference,
|
||||||
python_downloads,
|
python_downloads,
|
||||||
&client_builder,
|
&client_builder,
|
||||||
|
@ -489,10 +511,10 @@ async fn init_project(
|
||||||
|
|
||||||
(requires_python, python_request)
|
(requires_python, python_request)
|
||||||
} else {
|
} else {
|
||||||
// (3) Default to the system Python
|
// (4) Default to the system Python
|
||||||
let interpreter = PythonInstallation::find_or_download(
|
let interpreter = PythonInstallation::find_or_download(
|
||||||
None,
|
None,
|
||||||
EnvironmentPreference::Any,
|
EnvironmentPreference::OnlySystem,
|
||||||
python_preference,
|
python_preference,
|
||||||
python_downloads,
|
python_downloads,
|
||||||
&client_builder,
|
&client_builder,
|
||||||
|
|
|
@ -2042,6 +2042,103 @@ fn init_requires_python_version_file() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Run `uv init`, inferring the Python version from an existing `.venv`
|
||||||
|
#[test]
|
||||||
|
fn init_existing_environment() -> Result<()> {
|
||||||
|
let context = TestContext::new_with_versions(&["3.8", "3.12"]);
|
||||||
|
|
||||||
|
let child = context.temp_dir.child("foo");
|
||||||
|
child.create_dir_all()?;
|
||||||
|
|
||||||
|
// Create a new virtual environment in the directory
|
||||||
|
uv_snapshot!(context.filters(), context.venv().current_dir(&child).arg("--python").arg("3.12"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||||
|
Creating virtual environment at: .venv
|
||||||
|
Activate with: source .venv/[BIN]/activate
|
||||||
|
"###);
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.init().current_dir(&context.temp_dir).arg(child.as_os_str()), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Initialized project `foo` at `[TEMP_DIR]/foo`
|
||||||
|
"###);
|
||||||
|
|
||||||
|
let pyproject_toml = fs_err::read_to_string(child.join("pyproject.toml"))?;
|
||||||
|
insta::with_settings!({
|
||||||
|
filters => context.filters(),
|
||||||
|
}, {
|
||||||
|
assert_snapshot!(
|
||||||
|
pyproject_toml, @r###"
|
||||||
|
[project]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.12"
|
||||||
|
dependencies = []
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run `uv init`, it should ignore a the Python version from a parent `.venv`
|
||||||
|
#[test]
|
||||||
|
fn init_existing_environment_parent() -> Result<()> {
|
||||||
|
let context = TestContext::new_with_versions(&["3.8", "3.12"]);
|
||||||
|
|
||||||
|
// Create a new virtual environment in the parent directory
|
||||||
|
uv_snapshot!(context.filters(), context.venv().current_dir(&context.temp_dir).arg("--python").arg("3.12"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Using CPython 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||||
|
Creating virtual environment at: .venv
|
||||||
|
Activate with: source .venv/[BIN]/activate
|
||||||
|
"###);
|
||||||
|
|
||||||
|
let child = context.temp_dir.child("foo");
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.init().current_dir(&context.temp_dir).arg(child.as_os_str()), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Initialized project `foo` at `[TEMP_DIR]/foo`
|
||||||
|
"###);
|
||||||
|
|
||||||
|
let pyproject_toml = fs_err::read_to_string(child.join("pyproject.toml"))?;
|
||||||
|
insta::with_settings!({
|
||||||
|
filters => context.filters(),
|
||||||
|
}, {
|
||||||
|
assert_snapshot!(
|
||||||
|
pyproject_toml, @r###"
|
||||||
|
[project]
|
||||||
|
name = "foo"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Add your description here"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.8"
|
||||||
|
dependencies = []
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
/// Run `uv init` from within an unmanaged project.
|
/// Run `uv init` from within an unmanaged project.
|
||||||
#[test]
|
#[test]
|
||||||
fn init_unmanaged() -> Result<()> {
|
fn init_unmanaged() -> Result<()> {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue