mirror of
https://github.com/astral-sh/uv.git
synced 2025-07-07 13:25:00 +00:00
Respect .python-version
in uv venv --preview
(#4360)
Adds support for reading Python version files (introduced in #4335) to `uv venv`. If present, we'll use the file version as the default.
This commit is contained in:
parent
76c26db444
commit
903dfc2f1f
6 changed files with 125 additions and 12 deletions
|
@ -1,6 +1,6 @@
|
||||||
3.8.12
|
|
||||||
3.8.18
|
|
||||||
3.9.18
|
|
||||||
3.10.13
|
|
||||||
3.11.7
|
|
||||||
3.12.1
|
3.12.1
|
||||||
|
3.11.7
|
||||||
|
3.10.13
|
||||||
|
3.9.18
|
||||||
|
3.8.18
|
||||||
|
3.8.12
|
||||||
|
|
|
@ -13,7 +13,7 @@ pub use crate::prefix::Prefix;
|
||||||
pub use crate::python_version::PythonVersion;
|
pub use crate::python_version::PythonVersion;
|
||||||
pub use crate::target::Target;
|
pub use crate::target::Target;
|
||||||
pub use crate::toolchain::Toolchain;
|
pub use crate::toolchain::Toolchain;
|
||||||
pub use crate::version_files::{request_from_version_files, requests_from_version_files};
|
pub use crate::version_files::{request_from_version_file, requests_from_version_file};
|
||||||
pub use crate::virtualenv::{Error as VirtualEnvError, PyVenvConfiguration, VirtualEnvironment};
|
pub use crate::virtualenv::{Error as VirtualEnvError, PyVenvConfiguration, VirtualEnvironment};
|
||||||
|
|
||||||
mod discovery;
|
mod discovery;
|
||||||
|
|
|
@ -8,7 +8,7 @@ use crate::ToolchainRequest;
|
||||||
///
|
///
|
||||||
/// Prefers `.python-versions` then `.python-version`.
|
/// Prefers `.python-versions` then `.python-version`.
|
||||||
/// If only one Python version is desired, use [`request_from_version_files`] which prefers the `.python-version` file.
|
/// If only one Python version is desired, use [`request_from_version_files`] which prefers the `.python-version` file.
|
||||||
pub async fn requests_from_version_files() -> Result<Option<Vec<ToolchainRequest>>, io::Error> {
|
pub async fn requests_from_version_file() -> Result<Option<Vec<ToolchainRequest>>, io::Error> {
|
||||||
if let Some(versions) = read_versions_file().await? {
|
if let Some(versions) = read_versions_file().await? {
|
||||||
Ok(Some(
|
Ok(Some(
|
||||||
versions
|
versions
|
||||||
|
@ -27,7 +27,7 @@ pub async fn requests_from_version_files() -> Result<Option<Vec<ToolchainRequest
|
||||||
///
|
///
|
||||||
/// Prefers `.python-version` then the first entry of `.python-versions`.
|
/// Prefers `.python-version` then the first entry of `.python-versions`.
|
||||||
/// If multiple Python versions are desired, use [`requests_from_version_files`] instead.
|
/// If multiple Python versions are desired, use [`requests_from_version_files`] instead.
|
||||||
pub async fn request_from_version_files() -> Result<Option<ToolchainRequest>, io::Error> {
|
pub async fn request_from_version_file() -> Result<Option<ToolchainRequest>, io::Error> {
|
||||||
if let Some(version) = read_version_file().await? {
|
if let Some(version) = read_version_file().await? {
|
||||||
Ok(Some(ToolchainRequest::parse(&version)))
|
Ok(Some(ToolchainRequest::parse(&version)))
|
||||||
} else if let Some(versions) = read_versions_file().await? {
|
} else if let Some(versions) = read_versions_file().await? {
|
||||||
|
|
|
@ -8,7 +8,7 @@ use uv_configuration::PreviewMode;
|
||||||
use uv_fs::Simplified;
|
use uv_fs::Simplified;
|
||||||
use uv_toolchain::downloads::{self, DownloadResult, PythonDownload, PythonDownloadRequest};
|
use uv_toolchain::downloads::{self, DownloadResult, PythonDownload, PythonDownloadRequest};
|
||||||
use uv_toolchain::managed::{InstalledToolchain, InstalledToolchains};
|
use uv_toolchain::managed::{InstalledToolchain, InstalledToolchains};
|
||||||
use uv_toolchain::{requests_from_version_files, ToolchainRequest};
|
use uv_toolchain::{requests_from_version_file, ToolchainRequest};
|
||||||
use uv_warnings::warn_user;
|
use uv_warnings::warn_user;
|
||||||
|
|
||||||
use crate::commands::ExitStatus;
|
use crate::commands::ExitStatus;
|
||||||
|
@ -35,7 +35,7 @@ pub(crate) async fn install(
|
||||||
let toolchain_dir = toolchains.root();
|
let toolchain_dir = toolchains.root();
|
||||||
|
|
||||||
let requests: Vec<_> = if targets.is_empty() {
|
let requests: Vec<_> = if targets.is_empty() {
|
||||||
if let Some(requests) = requests_from_version_files().await? {
|
if let Some(requests) = requests_from_version_file().await? {
|
||||||
requests
|
requests
|
||||||
} else {
|
} else {
|
||||||
vec![ToolchainRequest::Any]
|
vec![ToolchainRequest::Any]
|
||||||
|
|
|
@ -23,7 +23,7 @@ use uv_dispatch::BuildDispatch;
|
||||||
use uv_fs::Simplified;
|
use uv_fs::Simplified;
|
||||||
use uv_git::GitResolver;
|
use uv_git::GitResolver;
|
||||||
use uv_resolver::{ExcludeNewer, FlatIndex, InMemoryIndex, OptionsBuilder};
|
use uv_resolver::{ExcludeNewer, FlatIndex, InMemoryIndex, OptionsBuilder};
|
||||||
use uv_toolchain::{SystemPython, Toolchain, ToolchainRequest};
|
use uv_toolchain::{request_from_version_file, SystemPython, Toolchain, ToolchainRequest};
|
||||||
use uv_types::{BuildContext, BuildIsolation, HashStrategy, InFlight};
|
use uv_types::{BuildContext, BuildIsolation, HashStrategy, InFlight};
|
||||||
|
|
||||||
use crate::commands::{pip, ExitStatus};
|
use crate::commands::{pip, ExitStatus};
|
||||||
|
@ -125,9 +125,14 @@ async fn venv_impl(
|
||||||
.connectivity(connectivity)
|
.connectivity(connectivity)
|
||||||
.native_tls(native_tls);
|
.native_tls(native_tls);
|
||||||
|
|
||||||
|
let mut interpreter_request = python_request.map(ToolchainRequest::parse);
|
||||||
|
if preview.is_enabled() && interpreter_request.is_none() {
|
||||||
|
interpreter_request = request_from_version_file().await.into_diagnostic()?;
|
||||||
|
}
|
||||||
|
|
||||||
// Locate the Python interpreter to use in the environment
|
// Locate the Python interpreter to use in the environment
|
||||||
let interpreter = Toolchain::find_or_fetch(
|
let interpreter = Toolchain::find_or_fetch(
|
||||||
python_request.map(ToolchainRequest::parse),
|
interpreter_request,
|
||||||
SystemPython::Required,
|
SystemPython::Required,
|
||||||
preview,
|
preview,
|
||||||
client_builder,
|
client_builder,
|
||||||
|
|
|
@ -88,6 +88,114 @@ fn create_venv_ignores_virtual_env_variable() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_venv_reads_request_from_python_version_file() {
|
||||||
|
let context = TestContext::new_with_versions(&["3.11", "3.12"]);
|
||||||
|
|
||||||
|
// Without the file, we should use the first on the PATH
|
||||||
|
uv_snapshot!(context.filters(), context.venv()
|
||||||
|
.arg("--preview"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Using Python 3.11.[X] interpreter at: [PYTHON-3.11]
|
||||||
|
Creating virtualenv at: .venv
|
||||||
|
Activate with: source .venv/bin/activate
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
|
||||||
|
// With a version file, we should prefer that version
|
||||||
|
context
|
||||||
|
.temp_dir
|
||||||
|
.child(".python-version")
|
||||||
|
.write_str("3.12")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.venv()
|
||||||
|
.arg("--preview"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||||
|
Creating virtualenv at: .venv
|
||||||
|
Activate with: source .venv/bin/activate
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
|
||||||
|
context.venv.assert(predicates::path::is_dir());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_venv_reads_request_from_python_versions_file() {
|
||||||
|
let context = TestContext::new_with_versions(&["3.11", "3.12"]);
|
||||||
|
|
||||||
|
// Without the file, we should use the first on the PATH
|
||||||
|
uv_snapshot!(context.filters(), context.venv()
|
||||||
|
.arg("--preview"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Using Python 3.11.[X] interpreter at: [PYTHON-3.11]
|
||||||
|
Creating virtualenv at: .venv
|
||||||
|
Activate with: source .venv/bin/activate
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
|
||||||
|
// With a versions file, we should prefer the first listed version
|
||||||
|
context
|
||||||
|
.temp_dir
|
||||||
|
.child(".python-versions")
|
||||||
|
.write_str("3.12\n3.11")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.venv()
|
||||||
|
.arg("--preview"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
|
||||||
|
Creating virtualenv at: .venv
|
||||||
|
Activate with: source .venv/bin/activate
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
|
||||||
|
context.venv.assert(predicates::path::is_dir());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn create_venv_explicit_request_takes_priority_over_python_version_file() {
|
||||||
|
let context = TestContext::new_with_versions(&["3.11", "3.12"]);
|
||||||
|
|
||||||
|
context
|
||||||
|
.temp_dir
|
||||||
|
.child(".python-version")
|
||||||
|
.write_str("3.12")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.venv()
|
||||||
|
.arg("--preview").arg("--python").arg("3.11"), @r###"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
Using Python 3.11.[X] interpreter at: [PYTHON-3.11]
|
||||||
|
Creating virtualenv at: .venv
|
||||||
|
Activate with: source .venv/bin/activate
|
||||||
|
"###
|
||||||
|
);
|
||||||
|
|
||||||
|
context.venv.assert(predicates::path::is_dir());
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn seed() {
|
fn seed() {
|
||||||
let context = TestContext::new_with_versions(&["3.12"]);
|
let context = TestContext::new_with_versions(&["3.12"]);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue