Make Python and PyPy install mirrors configurable in uv.toml (#8695)

<!--
Thank you for contributing to uv! To help us out with reviewing, please
consider the following:

- Does this pull request include a summary of the change? (See below.)
-->

## Summary

Adds python-install-mirror and pypy-install-mirror as keys for uv.toml,
and cli args for `uv python install`.

Could leave the cli args out if we think the env vars and configs are
sufficient.

Fixes #8186 

<!-- What's the purpose of the change? What does it do, and why? -->

---------

Co-authored-by: Zanie Blue <contact@zanie.dev>
This commit is contained in:
Owen Brooks 2024-11-14 03:08:55 +11:00 committed by GitHub
parent 2966471db2
commit 2ea81b3b55
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
29 changed files with 573 additions and 27 deletions

View file

@ -3938,6 +3938,22 @@ pub struct PythonInstallArgs {
/// See `uv help python` to view supported request formats. /// See `uv help python` to view supported request formats.
pub targets: Vec<String>, pub targets: Vec<String>,
/// Set the URL to use as the source for downloading Python installations.
///
/// The provided URL will replace `https://github.com/indygreg/python-build-standalone/releases/download` in, e.g., `https://github.com/indygreg/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz`.
///
/// Distributions can be read from a local directory by using the `file://` URL scheme.
#[arg(long, env = EnvVars::UV_PYTHON_INSTALL_MIRROR)]
pub mirror: Option<String>,
/// Set the URL to use as the source for downloading PyPy installations.
///
/// The provided URL will replace `https://downloads.python.org/pypy` in, e.g., `https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2`.
///
/// Distributions can be read from a local directory by using the `file://` URL scheme.
#[arg(long, env = EnvVars::UV_PYPY_INSTALL_MIRROR)]
pub pypy_mirror: Option<String>,
/// Reinstall the requested Python version, if it's already installed. /// Reinstall the requested Python version, if it's already installed.
/// ///
/// By default, uv will exit successfully if the version is already /// By default, uv will exit successfully if the version is already

View file

@ -466,9 +466,11 @@ impl ManagedPythonDownload {
installation_dir: &Path, installation_dir: &Path,
cache_dir: &Path, cache_dir: &Path,
reinstall: bool, reinstall: bool,
python_install_mirror: Option<String>,
pypy_install_mirror: Option<String>,
reporter: Option<&dyn Reporter>, reporter: Option<&dyn Reporter>,
) -> Result<DownloadResult, Error> { ) -> Result<DownloadResult, Error> {
let url = self.download_url()?; let url = self.download_url(python_install_mirror, pypy_install_mirror)?;
let path = installation_dir.join(self.key().to_string()); let path = installation_dir.join(self.key().to_string());
// If it is not a reinstall and the dir already exists, return it. // If it is not a reinstall and the dir already exists, return it.
@ -585,10 +587,14 @@ impl ManagedPythonDownload {
/// Return the [`Url`] to use when downloading the distribution. If a mirror is set via the /// Return the [`Url`] to use when downloading the distribution. If a mirror is set via the
/// appropriate environment variable, use it instead. /// appropriate environment variable, use it instead.
fn download_url(&self) -> Result<Url, Error> { fn download_url(
&self,
python_install_mirror: Option<String>,
pypy_install_mirror: Option<String>,
) -> Result<Url, Error> {
match self.key.implementation { match self.key.implementation {
LenientImplementationName::Known(ImplementationName::CPython) => { LenientImplementationName::Known(ImplementationName::CPython) => {
if let Ok(mirror) = std::env::var(EnvVars::UV_PYTHON_INSTALL_MIRROR) { if let Some(mirror) = python_install_mirror {
let Some(suffix) = self.url.strip_prefix( let Some(suffix) = self.url.strip_prefix(
"https://github.com/indygreg/python-build-standalone/releases/download/", "https://github.com/indygreg/python-build-standalone/releases/download/",
) else { ) else {
@ -601,7 +607,7 @@ impl ManagedPythonDownload {
} }
LenientImplementationName::Known(ImplementationName::PyPy) => { LenientImplementationName::Known(ImplementationName::PyPy) => {
if let Ok(mirror) = std::env::var(EnvVars::UV_PYPY_INSTALL_MIRROR) { if let Some(mirror) = pypy_install_mirror {
let Some(suffix) = self.url.strip_prefix("https://downloads.python.org/pypy/") let Some(suffix) = self.url.strip_prefix("https://downloads.python.org/pypy/")
else { else {
return Err(Error::Mirror(EnvVars::UV_PYPY_INSTALL_MIRROR, self.url)); return Err(Error::Mirror(EnvVars::UV_PYPY_INSTALL_MIRROR, self.url));

View file

@ -86,6 +86,8 @@ impl PythonInstallation {
client_builder: &BaseClientBuilder<'a>, client_builder: &BaseClientBuilder<'a>,
cache: &Cache, cache: &Cache,
reporter: Option<&dyn Reporter>, reporter: Option<&dyn Reporter>,
python_install_mirror: Option<String>,
pypy_install_mirror: Option<String>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let request = request.unwrap_or_else(|| &PythonRequest::Default); let request = request.unwrap_or_else(|| &PythonRequest::Default);
@ -100,7 +102,16 @@ impl PythonInstallation {
{ {
if let Some(request) = PythonDownloadRequest::from_request(request) { if let Some(request) = PythonDownloadRequest::from_request(request) {
debug!("Requested Python not found, checking for available download..."); debug!("Requested Python not found, checking for available download...");
match Self::fetch(request.fill()?, client_builder, cache, reporter).await { match Self::fetch(
request.fill()?,
client_builder,
cache,
reporter,
python_install_mirror,
pypy_install_mirror,
)
.await
{
Ok(installation) => Ok(installation), Ok(installation) => Ok(installation),
Err(Error::Download(downloads::Error::NoDownloadFound(_))) => { Err(Error::Download(downloads::Error::NoDownloadFound(_))) => {
Err(Error::MissingPython(err)) Err(Error::MissingPython(err))
@ -121,6 +132,8 @@ impl PythonInstallation {
client_builder: &BaseClientBuilder<'a>, client_builder: &BaseClientBuilder<'a>,
cache: &Cache, cache: &Cache,
reporter: Option<&dyn Reporter>, reporter: Option<&dyn Reporter>,
python_install_mirror: Option<String>,
pypy_install_mirror: Option<String>,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
let installations = ManagedPythonInstallations::from_settings()?.init()?; let installations = ManagedPythonInstallations::from_settings()?.init()?;
let installations_dir = installations.root(); let installations_dir = installations.root();
@ -132,7 +145,15 @@ impl PythonInstallation {
info!("Fetching requested Python..."); info!("Fetching requested Python...");
let result = download let result = download
.fetch(&client, installations_dir, &cache_dir, false, reporter) .fetch(
&client,
installations_dir,
&cache_dir,
false,
python_install_mirror,
pypy_install_mirror,
reporter,
)
.await?; .await?;
let path = match result { let path = match result {

View file

@ -14,6 +14,7 @@ use uv_pep508::Requirement;
use uv_pypi_types::{SupportedEnvironments, VerbatimParsedUrl}; use uv_pypi_types::{SupportedEnvironments, VerbatimParsedUrl};
use uv_python::{PythonDownloads, PythonPreference, PythonVersion}; use uv_python::{PythonDownloads, PythonPreference, PythonVersion};
use uv_resolver::{AnnotationStyle, ExcludeNewer, PrereleaseMode, ResolutionMode}; use uv_resolver::{AnnotationStyle, ExcludeNewer, PrereleaseMode, ResolutionMode};
use uv_static::EnvVars;
/// A `pyproject.toml` with an (optional) `[tool.uv]` section. /// A `pyproject.toml` with an (optional) `[tool.uv]` section.
#[allow(dead_code)] #[allow(dead_code)]
@ -41,6 +42,9 @@ pub struct Options {
#[serde(flatten)] #[serde(flatten)]
pub top_level: ResolverInstallerOptions, pub top_level: ResolverInstallerOptions,
#[serde(flatten)]
pub install_mirrors: PythonInstallMirrors,
#[serde(flatten)] #[serde(flatten)]
pub publish: PublishOptions, pub publish: PublishOptions,
@ -676,6 +680,61 @@ pub struct ResolverInstallerOptions {
pub no_binary_package: Option<Vec<PackageName>>, pub no_binary_package: Option<Vec<PackageName>>,
} }
/// Shared settings, relevant to all operations that might create managed python installations.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, CombineOptions, OptionsMetadata)]
#[serde(rename_all = "kebab-case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct PythonInstallMirrors {
/// Mirror URL for downloading managed Python installations.
///
/// By default, managed Python installations are downloaded from [`python-build-standalone`](https://github.com/indygreg/python-build-standalone).
/// This variable can be set to a mirror URL to use a different source for Python installations.
/// The provided URL will replace `https://github.com/indygreg/python-build-standalone/releases/download` in, e.g., `https://github.com/indygreg/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz`.
///
/// Distributions can be read from a local directory by using the `file://` URL scheme.
#[option(
default = "None",
value_type = "str",
example = r#"
python-install-mirror = "https://github.com/indygreg/python-build-standalone/releases/download"
"#
)]
pub python_install_mirror: Option<String>,
/// Mirror URL to use for downloading managed PyPy installations.
///
/// By default, managed PyPy installations are downloaded from [downloads.python.org](https://downloads.python.org/).
/// This variable can be set to a mirror URL to use a different source for PyPy installations.
/// The provided URL will replace `https://downloads.python.org/pypy` in, e.g., `https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2`.
///
/// Distributions can be read from a
/// local directory by using the `file://` URL scheme.
#[option(
default = "None",
value_type = "str",
example = r#"
pypy-install-mirror = "https://downloads.python.org/pypy"
"#
)]
pub pypy_install_mirror: Option<String>,
}
impl Default for PythonInstallMirrors {
fn default() -> Self {
PythonInstallMirrors::resolve(None, None)
}
}
impl PythonInstallMirrors {
pub fn resolve(python_mirror: Option<String>, pypy_mirror: Option<String>) -> Self {
let python_mirror_env = std::env::var(EnvVars::UV_PYTHON_INSTALL_MIRROR).ok();
let pypy_mirror_env = std::env::var(EnvVars::UV_PYPY_INSTALL_MIRROR).ok();
PythonInstallMirrors {
python_install_mirror: python_mirror_env.or(python_mirror),
pypy_install_mirror: pypy_mirror_env.or(pypy_mirror),
}
}
}
/// Settings that are specific to the `uv pip` command-line interface. /// Settings that are specific to the `uv pip` command-line interface.
/// ///
/// These values will be ignored when running commands outside the `uv pip` namespace (e.g., /// These values will be ignored when running commands outside the `uv pip` namespace (e.g.,
@ -1544,6 +1603,11 @@ pub struct OptionsWire {
no_binary: Option<bool>, no_binary: Option<bool>,
no_binary_package: Option<Vec<PackageName>>, no_binary_package: Option<Vec<PackageName>>,
// #[serde(flatten)]
// install_mirror: PythonInstallMirrors,
python_install_mirror: Option<String>,
pypy_install_mirror: Option<String>,
// #[serde(flatten)] // #[serde(flatten)]
// publish: PublishOptions // publish: PublishOptions
publish_url: Option<Url>, publish_url: Option<Url>,
@ -1581,6 +1645,8 @@ impl From<OptionsWire> for Options {
preview, preview,
python_preference, python_preference,
python_downloads, python_downloads,
python_install_mirror,
pypy_install_mirror,
concurrent_downloads, concurrent_downloads,
concurrent_builds, concurrent_builds,
concurrent_installs, concurrent_installs,
@ -1673,6 +1739,10 @@ impl From<OptionsWire> for Options {
override_dependencies, override_dependencies,
constraint_dependencies, constraint_dependencies,
environments, environments,
install_mirrors: PythonInstallMirrors::resolve(
python_install_mirror,
pypy_install_mirror,
),
conflicting_groups, conflicting_groups,
publish: PublishOptions { publish: PublishOptions {
publish_url, publish_url,

View file

@ -28,6 +28,7 @@ use uv_python::{
}; };
use uv_requirements::RequirementsSource; use uv_requirements::RequirementsSource;
use uv_resolver::{ExcludeNewer, FlatIndex, RequiresPython}; use uv_resolver::{ExcludeNewer, FlatIndex, RequiresPython};
use uv_settings::PythonInstallMirrors;
use uv_types::{BuildContext, BuildIsolation, HashStrategy}; use uv_types::{BuildContext, BuildIsolation, HashStrategy};
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceError}; use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceError};
@ -52,6 +53,7 @@ pub(crate) async fn build_frontend(
build_constraints: Vec<RequirementsSource>, build_constraints: Vec<RequirementsSource>,
hash_checking: Option<HashCheckingMode>, hash_checking: Option<HashCheckingMode>,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
settings: ResolverSettings, settings: ResolverSettings,
no_config: bool, no_config: bool,
python_preference: PythonPreference, python_preference: PythonPreference,
@ -75,6 +77,7 @@ pub(crate) async fn build_frontend(
&build_constraints, &build_constraints,
hash_checking, hash_checking,
python.as_deref(), python.as_deref(),
install_mirrors,
settings.as_ref(), settings.as_ref(),
no_config, no_config,
python_preference, python_preference,
@ -116,6 +119,7 @@ async fn build_impl(
build_constraints: &[RequirementsSource], build_constraints: &[RequirementsSource],
hash_checking: Option<HashCheckingMode>, hash_checking: Option<HashCheckingMode>,
python_request: Option<&str>, python_request: Option<&str>,
install_mirrors: PythonInstallMirrors,
settings: ResolverSettingsRef<'_>, settings: ResolverSettingsRef<'_>,
no_config: bool, no_config: bool,
python_preference: PythonPreference, python_preference: PythonPreference,
@ -251,6 +255,7 @@ async fn build_impl(
source.clone(), source.clone(),
output_dir, output_dir,
python_request, python_request,
install_mirrors.clone(),
no_config, no_config,
workspace.as_ref(), workspace.as_ref(),
python_preference, python_preference,
@ -346,6 +351,7 @@ async fn build_package(
source: AnnotatedSource<'_>, source: AnnotatedSource<'_>,
output_dir: Option<&Path>, output_dir: Option<&Path>,
python_request: Option<&str>, python_request: Option<&str>,
install_mirrors: PythonInstallMirrors,
no_config: bool, no_config: bool,
workspace: Result<&Workspace, &WorkspaceError>, workspace: Result<&Workspace, &WorkspaceError>,
python_preference: PythonPreference, python_preference: PythonPreference,
@ -424,6 +430,8 @@ async fn build_package(
client_builder, client_builder,
cache, cache,
Some(&PythonDownloadReporter::single(printer)), Some(&PythonDownloadReporter::single(printer)),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await? .await?
.into_interpreter(); .into_interpreter();

View file

@ -33,6 +33,7 @@ use uv_python::{
use uv_requirements::{NamedRequirementsResolver, RequirementsSource, RequirementsSpecification}; use uv_requirements::{NamedRequirementsResolver, RequirementsSource, RequirementsSpecification};
use uv_resolver::{FlatIndex, InstallTarget}; use uv_resolver::{FlatIndex, InstallTarget};
use uv_scripts::{Pep723Item, Pep723Script}; use uv_scripts::{Pep723Item, Pep723Script};
use uv_settings::PythonInstallMirrors;
use uv_types::{BuildIsolation, HashStrategy}; use uv_types::{BuildIsolation, HashStrategy};
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
use uv_workspace::pyproject::{DependencyType, Source, SourceError}; use uv_workspace::pyproject::{DependencyType, Source, SourceError};
@ -71,6 +72,7 @@ pub(crate) async fn add(
extras: Vec<ExtraName>, extras: Vec<ExtraName>,
package: Option<PackageName>, package: Option<PackageName>,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
settings: ResolverInstallerSettings, settings: ResolverInstallerSettings,
script: Option<PathBuf>, script: Option<PathBuf>,
python_preference: PythonPreference, python_preference: PythonPreference,
@ -140,6 +142,7 @@ pub(crate) async fn add(
} else { } else {
let requires_python = init_script_python_requirement( let requires_python = init_script_python_requirement(
python.as_deref(), python.as_deref(),
install_mirrors.clone(),
project_dir, project_dir,
false, false,
python_preference, python_preference,
@ -173,6 +176,8 @@ pub(crate) async fn add(
&client_builder, &client_builder,
cache, cache,
Some(&reporter), Some(&reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await? .await?
.into_interpreter(); .into_interpreter();
@ -227,6 +232,7 @@ pub(crate) async fn add(
connectivity, connectivity,
native_tls, native_tls,
allow_insecure_host, allow_insecure_host,
install_mirrors.clone(),
no_config, no_config,
cache, cache,
printer, printer,
@ -240,6 +246,7 @@ pub(crate) async fn add(
let venv = project::get_or_init_environment( let venv = project::get_or_init_environment(
project.workspace(), project.workspace(),
python.as_deref().map(PythonRequest::parse), python.as_deref().map(PythonRequest::parse),
install_mirrors.clone(),
python_preference, python_preference,
python_downloads, python_downloads,
connectivity, connectivity,

View file

@ -4,6 +4,7 @@ use anyhow::{Context, Result};
use itertools::Itertools; use itertools::Itertools;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use uv_settings::PythonInstallMirrors;
use uv_cache::Cache; use uv_cache::Cache;
use uv_client::Connectivity; use uv_client::Connectivity;
@ -42,6 +43,7 @@ pub(crate) async fn export(
frozen: bool, frozen: bool,
include_header: bool, include_header: bool,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
settings: ResolverSettings, settings: ResolverSettings,
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
@ -107,6 +109,7 @@ pub(crate) async fn export(
connectivity, connectivity,
native_tls, native_tls,
allow_insecure_host, allow_insecure_host,
install_mirrors,
no_config, no_config,
cache, cache,
printer, printer,

View file

@ -23,6 +23,7 @@ use uv_python::{
}; };
use uv_resolver::RequiresPython; use uv_resolver::RequiresPython;
use uv_scripts::{Pep723Script, ScriptTag}; use uv_scripts::{Pep723Script, ScriptTag};
use uv_settings::PythonInstallMirrors;
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
use uv_workspace::pyproject_mut::{DependencyTarget, PyProjectTomlMut}; use uv_workspace::pyproject_mut::{DependencyTarget, PyProjectTomlMut};
use uv_workspace::{DiscoveryOptions, MemberDiscovery, Workspace, WorkspaceError}; use uv_workspace::{DiscoveryOptions, MemberDiscovery, Workspace, WorkspaceError};
@ -46,6 +47,7 @@ pub(crate) async fn init(
author_from: Option<AuthorFrom>, author_from: Option<AuthorFrom>,
no_pin_python: bool, no_pin_python: bool,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
no_workspace: bool, no_workspace: bool,
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
@ -65,6 +67,7 @@ pub(crate) async fn init(
init_script( init_script(
path, path,
python, python,
install_mirrors,
connectivity, connectivity,
python_preference, python_preference,
python_downloads, python_downloads,
@ -128,6 +131,7 @@ pub(crate) async fn init(
author_from, author_from,
no_pin_python, no_pin_python,
python, python,
install_mirrors,
no_workspace, no_workspace,
python_preference, python_preference,
python_downloads, python_downloads,
@ -175,6 +179,7 @@ pub(crate) async fn init(
async fn init_script( async fn init_script(
script_path: &Path, script_path: &Path,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
connectivity: Connectivity, connectivity: Connectivity,
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
@ -233,6 +238,7 @@ async fn init_script(
let requires_python = init_script_python_requirement( let requires_python = init_script_python_requirement(
python.as_deref(), python.as_deref(),
install_mirrors,
&CWD, &CWD,
no_pin_python, no_pin_python,
python_preference, python_preference,
@ -266,6 +272,7 @@ async fn init_project(
author_from: Option<AuthorFrom>, author_from: Option<AuthorFrom>,
no_pin_python: bool, no_pin_python: bool,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
no_workspace: bool, no_workspace: bool,
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
@ -416,6 +423,8 @@ async fn init_project(
&client_builder, &client_builder,
cache, cache,
Some(&reporter), Some(&reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await? .await?
.into_interpreter(); .into_interpreter();
@ -438,6 +447,8 @@ async fn init_project(
&client_builder, &client_builder,
cache, cache,
Some(&reporter), Some(&reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await? .await?
.into_interpreter(); .into_interpreter();
@ -498,6 +509,8 @@ async fn init_project(
&client_builder, &client_builder,
cache, cache,
Some(&reporter), Some(&reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await? .await?
.into_interpreter(); .into_interpreter();
@ -520,6 +533,8 @@ async fn init_project(
&client_builder, &client_builder,
cache, cache,
Some(&reporter), Some(&reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await? .await?
.into_interpreter(); .into_interpreter();

View file

@ -30,6 +30,7 @@ use uv_resolver::{
FlatIndex, InMemoryIndex, Lock, LockVersion, Options, OptionsBuilder, PythonRequirement, FlatIndex, InMemoryIndex, Lock, LockVersion, Options, OptionsBuilder, PythonRequirement,
RequiresPython, ResolverEnvironment, ResolverManifest, SatisfiesResult, VERSION, RequiresPython, ResolverEnvironment, ResolverManifest, SatisfiesResult, VERSION,
}; };
use uv_settings::PythonInstallMirrors;
use uv_types::{BuildContext, BuildIsolation, EmptyInstalledPackages, HashStrategy}; use uv_types::{BuildContext, BuildIsolation, EmptyInstalledPackages, HashStrategy};
use uv_warnings::{warn_user, warn_user_once}; use uv_warnings::{warn_user, warn_user_once};
use uv_workspace::{DiscoveryOptions, Workspace}; use uv_workspace::{DiscoveryOptions, Workspace};
@ -76,6 +77,7 @@ pub(crate) async fn lock(
frozen: bool, frozen: bool,
dry_run: bool, dry_run: bool,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
settings: ResolverSettings, settings: ResolverSettings,
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
@ -105,6 +107,7 @@ pub(crate) async fn lock(
connectivity, connectivity,
native_tls, native_tls,
allow_insecure_host, allow_insecure_host,
install_mirrors,
no_config, no_config,
cache, cache,
printer, printer,

View file

@ -35,6 +35,7 @@ use uv_resolver::{
ResolverEnvironment, ResolverEnvironment,
}; };
use uv_scripts::Pep723Item; use uv_scripts::Pep723Item;
use uv_settings::PythonInstallMirrors;
use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy}; use uv_types::{BuildIsolation, EmptyInstalledPackages, HashStrategy};
use uv_warnings::{warn_user, warn_user_once}; use uv_warnings::{warn_user, warn_user_once};
use uv_workspace::dependency_groups::DependencyGroupError; use uv_workspace::dependency_groups::DependencyGroupError;
@ -544,6 +545,7 @@ impl ProjectInterpreter {
connectivity: Connectivity, connectivity: Connectivity,
native_tls: bool, native_tls: bool,
allow_insecure_host: &[TrustedHost], allow_insecure_host: &[TrustedHost],
install_mirrors: PythonInstallMirrors,
no_config: bool, no_config: bool,
cache: &Cache, cache: &Cache,
printer: Printer, printer: Printer,
@ -638,6 +640,8 @@ impl ProjectInterpreter {
&client_builder, &client_builder,
cache, cache,
Some(&reporter), Some(&reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await?; .await?;
@ -682,6 +686,7 @@ impl ProjectInterpreter {
pub(crate) async fn get_or_init_environment( pub(crate) async fn get_or_init_environment(
workspace: &Workspace, workspace: &Workspace,
python: Option<PythonRequest>, python: Option<PythonRequest>,
install_mirrors: PythonInstallMirrors,
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
connectivity: Connectivity, connectivity: Connectivity,
@ -700,6 +705,7 @@ pub(crate) async fn get_or_init_environment(
connectivity, connectivity,
native_tls, native_tls,
allow_insecure_host, allow_insecure_host,
install_mirrors,
no_config, no_config,
cache, cache,
printer, printer,
@ -1498,6 +1504,7 @@ pub(crate) async fn update_environment(
/// Determine the [`RequiresPython`] requirement for a new PEP 723 script. /// Determine the [`RequiresPython`] requirement for a new PEP 723 script.
pub(crate) async fn init_script_python_requirement( pub(crate) async fn init_script_python_requirement(
python: Option<&str>, python: Option<&str>,
install_mirrors: PythonInstallMirrors,
directory: &Path, directory: &Path,
no_pin_python: bool, no_pin_python: bool,
python_preference: PythonPreference, python_preference: PythonPreference,
@ -1534,6 +1541,8 @@ pub(crate) async fn init_script_python_requirement(
client_builder, client_builder,
cache, cache,
Some(reporter), Some(reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await? .await?
.into_interpreter(); .into_interpreter();

View file

@ -1,6 +1,7 @@
use anyhow::{Context, Result}; use anyhow::{Context, Result};
use std::fmt::Write; use std::fmt::Write;
use std::path::Path; use std::path::Path;
use uv_settings::PythonInstallMirrors;
use owo_colors::OwoColorize; use owo_colors::OwoColorize;
use uv_cache::Cache; use uv_cache::Cache;
@ -39,6 +40,7 @@ pub(crate) async fn remove(
dependency_type: DependencyType, dependency_type: DependencyType,
package: Option<PackageName>, package: Option<PackageName>,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
settings: ResolverInstallerSettings, settings: ResolverInstallerSettings,
script: Option<Pep723Script>, script: Option<Pep723Script>,
python_preference: PythonPreference, python_preference: PythonPreference,
@ -189,6 +191,7 @@ pub(crate) async fn remove(
let venv = project::get_or_init_environment( let venv = project::get_or_init_environment(
project.workspace(), project.workspace(),
python.as_deref().map(PythonRequest::parse), python.as_deref().map(PythonRequest::parse),
install_mirrors,
python_preference, python_preference,
python_downloads, python_downloads,
connectivity, connectivity,

View file

@ -32,6 +32,7 @@ use uv_python::{
use uv_requirements::{RequirementsSource, RequirementsSpecification}; use uv_requirements::{RequirementsSource, RequirementsSpecification};
use uv_resolver::{InstallTarget, Lock}; use uv_resolver::{InstallTarget, Lock};
use uv_scripts::Pep723Item; use uv_scripts::Pep723Item;
use uv_settings::PythonInstallMirrors;
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_warnings::warn_user; use uv_warnings::warn_user;
use uv_workspace::{DiscoveryOptions, VirtualProject, Workspace, WorkspaceError}; use uv_workspace::{DiscoveryOptions, VirtualProject, Workspace, WorkspaceError};
@ -71,6 +72,7 @@ pub(crate) async fn run(
dev: DevGroupsSpecification, dev: DevGroupsSpecification,
editable: EditableMode, editable: EditableMode,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
settings: ResolverInstallerSettings, settings: ResolverInstallerSettings,
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
@ -201,6 +203,8 @@ pub(crate) async fn run(
&client_builder, &client_builder,
cache, cache,
Some(&download_reporter), Some(&download_reporter),
install_mirrors.python_install_mirror.clone(),
install_mirrors.pypy_install_mirror.clone(),
) )
.await? .await?
.into_interpreter(); .into_interpreter();
@ -509,6 +513,8 @@ pub(crate) async fn run(
&client_builder, &client_builder,
cache, cache,
Some(&download_reporter), Some(&download_reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await? .await?
.into_interpreter(); .into_interpreter();
@ -539,6 +545,7 @@ pub(crate) async fn run(
project::get_or_init_environment( project::get_or_init_environment(
project.workspace(), project.workspace(),
python.as_deref().map(PythonRequest::parse), python.as_deref().map(PythonRequest::parse),
install_mirrors,
python_preference, python_preference,
python_downloads, python_downloads,
connectivity, connectivity,
@ -712,6 +719,8 @@ pub(crate) async fn run(
&client_builder, &client_builder,
cache, cache,
Some(&download_reporter), Some(&download_reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await?; .await?;

View file

@ -22,6 +22,7 @@ use uv_pypi_types::{
}; };
use uv_python::{PythonDownloads, PythonEnvironment, PythonPreference, PythonRequest}; use uv_python::{PythonDownloads, PythonEnvironment, PythonPreference, PythonRequest};
use uv_resolver::{FlatIndex, InstallTarget}; use uv_resolver::{FlatIndex, InstallTarget};
use uv_settings::PythonInstallMirrors;
use uv_types::{BuildIsolation, HashStrategy}; use uv_types::{BuildIsolation, HashStrategy};
use uv_warnings::warn_user; use uv_warnings::warn_user;
use uv_workspace::pyproject::{DependencyGroupSpecifier, Source, Sources, ToolUvSources}; use uv_workspace::pyproject::{DependencyGroupSpecifier, Source, Sources, ToolUvSources};
@ -52,6 +53,7 @@ pub(crate) async fn sync(
install_options: InstallOptions, install_options: InstallOptions,
modifications: Modifications, modifications: Modifications,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
settings: ResolverInstallerSettings, settings: ResolverInstallerSettings,
@ -114,6 +116,7 @@ pub(crate) async fn sync(
let venv = project::get_or_init_environment( let venv = project::get_or_init_environment(
project.workspace(), project.workspace(),
python.as_deref().map(PythonRequest::parse), python.as_deref().map(PythonRequest::parse),
install_mirrors,
python_preference, python_preference,
python_downloads, python_downloads,
connectivity, connectivity,

View file

@ -15,6 +15,7 @@ use uv_pep440::Version;
use uv_pep508::PackageName; use uv_pep508::PackageName;
use uv_python::{PythonDownloads, PythonPreference, PythonRequest, PythonVersion}; use uv_python::{PythonDownloads, PythonPreference, PythonRequest, PythonVersion};
use uv_resolver::{PackageMap, TreeDisplay}; use uv_resolver::{PackageMap, TreeDisplay};
use uv_settings::PythonInstallMirrors;
use uv_workspace::{DiscoveryOptions, Workspace}; use uv_workspace::{DiscoveryOptions, Workspace};
use crate::commands::pip::latest::LatestClient; use crate::commands::pip::latest::LatestClient;
@ -45,6 +46,7 @@ pub(crate) async fn tree(
python_version: Option<PythonVersion>, python_version: Option<PythonVersion>,
python_platform: Option<TargetTriple>, python_platform: Option<TargetTriple>,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
settings: ResolverSettings, settings: ResolverSettings,
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
@ -82,6 +84,7 @@ pub(crate) async fn tree(
connectivity, connectivity,
native_tls, native_tls,
allow_insecure_host, allow_insecure_host,
install_mirrors,
no_config, no_config,
cache, cache,
printer, printer,

View file

@ -113,6 +113,8 @@ pub(crate) async fn install(
targets: Vec<String>, targets: Vec<String>,
reinstall: bool, reinstall: bool,
force: bool, force: bool,
python_install_mirror: Option<String>,
pypy_install_mirror: Option<String>,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
native_tls: bool, native_tls: bool,
connectivity: Connectivity, connectivity: Connectivity,
@ -234,6 +236,8 @@ pub(crate) async fn install(
installations_dir, installations_dir,
&cache_dir, &cache_dir,
reinstall, reinstall,
python_install_mirror.clone(),
pypy_install_mirror.clone(),
Some(&reporter), Some(&reporter),
) )
.await, .await,

View file

@ -17,7 +17,7 @@ use uv_python::{
EnvironmentPreference, PythonDownloads, PythonInstallation, PythonPreference, PythonRequest, EnvironmentPreference, PythonDownloads, PythonInstallation, PythonPreference, PythonRequest,
}; };
use uv_requirements::{RequirementsSource, RequirementsSpecification}; use uv_requirements::{RequirementsSource, RequirementsSpecification};
use uv_settings::{ResolverInstallerOptions, ToolOptions}; use uv_settings::{PythonInstallMirrors, ResolverInstallerOptions, ToolOptions};
use uv_tool::InstalledTools; use uv_tool::InstalledTools;
use uv_warnings::warn_user; use uv_warnings::warn_user;
@ -43,6 +43,7 @@ pub(crate) async fn install(
from: Option<String>, from: Option<String>,
with: &[RequirementsSource], with: &[RequirementsSource],
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
force: bool, force: bool,
options: ResolverInstallerOptions, options: ResolverInstallerOptions,
settings: ResolverInstallerSettings, settings: ResolverInstallerSettings,
@ -74,6 +75,8 @@ pub(crate) async fn install(
&client_builder, &client_builder,
&cache, &cache,
Some(&reporter), Some(&reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await? .await?
.into_interpreter(); .into_interpreter();

View file

@ -26,6 +26,7 @@ use uv_python::{
PythonPreference, PythonRequest, PythonPreference, PythonRequest,
}; };
use uv_requirements::{RequirementsSource, RequirementsSpecification}; use uv_requirements::{RequirementsSource, RequirementsSpecification};
use uv_settings::PythonInstallMirrors;
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_tool::{entrypoint_paths, InstalledTools}; use uv_tool::{entrypoint_paths, InstalledTools};
use uv_warnings::warn_user; use uv_warnings::warn_user;
@ -68,6 +69,7 @@ pub(crate) async fn run(
with: &[RequirementsSource], with: &[RequirementsSource],
show_resolution: bool, show_resolution: bool,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
settings: ResolverInstallerSettings, settings: ResolverInstallerSettings,
invocation_source: ToolRunCommand, invocation_source: ToolRunCommand,
isolated: bool, isolated: bool,
@ -111,6 +113,7 @@ pub(crate) async fn run(
with, with,
show_resolution, show_resolution,
python.as_deref(), python.as_deref(),
install_mirrors,
&settings, &settings,
isolated, isolated,
python_preference, python_preference,
@ -426,6 +429,7 @@ async fn get_or_create_environment(
with: &[RequirementsSource], with: &[RequirementsSource],
show_resolution: bool, show_resolution: bool,
python: Option<&str>, python: Option<&str>,
install_mirrors: PythonInstallMirrors,
settings: &ResolverInstallerSettings, settings: &ResolverInstallerSettings,
isolated: bool, isolated: bool,
python_preference: PythonPreference, python_preference: PythonPreference,
@ -455,6 +459,8 @@ async fn get_or_create_environment(
&client_builder, &client_builder,
cache, cache,
Some(&reporter), Some(&reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await? .await?
.into_interpreter(); .into_interpreter();

View file

@ -14,7 +14,7 @@ use uv_python::{
PythonRequest, PythonRequest,
}; };
use uv_requirements::RequirementsSpecification; use uv_requirements::RequirementsSpecification;
use uv_settings::{Combine, ResolverInstallerOptions, ToolOptions}; use uv_settings::{Combine, PythonInstallMirrors, ResolverInstallerOptions, ToolOptions};
use uv_tool::InstalledTools; use uv_tool::InstalledTools;
use crate::commands::pip::loggers::{ use crate::commands::pip::loggers::{
@ -33,6 +33,7 @@ use crate::settings::ResolverInstallerSettings;
pub(crate) async fn upgrade( pub(crate) async fn upgrade(
name: Vec<PackageName>, name: Vec<PackageName>,
python: Option<String>, python: Option<String>,
install_mirrors: PythonInstallMirrors,
connectivity: Connectivity, connectivity: Connectivity,
args: ResolverInstallerOptions, args: ResolverInstallerOptions,
filesystem: ResolverInstallerOptions, filesystem: ResolverInstallerOptions,
@ -84,6 +85,8 @@ pub(crate) async fn upgrade(
&client_builder, &client_builder,
cache, cache,
Some(&reporter), Some(&reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await? .await?
.into_interpreter(), .into_interpreter(),

View file

@ -24,6 +24,7 @@ use uv_python::{
EnvironmentPreference, PythonDownloads, PythonInstallation, PythonPreference, PythonRequest, EnvironmentPreference, PythonDownloads, PythonInstallation, PythonPreference, PythonRequest,
}; };
use uv_resolver::{ExcludeNewer, FlatIndex}; use uv_resolver::{ExcludeNewer, FlatIndex};
use uv_settings::PythonInstallMirrors;
use uv_shell::Shell; use uv_shell::Shell;
use uv_types::{BuildContext, BuildIsolation, HashStrategy}; use uv_types::{BuildContext, BuildIsolation, HashStrategy};
use uv_warnings::{warn_user, warn_user_once}; use uv_warnings::{warn_user, warn_user_once};
@ -42,6 +43,7 @@ pub(crate) async fn venv(
project_dir: &Path, project_dir: &Path,
path: Option<PathBuf>, path: Option<PathBuf>,
python_request: Option<&str>, python_request: Option<&str>,
install_mirrors: PythonInstallMirrors,
python_preference: PythonPreference, python_preference: PythonPreference,
python_downloads: PythonDownloads, python_downloads: PythonDownloads,
link_mode: LinkMode, link_mode: LinkMode,
@ -68,6 +70,7 @@ pub(crate) async fn venv(
project_dir, project_dir,
path, path,
python_request, python_request,
install_mirrors,
link_mode, link_mode,
index_locations, index_locations,
index_strategy, index_strategy,
@ -125,6 +128,7 @@ async fn venv_impl(
project_dir: &Path, project_dir: &Path,
path: Option<PathBuf>, path: Option<PathBuf>,
python_request: Option<&str>, python_request: Option<&str>,
install_mirrors: PythonInstallMirrors,
link_mode: LinkMode, link_mode: LinkMode,
index_locations: &IndexLocations, index_locations: &IndexLocations,
index_strategy: IndexStrategy, index_strategy: IndexStrategy,
@ -205,6 +209,8 @@ async fn venv_impl(
&client_builder, &client_builder,
cache, cache,
Some(&reporter), Some(&reporter),
install_mirrors.python_install_mirror,
install_mirrors.pypy_install_mirror,
) )
.await .await
.into_diagnostic()?; .into_diagnostic()?;

View file

@ -734,6 +734,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
build_constraints, build_constraints,
args.hash_checking, args.hash_checking,
args.python, args.python,
args.install_mirrors,
args.settings, args.settings,
cli.top_level.no_config, cli.top_level.no_config,
globals.python_preference, globals.python_preference,
@ -778,6 +779,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
&project_dir, &project_dir,
args.path, args.path,
args.settings.python.as_deref(), args.settings.python.as_deref(),
args.settings.install_mirrors,
globals.python_preference, globals.python_preference,
globals.python_downloads, globals.python_downloads,
args.settings.link_mode, args.settings.link_mode,
@ -906,6 +908,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
&requirements, &requirements,
args.show_resolution || globals.verbose > 0, args.show_resolution || globals.verbose > 0,
args.python, args.python,
args.install_mirrors,
args.settings, args.settings,
invocation_source, invocation_source,
args.isolated, args.isolated,
@ -956,6 +959,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.from, args.from,
&requirements, &requirements,
args.python, args.python,
args.install_mirrors,
args.force, args.force,
args.options, args.options,
args.settings, args.settings,
@ -1001,6 +1005,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
Box::pin(commands::tool_upgrade( Box::pin(commands::tool_upgrade(
args.name, args.name,
args.python, args.python,
args.install_mirrors,
globals.connectivity, globals.connectivity,
args.args, args.args,
args.filesystem, args.filesystem,
@ -1072,6 +1077,8 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.targets, args.targets,
args.reinstall, args.reinstall,
args.force, args.force,
args.python_install_mirror,
args.pypy_install_mirror,
globals.python_downloads, globals.python_downloads,
globals.native_tls, globals.native_tls,
globals.connectivity, globals.connectivity,
@ -1274,6 +1281,7 @@ async fn run_project(
args.author_from, args.author_from,
args.no_pin_python, args.no_pin_python,
args.python, args.python,
args.install_mirrors,
args.no_workspace, args.no_workspace,
globals.python_preference, globals.python_preference,
globals.python_downloads, globals.python_downloads,
@ -1332,6 +1340,7 @@ async fn run_project(
args.dev, args.dev,
args.editable, args.editable,
args.python, args.python,
args.install_mirrors,
args.settings, args.settings,
globals.python_preference, globals.python_preference,
globals.python_downloads, globals.python_downloads,
@ -1370,6 +1379,7 @@ async fn run_project(
args.install_options, args.install_options,
args.modifications, args.modifications,
args.python, args.python,
args.install_mirrors,
globals.python_preference, globals.python_preference,
globals.python_downloads, globals.python_downloads,
args.settings, args.settings,
@ -1400,6 +1410,7 @@ async fn run_project(
args.frozen, args.frozen,
args.dry_run, args.dry_run,
args.python, args.python,
args.install_mirrors,
args.settings, args.settings,
globals.python_preference, globals.python_preference,
globals.python_downloads, globals.python_downloads,
@ -1452,6 +1463,7 @@ async fn run_project(
args.extras, args.extras,
args.package, args.package,
args.python, args.python,
args.install_mirrors,
args.settings, args.settings,
args.script, args.script,
globals.python_preference, globals.python_preference,
@ -1494,6 +1506,7 @@ async fn run_project(
args.dependency_type, args.dependency_type,
args.package, args.package,
args.python, args.python,
args.install_mirrors,
args.settings, args.settings,
script, script,
globals.python_preference, globals.python_preference,
@ -1531,6 +1544,7 @@ async fn run_project(
args.python_version, args.python_version,
args.python_platform, args.python_platform,
args.python, args.python,
args.install_mirrors,
args.resolver, args.resolver,
globals.python_preference, globals.python_preference,
globals.python_downloads, globals.python_downloads,
@ -1567,6 +1581,7 @@ async fn run_project(
args.frozen, args.frozen,
args.include_header, args.include_header,
args.python, args.python,
args.install_mirrors,
args.settings, args.settings,
globals.python_preference, globals.python_preference,
globals.python_downloads, globals.python_downloads,

View file

@ -33,8 +33,8 @@ use uv_pypi_types::{Requirement, SupportedEnvironments};
use uv_python::{Prefix, PythonDownloads, PythonPreference, PythonVersion, Target}; use uv_python::{Prefix, PythonDownloads, PythonPreference, PythonVersion, Target};
use uv_resolver::{AnnotationStyle, DependencyMode, ExcludeNewer, PrereleaseMode, ResolutionMode}; use uv_resolver::{AnnotationStyle, DependencyMode, ExcludeNewer, PrereleaseMode, ResolutionMode};
use uv_settings::{ use uv_settings::{
Combine, FilesystemOptions, Options, PipOptions, PublishOptions, ResolverInstallerOptions, Combine, FilesystemOptions, Options, PipOptions, PublishOptions, PythonInstallMirrors,
ResolverOptions, ResolverInstallerOptions, ResolverOptions,
}; };
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_warnings::warn_user_once; use uv_warnings::warn_user_once;
@ -191,12 +191,13 @@ pub(crate) struct InitSettings {
pub(crate) no_pin_python: bool, pub(crate) no_pin_python: bool,
pub(crate) no_workspace: bool, pub(crate) no_workspace: bool,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
} }
impl InitSettings { impl InitSettings {
/// Resolve the [`InitSettings`] from the CLI and filesystem configuration. /// Resolve the [`InitSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: InitArgs, _filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(args: InitArgs, filesystem: Option<FilesystemOptions>) -> Self {
let InitArgs { let InitArgs {
path, path,
name, name,
@ -226,6 +227,10 @@ impl InitSettings {
let package = flag(package || build_backend.is_some(), no_package || r#virtual) let package = flag(package || build_backend.is_some(), no_package || r#virtual)
.unwrap_or(kind.packaged_by_default()); .unwrap_or(kind.packaged_by_default());
let install_mirrors = filesystem
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
Self { Self {
path, path,
name, name,
@ -238,6 +243,7 @@ impl InitSettings {
no_pin_python, no_pin_python,
no_workspace, no_workspace,
python: python.and_then(Maybe::into_option), python: python.and_then(Maybe::into_option),
install_mirrors,
} }
} }
} }
@ -261,6 +267,7 @@ pub(crate) struct RunSettings {
pub(crate) no_project: bool, pub(crate) no_project: bool,
pub(crate) no_sync: bool, pub(crate) no_sync: bool,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh, pub(crate) refresh: Refresh,
pub(crate) settings: ResolverInstallerSettings, pub(crate) settings: ResolverInstallerSettings,
pub(crate) env_file: Vec<PathBuf>, pub(crate) env_file: Vec<PathBuf>,
@ -304,6 +311,11 @@ impl RunSettings {
no_env_file, no_env_file,
} = args; } = args;
let install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
Self { Self {
locked, locked,
frozen, frozen,
@ -341,6 +353,7 @@ impl RunSettings {
), ),
env_file, env_file,
no_env_file, no_env_file,
install_mirrors,
} }
} }
} }
@ -357,6 +370,7 @@ pub(crate) struct ToolRunSettings {
pub(crate) isolated: bool, pub(crate) isolated: bool,
pub(crate) show_resolution: bool, pub(crate) show_resolution: bool,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh, pub(crate) refresh: Refresh,
pub(crate) settings: ResolverInstallerSettings, pub(crate) settings: ResolverInstallerSettings,
} }
@ -402,6 +416,11 @@ impl ToolRunSettings {
} }
} }
let install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
Self { Self {
command, command,
from, from,
@ -425,6 +444,7 @@ impl ToolRunSettings {
resolver_installer_options(installer, build), resolver_installer_options(installer, build),
filesystem, filesystem,
), ),
install_mirrors,
} }
} }
} }
@ -444,6 +464,7 @@ pub(crate) struct ToolInstallSettings {
pub(crate) settings: ResolverInstallerSettings, pub(crate) settings: ResolverInstallerSettings,
pub(crate) force: bool, pub(crate) force: bool,
pub(crate) editable: bool, pub(crate) editable: bool,
pub(crate) install_mirrors: PythonInstallMirrors,
} }
impl ToolInstallSettings { impl ToolInstallSettings {
@ -466,11 +487,17 @@ impl ToolInstallSettings {
let options = resolver_installer_options(installer, build).combine( let options = resolver_installer_options(installer, build).combine(
filesystem filesystem
.clone()
.map(FilesystemOptions::into_options) .map(FilesystemOptions::into_options)
.map(|options| options.top_level) .map(|options| options.top_level)
.unwrap_or_default(), .unwrap_or_default(),
); );
let install_mirrors = filesystem
.map(FilesystemOptions::into_options)
.map(|options| options.install_mirrors)
.unwrap_or_default();
let settings = ResolverInstallerSettings::from(options.clone()); let settings = ResolverInstallerSettings::from(options.clone());
Self { Self {
@ -494,6 +521,7 @@ impl ToolInstallSettings {
refresh: Refresh::from(refresh), refresh: Refresh::from(refresh),
options, options,
settings, settings,
install_mirrors,
} }
} }
} }
@ -504,10 +532,10 @@ impl ToolInstallSettings {
pub(crate) struct ToolUpgradeSettings { pub(crate) struct ToolUpgradeSettings {
pub(crate) name: Vec<PackageName>, pub(crate) name: Vec<PackageName>,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) args: ResolverInstallerOptions, pub(crate) args: ResolverInstallerOptions,
pub(crate) filesystem: ResolverInstallerOptions, pub(crate) filesystem: ResolverInstallerOptions,
} }
impl ToolUpgradeSettings { impl ToolUpgradeSettings {
/// Resolve the [`ToolUpgradeSettings`] from the CLI and filesystem configuration. /// Resolve the [`ToolUpgradeSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
@ -529,8 +557,12 @@ impl ToolUpgradeSettings {
} }
let args = resolver_installer_options(installer, build); let args = resolver_installer_options(installer, build);
let filesystem = filesystem let filesystem = filesystem.map(FilesystemOptions::into_options);
.map(FilesystemOptions::into_options) let install_mirrors = filesystem
.clone()
.map(|options| options.install_mirrors)
.unwrap_or_default();
let top_level = filesystem
.map(|options| options.top_level) .map(|options| options.top_level)
.unwrap_or_default(); .unwrap_or_default();
@ -538,7 +570,8 @@ impl ToolUpgradeSettings {
name: if all { vec![] } else { name }, name: if all { vec![] } else { name },
python: python.and_then(Maybe::into_option), python: python.and_then(Maybe::into_option),
args, args,
filesystem, filesystem: top_level,
install_mirrors,
} }
} }
} }
@ -669,22 +702,39 @@ pub(crate) struct PythonInstallSettings {
pub(crate) targets: Vec<String>, pub(crate) targets: Vec<String>,
pub(crate) reinstall: bool, pub(crate) reinstall: bool,
pub(crate) force: bool, pub(crate) force: bool,
pub(crate) python_install_mirror: Option<String>,
pub(crate) pypy_install_mirror: Option<String>,
} }
impl PythonInstallSettings { impl PythonInstallSettings {
/// Resolve the [`PythonInstallSettings`] from the CLI and filesystem configuration. /// Resolve the [`PythonInstallSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: PythonInstallArgs, _filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(args: PythonInstallArgs, filesystem: Option<FilesystemOptions>) -> Self {
let options = filesystem.map(uv_settings::FilesystemOptions::into_options);
let (python_mirror, pypy_mirror) = match options {
Some(options) => (
options.install_mirrors.python_install_mirror,
options.install_mirrors.pypy_install_mirror,
),
None => (None, None),
};
let python_mirror = args.mirror.or(python_mirror);
let pypy_mirror = args.pypy_mirror.or(pypy_mirror);
let PythonInstallArgs { let PythonInstallArgs {
targets, targets,
reinstall, reinstall,
force, force,
mirror: _,
pypy_mirror: _,
} = args; } = args;
Self { Self {
targets, targets,
reinstall, reinstall,
force, force,
python_install_mirror: python_mirror,
pypy_install_mirror: pypy_mirror,
} }
} }
} }
@ -780,6 +830,7 @@ pub(crate) struct SyncSettings {
pub(crate) all_packages: bool, pub(crate) all_packages: bool,
pub(crate) package: Option<PackageName>, pub(crate) package: Option<PackageName>,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh, pub(crate) refresh: Refresh,
pub(crate) settings: ResolverInstallerSettings, pub(crate) settings: ResolverInstallerSettings,
} }
@ -813,6 +864,10 @@ impl SyncSettings {
package, package,
python, python,
} = args; } = args;
let install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
let settings = ResolverInstallerSettings::combine( let settings = ResolverInstallerSettings::combine(
resolver_installer_options(installer, build), resolver_installer_options(installer, build),
@ -845,6 +900,7 @@ impl SyncSettings {
python: python.and_then(Maybe::into_option), python: python.and_then(Maybe::into_option),
refresh: Refresh::from(refresh), refresh: Refresh::from(refresh),
settings, settings,
install_mirrors,
} }
} }
} }
@ -857,6 +913,7 @@ pub(crate) struct LockSettings {
pub(crate) frozen: bool, pub(crate) frozen: bool,
pub(crate) dry_run: bool, pub(crate) dry_run: bool,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh, pub(crate) refresh: Refresh,
pub(crate) settings: ResolverSettings, pub(crate) settings: ResolverSettings,
} }
@ -875,6 +932,11 @@ impl LockSettings {
python, python,
} = args; } = args;
let install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
Self { Self {
locked, locked,
frozen, frozen,
@ -882,6 +944,7 @@ impl LockSettings {
python: python.and_then(Maybe::into_option), python: python.and_then(Maybe::into_option),
refresh: Refresh::from(refresh), refresh: Refresh::from(refresh),
settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem), settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem),
install_mirrors,
} }
} }
} }
@ -905,6 +968,7 @@ pub(crate) struct AddSettings {
pub(crate) package: Option<PackageName>, pub(crate) package: Option<PackageName>,
pub(crate) script: Option<PathBuf>, pub(crate) script: Option<PathBuf>,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh, pub(crate) refresh: Refresh,
pub(crate) indexes: Vec<Index>, pub(crate) indexes: Vec<Index>,
pub(crate) settings: ResolverInstallerSettings, pub(crate) settings: ResolverInstallerSettings,
@ -993,6 +1057,11 @@ impl AddSettings {
} }
} }
let install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
Self { Self {
locked, locked,
frozen, frozen,
@ -1015,6 +1084,7 @@ impl AddSettings {
resolver_installer_options(installer, build), resolver_installer_options(installer, build),
filesystem, filesystem,
), ),
install_mirrors,
} }
} }
} }
@ -1031,6 +1101,7 @@ pub(crate) struct RemoveSettings {
pub(crate) package: Option<PackageName>, pub(crate) package: Option<PackageName>,
pub(crate) script: Option<PathBuf>, pub(crate) script: Option<PathBuf>,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh, pub(crate) refresh: Refresh,
pub(crate) settings: ResolverInstallerSettings, pub(crate) settings: ResolverInstallerSettings,
} }
@ -1065,6 +1136,11 @@ impl RemoveSettings {
DependencyType::Production DependencyType::Production
}; };
let install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
Self { Self {
locked, locked,
frozen, frozen,
@ -1079,6 +1155,7 @@ impl RemoveSettings {
resolver_installer_options(installer, build), resolver_installer_options(installer, build),
filesystem, filesystem,
), ),
install_mirrors,
} }
} }
} }
@ -1100,6 +1177,7 @@ pub(crate) struct TreeSettings {
pub(crate) python_version: Option<PythonVersion>, pub(crate) python_version: Option<PythonVersion>,
pub(crate) python_platform: Option<TargetTriple>, pub(crate) python_platform: Option<TargetTriple>,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) resolver: ResolverSettings, pub(crate) resolver: ResolverSettings,
} }
@ -1123,6 +1201,10 @@ impl TreeSettings {
python_platform, python_platform,
python, python,
} = args; } = args;
let install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
Self { Self {
dev: DevGroupsSpecification::from_args( dev: DevGroupsSpecification::from_args(
@ -1141,6 +1223,7 @@ impl TreeSettings {
python_platform, python_platform,
python: python.and_then(Maybe::into_option), python: python.and_then(Maybe::into_option),
resolver: ResolverSettings::combine(resolver_options(resolver, build), filesystem), resolver: ResolverSettings::combine(resolver_options(resolver, build), filesystem),
install_mirrors,
} }
} }
} }
@ -1162,6 +1245,7 @@ pub(crate) struct ExportSettings {
pub(crate) frozen: bool, pub(crate) frozen: bool,
pub(crate) include_header: bool, pub(crate) include_header: bool,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh, pub(crate) refresh: Refresh,
pub(crate) settings: ResolverSettings, pub(crate) settings: ResolverSettings,
} }
@ -1199,6 +1283,10 @@ impl ExportSettings {
refresh, refresh,
python, python,
} = args; } = args;
let install_mirrors = filesystem
.clone()
.map(|fs| fs.install_mirrors.clone())
.unwrap_or_default();
Self { Self {
format, format,
@ -1225,6 +1313,7 @@ impl ExportSettings {
python: python.and_then(Maybe::into_option), python: python.and_then(Maybe::into_option),
refresh: Refresh::from(refresh), refresh: Refresh::from(refresh),
settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem), settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem),
install_mirrors,
} }
} }
} }
@ -1868,6 +1957,7 @@ pub(crate) struct BuildSettings {
pub(crate) build_constraint: Vec<PathBuf>, pub(crate) build_constraint: Vec<PathBuf>,
pub(crate) hash_checking: Option<HashCheckingMode>, pub(crate) hash_checking: Option<HashCheckingMode>,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) refresh: Refresh, pub(crate) refresh: Refresh,
pub(crate) settings: ResolverSettings, pub(crate) settings: ResolverSettings,
} }
@ -1895,6 +1985,11 @@ impl BuildSettings {
resolver, resolver,
} = args; } = args;
let install_mirrors = match &filesystem {
Some(fs) => fs.install_mirrors.clone(),
None => PythonInstallMirrors::default(),
};
Self { Self {
src, src,
package, package,
@ -1914,6 +2009,7 @@ impl BuildSettings {
python: python.and_then(Maybe::into_option), python: python.and_then(Maybe::into_option),
refresh: Refresh::from(refresh), refresh: Refresh::from(refresh),
settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem), settings: ResolverSettings::combine(resolver_options(resolver, build), filesystem),
install_mirrors,
} }
} }
} }
@ -2269,6 +2365,7 @@ impl From<ResolverInstallerOptions> for ResolverInstallerSettings {
pub(crate) struct PipSettings { pub(crate) struct PipSettings {
pub(crate) index_locations: IndexLocations, pub(crate) index_locations: IndexLocations,
pub(crate) python: Option<String>, pub(crate) python: Option<String>,
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) system: bool, pub(crate) system: bool,
pub(crate) extras: ExtrasSpecification, pub(crate) extras: ExtrasSpecification,
pub(crate) break_system_packages: bool, pub(crate) break_system_packages: bool,
@ -2315,7 +2412,12 @@ pub(crate) struct PipSettings {
impl PipSettings { impl PipSettings {
/// Resolve the [`PipSettings`] from the CLI and filesystem configuration. /// Resolve the [`PipSettings`] from the CLI and filesystem configuration.
pub(crate) fn combine(args: PipOptions, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn combine(args: PipOptions, filesystem: Option<FilesystemOptions>) -> Self {
let Options { top_level, pip, .. } = filesystem let Options {
top_level,
pip,
install_mirrors,
..
} = filesystem
.map(FilesystemOptions::into_options) .map(FilesystemOptions::into_options)
.unwrap_or_default(); .unwrap_or_default();
@ -2592,6 +2694,7 @@ impl PipSettings {
top_level_no_build_package.unwrap_or_default(), top_level_no_build_package.unwrap_or_default(),
)), )),
), ),
install_mirrors,
} }
} }
} }

View file

@ -450,7 +450,7 @@ fn help_subcommand() {
fn help_subsubcommand() { fn help_subsubcommand() {
let context = TestContext::new_with_versions(&[]); let context = TestContext::new_with_versions(&[]);
uv_snapshot!(context.filters(), context.help().arg("python").arg("install"), @r###" uv_snapshot!(context.filters(), context.help().arg("python").arg("install"), @r##"
success: true success: true
exit_code: 0 exit_code: 0
----- stdout ----- ----- stdout -----
@ -483,6 +483,27 @@ fn help_subsubcommand() {
See `uv help python` to view supported request formats. See `uv help python` to view supported request formats.
Options: Options:
--mirror <MIRROR>
Set the URL to use as the source for downloading Python installations.
The provided URL will replace
`https://github.com/indygreg/python-build-standalone/releases/download` in, e.g.,
`https://github.com/indygreg/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz`.
Distributions can be read from a local directory by using the `file://` URL scheme.
[env: UV_PYTHON_INSTALL_MIRROR=]
--pypy-mirror <PYPY_MIRROR>
Set the URL to use as the source for downloading PyPy installations.
The provided URL will replace `https://downloads.python.org/pypy` in, e.g.,
`https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2`.
Distributions can be read from a local directory by using the `file://` URL scheme.
[env: UV_PYPY_INSTALL_MIRROR=]
-r, --reinstall -r, --reinstall
Reinstall the requested Python version, if it's already installed. Reinstall the requested Python version, if it's already installed.
@ -638,7 +659,7 @@ fn help_subsubcommand() {
----- stderr ----- ----- stderr -----
"###); "##);
} }
#[test] #[test]
@ -724,8 +745,12 @@ fn help_flag_subsubcommand() {
[TARGETS]... The Python version(s) to install [TARGETS]... The Python version(s) to install
Options: Options:
-r, --reinstall Reinstall the requested Python version, if it's already installed --mirror <MIRROR> Set the URL to use as the source for downloading Python
-f, --force Replace existing Python executables during installation installations [env: UV_PYTHON_INSTALL_MIRROR=]
--pypy-mirror <PYPY_MIRROR> Set the URL to use as the source for downloading PyPy
installations [env: UV_PYPY_INSTALL_MIRROR=]
-r, --reinstall Reinstall the requested Python version, if it's already installed
-f, --force Replace existing Python executables during installation
Cache options: Cache options:
-n, --no-cache Avoid reading from or writing to the cache, instead using a temporary -n, --no-cache Avoid reading from or writing to the cache, instead using a temporary

View file

@ -4286,7 +4286,7 @@ fn lock_requires_python() -> Result<()> {
"#, "#,
)?; )?;
uv_snapshot!(context.filters(), context.lock(), @r###" uv_snapshot!(context.filters(), context.lock(), @r"
success: false success: false
exit_code: 1 exit_code: 1
----- stdout ----- ----- stdout -----
@ -4309,7 +4309,7 @@ fn lock_requires_python() -> Result<()> {
hint: Pre-releases are available for pygls in the requested range (e.g., 2.0.0a2), but pre-releases weren't enabled (try: `--prerelease=allow`) hint: Pre-releases are available for pygls in the requested range (e.g., 2.0.0a2), but pre-releases weren't enabled (try: `--prerelease=allow`)
hint: The `requires-python` value (>=3.7) includes Python versions that are not supported by your dependencies (e.g., pygls>=1.1.0,<=1.2.1 only supports >=3.7.9, <4). Consider using a more restrictive `requires-python` value (like >=3.7.9, <4). hint: The `requires-python` value (>=3.7) includes Python versions that are not supported by your dependencies (e.g., pygls>=1.1.0,<=1.2.1 only supports >=3.7.9, <4). Consider using a more restrictive `requires-python` value (like >=3.7.9, <4).
"###); ");
// Require >=3.7, and allow locking to a version of `pygls` that is compatible (==1.0.1). // Require >=3.7, and allow locking to a version of `pygls` that is compatible (==1.0.1).
pyproject_toml.write_str( pyproject_toml.write_str(

View file

@ -191,7 +191,7 @@ fn invalid_pyproject_toml_option_unknown_field() -> Result<()> {
| |
2 | unknown = "field" 2 | unknown = "field"
| ^^^^^^^ | ^^^^^^^
unknown field `unknown`, expected one of `native-tls`, `offline`, `no-cache`, `cache-dir`, `preview`, `python-preference`, `python-downloads`, `concurrent-downloads`, `concurrent-builds`, `concurrent-installs`, `index`, `index-url`, `extra-index-url`, `no-index`, `find-links`, `index-strategy`, `keyring-provider`, `allow-insecure-host`, `resolution`, `prerelease`, `dependency-metadata`, `config-settings`, `no-build-isolation`, `no-build-isolation-package`, `exclude-newer`, `link-mode`, `compile-bytecode`, `no-sources`, `upgrade`, `upgrade-package`, `reinstall`, `reinstall-package`, `no-build`, `no-build-package`, `no-binary`, `no-binary-package`, `publish-url`, `trusted-publishing`, `pip`, `cache-keys`, `override-dependencies`, `constraint-dependencies`, `environments`, `conflicting-groups`, `workspace`, `sources`, `managed`, `package`, `default-groups`, `dev-dependencies` unknown field `unknown`, expected one of `native-tls`, `offline`, `no-cache`, `cache-dir`, `preview`, `python-preference`, `python-downloads`, `concurrent-downloads`, `concurrent-builds`, `concurrent-installs`, `index`, `index-url`, `extra-index-url`, `no-index`, `find-links`, `index-strategy`, `keyring-provider`, `allow-insecure-host`, `resolution`, `prerelease`, `dependency-metadata`, `config-settings`, `no-build-isolation`, `no-build-isolation-package`, `exclude-newer`, `link-mode`, `compile-bytecode`, `no-sources`, `upgrade`, `upgrade-package`, `reinstall`, `reinstall-package`, `no-build`, `no-build-package`, `no-binary`, `no-binary-package`, `python-install-mirror`, `pypy-install-mirror`, `publish-url`, `trusted-publishing`, `pip`, `cache-keys`, `override-dependencies`, `constraint-dependencies`, `environments`, `conflicting-groups`, `workspace`, `sources`, `managed`, `package`, `default-groups`, `dev-dependencies`
Resolved in [TIME] Resolved in [TIME]
Audited in [TIME] Audited in [TIME]

View file

@ -123,6 +123,10 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -270,6 +274,10 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -418,6 +426,10 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -598,6 +610,10 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -718,6 +734,10 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -876,6 +896,10 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -1076,6 +1100,10 @@ fn resolve_index_url() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -1283,6 +1311,10 @@ fn resolve_index_url() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -1455,6 +1487,10 @@ fn resolve_find_links() -> anyhow::Result<()> {
no_index: true, no_index: true,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -1597,6 +1633,10 @@ fn resolve_top_level() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -1789,6 +1829,10 @@ fn resolve_top_level() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -1964,6 +2008,10 @@ fn resolve_top_level() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -2106,6 +2154,10 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -2231,6 +2283,10 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -2356,6 +2412,10 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -2483,6 +2543,10 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -2687,6 +2751,10 @@ fn resolve_tool() -> anyhow::Result<()> {
}, },
force: false, force: false,
editable: false, editable: false,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
} }
----- stderr ----- ----- stderr -----
@ -2786,6 +2854,10 @@ fn resolve_poetry_toml() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -2968,6 +3040,10 @@ fn resolve_both() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -3238,6 +3314,10 @@ fn resolve_config_file() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -3325,7 +3405,7 @@ fn resolve_config_file() -> anyhow::Result<()> {
| |
1 | [project] 1 | [project]
| ^^^^^^^ | ^^^^^^^
unknown field `project`, expected one of `native-tls`, `offline`, `no-cache`, `cache-dir`, `preview`, `python-preference`, `python-downloads`, `concurrent-downloads`, `concurrent-builds`, `concurrent-installs`, `index`, `index-url`, `extra-index-url`, `no-index`, `find-links`, `index-strategy`, `keyring-provider`, `allow-insecure-host`, `resolution`, `prerelease`, `dependency-metadata`, `config-settings`, `no-build-isolation`, `no-build-isolation-package`, `exclude-newer`, `link-mode`, `compile-bytecode`, `no-sources`, `upgrade`, `upgrade-package`, `reinstall`, `reinstall-package`, `no-build`, `no-build-package`, `no-binary`, `no-binary-package`, `publish-url`, `trusted-publishing`, `pip`, `cache-keys`, `override-dependencies`, `constraint-dependencies`, `environments`, `conflicting-groups`, `workspace`, `sources`, `managed`, `package`, `default-groups`, `dev-dependencies` unknown field `project`, expected one of `native-tls`, `offline`, `no-cache`, `cache-dir`, `preview`, `python-preference`, `python-downloads`, `concurrent-downloads`, `concurrent-builds`, `concurrent-installs`, `index`, `index-url`, `extra-index-url`, `no-index`, `find-links`, `index-strategy`, `keyring-provider`, `allow-insecure-host`, `resolution`, `prerelease`, `dependency-metadata`, `config-settings`, `no-build-isolation`, `no-build-isolation-package`, `exclude-newer`, `link-mode`, `compile-bytecode`, `no-sources`, `upgrade`, `upgrade-package`, `reinstall`, `reinstall-package`, `no-build`, `no-build-package`, `no-binary`, `no-binary-package`, `python-install-mirror`, `pypy-install-mirror`, `publish-url`, `trusted-publishing`, `pip`, `cache-keys`, `override-dependencies`, `constraint-dependencies`, `environments`, `conflicting-groups`, `workspace`, `sources`, `managed`, `package`, `default-groups`, `dev-dependencies`
"### "###
); );
@ -3457,6 +3537,10 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -3585,6 +3669,10 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -3732,6 +3820,10 @@ fn allow_insecure_host() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -3930,6 +4022,10 @@ fn index_priority() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -4107,6 +4203,10 @@ fn index_priority() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -4290,6 +4390,10 @@ fn index_priority() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -4468,6 +4572,10 @@ fn index_priority() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -4653,6 +4761,10 @@ fn index_priority() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,
@ -4831,6 +4943,10 @@ fn index_priority() -> anyhow::Result<()> {
no_index: false, no_index: false,
}, },
python: None, python: None,
install_mirrors: PythonInstallMirrors {
python_install_mirror: None,
pypy_install_mirror: None,
},
system: false, system: false,
extras: None, extras: None,
break_system_packages: false, break_system_packages: false,

View file

@ -30,7 +30,7 @@ fn sync() -> Result<()> {
)?; )?;
// Running `uv sync` should generate a lockfile. // Running `uv sync` should generate a lockfile.
uv_snapshot!(context.filters(), context.sync(), @r###" uv_snapshot!(context.filters(), context.sync(), @r"
success: true success: true
exit_code: 0 exit_code: 0
----- stdout ----- ----- stdout -----
@ -41,7 +41,7 @@ fn sync() -> Result<()> {
Installed 2 packages in [TIME] Installed 2 packages in [TIME]
+ iniconfig==2.0.0 + iniconfig==2.0.0
+ project==0.1.0 (from file://[TEMP_DIR]/) + project==0.1.0 (from file://[TEMP_DIR]/)
"###); ");
assert!(context.temp_dir.child("uv.lock").exists()); assert!(context.temp_dir.child("uv.lock").exists());

View file

@ -4457,6 +4457,13 @@ uv python install [OPTIONS] [TARGETS]...
</dd><dt><code>--help</code>, <code>-h</code></dt><dd><p>Display the concise help for this command</p> </dd><dt><code>--help</code>, <code>-h</code></dt><dd><p>Display the concise help for this command</p>
</dd><dt><code>--mirror</code> <i>mirror</i></dt><dd><p>Set the URL to use as the source for downloading Python installations.</p>
<p>The provided URL will replace <code>https://github.com/indygreg/python-build-standalone/releases/download</code> in, e.g., <code>https://github.com/indygreg/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz</code>.</p>
<p>Distributions can be read from a local directory by using the <code>file://</code> URL scheme.</p>
<p>May also be set with the <code>UV_PYTHON_INSTALL_MIRROR</code> environment variable.</p>
</dd><dt><code>--native-tls</code></dt><dd><p>Whether to load TLS certificates from the platform&#8217;s native certificate store.</p> </dd><dt><code>--native-tls</code></dt><dd><p>Whether to load TLS certificates from the platform&#8217;s native certificate store.</p>
<p>By default, uv loads certificates from the bundled <code>webpki-roots</code> crate. The <code>webpki-roots</code> are a reliable set of trust roots from Mozilla, and including them in uv improves portability and performance (especially on macOS).</p> <p>By default, uv loads certificates from the bundled <code>webpki-roots</code> crate. The <code>webpki-roots</code> are a reliable set of trust roots from Mozilla, and including them in uv improves portability and performance (especially on macOS).</p>
@ -4493,6 +4500,13 @@ uv python install [OPTIONS] [TARGETS]...
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p> <p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--pypy-mirror</code> <i>pypy-mirror</i></dt><dd><p>Set the URL to use as the source for downloading PyPy installations.</p>
<p>The provided URL will replace <code>https://downloads.python.org/pypy</code> in, e.g., <code>https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2</code>.</p>
<p>Distributions can be read from a local directory by using the <code>file://</code> URL scheme.</p>
<p>May also be set with the <code>UV_PYPY_INSTALL_MIRROR</code> environment variable.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p> </dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p> <p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>

View file

@ -1226,6 +1226,37 @@ The URL for publishing packages to the Python package index (by default:
--- ---
### [`pypy-install-mirror`](#pypy-install-mirror) {: #pypy-install-mirror }
Mirror URL to use for downloading managed PyPy installations.
By default, managed PyPy installations are downloaded from [downloads.python.org](https://downloads.python.org/).
This variable can be set to a mirror URL to use a different source for PyPy installations.
The provided URL will replace `https://downloads.python.org/pypy` in, e.g., `https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2`.
Distributions can be read from a
local directory by using the `file://` URL scheme.
**Default value**: `None`
**Type**: `str`
**Example usage**:
=== "pyproject.toml"
```toml
[tool.uv]
pypy-install-mirror = "https://downloads.python.org/pypy"
```
=== "uv.toml"
```toml
pypy-install-mirror = "https://downloads.python.org/pypy"
```
---
### [`python-downloads`](#python-downloads) {: #python-downloads } ### [`python-downloads`](#python-downloads) {: #python-downloads }
Whether to allow Python downloads. Whether to allow Python downloads.
@ -1254,6 +1285,36 @@ Whether to allow Python downloads.
--- ---
### [`python-install-mirror`](#python-install-mirror) {: #python-install-mirror }
Mirror URL for downloading managed Python installations.
By default, managed Python installations are downloaded from [`python-build-standalone`](https://github.com/indygreg/python-build-standalone).
This variable can be set to a mirror URL to use a different source for Python installations.
The provided URL will replace `https://github.com/indygreg/python-build-standalone/releases/download` in, e.g., `https://github.com/indygreg/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz`.
Distributions can be read from a local directory by using the `file://` URL scheme.
**Default value**: `None`
**Type**: `str`
**Example usage**:
=== "pyproject.toml"
```toml
[tool.uv]
python-install-mirror = "https://github.com/indygreg/python-build-standalone/releases/download"
```
=== "uv.toml"
```toml
python-install-mirror = "https://github.com/indygreg/python-build-standalone/releases/download"
```
---
### [`python-preference`](#python-preference) {: #python-preference } ### [`python-preference`](#python-preference) {: #python-preference }
Whether to prefer using Python installations that are already present on the system, or Whether to prefer using Python installations that are already present on the system, or

14
uv.schema.json generated
View file

@ -357,6 +357,13 @@
], ],
"format": "uri" "format": "uri"
}, },
"pypy-install-mirror": {
"description": "Mirror URL to use for downloading managed PyPy installations.\n\nBy default, managed PyPy installations are downloaded from [downloads.python.org](https://downloads.python.org/). This variable can be set to a mirror URL to use a different source for PyPy installations. The provided URL will replace `https://downloads.python.org/pypy` in, e.g., `https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2`.\n\nDistributions can be read from a local directory by using the `file://` URL scheme.",
"type": [
"string",
"null"
]
},
"python-downloads": { "python-downloads": {
"description": "Whether to allow Python downloads.", "description": "Whether to allow Python downloads.",
"anyOf": [ "anyOf": [
@ -368,6 +375,13 @@
} }
] ]
}, },
"python-install-mirror": {
"description": "Mirror URL for downloading managed Python installations.\n\nBy default, managed Python installations are downloaded from [`python-build-standalone`](https://github.com/indygreg/python-build-standalone). This variable can be set to a mirror URL to use a different source for Python installations. The provided URL will replace `https://github.com/indygreg/python-build-standalone/releases/download` in, e.g., `https://github.com/indygreg/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz`.\n\nDistributions can be read from a local directory by using the `file://` URL scheme.",
"type": [
"string",
"null"
]
},
"python-preference": { "python-preference": {
"description": "Whether to prefer using Python installations that are already present on the system, or those that are downloaded and installed by uv.", "description": "Whether to prefer using Python installations that are already present on the system, or those that are downloaded and installed by uv.",
"anyOf": [ "anyOf": [