Add install_mirrors to EnvironmentOptions (#15937)
Some checks are pending
CI / integration test | uv publish (push) Blocked by required conditions
CI / Determine changes (push) Waiting to run
CI / lint (push) Waiting to run
CI / cargo clippy | ubuntu (push) Blocked by required conditions
CI / cargo clippy | windows (push) Blocked by required conditions
CI / cargo dev generate-all (push) Blocked by required conditions
CI / cargo shear (push) Waiting to run
CI / cargo test | ubuntu (push) Blocked by required conditions
CI / cargo test | macos (push) Blocked by required conditions
CI / cargo test | windows (push) Blocked by required conditions
CI / check windows trampoline | aarch64 (push) Blocked by required conditions
CI / check windows trampoline | i686 (push) Blocked by required conditions
CI / check windows trampoline | x86_64 (push) Blocked by required conditions
CI / test windows trampoline | aarch64 (push) Blocked by required conditions
CI / test windows trampoline | i686 (push) Blocked by required conditions
CI / test windows trampoline | x86_64 (push) Blocked by required conditions
CI / typos (push) Waiting to run
CI / mkdocs (push) Waiting to run
CI / build binary | linux libc (push) Blocked by required conditions
CI / build binary | linux aarch64 (push) Blocked by required conditions
CI / build binary | linux musl (push) Blocked by required conditions
CI / build binary | freebsd (push) Blocked by required conditions
CI / build binary | macos aarch64 (push) Blocked by required conditions
CI / build binary | macos x86_64 (push) Blocked by required conditions
CI / build binary | windows x86_64 (push) Blocked by required conditions
CI / build binary | windows aarch64 (push) Blocked by required conditions
CI / build binary | msrv (push) Blocked by required conditions
CI / ecosystem test | pydantic/pydantic-core (push) Blocked by required conditions
CI / ecosystem test | prefecthq/prefect (push) Blocked by required conditions
CI / ecosystem test | pallets/flask (push) Blocked by required conditions
CI / check system | pyston (push) Blocked by required conditions
CI / smoke test | linux aarch64 (push) Blocked by required conditions
CI / check system | alpine (push) Blocked by required conditions
CI / smoke test | macos (push) Blocked by required conditions
CI / smoke test | windows x86_64 (push) Blocked by required conditions
CI / integration test | aarch64 windows implicit (push) Blocked by required conditions
CI / integration test | aarch64 windows explicit (push) Blocked by required conditions
CI / integration test | pypy on ubuntu (push) Blocked by required conditions
CI / integration test | graalpy on windows (push) Blocked by required conditions
CI / integration test | free-threaded python on github actions (push) Blocked by required conditions
CI / integration test | pyenv on wsl x86-64 (push) Blocked by required conditions
CI / integration test | determine publish changes (push) Blocked by required conditions
CI / integration test | registries (push) Blocked by required conditions
CI / integration test | uv_build (push) Blocked by required conditions
CI / check cache | macos aarch64 (push) Blocked by required conditions
CI / check system | python on debian (push) Blocked by required conditions
CI / check system | python on fedora (push) Blocked by required conditions
CI / check system | x86-64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | windows registry (push) Blocked by required conditions
CI / check system | python3.12 via chocolatey (push) Blocked by required conditions
CI / check system | python3.9 via pyenv (push) Blocked by required conditions
CI / check system | python3.13 (push) Blocked by required conditions
CI / check system | conda3.8 on macos aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.8 on linux x86-64 (push) Blocked by required conditions
CI / check system | conda3.11 on windows x86-64 (push) Blocked by required conditions
CI / smoke test | linux (push) Blocked by required conditions
CI / smoke test | windows aarch64 (push) Blocked by required conditions
CI / integration test | activate nushell venv (push) Blocked by required conditions
CI / integration test | conda on ubuntu (push) Blocked by required conditions
CI / integration test | deadsnakes python3.9 on ubuntu (push) Blocked by required conditions
CI / integration test | free-threaded on windows (push) Blocked by required conditions
CI / integration test | graalpy on ubuntu (push) Blocked by required conditions
CI / integration test | pypy on windows (push) Blocked by required conditions
CI / integration test | pyodide on ubuntu (push) Blocked by required conditions
CI / integration test | github actions (push) Blocked by required conditions
CI / check cache | ubuntu (push) Blocked by required conditions
CI / check system | python on ubuntu (push) Blocked by required conditions
CI / check system | python on rocky linux 8 (push) Blocked by required conditions
CI / check system | python on rocky linux 9 (push) Blocked by required conditions
CI / check system | graalpy on ubuntu (push) Blocked by required conditions
CI / check system | pypy on ubuntu (push) Blocked by required conditions
CI / check system | python on macos aarch64 (push) Blocked by required conditions
CI / check system | homebrew python on macos aarch64 (push) Blocked by required conditions
CI / check system | x86-64 python on macos aarch64 (push) Blocked by required conditions
CI / check system | python on macos x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86-64 (push) Blocked by required conditions
CI / check system | python3.10 on windows x86 (push) Blocked by required conditions
CI / check system | python3.13 on windows x86-64 (push) Blocked by required conditions
CI / check system | aarch64 python3.13 on windows aarch64 (push) Blocked by required conditions
CI / check system | conda3.11 on macos aarch64 (push) Blocked by required conditions
CI / check system | embedded python3.10 on windows x86-64 (push) Blocked by required conditions
CI / benchmarks | walltime aarch64 linux (push) Blocked by required conditions
CI / benchmarks | instrumented (push) Blocked by required conditions
CI / check system | conda3.8 on windows x86-64 (push) Blocked by required conditions
CI / check system | amazonlinux (push) Blocked by required conditions
zizmor / Run zizmor (push) Waiting to run

## Summary

Add install_mirrors to EnvironmentOptions
Relates #14720

## Test Plan

Tests with existing tests
This commit is contained in:
Andrei Berenda 2025-09-25 19:35:09 +04:00 committed by GitHub
parent 15975b00ea
commit 372283c0cf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 366 additions and 162 deletions

View file

@ -28,6 +28,7 @@ use uv_resolver::{
AnnotationStyle, ExcludeNewerPackageEntry, ExcludeNewerTimestamp, ForkStrategy, PrereleaseMode, AnnotationStyle, ExcludeNewerPackageEntry, ExcludeNewerTimestamp, ForkStrategy, PrereleaseMode,
ResolutionMode, ResolutionMode,
}; };
use uv_settings::PythonInstallMirrors;
use uv_static::EnvVars; use uv_static::EnvVars;
use uv_torch::TorchMode; use uv_torch::TorchMode;
use uv_workspace::pyproject_mut::AddBoundsKind; use uv_workspace::pyproject_mut::AddBoundsKind;
@ -5363,7 +5364,7 @@ pub struct PythonListArgs {
/// URL pointing to JSON of custom Python installations. /// URL pointing to JSON of custom Python installations.
/// ///
/// Note that currently, only local paths are supported. /// Note that currently, only local paths are supported.
#[arg(long, env = EnvVars::UV_PYTHON_DOWNLOADS_JSON_URL)] #[arg(long)]
pub python_downloads_json_url: Option<String>, pub python_downloads_json_url: Option<String>,
} }
@ -5446,7 +5447,7 @@ pub struct PythonInstallArgs {
/// `https://github.com/astral-sh/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz`. /// `https://github.com/astral-sh/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. /// Distributions can be read from a local directory by using the `file://` URL scheme.
#[arg(long, env = EnvVars::UV_PYTHON_INSTALL_MIRROR)] #[arg(long)]
pub mirror: Option<String>, pub mirror: Option<String>,
/// Set the URL to use as the source for downloading PyPy installations. /// Set the URL to use as the source for downloading PyPy installations.
@ -5455,13 +5456,13 @@ pub struct PythonInstallArgs {
/// `https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2`. /// `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. /// Distributions can be read from a local directory by using the `file://` URL scheme.
#[arg(long, env = EnvVars::UV_PYPY_INSTALL_MIRROR)] #[arg(long)]
pub pypy_mirror: Option<String>, pub pypy_mirror: Option<String>,
/// URL pointing to JSON of custom Python installations. /// URL pointing to JSON of custom Python installations.
/// ///
/// Note that currently, only local paths are supported. /// Note that currently, only local paths are supported.
#[arg(long, env = EnvVars::UV_PYTHON_DOWNLOADS_JSON_URL)] #[arg(long)]
pub python_downloads_json_url: Option<String>, pub python_downloads_json_url: Option<String>,
/// Reinstall the requested Python version, if it's already installed. /// Reinstall the requested Python version, if it's already installed.
@ -5494,6 +5495,17 @@ pub struct PythonInstallArgs {
pub default: bool, pub default: bool,
} }
impl PythonInstallArgs {
#[must_use]
pub fn install_mirrors(&self) -> PythonInstallMirrors {
PythonInstallMirrors {
python_install_mirror: self.mirror.clone(),
pypy_install_mirror: self.pypy_mirror.clone(),
python_downloads_json_url: self.python_downloads_json_url.clone(),
}
}
}
#[derive(Args)] #[derive(Args)]
pub struct PythonUpgradeArgs { pub struct PythonUpgradeArgs {
/// The directory Python installations are stored in. /// The directory Python installations are stored in.
@ -5519,7 +5531,7 @@ pub struct PythonUpgradeArgs {
/// `https://github.com/astral-sh/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz`. /// `https://github.com/astral-sh/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. /// Distributions can be read from a local directory by using the `file://` URL scheme.
#[arg(long, env = EnvVars::UV_PYTHON_INSTALL_MIRROR)] #[arg(long)]
pub mirror: Option<String>, pub mirror: Option<String>,
/// Set the URL to use as the source for downloading PyPy installations. /// Set the URL to use as the source for downloading PyPy installations.
@ -5528,7 +5540,7 @@ pub struct PythonUpgradeArgs {
/// `https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2`. /// `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. /// Distributions can be read from a local directory by using the `file://` URL scheme.
#[arg(long, env = EnvVars::UV_PYPY_INSTALL_MIRROR)] #[arg(long)]
pub pypy_mirror: Option<String>, pub pypy_mirror: Option<String>,
/// Reinstall the latest Python patch, if it's already installed. /// Reinstall the latest Python patch, if it's already installed.
@ -5541,10 +5553,21 @@ pub struct PythonUpgradeArgs {
/// URL pointing to JSON of custom Python installations. /// URL pointing to JSON of custom Python installations.
/// ///
/// Note that currently, only local paths are supported. /// Note that currently, only local paths are supported.
#[arg(long, env = EnvVars::UV_PYTHON_DOWNLOADS_JSON_URL)] #[arg(long)]
pub python_downloads_json_url: Option<String>, pub python_downloads_json_url: Option<String>,
} }
impl PythonUpgradeArgs {
#[must_use]
pub fn install_mirrors(&self) -> PythonInstallMirrors {
PythonInstallMirrors {
python_install_mirror: self.mirror.clone(),
pypy_install_mirror: self.pypy_mirror.clone(),
python_downloads_json_url: self.python_downloads_json_url.clone(),
}
}
}
#[derive(Args)] #[derive(Args)]
pub struct PythonUninstallArgs { pub struct PythonUninstallArgs {
/// The directory where the Python was installed. /// The directory where the Python was installed.

View file

@ -570,6 +570,7 @@ pub enum Error {
pub struct EnvironmentOptions { pub struct EnvironmentOptions {
pub python_install_bin: Option<bool>, pub python_install_bin: Option<bool>,
pub python_install_registry: Option<bool>, pub python_install_registry: Option<bool>,
pub install_mirrors: PythonInstallMirrors,
} }
impl EnvironmentOptions { impl EnvironmentOptions {
@ -580,6 +581,17 @@ impl EnvironmentOptions {
python_install_registry: parse_boolish_environment_variable( python_install_registry: parse_boolish_environment_variable(
EnvVars::UV_PYTHON_INSTALL_REGISTRY, EnvVars::UV_PYTHON_INSTALL_REGISTRY,
)?, )?,
install_mirrors: PythonInstallMirrors {
python_install_mirror: parse_string_environment_variable(
EnvVars::UV_PYTHON_INSTALL_MIRROR,
)?,
pypy_install_mirror: parse_string_environment_variable(
EnvVars::UV_PYPY_INSTALL_MIRROR,
)?,
python_downloads_json_url: parse_string_environment_variable(
EnvVars::UV_PYTHON_DOWNLOADS_JSON_URL,
)?,
},
}) })
} }
} }
@ -635,3 +647,24 @@ fn parse_boolish_environment_variable(name: &'static str) -> Result<Option<bool>
Ok(Some(value)) Ok(Some(value))
} }
/// Parse a string environment variable.
fn parse_string_environment_variable(name: &'static str) -> Result<Option<String>, Error> {
match std::env::var(name) {
Ok(v) => {
if v.is_empty() {
Ok(None)
} else {
Ok(Some(v))
}
}
Err(e) => match e {
std::env::VarError::NotPresent => Ok(None),
std::env::VarError::NotUnicode(err) => Err(Error::InvalidEnvironmentVariable {
name: name.to_string(),
value: err.to_string_lossy().to_string(),
err: "expected a valid UTF-8 string".to_string(),
}),
},
}
}

View file

@ -22,7 +22,6 @@ use uv_resolver::{
AnnotationStyle, ExcludeNewer, ExcludeNewerPackage, ExcludeNewerTimestamp, ForkStrategy, AnnotationStyle, ExcludeNewer, ExcludeNewerPackage, ExcludeNewerTimestamp, ForkStrategy,
PrereleaseMode, ResolutionMode, PrereleaseMode, ResolutionMode,
}; };
use uv_static::EnvVars;
use uv_torch::TorchMode; use uv_torch::TorchMode;
use uv_workspace::pyproject::ExtraBuildDependencies; use uv_workspace::pyproject::ExtraBuildDependencies;
use uv_workspace::pyproject_mut::AddBoundsKind; use uv_workspace::pyproject_mut::AddBoundsKind;
@ -958,7 +957,7 @@ pub struct ResolverInstallerSchema {
} }
/// Shared settings, relevant to all operations that might create managed python installations. /// Shared settings, relevant to all operations that might create managed python installations.
#[derive(Debug, Clone, PartialEq, Eq, Deserialize, CombineOptions, OptionsMetadata)] #[derive(Debug, Clone, Default, PartialEq, Eq, Deserialize, CombineOptions, OptionsMetadata)]
#[serde(rename_all = "kebab-case")] #[serde(rename_all = "kebab-case")]
#[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))] #[cfg_attr(feature = "schemars", derive(schemars::JsonSchema))]
pub struct PythonInstallMirrors { pub struct PythonInstallMirrors {
@ -1007,26 +1006,15 @@ pub struct PythonInstallMirrors {
pub python_downloads_json_url: Option<String>, pub python_downloads_json_url: Option<String>,
} }
impl Default for PythonInstallMirrors {
fn default() -> Self {
Self::resolve(None, None, None)
}
}
impl PythonInstallMirrors { impl PythonInstallMirrors {
pub fn resolve( #[must_use]
python_mirror: Option<String>, pub fn combine(self, other: Self) -> Self {
pypy_mirror: Option<String>,
python_downloads_json_url: 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();
let python_downloads_json_url_env =
std::env::var(EnvVars::UV_PYTHON_DOWNLOADS_JSON_URL).ok();
Self { Self {
python_install_mirror: python_mirror_env.or(python_mirror), python_install_mirror: self.python_install_mirror.or(other.python_install_mirror),
pypy_install_mirror: pypy_mirror_env.or(pypy_mirror), pypy_install_mirror: self.pypy_install_mirror.or(other.pypy_install_mirror),
python_downloads_json_url: python_downloads_json_url_env.or(python_downloads_json_url), python_downloads_json_url: self
.python_downloads_json_url
.or(other.python_downloads_json_url),
} }
} }
} }
@ -2270,11 +2258,11 @@ impl From<OptionsWire> for Options {
build_constraint_dependencies, build_constraint_dependencies,
environments, environments,
required_environments, required_environments,
install_mirrors: PythonInstallMirrors::resolve( install_mirrors: PythonInstallMirrors {
python_install_mirror, python_install_mirror,
pypy_install_mirror, pypy_install_mirror,
python_downloads_json_url, python_downloads_json_url,
), },
conflicts, conflicts,
publish: PublishOptions { publish: PublishOptions {
publish_url, publish_url,

View file

@ -523,7 +523,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.compat_args.validate()?; args.compat_args.validate()?;
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = PipCompileSettings::resolve(args, filesystem); let args = PipCompileSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -624,7 +624,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.compat_args.validate()?; args.compat_args.validate()?;
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = PipSyncSettings::resolve(args, filesystem); let args = PipSyncSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -703,7 +703,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.compat_args.validate()?; args.compat_args.validate()?;
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let mut args = PipInstallSettings::resolve(args, filesystem); let mut args = PipInstallSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
let mut requirements = Vec::with_capacity( let mut requirements = Vec::with_capacity(
@ -845,7 +845,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
command: PipCommand::Uninstall(args), command: PipCommand::Uninstall(args),
}) => { }) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = PipUninstallSettings::resolve(args, filesystem); let args = PipUninstallSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -881,7 +881,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
command: PipCommand::Freeze(args), command: PipCommand::Freeze(args),
}) => { }) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = PipFreezeSettings::resolve(args, filesystem); let args = PipFreezeSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -904,7 +904,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.compat_args.validate()?; args.compat_args.validate()?;
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = PipListSettings::resolve(args, filesystem); let args = PipListSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -935,7 +935,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
command: PipCommand::Show(args), command: PipCommand::Show(args),
}) => { }) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = PipShowSettings::resolve(args, filesystem); let args = PipShowSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -956,7 +956,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
command: PipCommand::Tree(args), command: PipCommand::Tree(args),
}) => { }) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = PipTreeSettings::resolve(args, filesystem); let args = PipTreeSettings::resolve(args, filesystem, environment);
// Initialize the cache. // Initialize the cache.
let cache = cache.init()?; let cache = cache.init()?;
@ -989,7 +989,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
command: PipCommand::Check(args), command: PipCommand::Check(args),
}) => { }) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = PipCheckSettings::resolve(args, filesystem); let args = PipCheckSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -1026,7 +1026,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
} }
Commands::Build(args) => { Commands::Build(args) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::BuildSettings::resolve(args, filesystem); let args = settings::BuildSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -1085,7 +1085,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
} }
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::VenvSettings::resolve(args, filesystem); let args = settings::VenvSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -1222,7 +1222,12 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
} }
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::ToolRunSettings::resolve(args, filesystem, invocation_source); let args = settings::ToolRunSettings::resolve(
args,
filesystem,
invocation_source,
environment,
);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -1299,7 +1304,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
command: ToolCommand::Install(args), command: ToolCommand::Install(args),
}) => { }) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::ToolInstallSettings::resolve(args, filesystem); let args = settings::ToolInstallSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -1405,7 +1410,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
command: ToolCommand::Upgrade(args), command: ToolCommand::Upgrade(args),
}) => { }) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::ToolUpgradeSettings::resolve(args, filesystem); let args = settings::ToolUpgradeSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -1458,7 +1463,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
command: PythonCommand::List(args), command: PythonCommand::List(args),
}) => { }) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::PythonListSettings::resolve(args, filesystem); let args = settings::PythonListSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -1515,7 +1520,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
command: PythonCommand::Upgrade(args), command: PythonCommand::Upgrade(args),
}) => { }) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::PythonUpgradeSettings::resolve(args, filesystem); let args = settings::PythonUpgradeSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
let upgrade = true; let upgrade = true;
@ -1598,7 +1603,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
command: PythonCommand::Pin(args), command: PythonCommand::Pin(args),
}) => { }) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::PythonPinSettings::resolve(args, filesystem); let args = settings::PythonPinSettings::resolve(args, filesystem, environment);
// Initialize the cache. // Initialize the cache.
let cache = cache.init()?; let cache = cache.init()?;
@ -1744,10 +1749,13 @@ async fn run_project(
}; };
} }
// Load environment variables not handled by Clap
let environment = EnvironmentOptions::new()?;
match *project_command { match *project_command {
ProjectCommand::Init(args) => { ProjectCommand::Init(args) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::InitSettings::resolve(args, filesystem); let args = settings::InitSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -1782,7 +1790,7 @@ async fn run_project(
} }
ProjectCommand::Run(args) => { ProjectCommand::Run(args) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::RunSettings::resolve(args, filesystem); let args = settings::RunSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -1846,7 +1854,7 @@ async fn run_project(
} }
ProjectCommand::Sync(args) => { ProjectCommand::Sync(args) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::SyncSettings::resolve(args, filesystem); let args = settings::SyncSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -1896,7 +1904,7 @@ async fn run_project(
} }
ProjectCommand::Lock(args) => { ProjectCommand::Lock(args) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::LockSettings::resolve(args, filesystem); let args = settings::LockSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -1942,7 +1950,7 @@ async fn run_project(
} }
ProjectCommand::Add(args) => { ProjectCommand::Add(args) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let mut args = settings::AddSettings::resolve(args, filesystem); let mut args = settings::AddSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// If the script already exists, use it; otherwise, propagate the file path and we'll // If the script already exists, use it; otherwise, propagate the file path and we'll
@ -2065,7 +2073,7 @@ async fn run_project(
} }
ProjectCommand::Remove(args) => { ProjectCommand::Remove(args) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::RemoveSettings::resolve(args, filesystem); let args = settings::RemoveSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -2109,7 +2117,7 @@ async fn run_project(
} }
ProjectCommand::Version(args) => { ProjectCommand::Version(args) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::VersionSettings::resolve(args, filesystem); let args = settings::VersionSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -2149,7 +2157,7 @@ async fn run_project(
} }
ProjectCommand::Tree(args) => { ProjectCommand::Tree(args) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::TreeSettings::resolve(args, filesystem); let args = settings::TreeSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.
@ -2194,7 +2202,7 @@ async fn run_project(
} }
ProjectCommand::Export(args) => { ProjectCommand::Export(args) => {
// Resolve the settings from the command-line arguments and workspace configuration. // Resolve the settings from the command-line arguments and workspace configuration.
let args = settings::ExportSettings::resolve(args, filesystem); let args = settings::ExportSettings::resolve(args, filesystem, environment);
show_settings!(args); show_settings!(args);
// Initialize the cache. // Initialize the cache.

View file

@ -254,7 +254,11 @@ pub(crate) struct InitSettings {
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>,
environment: EnvironmentOptions,
) -> Self {
let InitArgs { let InitArgs {
path, path,
name, name,
@ -293,7 +297,7 @@ impl InitSettings {
) )
.unwrap_or(kind.packaged_by_default()); .unwrap_or(kind.packaged_by_default());
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.map(|fs| fs.install_mirrors.clone()) .map(|fs| fs.install_mirrors.clone())
.unwrap_or_default(); .unwrap_or_default();
@ -314,7 +318,9 @@ impl InitSettings {
pin_python: flag(pin_python, no_pin_python, "pin-python").unwrap_or(!bare), pin_python: flag(pin_python, no_pin_python, "pin-python").unwrap_or(!bare),
no_workspace, no_workspace,
python: python.and_then(Maybe::into_option), python: python.and_then(Maybe::into_option),
install_mirrors, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -356,7 +362,11 @@ impl RunSettings {
/// Resolve the [`RunSettings`] from the CLI and filesystem configuration. /// Resolve the [`RunSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: RunArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: RunArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let RunArgs { let RunArgs {
extra, extra,
all_extras, all_extras,
@ -401,7 +411,7 @@ impl RunSettings {
max_recursion_depth, max_recursion_depth,
} = args; } = args;
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.clone() .clone()
.map(|fs| fs.install_mirrors.clone()) .map(|fs| fs.install_mirrors.clone())
.unwrap_or_default(); .unwrap_or_default();
@ -461,7 +471,9 @@ impl RunSettings {
filesystem, filesystem,
), ),
env_file: EnvFile::from_args(env_file, no_env_file), env_file: EnvFile::from_args(env_file, no_env_file),
install_mirrors, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
max_recursion_depth: max_recursion_depth.unwrap_or(Self::DEFAULT_MAX_RECURSION_DEPTH), max_recursion_depth: max_recursion_depth.unwrap_or(Self::DEFAULT_MAX_RECURSION_DEPTH),
} }
} }
@ -497,6 +509,7 @@ impl ToolRunSettings {
args: ToolRunArgs, args: ToolRunArgs,
filesystem: Option<FilesystemOptions>, filesystem: Option<FilesystemOptions>,
invocation_source: ToolRunCommand, invocation_source: ToolRunCommand,
environment: EnvironmentOptions,
) -> Self { ) -> Self {
let ToolRunArgs { let ToolRunArgs {
command, command,
@ -554,7 +567,7 @@ impl ToolRunSettings {
.unwrap_or_default(), .unwrap_or_default(),
)); ));
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.map(FilesystemOptions::into_options) .map(FilesystemOptions::into_options)
.map(|options| options.install_mirrors) .map(|options| options.install_mirrors)
.unwrap_or_default(); .unwrap_or_default();
@ -595,7 +608,9 @@ impl ToolRunSettings {
refresh: Refresh::from(refresh), refresh: Refresh::from(refresh),
settings, settings,
options, options,
install_mirrors, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
env_file, env_file,
no_env_file, no_env_file,
} }
@ -627,7 +642,11 @@ pub(crate) struct ToolInstallSettings {
impl ToolInstallSettings { impl ToolInstallSettings {
/// Resolve the [`ToolInstallSettings`] from the CLI and filesystem configuration. /// Resolve the [`ToolInstallSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: ToolInstallArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: ToolInstallArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let ToolInstallArgs { let ToolInstallArgs {
package, package,
editable, editable,
@ -656,7 +675,7 @@ impl ToolInstallSettings {
.unwrap_or_default(), .unwrap_or_default(),
)); ));
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.map(FilesystemOptions::into_options) .map(FilesystemOptions::into_options)
.map(|options| options.install_mirrors) .map(|options| options.install_mirrors)
.unwrap_or_default(); .unwrap_or_default();
@ -701,7 +720,9 @@ impl ToolInstallSettings {
refresh: Refresh::from(refresh), refresh: Refresh::from(refresh),
options, options,
settings, settings,
install_mirrors, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -719,7 +740,11 @@ pub(crate) struct ToolUpgradeSettings {
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)]
pub(crate) fn resolve(args: ToolUpgradeArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: ToolUpgradeArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let ToolUpgradeArgs { let ToolUpgradeArgs {
name, name,
python, python,
@ -788,7 +813,7 @@ impl ToolUpgradeSettings {
let args = resolver_installer_options(installer, build); let args = resolver_installer_options(installer, build);
let filesystem = filesystem.map(FilesystemOptions::into_options); let filesystem = filesystem.map(FilesystemOptions::into_options);
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.clone() .clone()
.map(|options| options.install_mirrors) .map(|options| options.install_mirrors)
.unwrap_or_default(); .unwrap_or_default();
@ -804,7 +829,9 @@ impl ToolUpgradeSettings {
python_platform, python_platform,
args, args,
filesystem: top_level, filesystem: top_level,
install_mirrors, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -900,7 +927,11 @@ pub(crate) struct PythonListSettings {
impl PythonListSettings { impl PythonListSettings {
/// Resolve the [`PythonListSettings`] from the CLI and filesystem configuration. /// Resolve the [`PythonListSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: PythonListArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: PythonListArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PythonListArgs { let PythonListArgs {
request, request,
all_versions, all_versions,
@ -919,8 +950,9 @@ impl PythonListSettings {
None => None, None => None,
}; };
let python_downloads_json_url = let python_downloads_json_url = python_downloads_json_url_arg
python_downloads_json_url_arg.or(python_downloads_json_url_option); .or(environment.install_mirrors.python_downloads_json_url)
.or(python_downloads_json_url_option);
let kinds = if only_installed { let kinds = if only_installed {
PythonListKinds::Installed PythonListKinds::Installed
@ -982,19 +1014,20 @@ impl PythonInstallSettings {
filesystem: Option<FilesystemOptions>, filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions, environment: EnvironmentOptions,
) -> Self { ) -> Self {
let options = filesystem.map(FilesystemOptions::into_options); let filesystem_install_mirrors = filesystem
let (python_mirror, pypy_mirror, python_downloads_json_url) = match options { .map(|fs| fs.install_mirrors.clone())
Some(options) => ( .unwrap_or_default();
options.install_mirrors.python_install_mirror,
options.install_mirrors.pypy_install_mirror, let install_mirrors = args
options.install_mirrors.python_downloads_json_url, .install_mirrors()
), .combine(environment.install_mirrors)
None => (None, None, None), .combine(filesystem_install_mirrors);
};
let python_mirror = args.mirror.or(python_mirror); let PythonInstallMirrors {
let pypy_mirror = args.pypy_mirror.or(pypy_mirror); python_install_mirror,
let python_downloads_json_url = pypy_install_mirror,
args.python_downloads_json_url.or(python_downloads_json_url); python_downloads_json_url,
} = install_mirrors;
let PythonInstallArgs { let PythonInstallArgs {
install_dir, install_dir,
@ -1019,8 +1052,8 @@ impl PythonInstallSettings {
bin: flag(bin, no_bin, "bin").or(environment.python_install_bin), bin: flag(bin, no_bin, "bin").or(environment.python_install_bin),
registry: flag(registry, no_registry, "registry") registry: flag(registry, no_registry, "registry")
.or(environment.python_install_registry), .or(environment.python_install_registry),
python_install_mirror: python_mirror, python_install_mirror,
pypy_install_mirror: pypy_mirror, pypy_install_mirror,
python_downloads_json_url, python_downloads_json_url,
default, default,
} }
@ -1046,20 +1079,26 @@ pub(crate) struct PythonUpgradeSettings {
impl PythonUpgradeSettings { impl PythonUpgradeSettings {
/// Resolve the [`PythonUpgradeSettings`] from the CLI and filesystem configuration. /// Resolve the [`PythonUpgradeSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: PythonUpgradeArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
let options = filesystem.map(FilesystemOptions::into_options); args: PythonUpgradeArgs,
let (python_mirror, pypy_mirror, python_downloads_json_url) = match options { filesystem: Option<FilesystemOptions>,
Some(options) => ( environment: EnvironmentOptions,
options.install_mirrors.python_install_mirror, ) -> Self {
options.install_mirrors.pypy_install_mirror, let filesystem_install_mirrors = filesystem
options.install_mirrors.python_downloads_json_url, .map(|fs| fs.install_mirrors.clone())
), .unwrap_or_default();
None => (None, None, None),
}; let install_mirrors = args
let python_mirror = args.mirror.or(python_mirror); .install_mirrors()
let pypy_mirror = args.pypy_mirror.or(pypy_mirror); .combine(environment.install_mirrors)
let python_downloads_json_url = .combine(filesystem_install_mirrors);
args.python_downloads_json_url.or(python_downloads_json_url);
let PythonInstallMirrors {
python_install_mirror,
pypy_install_mirror,
python_downloads_json_url,
} = install_mirrors;
let force = false; let force = false;
let default = false; let default = false;
let bin = None; let bin = None;
@ -1079,8 +1118,8 @@ impl PythonUpgradeSettings {
targets, targets,
force, force,
registry, registry,
python_install_mirror: python_mirror, python_install_mirror,
pypy_install_mirror: pypy_mirror, pypy_install_mirror,
reinstall, reinstall,
python_downloads_json_url, python_downloads_json_url,
default, default,
@ -1163,7 +1202,11 @@ pub(crate) struct PythonPinSettings {
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>,
environment: EnvironmentOptions,
) -> Self {
let PythonPinArgs { let PythonPinArgs {
request, request,
no_resolved, no_resolved,
@ -1173,7 +1216,7 @@ impl PythonPinSettings {
rm, rm,
} = args; } = args;
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.map(|fs| fs.install_mirrors.clone()) .map(|fs| fs.install_mirrors.clone())
.unwrap_or_default(); .unwrap_or_default();
@ -1183,7 +1226,9 @@ impl PythonPinSettings {
no_project, no_project,
global, global,
rm, rm,
install_mirrors, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -1215,7 +1260,11 @@ pub(crate) struct SyncSettings {
impl SyncSettings { impl SyncSettings {
/// Resolve the [`SyncSettings`] from the CLI and filesystem configuration. /// Resolve the [`SyncSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: SyncArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: SyncArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let SyncArgs { let SyncArgs {
extra, extra,
all_extras, all_extras,
@ -1254,7 +1303,7 @@ impl SyncSettings {
no_check, no_check,
output_format, output_format,
} = args; } = args;
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.clone() .clone()
.map(|fs| fs.install_mirrors.clone()) .map(|fs| fs.install_mirrors.clone())
.unwrap_or_default(); .unwrap_or_default();
@ -1315,7 +1364,9 @@ impl SyncSettings {
python_platform, python_platform,
refresh: Refresh::from(refresh), refresh: Refresh::from(refresh),
settings, settings,
install_mirrors, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -1337,7 +1388,11 @@ pub(crate) struct LockSettings {
impl LockSettings { impl LockSettings {
/// Resolve the [`LockSettings`] from the CLI and filesystem configuration. /// Resolve the [`LockSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: LockArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: LockArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let LockArgs { let LockArgs {
check, check,
check_exists, check_exists,
@ -1349,7 +1404,7 @@ impl LockSettings {
python, python,
} = args; } = args;
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.clone() .clone()
.map(|fs| fs.install_mirrors.clone()) .map(|fs| fs.install_mirrors.clone())
.unwrap_or_default(); .unwrap_or_default();
@ -1362,7 +1417,9 @@ 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, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -1403,7 +1460,11 @@ pub(crate) struct AddSettings {
impl AddSettings { impl AddSettings {
/// Resolve the [`AddSettings`] from the CLI and filesystem configuration. /// Resolve the [`AddSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: AddArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: AddArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let AddArgs { let AddArgs {
packages, packages,
requirements, requirements,
@ -1508,7 +1569,7 @@ impl AddSettings {
} }
} }
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.as_ref() .as_ref()
.map(|fs| fs.install_mirrors.clone()) .map(|fs| fs.install_mirrors.clone())
.unwrap_or_default(); .unwrap_or_default();
@ -1548,7 +1609,9 @@ impl AddSettings {
resolver_installer_options(installer, build), resolver_installer_options(installer, build),
filesystem, filesystem,
), ),
install_mirrors, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -1574,7 +1637,11 @@ pub(crate) struct RemoveSettings {
impl RemoveSettings { impl RemoveSettings {
/// Resolve the [`RemoveSettings`] from the CLI and filesystem configuration. /// Resolve the [`RemoveSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: RemoveArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: RemoveArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let RemoveArgs { let RemoveArgs {
dev, dev,
optional, optional,
@ -1603,7 +1670,7 @@ impl RemoveSettings {
DependencyType::Production DependencyType::Production
}; };
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.clone() .clone()
.map(|fs| fs.install_mirrors.clone()) .map(|fs| fs.install_mirrors.clone())
.unwrap_or_default(); .unwrap_or_default();
@ -1628,7 +1695,9 @@ impl RemoveSettings {
resolver_installer_options(installer, build), resolver_installer_options(installer, build),
filesystem, filesystem,
), ),
install_mirrors, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -1656,7 +1725,11 @@ pub(crate) struct VersionSettings {
impl VersionSettings { impl VersionSettings {
/// Resolve the [`RemoveSettings`] from the CLI and filesystem configuration. /// Resolve the [`RemoveSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: VersionArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: VersionArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let VersionArgs { let VersionArgs {
value, value,
bump, bump,
@ -1675,7 +1748,7 @@ impl VersionSettings {
python, python,
} = args; } = args;
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.clone() .clone()
.map(|fs| fs.install_mirrors.clone()) .map(|fs| fs.install_mirrors.clone())
.unwrap_or_default(); .unwrap_or_default();
@ -1697,7 +1770,9 @@ impl VersionSettings {
resolver_installer_options(installer, build), resolver_installer_options(installer, build),
filesystem, filesystem,
), ),
install_mirrors, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -1727,7 +1802,11 @@ pub(crate) struct TreeSettings {
impl TreeSettings { impl TreeSettings {
/// Resolve the [`TreeSettings`] from the CLI and workspace configuration. /// Resolve the [`TreeSettings`] from the CLI and workspace configuration.
pub(crate) fn resolve(args: TreeArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: TreeArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let TreeArgs { let TreeArgs {
tree, tree,
universal, universal,
@ -1748,7 +1827,8 @@ impl TreeSettings {
python_platform, python_platform,
python, python,
} = args; } = args;
let install_mirrors = filesystem
let filesystem_install_mirrors = filesystem
.clone() .clone()
.map(|fs| fs.install_mirrors.clone()) .map(|fs| fs.install_mirrors.clone())
.unwrap_or_default(); .unwrap_or_default();
@ -1779,7 +1859,9 @@ 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, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -1812,7 +1894,11 @@ pub(crate) struct ExportSettings {
impl ExportSettings { impl ExportSettings {
/// Resolve the [`ExportSettings`] from the CLI and filesystem configuration. /// Resolve the [`ExportSettings`] from the CLI and filesystem configuration.
#[allow(clippy::needless_pass_by_value)] #[allow(clippy::needless_pass_by_value)]
pub(crate) fn resolve(args: ExportArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: ExportArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let ExportArgs { let ExportArgs {
format, format,
all_packages, all_packages,
@ -1851,7 +1937,7 @@ impl ExportSettings {
script, script,
python, python,
} = args; } = args;
let install_mirrors = filesystem let filesystem_install_mirrors = filesystem
.clone() .clone()
.map(|fs| fs.install_mirrors.clone()) .map(|fs| fs.install_mirrors.clone())
.unwrap_or_default(); .unwrap_or_default();
@ -1897,7 +1983,9 @@ 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, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -1951,7 +2039,11 @@ pub(crate) struct PipCompileSettings {
impl PipCompileSettings { impl PipCompileSettings {
/// Resolve the [`PipCompileSettings`] from the CLI and filesystem configuration. /// Resolve the [`PipCompileSettings`] from the CLI and filesystem configuration.
pub(crate) fn resolve(args: PipCompileArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: PipCompileArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipCompileArgs { let PipCompileArgs {
src_file, src_file,
constraints, constraints,
@ -2117,6 +2209,7 @@ impl PipCompileSettings {
..PipOptions::from(resolver) ..PipOptions::from(resolver)
}, },
filesystem, filesystem,
environment,
), ),
} }
} }
@ -2135,7 +2228,11 @@ pub(crate) struct PipSyncSettings {
impl PipSyncSettings { impl PipSyncSettings {
/// Resolve the [`PipSyncSettings`] from the CLI and filesystem configuration. /// Resolve the [`PipSyncSettings`] from the CLI and filesystem configuration.
pub(crate) fn resolve(args: Box<PipSyncArgs>, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: Box<PipSyncArgs>,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipSyncArgs { let PipSyncArgs {
src_file, src_file,
constraints, constraints,
@ -2215,6 +2312,7 @@ impl PipSyncSettings {
..PipOptions::from(installer) ..PipOptions::from(installer)
}, },
filesystem, filesystem,
environment,
), ),
} }
} }
@ -2240,7 +2338,11 @@ pub(crate) struct PipInstallSettings {
impl PipInstallSettings { impl PipInstallSettings {
/// Resolve the [`PipInstallSettings`] from the CLI and filesystem configuration. /// Resolve the [`PipInstallSettings`] from the CLI and filesystem configuration.
pub(crate) fn resolve(args: PipInstallArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: PipInstallArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipInstallArgs { let PipInstallArgs {
package, package,
requirements, requirements,
@ -2377,6 +2479,7 @@ impl PipInstallSettings {
..PipOptions::from(installer) ..PipOptions::from(installer)
}, },
filesystem, filesystem,
environment,
), ),
} }
} }
@ -2393,7 +2496,11 @@ pub(crate) struct PipUninstallSettings {
impl PipUninstallSettings { impl PipUninstallSettings {
/// Resolve the [`PipUninstallSettings`] from the CLI and filesystem configuration. /// Resolve the [`PipUninstallSettings`] from the CLI and filesystem configuration.
pub(crate) fn resolve(args: PipUninstallArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: PipUninstallArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipUninstallArgs { let PipUninstallArgs {
package, package,
requirements, requirements,
@ -2428,6 +2535,7 @@ impl PipUninstallSettings {
..PipOptions::default() ..PipOptions::default()
}, },
filesystem, filesystem,
environment,
), ),
} }
} }
@ -2443,7 +2551,11 @@ pub(crate) struct PipFreezeSettings {
impl PipFreezeSettings { impl PipFreezeSettings {
/// Resolve the [`PipFreezeSettings`] from the CLI and filesystem configuration. /// Resolve the [`PipFreezeSettings`] from the CLI and filesystem configuration.
pub(crate) fn resolve(args: PipFreezeArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: PipFreezeArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipFreezeArgs { let PipFreezeArgs {
exclude_editable, exclude_editable,
strict, strict,
@ -2466,6 +2578,7 @@ impl PipFreezeSettings {
..PipOptions::default() ..PipOptions::default()
}, },
filesystem, filesystem,
environment,
), ),
} }
} }
@ -2483,7 +2596,11 @@ pub(crate) struct PipListSettings {
impl PipListSettings { impl PipListSettings {
/// Resolve the [`PipListSettings`] from the CLI and filesystem configuration. /// Resolve the [`PipListSettings`] from the CLI and filesystem configuration.
pub(crate) fn resolve(args: PipListArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: PipListArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipListArgs { let PipListArgs {
editable, editable,
exclude_editable, exclude_editable,
@ -2513,6 +2630,7 @@ impl PipListSettings {
..PipOptions::from(fetch) ..PipOptions::from(fetch)
}, },
filesystem, filesystem,
environment,
), ),
} }
} }
@ -2528,7 +2646,11 @@ pub(crate) struct PipShowSettings {
impl PipShowSettings { impl PipShowSettings {
/// Resolve the [`PipShowSettings`] from the CLI and filesystem configuration. /// Resolve the [`PipShowSettings`] from the CLI and filesystem configuration.
pub(crate) fn resolve(args: PipShowArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: PipShowArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipShowArgs { let PipShowArgs {
package, package,
strict, strict,
@ -2551,6 +2673,7 @@ impl PipShowSettings {
..PipOptions::default() ..PipOptions::default()
}, },
filesystem, filesystem,
environment,
), ),
} }
} }
@ -2571,7 +2694,11 @@ pub(crate) struct PipTreeSettings {
impl PipTreeSettings { impl PipTreeSettings {
/// Resolve the [`PipTreeSettings`] from the CLI and workspace configuration. /// Resolve the [`PipTreeSettings`] from the CLI and workspace configuration.
pub(crate) fn resolve(args: PipTreeArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: PipTreeArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipTreeArgs { let PipTreeArgs {
show_version_specifiers, show_version_specifiers,
tree, tree,
@ -2600,6 +2727,7 @@ impl PipTreeSettings {
..PipOptions::from(fetch) ..PipOptions::from(fetch)
}, },
filesystem, filesystem,
environment,
), ),
} }
} }
@ -2613,7 +2741,11 @@ pub(crate) struct PipCheckSettings {
impl PipCheckSettings { impl PipCheckSettings {
/// Resolve the [`PipCheckSettings`] from the CLI and filesystem configuration. /// Resolve the [`PipCheckSettings`] from the CLI and filesystem configuration.
pub(crate) fn resolve(args: PipCheckArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: PipCheckArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let PipCheckArgs { let PipCheckArgs {
python, python,
system, system,
@ -2632,6 +2764,7 @@ impl PipCheckSettings {
..PipOptions::default() ..PipOptions::default()
}, },
filesystem, filesystem,
environment,
), ),
} }
} }
@ -2659,7 +2792,11 @@ pub(crate) struct BuildSettings {
impl BuildSettings { impl BuildSettings {
/// Resolve the [`BuildSettings`] from the CLI and filesystem configuration. /// Resolve the [`BuildSettings`] from the CLI and filesystem configuration.
pub(crate) fn resolve(args: BuildArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: BuildArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let BuildArgs { let BuildArgs {
src, src,
out_dir, out_dir,
@ -2681,8 +2818,7 @@ impl BuildSettings {
refresh, refresh,
resolver, resolver,
} = args; } = args;
let filesystem_install_mirrors = match &filesystem {
let install_mirrors = match &filesystem {
Some(fs) => fs.install_mirrors.clone(), Some(fs) => fs.install_mirrors.clone(),
None => PythonInstallMirrors::default(), None => PythonInstallMirrors::default(),
}; };
@ -2708,7 +2844,9 @@ 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, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }
@ -2731,7 +2869,11 @@ pub(crate) struct VenvSettings {
impl VenvSettings { impl VenvSettings {
/// Resolve the [`VenvSettings`] from the CLI and filesystem configuration. /// Resolve the [`VenvSettings`] from the CLI and filesystem configuration.
pub(crate) fn resolve(args: VenvArgs, filesystem: Option<FilesystemOptions>) -> Self { pub(crate) fn resolve(
args: VenvArgs,
filesystem: Option<FilesystemOptions>,
environment: EnvironmentOptions,
) -> Self {
let VenvArgs { let VenvArgs {
python, python,
system, system,
@ -2779,6 +2921,7 @@ impl VenvSettings {
..PipOptions::from(index_args) ..PipOptions::from(index_args)
}, },
filesystem, filesystem,
environment,
), ),
} }
} }
@ -3041,11 +3184,15 @@ 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>,
environment: EnvironmentOptions,
) -> Self {
let Options { let Options {
top_level, top_level,
pip, pip,
install_mirrors, install_mirrors: filesystem_install_mirrors,
.. ..
} = filesystem } = filesystem
.map(FilesystemOptions::into_options) .map(FilesystemOptions::into_options)
@ -3386,7 +3533,9 @@ impl PipSettings {
top_level_no_build_package.unwrap_or_default(), top_level_no_build_package.unwrap_or_default(),
)), )),
), ),
install_mirrors, install_mirrors: environment
.install_mirrors
.combine(filesystem_install_mirrors),
} }
} }
} }

View file

@ -466,6 +466,15 @@ impl TestContext {
self self
} }
#[must_use]
pub fn with_empty_python_install_mirror(mut self) -> Self {
self.extra_env.push((
EnvVars::UV_PYTHON_INSTALL_MIRROR.into(),
String::new().into(),
));
self
}
/// Add extra directories and configuration for managed Python installations. /// Add extra directories and configuration for managed Python installations.
#[must_use] #[must_use]
pub fn with_managed_python_dirs(mut self) -> Self { pub fn with_managed_python_dirs(mut self) -> Self {

View file

@ -529,8 +529,6 @@ fn help_subsubcommand() {
`https://github.com/astral-sh/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz`. `https://github.com/astral-sh/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. Distributions can be read from a local directory by using the `file://` URL scheme.
[env: UV_PYTHON_INSTALL_MIRROR=]
--pypy-mirror <PYPY_MIRROR> --pypy-mirror <PYPY_MIRROR>
Set the URL to use as the source for downloading PyPy installations. Set the URL to use as the source for downloading PyPy installations.
@ -539,15 +537,11 @@ fn help_subsubcommand() {
`https://downloads.python.org/pypy/pypy3.8-v7.3.7-osx64.tar.bz2`. `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. Distributions can be read from a local directory by using the `file://` URL scheme.
[env: UV_PYPY_INSTALL_MIRROR=]
--python-downloads-json-url <PYTHON_DOWNLOADS_JSON_URL> --python-downloads-json-url <PYTHON_DOWNLOADS_JSON_URL>
URL pointing to JSON of custom Python installations. URL pointing to JSON of custom Python installations.
Note that currently, only local paths are supported. Note that currently, only local paths are supported.
[env: UV_PYTHON_DOWNLOADS_JSON_URL=]
-r, --reinstall -r, --reinstall
Reinstall the requested Python version, if it's already installed. Reinstall the requested Python version, if it's already installed.
@ -812,13 +806,11 @@ fn help_flag_subsubcommand() {
--no-registry --no-registry
Do not register the Python installation in the Windows registry Do not register the Python installation in the Windows registry
--mirror <MIRROR> --mirror <MIRROR>
Set the URL to use as the source for downloading Python installations [env: Set the URL to use as the source for downloading Python installations
UV_PYTHON_INSTALL_MIRROR=]
--pypy-mirror <PYPY_MIRROR> --pypy-mirror <PYPY_MIRROR>
Set the URL to use as the source for downloading PyPy installations [env: Set the URL to use as the source for downloading PyPy installations
UV_PYPY_INSTALL_MIRROR=]
--python-downloads-json-url <PYTHON_DOWNLOADS_JSON_URL> --python-downloads-json-url <PYTHON_DOWNLOADS_JSON_URL>
URL pointing to JSON of custom Python installations [env: UV_PYTHON_DOWNLOADS_JSON_URL=] URL pointing to JSON of custom Python installations
-r, --reinstall -r, --reinstall
Reinstall the requested Python version, if it's already installed Reinstall the requested Python version, if it's already installed
-f, --force -f, --force

View file

@ -22,6 +22,7 @@ fn python_install() {
.with_filtered_python_keys() .with_filtered_python_keys()
.with_filtered_exe_suffix() .with_filtered_exe_suffix()
.with_managed_python_dirs() .with_managed_python_dirs()
.with_empty_python_install_mirror()
.with_python_download_cache(); .with_python_download_cache();
// Install the latest version // Install the latest version

View file

@ -703,6 +703,7 @@ fn python_upgrade_force_install() -> Result<()> {
let context = TestContext::new_with_versions(&["3.13"]) let context = TestContext::new_with_versions(&["3.13"])
.with_filtered_python_keys() .with_filtered_python_keys()
.with_filtered_exe_suffix() .with_filtered_exe_suffix()
.with_empty_python_install_mirror()
.with_managed_python_dirs(); .with_managed_python_dirs();
context context

View file

@ -3405,7 +3405,7 @@ uv python list [OPTIONS] [REQUEST]
<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>
<p>May also be set with the <code>UV_PROJECT</code> environment variable.</p></dd><dt id="uv-python-list--python-downloads-json-url"><a href="#uv-python-list--python-downloads-json-url"><code>--python-downloads-json-url</code></a> <i>python-downloads-json-url</i></dt><dd><p>URL pointing to JSON of custom Python installations.</p> <p>May also be set with the <code>UV_PROJECT</code> environment variable.</p></dd><dt id="uv-python-list--python-downloads-json-url"><a href="#uv-python-list--python-downloads-json-url"><code>--python-downloads-json-url</code></a> <i>python-downloads-json-url</i></dt><dd><p>URL pointing to JSON of custom Python installations.</p>
<p>Note that currently, only local paths are supported.</p> <p>Note that currently, only local paths are supported.</p>
<p>May also be set with the <code>UV_PYTHON_DOWNLOADS_JSON_URL</code> environment variable.</p></dd><dt id="uv-python-list--quiet"><a href="#uv-python-list--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p> </dd><dt id="uv-python-list--quiet"><a href="#uv-python-list--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p>
<p>Repeating this option, e.g., <code>-qq</code>, will enable a silent mode in which uv will write no output to stdout.</p> <p>Repeating this option, e.g., <code>-qq</code>, will enable a silent mode in which uv will write no output to stdout.</p>
</dd><dt id="uv-python-list--show-urls"><a href="#uv-python-list--show-urls"><code>--show-urls</code></a></dt><dd><p>Show the URLs of available Python downloads.</p> </dd><dt id="uv-python-list--show-urls"><a href="#uv-python-list--show-urls"><code>--show-urls</code></a></dt><dd><p>Show the URLs of available Python downloads.</p>
<p>By default, these display as <code>&lt;download available&gt;</code>.</p> <p>By default, these display as <code>&lt;download available&gt;</code>.</p>
@ -3477,7 +3477,7 @@ uv python install [OPTIONS] [TARGETS]...
<p>May also be set with the <code>UV_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-python-install--mirror"><a href="#uv-python-install--mirror"><code>--mirror</code></a> <i>mirror</i></dt><dd><p>Set the URL to use as the source for downloading Python installations.</p> <p>May also be set with the <code>UV_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-python-install--mirror"><a href="#uv-python-install--mirror"><code>--mirror</code></a> <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/astral-sh/python-build-standalone/releases/download</code> in, e.g., <code>https://github.com/astral-sh/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz</code>.</p> <p>The provided URL will replace <code>https://github.com/astral-sh/python-build-standalone/releases/download</code> in, e.g., <code>https://github.com/astral-sh/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>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 id="uv-python-install--native-tls"><a href="#uv-python-install--native-tls"><code>--native-tls</code></a></dt><dd><p>Whether to load TLS certificates from the platform's native certificate store.</p> </dd><dt id="uv-python-install--native-tls"><a href="#uv-python-install--native-tls"><code>--native-tls</code></a></dt><dd><p>Whether to load TLS certificates from the platform'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>
<p>However, in some cases, you may want to use the platform's native certificate store, especially if you're relying on a corporate trust root (e.g., for a mandatory proxy) that's included in your system's certificate store.</p> <p>However, in some cases, you may want to use the platform's native certificate store, especially if you're relying on a corporate trust root (e.g., for a mandatory proxy) that's included in your system's certificate store.</p>
<p>May also be set with the <code>UV_NATIVE_TLS</code> environment variable.</p></dd><dt id="uv-python-install--no-bin"><a href="#uv-python-install--no-bin"><code>--no-bin</code></a></dt><dd><p>Do not install a Python executable into the <code>bin</code> directory.</p> <p>May also be set with the <code>UV_NATIVE_TLS</code> environment variable.</p></dd><dt id="uv-python-install--no-bin"><a href="#uv-python-install--no-bin"><code>--no-bin</code></a></dt><dd><p>Do not install a Python executable into the <code>bin</code> directory.</p>
@ -3502,9 +3502,9 @@ uv python install [OPTIONS] [TARGETS]...
<p>May also be set with the <code>UV_PROJECT</code> environment variable.</p></dd><dt id="uv-python-install--pypy-mirror"><a href="#uv-python-install--pypy-mirror"><code>--pypy-mirror</code></a> <i>pypy-mirror</i></dt><dd><p>Set the URL to use as the source for downloading PyPy installations.</p> <p>May also be set with the <code>UV_PROJECT</code> environment variable.</p></dd><dt id="uv-python-install--pypy-mirror"><a href="#uv-python-install--pypy-mirror"><code>--pypy-mirror</code></a> <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>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>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 id="uv-python-install--python-downloads-json-url"><a href="#uv-python-install--python-downloads-json-url"><code>--python-downloads-json-url</code></a> <i>python-downloads-json-url</i></dt><dd><p>URL pointing to JSON of custom Python installations.</p> </dd><dt id="uv-python-install--python-downloads-json-url"><a href="#uv-python-install--python-downloads-json-url"><code>--python-downloads-json-url</code></a> <i>python-downloads-json-url</i></dt><dd><p>URL pointing to JSON of custom Python installations.</p>
<p>Note that currently, only local paths are supported.</p> <p>Note that currently, only local paths are supported.</p>
<p>May also be set with the <code>UV_PYTHON_DOWNLOADS_JSON_URL</code> environment variable.</p></dd><dt id="uv-python-install--quiet"><a href="#uv-python-install--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p> </dd><dt id="uv-python-install--quiet"><a href="#uv-python-install--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p>
<p>Repeating this option, e.g., <code>-qq</code>, will enable a silent mode in which uv will write no output to stdout.</p> <p>Repeating this option, e.g., <code>-qq</code>, will enable a silent mode in which uv will write no output to stdout.</p>
</dd><dt id="uv-python-install--reinstall"><a href="#uv-python-install--reinstall"><code>--reinstall</code></a>, <code>-r</code></dt><dd><p>Reinstall the requested Python version, if it's already installed.</p> </dd><dt id="uv-python-install--reinstall"><a href="#uv-python-install--reinstall"><code>--reinstall</code></a>, <code>-r</code></dt><dd><p>Reinstall the requested Python version, if it's already installed.</p>
<p>By default, uv will exit successfully if the version is already installed.</p> <p>By default, uv will exit successfully if the version is already installed.</p>
@ -3570,7 +3570,7 @@ uv python upgrade [OPTIONS] [TARGETS]...
<p>May also be set with the <code>UV_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-python-upgrade--mirror"><a href="#uv-python-upgrade--mirror"><code>--mirror</code></a> <i>mirror</i></dt><dd><p>Set the URL to use as the source for downloading Python installations.</p> <p>May also be set with the <code>UV_MANAGED_PYTHON</code> environment variable.</p></dd><dt id="uv-python-upgrade--mirror"><a href="#uv-python-upgrade--mirror"><code>--mirror</code></a> <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/astral-sh/python-build-standalone/releases/download</code> in, e.g., <code>https://github.com/astral-sh/python-build-standalone/releases/download/20240713/cpython-3.12.4%2B20240713-aarch64-apple-darwin-install_only.tar.gz</code>.</p> <p>The provided URL will replace <code>https://github.com/astral-sh/python-build-standalone/releases/download</code> in, e.g., <code>https://github.com/astral-sh/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>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 id="uv-python-upgrade--native-tls"><a href="#uv-python-upgrade--native-tls"><code>--native-tls</code></a></dt><dd><p>Whether to load TLS certificates from the platform's native certificate store.</p> </dd><dt id="uv-python-upgrade--native-tls"><a href="#uv-python-upgrade--native-tls"><code>--native-tls</code></a></dt><dd><p>Whether to load TLS certificates from the platform'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>
<p>However, in some cases, you may want to use the platform's native certificate store, especially if you're relying on a corporate trust root (e.g., for a mandatory proxy) that's included in your system's certificate store.</p> <p>However, in some cases, you may want to use the platform's native certificate store, especially if you're relying on a corporate trust root (e.g., for a mandatory proxy) that's included in your system's certificate store.</p>
<p>May also be set with the <code>UV_NATIVE_TLS</code> environment variable.</p></dd><dt id="uv-python-upgrade--no-cache"><a href="#uv-python-upgrade--no-cache"><code>--no-cache</code></a>, <code>--no-cache-dir</code>, <code>-n</code></dt><dd><p>Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation</p> <p>May also be set with the <code>UV_NATIVE_TLS</code> environment variable.</p></dd><dt id="uv-python-upgrade--no-cache"><a href="#uv-python-upgrade--no-cache"><code>--no-cache</code></a>, <code>--no-cache-dir</code>, <code>-n</code></dt><dd><p>Avoid reading from or writing to the cache, instead using a temporary directory for the duration of the operation</p>
@ -3591,9 +3591,9 @@ uv python upgrade [OPTIONS] [TARGETS]...
<p>May also be set with the <code>UV_PROJECT</code> environment variable.</p></dd><dt id="uv-python-upgrade--pypy-mirror"><a href="#uv-python-upgrade--pypy-mirror"><code>--pypy-mirror</code></a> <i>pypy-mirror</i></dt><dd><p>Set the URL to use as the source for downloading PyPy installations.</p> <p>May also be set with the <code>UV_PROJECT</code> environment variable.</p></dd><dt id="uv-python-upgrade--pypy-mirror"><a href="#uv-python-upgrade--pypy-mirror"><code>--pypy-mirror</code></a> <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>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>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 id="uv-python-upgrade--python-downloads-json-url"><a href="#uv-python-upgrade--python-downloads-json-url"><code>--python-downloads-json-url</code></a> <i>python-downloads-json-url</i></dt><dd><p>URL pointing to JSON of custom Python installations.</p> </dd><dt id="uv-python-upgrade--python-downloads-json-url"><a href="#uv-python-upgrade--python-downloads-json-url"><code>--python-downloads-json-url</code></a> <i>python-downloads-json-url</i></dt><dd><p>URL pointing to JSON of custom Python installations.</p>
<p>Note that currently, only local paths are supported.</p> <p>Note that currently, only local paths are supported.</p>
<p>May also be set with the <code>UV_PYTHON_DOWNLOADS_JSON_URL</code> environment variable.</p></dd><dt id="uv-python-upgrade--quiet"><a href="#uv-python-upgrade--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p> </dd><dt id="uv-python-upgrade--quiet"><a href="#uv-python-upgrade--quiet"><code>--quiet</code></a>, <code>-q</code></dt><dd><p>Use quiet output.</p>
<p>Repeating this option, e.g., <code>-qq</code>, will enable a silent mode in which uv will write no output to stdout.</p> <p>Repeating this option, e.g., <code>-qq</code>, will enable a silent mode in which uv will write no output to stdout.</p>
</dd><dt id="uv-python-upgrade--reinstall"><a href="#uv-python-upgrade--reinstall"><code>--reinstall</code></a>, <code>-r</code></dt><dd><p>Reinstall the latest Python patch, if it's already installed.</p> </dd><dt id="uv-python-upgrade--reinstall"><a href="#uv-python-upgrade--reinstall"><code>--reinstall</code></a>, <code>-r</code></dt><dd><p>Reinstall the latest Python patch, if it's already installed.</p>
<p>By default, uv will exit successfully if the latest patch is already installed.</p> <p>By default, uv will exit successfully if the latest patch is already installed.</p>