mirror of https://github.com/astral-sh/uv
Download versions in `uv python pin` if not found (#13946)
As another follow-up in the vein of https://github.com/astral-sh/uv/pull/13944, I noticed `uv python pin` doesn't download Python versions, which is a bit weird because we'll warn it's not found.
This commit is contained in:
parent
210b579188
commit
f20a25f91f
|
|
@ -7,17 +7,22 @@ use owo_colors::OwoColorize;
|
||||||
use tracing::debug;
|
use tracing::debug;
|
||||||
|
|
||||||
use uv_cache::Cache;
|
use uv_cache::Cache;
|
||||||
|
use uv_client::BaseClientBuilder;
|
||||||
use uv_dirs::user_uv_config_dir;
|
use uv_dirs::user_uv_config_dir;
|
||||||
use uv_fs::Simplified;
|
use uv_fs::Simplified;
|
||||||
use uv_python::{
|
use uv_python::{
|
||||||
EnvironmentPreference, PYTHON_VERSION_FILENAME, PythonInstallation, PythonPreference,
|
EnvironmentPreference, PYTHON_VERSION_FILENAME, PythonDownloads, PythonInstallation,
|
||||||
PythonRequest, PythonVersionFile, VersionFileDiscoveryOptions,
|
PythonPreference, PythonRequest, PythonVersionFile, VersionFileDiscoveryOptions,
|
||||||
};
|
};
|
||||||
|
use uv_settings::PythonInstallMirrors;
|
||||||
use uv_warnings::warn_user_once;
|
use uv_warnings::warn_user_once;
|
||||||
use uv_workspace::{DiscoveryOptions, VirtualProject, WorkspaceCache};
|
use uv_workspace::{DiscoveryOptions, VirtualProject, WorkspaceCache};
|
||||||
|
|
||||||
use crate::commands::{ExitStatus, project::find_requires_python};
|
use crate::commands::{
|
||||||
|
ExitStatus, project::find_requires_python, reporters::PythonDownloadReporter,
|
||||||
|
};
|
||||||
use crate::printer::Printer;
|
use crate::printer::Printer;
|
||||||
|
use crate::settings::NetworkSettings;
|
||||||
|
|
||||||
/// Pin to a specific Python version.
|
/// Pin to a specific Python version.
|
||||||
#[allow(clippy::fn_params_excessive_bools)]
|
#[allow(clippy::fn_params_excessive_bools)]
|
||||||
|
|
@ -26,9 +31,12 @@ pub(crate) async fn pin(
|
||||||
request: Option<String>,
|
request: Option<String>,
|
||||||
resolved: bool,
|
resolved: bool,
|
||||||
python_preference: PythonPreference,
|
python_preference: PythonPreference,
|
||||||
|
python_downloads: PythonDownloads,
|
||||||
no_project: bool,
|
no_project: bool,
|
||||||
global: bool,
|
global: bool,
|
||||||
rm: bool,
|
rm: bool,
|
||||||
|
install_mirrors: PythonInstallMirrors,
|
||||||
|
network_settings: NetworkSettings,
|
||||||
cache: &Cache,
|
cache: &Cache,
|
||||||
printer: Printer,
|
printer: Printer,
|
||||||
) -> Result<ExitStatus> {
|
) -> Result<ExitStatus> {
|
||||||
|
|
@ -98,12 +106,26 @@ pub(crate) async fn pin(
|
||||||
bail!("Requests for arbitrary names (e.g., `{name}`) are not supported in version files");
|
bail!("Requests for arbitrary names (e.g., `{name}`) are not supported in version files");
|
||||||
}
|
}
|
||||||
|
|
||||||
let python = match PythonInstallation::find(
|
let client_builder = BaseClientBuilder::new()
|
||||||
&request,
|
.connectivity(network_settings.connectivity)
|
||||||
|
.native_tls(network_settings.native_tls)
|
||||||
|
.allow_insecure_host(network_settings.allow_insecure_host.clone());
|
||||||
|
let reporter = PythonDownloadReporter::single(printer);
|
||||||
|
|
||||||
|
let python = match PythonInstallation::find_or_download(
|
||||||
|
Some(&request),
|
||||||
EnvironmentPreference::OnlySystem,
|
EnvironmentPreference::OnlySystem,
|
||||||
python_preference,
|
python_preference,
|
||||||
|
python_downloads,
|
||||||
|
&client_builder,
|
||||||
cache,
|
cache,
|
||||||
) {
|
Some(&reporter),
|
||||||
|
install_mirrors.python_install_mirror.as_deref(),
|
||||||
|
install_mirrors.pypy_install_mirror.as_deref(),
|
||||||
|
install_mirrors.python_downloads_json_url.as_deref(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(python) => Some(python),
|
Ok(python) => Some(python),
|
||||||
// If no matching Python version is found, don't fail unless `resolved` was requested
|
// If no matching Python version is found, don't fail unless `resolved` was requested
|
||||||
Err(uv_python::Error::MissingPython(err)) if !resolved => {
|
Err(uv_python::Error::MissingPython(err)) if !resolved => {
|
||||||
|
|
|
||||||
|
|
@ -1464,9 +1464,12 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
|
||||||
args.request,
|
args.request,
|
||||||
args.resolved,
|
args.resolved,
|
||||||
globals.python_preference,
|
globals.python_preference,
|
||||||
|
globals.python_downloads,
|
||||||
args.no_project,
|
args.no_project,
|
||||||
args.global,
|
args.global,
|
||||||
args.rm,
|
args.rm,
|
||||||
|
args.install_mirrors,
|
||||||
|
globals.network_settings,
|
||||||
&cache,
|
&cache,
|
||||||
printer,
|
printer,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -1057,12 +1057,13 @@ pub(crate) struct PythonPinSettings {
|
||||||
pub(crate) no_project: bool,
|
pub(crate) no_project: bool,
|
||||||
pub(crate) global: bool,
|
pub(crate) global: bool,
|
||||||
pub(crate) rm: bool,
|
pub(crate) rm: bool,
|
||||||
|
pub(crate) install_mirrors: PythonInstallMirrors,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PythonPinSettings {
|
impl PythonPinSettings {
|
||||||
/// Resolve the [`PythonPinSettings`] from the CLI and workspace configuration.
|
/// Resolve the [`PythonPinSettings`] from the CLI and workspace configuration.
|
||||||
#[allow(clippy::needless_pass_by_value)]
|
#[allow(clippy::needless_pass_by_value)]
|
||||||
pub(crate) fn resolve(args: PythonPinArgs, _filesystem: Option<FilesystemOptions>) -> Self {
|
pub(crate) fn resolve(args: PythonPinArgs, filesystem: Option<FilesystemOptions>) -> Self {
|
||||||
let PythonPinArgs {
|
let PythonPinArgs {
|
||||||
request,
|
request,
|
||||||
no_resolved,
|
no_resolved,
|
||||||
|
|
@ -1072,12 +1073,17 @@ impl PythonPinSettings {
|
||||||
rm,
|
rm,
|
||||||
} = args;
|
} = args;
|
||||||
|
|
||||||
|
let install_mirrors = filesystem
|
||||||
|
.map(|fs| fs.install_mirrors.clone())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
request,
|
request,
|
||||||
resolved: flag(resolved, no_resolved).unwrap_or(false),
|
resolved: flag(resolved, no_resolved).unwrap_or(false),
|
||||||
no_project,
|
no_project,
|
||||||
global,
|
global,
|
||||||
rm,
|
rm,
|
||||||
|
install_mirrors,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -816,6 +816,32 @@ fn python_pin_with_comments() -> Result<()> {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(feature = "python-managed")]
|
||||||
|
fn python_pin_install() {
|
||||||
|
let context: TestContext = TestContext::new_with_versions(&[]).with_filtered_python_sources();
|
||||||
|
|
||||||
|
// Should not install 3.12 when downloads are not automatic
|
||||||
|
uv_snapshot!(context.filters(), context.python_pin().arg("3.12"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
Pinned `.python-version` to `3.12`
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
warning: No interpreter found for Python 3.12 in [PYTHON SOURCES]
|
||||||
|
");
|
||||||
|
|
||||||
|
uv_snapshot!(context.filters(), context.python_pin().arg("3.12").env("UV_PYTHON_DOWNLOADS", "auto"), @r"
|
||||||
|
success: true
|
||||||
|
exit_code: 0
|
||||||
|
----- stdout -----
|
||||||
|
Pinned `.python-version` to `3.12`
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
");
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn python_pin_rm() {
|
fn python_pin_rm() {
|
||||||
let context: TestContext = TestContext::new_with_versions(&["3.12"]);
|
let context: TestContext = TestContext::new_with_versions(&["3.12"]);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue