#![deny(clippy::print_stdout, clippy::print_stderr)]
use std::borrow::Cow;
use std::ffi::OsString;
use std::fmt::Write;
use std::io::stdout;
#[cfg(feature = "self-update")]
use std::ops::Bound;
use std::path::Path;
use std::process::ExitCode;
use std::str::FromStr;
use std::sync::atomic::Ordering;
use anstream::eprintln;
use anyhow::{Result, anyhow, bail};
use clap::error::{ContextKind, ContextValue};
use clap::{CommandFactory, Parser};
use futures::FutureExt;
use owo_colors::OwoColorize;
use settings::PipTreeSettings;
use tokio::task::spawn_blocking;
use tracing::{debug, instrument, trace};
#[cfg(not(feature = "self-update"))]
use crate::install_source::InstallSource;
use uv_cache::{Cache, Refresh};
use uv_cache_info::Timestamp;
#[cfg(feature = "self-update")]
use uv_cli::SelfUpdateArgs;
use uv_cli::{
AuthCommand, AuthHelperCommand, AuthNamespace, BuildBackendCommand, CacheCommand,
CacheNamespace, Cli, Commands, PipCommand, PipNamespace, ProjectCommand, PythonCommand,
PythonNamespace, SelfCommand, SelfNamespace, ToolCommand, ToolNamespace, TopLevelArgs,
WorkspaceCommand, WorkspaceNamespace, compat::CompatArgs,
};
use uv_client::BaseClientBuilder;
use uv_configuration::min_stack_size;
use uv_flags::EnvironmentFlags;
use uv_fs::{CWD, Simplified};
#[cfg(feature = "self-update")]
use uv_pep440::release_specifiers_to_ranges;
use uv_pep508::VersionOrUrl;
use uv_preview::{Preview, PreviewFeature};
use uv_pypi_types::{ParsedDirectoryUrl, ParsedUrl};
use uv_python::PythonRequest;
use uv_requirements::{GroupsSpecification, RequirementsSource};
use uv_requirements_txt::RequirementsTxtRequirement;
use uv_scripts::{Pep723Error, Pep723Item, Pep723Script};
use uv_settings::{Combine, EnvironmentOptions, FilesystemOptions, Options};
use uv_static::EnvVars;
use uv_warnings::{warn_user, warn_user_once};
use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache};
use crate::commands::{ExitStatus, ParsedRunCommand, RunCommand, ScriptPath, ToolRunCommand};
use crate::printer::Printer;
use crate::settings::{
CacheSettings, GlobalSettings, PipCheckSettings, PipCompileSettings, PipFreezeSettings,
PipInstallSettings, PipListSettings, PipShowSettings, PipSyncSettings, PipUninstallSettings,
PublishSettings,
};
pub(crate) mod child;
pub(crate) mod commands;
#[cfg(not(feature = "self-update"))]
mod install_source;
pub(crate) mod logging;
pub(crate) mod printer;
pub(crate) mod settings;
#[cfg(windows)]
mod windows_exception;
#[instrument(skip_all)]
async fn run(cli: Cli) -> Result<ExitStatus> {
if cli.top_level.global_args.quiet == 0 {
uv_warnings::enable();
}
let directory =
cli.top_level.global_args.directory.clone().or_else(|| {
std::env::var_os(EnvVars::UV_WORKING_DIRECTORY).map(std::path::PathBuf::from)
});
if let Some(directory) = directory.as_ref() {
std::env::set_current_dir(directory)?;
}
let parsed_run_command = if let Commands::Project(command) = &*cli.command
&& let ProjectCommand::Run(uv_cli::RunArgs {
command: Some(ref command),
module,
script,
gui_script,
..
}) = **command
{
Some(ParsedRunCommand::from_args(
command, module, script, gui_script,
)?)
} else {
None
};
let environment = EnvironmentOptions::new()?;
let early_preview = Preview::from_args(
settings::resolve_preview(&cli.top_level.global_args, None, &environment),
cli.top_level.global_args.no_preview,
&cli.top_level.global_args.preview_features,
);
let project_dir = if let Some(project) = &cli.top_level.global_args.project {
let path = uv_fs::normalize_path_buf(std::path::absolute(project)?);
if let Some(name) = path.file_name()
&& name == "pyproject.toml"
&& path.is_file()
&& let Some(parent) = path.parent()
{
Cow::Owned(parent.to_path_buf())
} else {
Cow::Owned(path)
}
} else if let Some(run_command) = &parsed_run_command
&& early_preview.is_enabled(PreviewFeature::TargetWorkspaceDiscovery)
&& let Some(dir) = run_command.script_dir()
{
Cow::Owned(std::path::absolute(dir)?)
} else {
Cow::Borrowed(&*CWD)
};
let skip_project_validation = matches!(
&*cli.command,
Commands::Project(command) if matches!(**command, ProjectCommand::Init(_))
);
if !skip_project_validation {
if let Some(project_path) = cli.top_level.global_args.project.as_ref() {
if !project_dir.exists() {
if early_preview.is_enabled(PreviewFeature::ProjectDirectoryMustExist) {
bail!(
"Project directory `{}` does not exist",
project_path.user_display()
);
}
warn_user_once!(
"Project directory `{}` does not exist. \
This will become an error in a future release. \
Use `--preview-features project-directory-must-exist` to error on this now.",
project_path.user_display()
);
} else if !project_dir.is_dir() {
if early_preview.is_enabled(PreviewFeature::ProjectDirectoryMustExist) {
bail!(
"Project path `{}` is not a directory",
project_path.user_display()
);
}
warn_user_once!(
"Project path `{}` is not a directory. \
This will become an error in a future release. \
Use `--preview-features project-directory-must-exist` to error on this now.",
project_path.user_display()
);
}
}
}
let deprecated_isolated = if cli.top_level.global_args.isolated {
match &*cli.command {
Commands::Tool(ToolNamespace {
command: ToolCommand::Uvx(_) | ToolCommand::Run(_),
}) => false,
Commands::Project(command) if matches!(**command, ProjectCommand::Run(_)) => false,
Commands::Project(command) if matches!(**command, ProjectCommand::Init(_)) => {
warn_user!(
"The `--isolated` flag is deprecated and has no effect. Instead, use `--no-config` to prevent uv from discovering configuration files or `--no-workspace` to prevent uv from adding the initialized project to the containing workspace."
);
false
}
Commands::Project(_) | Commands::Tool(_) | Commands::Python(_) => {
warn_user!(
"The `--isolated` flag is deprecated and has no effect. Instead, use `--no-config` to prevent uv from discovering configuration files."
);
false
}
_ => {
warn_user!(
"The `--isolated` flag is deprecated. Instead, use `--no-config` to prevent uv from discovering configuration files."
);
true
}
}
} else {
false
};
let workspace_cache = WorkspaceCache::default();
let filesystem = if let Some(config_file) = cli.top_level.config_file.as_ref() {
if config_file
.file_name()
.is_some_and(|file_name| file_name == "pyproject.toml")
{
warn_user!(
"The `--config-file` argument expects to receive a `uv.toml` file, not a `pyproject.toml`. If you're trying to run a command from another project, use the `--project` argument instead."
);
}
Some(FilesystemOptions::from_file(config_file)?)
} else if deprecated_isolated || cli.top_level.no_config {
None
} else if matches!(&*cli.command, Commands::Tool(_) | Commands::Self_(_)) {
FilesystemOptions::user()?.combine(FilesystemOptions::system()?)
} else if let Ok(workspace) =
Workspace::discover(&project_dir, &DiscoveryOptions::default(), &workspace_cache).await
{
let project = FilesystemOptions::find(workspace.install_path())?;
let system = FilesystemOptions::system()?;
let user = FilesystemOptions::user()?;
project.combine(user).combine(system)
} else {
let project = FilesystemOptions::find(&project_dir)?;
let system = FilesystemOptions::system()?;
let user = FilesystemOptions::user()?;
project.combine(user).combine(system)
};
let (run_script, run_command) = if let Some(parsed_run_command) = parsed_run_command {
let (script, run_command) = parsed_run_command
.resolve(
&cli.top_level.global_args,
filesystem.as_ref(),
&environment,
)
.await?;
(script, Some(run_command))
} else {
(None, None)
};
let script = if let Some(run_script) = run_script {
Some(run_script)
} else if let Commands::Project(command) = &*cli.command {
match &**command {
ProjectCommand::Add(uv_cli::AddArgs {
script: Some(script),
..
})
| ProjectCommand::Lock(uv_cli::LockArgs {
script: Some(script),
..
}) => match Pep723Script::read(script).await {
Ok(Some(script)) => Some(Pep723Item::Script(script)),
Ok(None) => None,
Err(err) => return Err(err.into()),
},
ProjectCommand::Remove(uv_cli::RemoveArgs {
script: Some(script),
..
})
| ProjectCommand::Sync(uv_cli::SyncArgs {
script: Some(script),
..
})
| ProjectCommand::Tree(uv_cli::TreeArgs {
script: Some(script),
..
})
| ProjectCommand::Export(uv_cli::ExportArgs {
script: Some(script),
..
}) => match Pep723Script::read(script).await {
Ok(Some(script)) => Some(Pep723Item::Script(script)),
Ok(None) => {
bail!(
"`{}` does not contain a PEP 723 metadata tag; run `{}` to initialize the script",
script.user_display().cyan(),
format!("uv init --script {}", script.user_display()).green()
)
}
Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
bail!(
"Failed to read `{}` (not found); run `{}` to create a PEP 723 script",
script.user_display().cyan(),
format!("uv init --script {}", script.user_display()).green()
)
}
Err(err) => return Err(err.into()),
},
_ => None,
}
} else if let Commands::Python(uv_cli::PythonNamespace {
command:
PythonCommand::Find(uv_cli::PythonFindArgs {
script: Some(script),
..
}),
}) = &*cli.command
{
match Pep723Script::read(&script).await {
Ok(Some(script)) => Some(Pep723Item::Script(script)),
Ok(None) => {
bail!(
"`{}` does not contain a PEP 723 metadata tag; run `{}` to initialize the script",
script.user_display().cyan(),
format!("uv init --script {}", script.user_display()).green()
)
}
Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
bail!(
"Failed to read `{}` (not found); run `{}` to create a PEP 723 script",
script.user_display().cyan(),
format!("uv init --script {}", script.user_display()).green()
)
}
Err(err) => return Err(err.into()),
}
} else {
None
};
let filesystem = script
.as_ref()
.map(Pep723Item::metadata)
.and_then(|metadata| metadata.tool.as_ref())
.and_then(|tool| tool.uv.as_ref())
.map(|uv| Options::simple(uv.globals.clone(), uv.top_level.clone()))
.map(FilesystemOptions::from)
.combine(filesystem);
let globals = GlobalSettings::resolve(
&cli.top_level.global_args,
filesystem.as_ref(),
&environment,
);
uv_flags::init(EnvironmentFlags::from(&environment))
.map_err(|()| anyhow::anyhow!("Flags are already initialized"))?;
#[cfg(feature = "tracing-durations-export")]
let (durations_layer, _duration_guard) =
logging::setup_durations(environment.tracing_durations_file.as_ref())?;
#[cfg(not(feature = "tracing-durations-export"))]
let durations_layer = None::<tracing_subscriber::layer::Identity>;
logging::setup_logging(
match globals.verbose {
0 => logging::Level::Off,
1 => logging::Level::DebugUv,
2 => logging::Level::TraceUv,
3.. => logging::Level::TraceAll,
},
durations_layer,
globals.color,
environment.log_context.unwrap_or_default(),
)?;
debug!("uv {}", uv_cli::version::uv_self_version());
if let Some(config_file) = cli.top_level.config_file.as_ref() {
debug!("Using configuration file: {}", config_file.user_display());
}
if globals.preview.all_enabled() {
debug!("All preview features are enabled");
} else if globals.preview.any_enabled() {
debug!(
"The following preview features are enabled: {}",
globals.preview
);
}
#[cfg(unix)]
if globals.preview.is_enabled(PreviewFeature::AdjustUlimit) {
match uv_unix::adjust_open_file_limit() {
Ok(_) | Err(uv_unix::OpenFileLimitError::AlreadySufficient { .. }) => {}
Err(err) => warn_user!("{err}"),
}
}
let cache_settings = CacheSettings::resolve(*cli.top_level.cache_args, filesystem.as_ref());
uv_preview::init(globals.preview)?;
if let Some(required_version) = globals.required_version.as_ref() {
let package_version = uv_pep440::Version::from_str(uv_version::version())?;
if !required_version.contains(&package_version) {
#[cfg(feature = "self-update")]
let hint = {
let ranges = release_specifiers_to_ranges(required_version.specifiers().clone());
if let Some(singleton) = ranges.as_singleton() {
format!(
". Update `uv` by running `{}`.",
format!("uv self update {singleton}").green()
)
} else if ranges
.bounding_range()
.iter()
.any(|(lowest, _highest)| match lowest {
Bound::Included(version) => **version > package_version,
Bound::Excluded(version) => **version > package_version,
Bound::Unbounded => false,
})
{
format!(". Update `uv` by running `{}`.", "uv self update".cyan())
} else {
String::new()
}
};
#[cfg(not(feature = "self-update"))]
let hint = "";
return Err(anyhow::anyhow!(
"Required uv version `{required_version}` does not match the running version `{package_version}`{hint}",
));
}
}
let printer = if globals.quiet == 1 {
Printer::Quiet
} else if globals.quiet > 1 {
Printer::Silent
} else if globals.verbose > 0 {
Printer::Verbose
} else if globals.no_progress {
Printer::NoProgress
} else {
Printer::Default
};
if globals.quiet > 0 {
uv_warnings::disable();
} else {
uv_warnings::enable();
}
anstream::ColorChoice::write_global(globals.color.into());
miette::set_hook(Box::new(|_| {
Box::new(
miette::MietteHandlerOpts::new()
.break_words(false)
.word_separator(textwrap::WordSeparator::AsciiSpace)
.word_splitter(textwrap::WordSplitter::NoHyphenation)
.wrap_lines(
std::env::var(EnvVars::UV_NO_WRAP)
.map(|_| false)
.unwrap_or(true),
)
.build(),
)
}))?;
uv_configuration::RAYON_PARALLELISM.store(globals.concurrency.installs, Ordering::Relaxed);
macro_rules! show_settings {
($arg:expr) => {
if globals.show_settings {
writeln!(printer.stdout(), "{:#?}", $arg)?;
return Ok(ExitStatus::Success);
}
};
($arg:expr, false) => {
if globals.show_settings {
writeln!(printer.stdout(), "{:#?}", $arg)?;
}
};
}
show_settings!(globals, false);
show_settings!(cache_settings, false);
if cache_settings.no_cache {
debug!("Disabling the uv cache due to `--no-cache`");
}
let cache = Cache::from_settings(cache_settings.no_cache, cache_settings.cache_dir)?;
let client_builder = BaseClientBuilder::new(
globals.network_settings.connectivity,
globals.network_settings.system_certs,
globals.network_settings.allow_insecure_host.clone(),
globals.preview,
globals.network_settings.read_timeout,
globals.network_settings.connect_timeout,
globals.network_settings.retries,
)
.http_proxy(globals.network_settings.http_proxy.clone())
.https_proxy(globals.network_settings.https_proxy.clone())
.no_proxy(globals.network_settings.no_proxy.clone());
match *cli.command {
Commands::Auth(AuthNamespace {
command: AuthCommand::Login(args),
}) => {
let args = settings::AuthLoginSettings::resolve(args);
show_settings!(args);
commands::auth_login(
args.service,
args.username,
args.password,
args.token,
client_builder,
printer,
globals.preview,
)
.await
}
Commands::Auth(AuthNamespace {
command: AuthCommand::Logout(args),
}) => {
let args = settings::AuthLogoutSettings::resolve(args);
show_settings!(args);
commands::auth_logout(
args.service,
args.username,
client_builder,
printer,
globals.preview,
)
.await
}
Commands::Auth(AuthNamespace {
command: AuthCommand::Token(args),
}) => {
let args = settings::AuthTokenSettings::resolve(args);
show_settings!(args);
commands::auth_token(
args.service,
args.username,
client_builder,
printer,
globals.preview,
)
.await
}
Commands::Auth(AuthNamespace {
command: AuthCommand::Dir(args),
}) => {
commands::auth_dir(args.service.as_ref(), printer)?;
Ok(ExitStatus::Success)
}
Commands::Auth(AuthNamespace {
command: AuthCommand::Helper(args),
}) => {
use uv_cli::AuthHelperProtocol;
match args.protocol {
AuthHelperProtocol::Bazel => {}
}
match args.command {
AuthHelperCommand::Get => {
commands::auth_helper(client_builder, globals.preview, printer).await
}
}
}
Commands::Help(args) => commands::help(
args.command.unwrap_or_default().as_slice(),
printer,
args.no_pager,
),
Commands::Pip(PipNamespace {
command: PipCommand::Compile(args),
}) => {
args.compat_args.validate()?;
let args = PipCompileSettings::resolve(args, filesystem, environment);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.reinstall.clone()))
.combine(Refresh::from(args.settings.upgrade.clone())),
);
let requirements = args
.src_file
.into_iter()
.map(RequirementsSource::from_requirements_file)
.collect::<Result<Vec<_>, _>>()?;
let constraints = args
.constraints
.into_iter()
.map(RequirementsSource::from_constraints_txt)
.collect::<Result<Vec<_>, _>>()?;
let overrides = args
.overrides
.into_iter()
.map(RequirementsSource::from_overrides_txt)
.collect::<Result<Vec<_>, _>>()?;
let excludes = args
.excludes
.into_iter()
.map(RequirementsSource::from_requirements_txt)
.collect::<Result<Vec<_>, _>>()?;
let build_constraints = args
.build_constraints
.into_iter()
.map(RequirementsSource::from_constraints_txt)
.collect::<Result<Vec<_>, _>>()?;
let groups = GroupsSpecification {
root: project_dir.to_path_buf(),
groups: args.settings.groups,
};
commands::pip_compile(
&requirements,
&constraints,
&overrides,
&excludes,
&build_constraints,
args.constraints_from_workspace,
args.overrides_from_workspace,
args.excludes_from_workspace,
args.build_constraints_from_workspace,
args.environments,
args.settings.extras,
groups,
args.settings.output_file.as_deref(),
args.format,
args.settings.resolution,
args.settings.prerelease,
args.settings.fork_strategy,
args.settings.dependency_mode,
args.settings.upgrade,
args.settings.generate_hashes,
args.settings.no_emit_package,
args.settings.no_strip_extras,
args.settings.no_strip_markers,
!args.settings.no_annotate,
!args.settings.no_header,
args.settings.custom_compile_command,
args.settings.emit_index_url,
args.settings.emit_find_links,
args.settings.emit_build_options,
args.settings.emit_marker_expression,
args.settings.emit_index_annotation,
args.settings.index_locations,
args.settings.index_strategy,
args.settings.torch_backend,
args.settings.dependency_metadata,
args.settings.keyring_provider,
&client_builder.subcommand(vec!["pip".to_owned(), "compile".to_owned()]),
args.settings.config_setting,
args.settings.config_settings_package,
args.settings.build_isolation.clone(),
&args.settings.extra_build_dependencies,
&args.settings.extra_build_variables,
args.settings.build_options,
args.settings.install_mirrors,
args.settings.python_version,
args.settings.python_platform,
globals.python_downloads,
args.settings.universal,
args.settings.exclude_newer,
args.settings.sources,
args.settings.annotation_style,
args.settings.link_mode,
args.settings.python,
args.settings.system,
globals.python_preference,
globals.concurrency,
globals.quiet > 0,
cache,
workspace_cache,
printer,
globals.preview,
)
.await
}
Commands::Pip(PipNamespace {
command: PipCommand::Sync(args),
}) => {
args.compat_args.validate()?;
let args = PipSyncSettings::resolve(args, filesystem, environment);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.reinstall.clone()))
.combine(Refresh::from(args.settings.upgrade.clone())),
);
let requirements = args
.src_file
.into_iter()
.map(RequirementsSource::from_requirements_file)
.collect::<Result<Vec<_>, _>>()?;
let constraints = args
.constraints
.into_iter()
.map(RequirementsSource::from_constraints_txt)
.collect::<Result<Vec<_>, _>>()?;
let build_constraints = args
.build_constraints
.into_iter()
.map(RequirementsSource::from_constraints_txt)
.collect::<Result<Vec<_>, _>>()?;
let groups = GroupsSpecification {
root: project_dir.to_path_buf(),
groups: args.settings.groups,
};
commands::pip_sync(
&requirements,
&constraints,
&build_constraints,
&args.settings.extras,
&groups,
args.settings.reinstall,
args.settings.link_mode,
args.settings.compile_bytecode,
args.settings.hash_checking,
args.settings.index_locations,
args.settings.index_strategy,
args.settings.torch_backend,
args.settings.dependency_metadata,
args.settings.keyring_provider,
&client_builder.subcommand(vec!["pip".to_owned(), "sync".to_owned()]),
args.settings.allow_empty_requirements,
globals.installer_metadata,
&args.settings.config_setting,
&args.settings.config_settings_package,
args.settings.build_isolation.clone(),
&args.settings.extra_build_dependencies,
&args.settings.extra_build_variables,
args.settings.build_options,
args.settings.python_version,
args.settings.python_platform,
globals.python_downloads,
args.settings.install_mirrors,
args.settings.strict,
args.settings.exclude_newer,
args.settings.python,
args.settings.system,
args.settings.break_system_packages,
args.settings.target,
args.settings.prefix,
args.settings.sources,
globals.python_preference,
globals.concurrency,
cache,
workspace_cache,
args.dry_run,
printer,
globals.preview,
)
.await
}
Commands::Pip(PipNamespace {
command: PipCommand::Install(args),
}) => {
args.compat_args.validate()?;
let mut args = PipInstallSettings::resolve(args, filesystem, environment);
show_settings!(args);
let mut requirements = Vec::with_capacity(
args.package.len() + args.editables.len() + args.requirements.len(),
);
for package in args.package {
requirements.push(RequirementsSource::from_package_argument(&package)?);
}
for package in args.editables {
requirements.push(RequirementsSource::from_editable(&package)?);
}
requirements.extend(
args.requirements
.into_iter()
.map(RequirementsSource::from_requirements_file)
.collect::<Result<Vec<_>, _>>()?,
);
let constraints = args
.constraints
.into_iter()
.map(RequirementsSource::from_constraints_txt)
.collect::<Result<Vec<_>, _>>()?;
let overrides = args
.overrides
.into_iter()
.map(RequirementsSource::from_overrides_txt)
.collect::<Result<Vec<_>, _>>()?;
let excludes = args
.excludes
.into_iter()
.map(RequirementsSource::from_requirements_txt)
.collect::<Result<Vec<_>, _>>()?;
let build_constraints = args
.build_constraints
.into_iter()
.map(RequirementsSource::from_overrides_txt)
.collect::<Result<Vec<_>, _>>()?;
let groups = GroupsSpecification {
root: project_dir.to_path_buf(),
groups: args.settings.groups,
};
for requirement in &requirements {
let requirement = match requirement {
RequirementsSource::Package(requirement) => requirement,
RequirementsSource::Editable(requirement) => requirement,
_ => continue,
};
match requirement {
RequirementsTxtRequirement::Named(requirement) => {
if let Some(VersionOrUrl::Url(url)) = requirement.version_or_url.as_ref() {
if let ParsedUrl::Directory(ParsedDirectoryUrl {
install_path, ..
}) = &url.parsed_url
{
debug!(
"Marking explicit source tree for reinstall: `{}`",
install_path.display()
);
args.settings.reinstall = args
.settings
.reinstall
.with_package(requirement.name.clone());
}
}
}
RequirementsTxtRequirement::Unnamed(requirement) => {
if let ParsedUrl::Directory(ParsedDirectoryUrl { install_path, .. }) =
&requirement.url.parsed_url
{
debug!(
"Marking explicit source tree for reinstall: `{}`",
install_path.display()
);
args.settings.reinstall =
args.settings.reinstall.with_path(install_path.clone());
}
}
}
}
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.reinstall.clone()))
.combine(Refresh::from(args.settings.upgrade.clone())),
);
Box::pin(commands::pip_install(
&requirements,
&constraints,
&overrides,
&excludes,
&build_constraints,
args.constraints_from_workspace,
args.overrides_from_workspace,
args.excludes_from_workspace,
args.build_constraints_from_workspace,
&args.settings.extras,
&groups,
args.settings.resolution,
args.settings.prerelease,
args.settings.dependency_mode,
args.settings.upgrade,
args.settings.index_locations,
args.settings.index_strategy,
args.settings.torch_backend,
args.settings.dependency_metadata,
args.settings.keyring_provider,
&client_builder.subcommand(vec!["pip".to_owned(), "install".to_owned()]),
args.settings.reinstall,
args.settings.link_mode,
args.settings.compile_bytecode,
args.settings.hash_checking,
globals.installer_metadata,
&args.settings.config_setting,
&args.settings.config_settings_package,
args.settings.build_isolation.clone(),
&args.settings.extra_build_dependencies,
&args.settings.extra_build_variables,
args.settings.build_options,
args.modifications,
args.settings.python_version,
args.settings.python_platform,
globals.python_downloads,
args.settings.install_mirrors,
args.settings.strict,
args.settings.exclude_newer,
args.settings.sources,
args.settings.python,
args.settings.system,
args.settings.break_system_packages,
args.settings.target,
args.settings.prefix,
globals.python_preference,
globals.concurrency,
cache,
workspace_cache,
args.dry_run,
printer,
globals.preview,
))
.await
}
Commands::Pip(PipNamespace {
command: PipCommand::Uninstall(args),
}) => {
let args = PipUninstallSettings::resolve(args, filesystem, environment);
show_settings!(args);
let cache = cache.init().await?;
let mut sources = Vec::with_capacity(args.package.len() + args.requirements.len());
for package in args.package {
sources.push(RequirementsSource::from_package_argument(&package)?);
}
sources.extend(
args.requirements
.into_iter()
.map(RequirementsSource::from_requirements_file)
.collect::<Result<Vec<_>, _>>()?,
);
commands::pip_uninstall(
&sources,
args.settings.python,
args.settings.system,
args.settings.break_system_packages,
args.settings.target,
args.settings.prefix,
cache,
args.settings.keyring_provider,
&client_builder.subcommand(vec!["pip".to_owned(), "uninstall".to_owned()]),
args.dry_run,
printer,
globals.preview,
)
.await
}
Commands::Pip(PipNamespace {
command: PipCommand::Freeze(args),
}) => {
let args = PipFreezeSettings::resolve(args, filesystem, environment);
show_settings!(args);
let cache = cache.init().await?;
commands::pip_freeze(
args.exclude_editable,
&args.exclude,
args.settings.strict,
&args.settings.dependency_metadata,
args.settings.python.as_deref(),
args.settings.system,
args.settings.target,
args.settings.prefix,
args.paths,
&cache,
printer,
globals.preview,
)
}
Commands::Pip(PipNamespace {
command: PipCommand::List(args),
}) => {
args.compat_args.validate()?;
let args = PipListSettings::resolve(args, filesystem, environment);
show_settings!(args);
let cache = cache.init().await?;
commands::pip_list(
args.editable,
&args.exclude,
&args.format,
args.outdated,
args.settings.prerelease,
args.settings.index_locations,
args.settings.index_strategy,
args.settings.keyring_provider,
&client_builder.subcommand(vec!["pip".to_owned(), "list".to_owned()]),
globals.concurrency,
args.settings.strict,
args.settings.exclude_newer,
&args.settings.dependency_metadata,
args.settings.python.as_deref(),
args.settings.system,
args.settings.target,
args.settings.prefix,
&cache,
printer,
globals.preview,
)
.await
}
Commands::Pip(PipNamespace {
command: PipCommand::Show(args),
}) => {
let args = PipShowSettings::resolve(args, filesystem, environment);
show_settings!(args);
let cache = cache.init().await?;
commands::pip_show(
args.package,
args.settings.strict,
&args.settings.dependency_metadata,
args.settings.python.as_deref(),
args.settings.system,
args.settings.target,
args.settings.prefix,
args.files,
&cache,
printer,
globals.preview,
)
}
Commands::Pip(PipNamespace {
command: PipCommand::Tree(args),
}) => {
let args = PipTreeSettings::resolve(args, filesystem, environment);
let cache = cache.init().await?;
commands::pip_tree(
args.show_version_specifiers,
args.depth,
&args.prune,
&args.package,
args.no_dedupe,
args.invert,
args.outdated,
args.settings.prerelease,
args.settings.index_locations,
args.settings.index_strategy,
args.settings.keyring_provider,
client_builder.subcommand(vec!["pip".to_owned(), "tree".to_owned()]),
globals.concurrency,
args.settings.strict,
args.settings.exclude_newer,
&args.settings.dependency_metadata,
args.settings.python.as_deref(),
args.settings.system,
&cache,
printer,
globals.preview,
)
.await
}
Commands::Pip(PipNamespace {
command: PipCommand::Check(args),
}) => {
let args = PipCheckSettings::resolve(args, filesystem, environment);
show_settings!(args);
let cache = cache.init().await?;
commands::pip_check(
args.settings.python.as_deref(),
args.settings.system,
args.settings.python_version.as_ref(),
args.settings.python_platform.as_ref(),
&args.settings.dependency_metadata,
&cache,
printer,
globals.preview,
)
}
Commands::Pip(PipNamespace {
command: PipCommand::Debug(_),
}) => Err(anyhow!(
"pip's `debug` is unsupported (consider using `uvx pip debug` instead)"
)),
Commands::Cache(CacheNamespace {
command: CacheCommand::Clean(args),
})
| Commands::Clean(args) => {
show_settings!(args);
commands::cache_clean(&args.package, args.force, cache, printer).await
}
Commands::Cache(CacheNamespace {
command: CacheCommand::Prune(args),
}) => {
show_settings!(args);
commands::cache_prune(args.ci, args.force, cache, printer).await
}
Commands::Cache(CacheNamespace {
command: CacheCommand::Dir,
}) => commands::cache_dir(&cache, printer),
Commands::Cache(CacheNamespace {
command: CacheCommand::Size(args),
}) => commands::cache_size(&cache, args.human, printer, globals.preview),
Commands::Build(args) => {
let args = settings::BuildSettings::resolve(args, filesystem, environment);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.upgrade.clone())),
);
let build_constraints = args
.build_constraints
.into_iter()
.map(RequirementsSource::from_constraints_txt)
.collect::<Result<Vec<_>, _>>()?;
commands::build_frontend(
&project_dir,
args.src,
args.package,
args.all_packages,
args.out_dir,
args.sdist,
args.wheel,
args.list,
args.build_logs,
args.gitignore,
args.force_pep517,
args.clear,
build_constraints,
args.build_constraints_from_workspace,
args.hash_checking,
args.python,
args.install_mirrors,
&args.settings,
&client_builder.subcommand(vec!["build".to_owned()]),
cli.top_level.no_config,
globals.python_preference,
globals.python_downloads,
globals.concurrency,
&cache,
&workspace_cache,
printer,
globals.preview,
)
.await
}
Commands::Venv(args) => {
args.compat_args.validate()?;
if args.no_system {
warn_user_once!(
"The `--no-system` flag has no effect, `uv venv` always ignores virtual environments when finding a Python interpreter; did you mean `--managed-python`?"
);
}
if args.system {
warn_user_once!(
"The `--system` flag has no effect, `uv venv` always ignores virtual environments when finding a Python interpreter; did you mean `--no-managed-python`?"
);
}
let args = settings::VenvSettings::resolve(args, filesystem, environment);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.reinstall.clone()))
.combine(Refresh::from(args.settings.upgrade.clone())),
);
let prompt = args.prompt.or_else(|| {
if args.path.is_none() {
Some(".".to_string())
} else {
None
}
});
let python_request: Option<PythonRequest> =
args.settings.python.as_deref().map(PythonRequest::parse);
let on_existing = uv_virtualenv::OnExisting::from_args(
args.allow_existing,
args.clear,
args.no_clear,
);
commands::venv(
&project_dir,
args.path,
python_request,
args.settings.install_mirrors,
globals.python_preference,
globals.python_downloads,
args.settings.link_mode,
&args.settings.index_locations,
args.settings.index_strategy,
args.settings.dependency_metadata,
args.settings.keyring_provider,
&client_builder.subcommand(vec!["venv".to_owned()]),
uv_virtualenv::Prompt::from_args(prompt),
args.system_site_packages,
args.seed,
on_existing,
args.settings.exclude_newer,
globals.concurrency,
cli.top_level.no_config,
args.no_project,
&cache,
&workspace_cache,
printer,
args.relocatable
|| (globals
.preview
.is_enabled(PreviewFeature::RelocatableEnvsDefault)
&& !args.no_relocatable),
globals.preview,
)
.await
}
Commands::Project(project) => {
Box::pin(run_project(
project,
&project_dir,
run_command,
script,
globals,
cli.top_level.no_config,
cli.top_level.global_args.project.is_some(),
client_builder,
filesystem,
cache,
&workspace_cache,
printer,
))
.await
}
#[cfg(feature = "self-update")]
Commands::Self_(SelfNamespace {
command:
SelfCommand::Update(SelfUpdateArgs {
target_version,
token,
dry_run,
}),
}) => {
commands::self_update(
target_version,
token,
dry_run,
printer,
client_builder.subcommand(vec!["self".to_owned(), "update".to_owned()]),
)
.await
}
Commands::Self_(SelfNamespace {
command:
SelfCommand::Version {
short,
output_format,
},
}) => {
commands::self_version(short, output_format, printer)?;
Ok(ExitStatus::Success)
}
#[cfg(not(feature = "self-update"))]
Commands::Self_(_) => {
const BASE_MESSAGE: &str =
"uv was installed through an external package manager and cannot update itself.";
let message = match InstallSource::detect() {
Some(source) => format!(
"{base}\n\n{hint}{colon} You installed uv using {}. To update uv, run `{}`",
source.description(),
source.update_instructions().green(),
hint = "hint".bold().cyan(),
colon = ":".bold(),
base = BASE_MESSAGE
),
None => format!("{BASE_MESSAGE} Please use your package manager to update uv."),
};
anyhow::bail!(message);
}
Commands::GenerateShellCompletion(args) => {
args.shell.generate(&mut Cli::command(), &mut stdout());
Ok(ExitStatus::Success)
}
Commands::Tool(ToolNamespace {
command: run_variant @ (ToolCommand::Uvx(_) | ToolCommand::Run(_)),
}) => {
let (args, invocation_source) = match run_variant {
ToolCommand::Uvx(args) => (args.tool_run, ToolRunCommand::Uvx),
ToolCommand::Run(args) => (args, ToolRunCommand::ToolRun),
_ => unreachable!(),
};
if let Some(shell) = args.generate_shell_completion {
let mut uvx = Cli::command()
.find_subcommand("tool")
.unwrap()
.find_subcommand("uvx")
.unwrap()
.clone()
.disable_help_flag(true)
.disable_version_flag(true);
for arg in TopLevelArgs::command().get_arguments() {
if arg.get_id() != "isolated" && arg.get_id() != "version" {
uvx = uvx.arg(arg);
}
}
shell.generate(&mut uvx, &mut stdout());
return Ok(ExitStatus::Success);
}
let args = settings::ToolRunSettings::resolve(
args,
filesystem,
invocation_source,
environment,
);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.reinstall.clone()))
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
);
let requirements = {
let mut requirements = Vec::with_capacity(
args.with.len() + args.with_editable.len() + args.with_requirements.len(),
);
for package in args.with {
requirements.push(RequirementsSource::from_with_package_argument(&package)?);
}
for package in args.with_editable {
requirements.push(RequirementsSource::from_editable(&package)?);
}
requirements.extend(
args.with_requirements
.into_iter()
.map(RequirementsSource::from_requirements_file)
.collect::<Result<Vec<_>, _>>()?,
);
requirements
};
let constraints = args
.constraints
.into_iter()
.map(RequirementsSource::from_constraints_txt)
.collect::<Result<Vec<_>, _>>()?;
let overrides = args
.overrides
.into_iter()
.map(RequirementsSource::from_overrides_txt)
.collect::<Result<Vec<_>, _>>()?;
let build_constraints = args
.build_constraints
.into_iter()
.map(RequirementsSource::from_constraints_txt)
.collect::<Result<Vec<_>, _>>()?;
let client_builder = match invocation_source {
ToolRunCommand::Uvx => client_builder.subcommand(vec!["uvx".to_owned()]),
ToolRunCommand::ToolRun => {
client_builder.subcommand(vec!["tool".to_owned(), "run".to_owned()])
}
};
Box::pin(commands::tool_run(
args.command,
args.from,
&requirements,
&constraints,
&overrides,
&build_constraints,
args.show_resolution || globals.verbose > 0,
args.lfs,
args.python,
args.python_platform,
args.install_mirrors,
args.options,
args.settings,
client_builder,
invocation_source,
args.isolated,
globals.python_preference,
globals.python_downloads,
globals.installer_metadata,
globals.concurrency,
cache,
workspace_cache,
printer,
args.env_file,
args.no_env_file,
globals.preview,
))
.await
}
Commands::Tool(ToolNamespace {
command: ToolCommand::Install(args),
}) => {
let args = settings::ToolInstallSettings::resolve(args, filesystem, environment);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.reinstall.clone()))
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
);
let mut entrypoints = Vec::with_capacity(args.with_executables_from.len());
let mut requirements = Vec::with_capacity(
args.with.len()
+ args.with_editable.len()
+ args.with_requirements.len()
+ args.with_executables_from.len(),
);
for pkg in args.with {
requirements.push(RequirementsSource::from_with_package_argument(&pkg)?);
}
for pkg in args.with_editable {
requirements.push(RequirementsSource::from_editable(&pkg)?);
}
for path in args.with_requirements {
requirements.push(RequirementsSource::from_requirements_file(path)?);
}
for pkg in &args.with_executables_from {
let source = RequirementsSource::from_with_package_argument(pkg)?;
let RequirementsSource::Package(RequirementsTxtRequirement::Named(requirement)) =
&source
else {
bail!(
"Expected a named package for `--with-executables-from`, but got: {}",
source.to_string().cyan()
)
};
entrypoints.push(requirement.name.clone());
requirements.push(source);
}
let constraints = args
.constraints
.into_iter()
.map(RequirementsSource::from_constraints_txt)
.collect::<Result<Vec<_>, _>>()?;
let overrides = args
.overrides
.into_iter()
.map(RequirementsSource::from_overrides_txt)
.collect::<Result<Vec<_>, _>>()?;
let excludes = args
.excludes
.into_iter()
.map(RequirementsSource::from_requirements_txt)
.collect::<Result<Vec<_>, _>>()?;
let build_constraints = args
.build_constraints
.into_iter()
.map(RequirementsSource::from_constraints_txt)
.collect::<Result<Vec<_>, _>>()?;
Box::pin(commands::tool_install(
args.package,
args.editable,
args.from,
&requirements,
&constraints,
&overrides,
&excludes,
&build_constraints,
&entrypoints,
args.lfs,
args.python,
args.python_platform,
args.install_mirrors,
args.force,
args.options,
args.settings,
client_builder.subcommand(vec!["tool".to_owned(), "install".to_owned()]),
globals.python_preference,
globals.python_downloads,
globals.installer_metadata,
globals.concurrency,
cli.top_level.no_config,
cache,
&workspace_cache,
printer,
globals.preview,
))
.await
}
Commands::Tool(ToolNamespace {
command: ToolCommand::List(args),
}) => {
let args = settings::ToolListSettings::resolve(args, filesystem);
show_settings!(args);
let cache = cache.init().await?;
commands::tool_list(
args.show_paths,
args.show_version_specifiers,
args.show_with,
args.show_extras,
args.show_python,
args.outdated,
args.args,
args.filesystem,
client_builder.subcommand(vec!["tool".to_owned(), "list".to_owned()]),
globals.concurrency,
&cache,
printer,
)
.await
}
Commands::Tool(ToolNamespace {
command: ToolCommand::Upgrade(args),
}) => {
let args = settings::ToolUpgradeSettings::resolve(args, filesystem, &environment);
show_settings!(args);
let cache = cache
.init()
.await?
.with_refresh(Refresh::All(Timestamp::now()));
Box::pin(commands::tool_upgrade(
args.names,
args.python,
args.python_platform,
args.install_mirrors,
args.args,
args.filesystem,
client_builder.subcommand(vec!["tool".to_owned(), "upgrade".to_owned()]),
globals.python_preference,
globals.python_downloads,
globals.installer_metadata,
globals.concurrency,
&cache,
&workspace_cache,
printer,
globals.preview,
))
.await
}
Commands::Tool(ToolNamespace {
command: ToolCommand::Uninstall(args),
}) => {
let args = settings::ToolUninstallSettings::resolve(args, filesystem);
show_settings!(args);
commands::tool_uninstall(args.name, printer).await
}
Commands::Tool(ToolNamespace {
command: ToolCommand::UpdateShell,
}) => {
commands::tool_update_shell(printer).await?;
Ok(ExitStatus::Success)
}
Commands::Tool(ToolNamespace {
command: ToolCommand::Dir(args),
}) => {
let args = settings::ToolDirSettings::resolve(args, filesystem);
show_settings!(args);
commands::tool_dir(args.bin, globals.preview, printer)?;
Ok(ExitStatus::Success)
}
Commands::Python(PythonNamespace {
command: PythonCommand::List(args),
}) => {
let args = settings::PythonListSettings::resolve(args, filesystem, environment);
show_settings!(args);
let cache = cache.init().await?;
commands::python_list(
args.request,
args.kinds,
args.all_versions,
args.all_platforms,
args.all_arches,
args.show_urls,
args.output_format,
args.python_downloads_json_url,
args.python_install_mirror,
args.pypy_install_mirror,
globals.python_preference,
globals.python_downloads,
&client_builder.subcommand(vec!["python".to_owned(), "list".to_owned()]),
&cache,
printer,
globals.preview,
)
.await
}
Commands::Python(PythonNamespace {
command: PythonCommand::Install(args),
}) => {
let args = settings::PythonInstallSettings::resolve(args, filesystem, environment);
show_settings!(args);
let cache = cache.init().await?;
commands::python_install(
&project_dir,
args.install_dir,
args.targets,
args.reinstall,
args.upgrade,
args.bin,
args.registry,
args.force,
args.python_install_mirror,
args.pypy_install_mirror,
args.python_downloads_json_url,
client_builder.subcommand(vec!["python".to_owned(), "install".to_owned()]),
args.default,
globals.python_downloads,
cli.top_level.no_config,
args.compile_bytecode,
&globals.concurrency,
&cache,
globals.preview,
printer,
)
.await
}
Commands::Python(PythonNamespace {
command: PythonCommand::Upgrade(args),
}) => {
let args = settings::PythonUpgradeSettings::resolve(args, filesystem, environment);
show_settings!(args);
let upgrade = commands::PythonUpgrade::Enabled(commands::PythonUpgradeSource::Upgrade);
let cache = cache.init().await?;
commands::python_install(
&project_dir,
args.install_dir,
args.targets,
args.reinstall,
upgrade,
args.bin,
args.registry,
args.force,
args.python_install_mirror,
args.pypy_install_mirror,
args.python_downloads_json_url,
client_builder.subcommand(vec!["python".to_owned(), "upgrade".to_owned()]),
args.default,
globals.python_downloads,
cli.top_level.no_config,
args.compile_bytecode,
&globals.concurrency,
&cache,
globals.preview,
printer,
)
.await
}
Commands::Python(PythonNamespace {
command: PythonCommand::Uninstall(args),
}) => {
let args = settings::PythonUninstallSettings::resolve(args, filesystem);
show_settings!(args);
commands::python_uninstall(args.install_dir, args.targets, args.all, printer).await
}
Commands::Python(PythonNamespace {
command: PythonCommand::Find(args),
}) => {
let args = settings::PythonFindSettings::resolve(args, filesystem, environment);
let cache = cache.init().await?;
if let Some(Pep723Item::Script(script)) = script {
commands::python_find_script(
(&script).into(),
args.show_version,
args.resolve_links,
&client_builder.subcommand(vec!["python".to_owned(), "find".to_owned()]),
globals.python_preference,
globals.python_downloads,
cli.top_level.no_config,
&cache,
printer,
globals.preview,
)
.await
} else {
commands::python_find(
&project_dir,
args.request,
args.show_version,
args.resolve_links,
args.no_project,
cli.top_level.no_config,
args.system,
globals.python_preference,
args.python_downloads_json_url.as_deref(),
&client_builder.subcommand(vec!["python".to_owned(), "find".to_owned()]),
&cache,
&workspace_cache,
printer,
globals.preview,
)
.await
}
}
Commands::Python(PythonNamespace {
command: PythonCommand::Pin(args),
}) => {
let args = settings::PythonPinSettings::resolve(args, filesystem, environment);
let cache = cache.init().await?;
commands::python_pin(
&project_dir,
args.request,
args.resolved,
globals.python_preference,
globals.python_downloads,
args.no_project,
args.global,
args.rm,
args.install_mirrors,
client_builder.subcommand(vec!["python".to_owned(), "pin".to_owned()]),
&cache,
&workspace_cache,
printer,
globals.preview,
)
.await
}
Commands::Python(PythonNamespace {
command: PythonCommand::Dir(args),
}) => {
let args = settings::PythonDirSettings::resolve(args, filesystem);
show_settings!(args);
commands::python_dir(args.bin, printer)?;
Ok(ExitStatus::Success)
}
Commands::Python(PythonNamespace {
command: PythonCommand::UpdateShell,
}) => {
commands::python_update_shell(printer).await?;
Ok(ExitStatus::Success)
}
Commands::Publish(args) => {
show_settings!(args);
if args.skip_existing {
bail!(
"`uv publish` does not support `--skip-existing` because there is not a \
reliable way to identify when an upload fails due to an existing \
distribution. Instead, use `--check-url` to provide the URL to the simple \
API for your index. uv will check the index for existing distributions before \
attempting uploads."
);
}
let PublishSettings {
files,
username,
password,
dry_run,
no_attestations,
direct,
publish_url,
trusted_publishing,
keyring_provider,
check_url,
index,
index_locations,
} = PublishSettings::resolve(args, filesystem);
commands::publish(
files,
publish_url,
trusted_publishing,
keyring_provider,
&environment,
&client_builder.subcommand(vec!["publish".to_owned()]),
username,
password,
check_url,
index,
index_locations,
dry_run,
no_attestations,
direct,
globals.preview,
&cache,
printer,
)
.await
}
Commands::Workspace(WorkspaceNamespace { command }) => match command {
WorkspaceCommand::Metadata(args) => {
let args = settings::MetadataSettings::resolve(args, filesystem, environment);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.clone()
.combine(Refresh::from(args.settings.upgrade.clone())),
);
Box::pin(commands::metadata(
&project_dir,
args.lock_check,
args.frozen,
args.dry_run,
args.refresh,
args.python,
args.install_mirrors,
args.settings,
client_builder.subcommand(vec!["workspace metadata".to_owned()]),
globals.python_preference,
globals.python_downloads,
globals.concurrency,
cli.top_level.no_config,
&cache,
&workspace_cache,
printer,
globals.preview,
))
.await
}
WorkspaceCommand::Dir(args) => {
commands::dir(args.package, &project_dir, &workspace_cache, printer).await
}
WorkspaceCommand::List(args) => {
commands::list(&project_dir, args.paths, &workspace_cache, printer).await
}
},
Commands::BuildBackend { command } => spawn_blocking(move || match command {
BuildBackendCommand::BuildSdist { sdist_directory } => {
commands::build_backend::build_sdist(&sdist_directory)
}
BuildBackendCommand::BuildWheel {
wheel_directory,
metadata_directory,
} => commands::build_backend::build_wheel(
&wheel_directory,
metadata_directory.as_deref(),
),
BuildBackendCommand::BuildEditable {
wheel_directory,
metadata_directory,
} => commands::build_backend::build_editable(
&wheel_directory,
metadata_directory.as_deref(),
),
BuildBackendCommand::GetRequiresForBuildSdist => {
commands::build_backend::get_requires_for_build_sdist()
}
BuildBackendCommand::GetRequiresForBuildWheel => {
commands::build_backend::get_requires_for_build_wheel()
}
BuildBackendCommand::PrepareMetadataForBuildWheel { wheel_directory } => {
commands::build_backend::prepare_metadata_for_build_wheel(&wheel_directory)
}
BuildBackendCommand::GetRequiresForBuildEditable => {
commands::build_backend::get_requires_for_build_editable()
}
BuildBackendCommand::PrepareMetadataForBuildEditable { wheel_directory } => {
commands::build_backend::prepare_metadata_for_build_editable(&wheel_directory)
}
})
.await
.expect("tokio threadpool exited unexpectedly"),
}
}
async fn run_project(
project_command: Box<ProjectCommand>,
project_dir: &Path,
command: Option<RunCommand>,
script: Option<Pep723Item>,
globals: GlobalSettings,
no_config: bool,
explicit_project: bool,
client_builder: BaseClientBuilder<'_>,
filesystem: Option<FilesystemOptions>,
cache: Cache,
workspace_cache: &WorkspaceCache,
printer: Printer,
) -> Result<ExitStatus> {
macro_rules! show_settings {
($arg:expr) => {
if globals.show_settings {
writeln!(printer.stdout(), "{:#?}", $arg)?;
return Ok(ExitStatus::Success);
}
};
}
let environment = EnvironmentOptions::new()?;
match *project_command {
ProjectCommand::Init(args) => {
let args = settings::InitSettings::resolve(args, filesystem, environment);
show_settings!(args);
if explicit_project {
if globals.preview.is_enabled(PreviewFeature::InitProjectFlag) {
bail!(
"The `--project` option cannot be used in `uv init`. {}",
if args.path.is_some() {
"Use `--directory` instead."
} else {
"Use `--directory` or a positional path instead."
}
)
}
warn_user!(
"Use of the `--project` option in `uv init` is deprecated and will be removed in a future release. {}",
if args.path.is_some() {
"Since a positional path was provided, the `--project` option has no effect. Consider using `--directory` instead."
} else {
"Consider using `uv init <PATH>` instead."
}
);
}
let cache = cache.init().await?;
commands::init(
project_dir,
args.path,
args.name,
args.package,
args.kind,
args.bare,
args.description,
args.no_description,
args.vcs,
args.build_backend,
args.no_readme,
args.author_from,
args.pin_python,
args.python,
args.install_mirrors,
args.no_workspace,
&client_builder.subcommand(vec!["init".to_owned()]),
globals.python_preference,
globals.python_downloads,
no_config,
&cache,
printer,
globals.preview,
)
.await
}
ProjectCommand::Run(args) => {
let args = settings::RunSettings::resolve(args, filesystem, environment);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.reinstall.clone()))
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
);
let mut requirements = Vec::with_capacity(
args.with.len() + args.with_editable.len() + args.with_requirements.len(),
);
for package in args.with {
requirements.push(RequirementsSource::from_with_package_argument(&package)?);
}
for package in args.with_editable {
requirements.push(RequirementsSource::from_editable(&package)?);
}
requirements.extend(
args.with_requirements
.into_iter()
.map(RequirementsSource::from_requirements_file)
.collect::<Result<Vec<_>, _>>()?,
);
Box::pin(commands::run(
project_dir,
script,
command,
requirements,
args.show_resolution || globals.verbose > 0,
args.lock_check,
args.frozen,
args.active,
args.no_sync,
args.isolated,
args.all_packages,
args.package,
args.no_project,
no_config,
args.extras,
args.groups,
args.editable,
args.modifications,
args.python,
args.python_platform,
args.install_mirrors,
args.settings,
client_builder.subcommand(vec!["run".to_owned()]),
globals.python_preference,
globals.python_downloads,
globals.installer_metadata,
globals.concurrency,
cache,
workspace_cache,
printer,
args.env_file,
globals.preview,
args.max_recursion_depth,
))
.await
}
ProjectCommand::Sync(args) => {
let args = settings::SyncSettings::resolve(args, filesystem, environment);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.reinstall.clone()))
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
);
let script = script.map(|script| match script {
Pep723Item::Script(script) => script,
Pep723Item::Stdin(..) => unreachable!("`uv lock` does not support stdin"),
Pep723Item::Remote(..) => unreachable!("`uv lock` does not support remote files"),
});
Box::pin(commands::sync(
project_dir,
args.lock_check,
args.frozen,
args.dry_run,
args.active,
args.all_packages,
args.package,
args.extras,
args.groups,
args.editable,
args.install_options,
args.modifications,
args.python,
args.python_platform,
args.install_mirrors,
globals.python_preference,
globals.python_downloads,
args.settings,
client_builder.subcommand(vec!["sync".to_owned()]),
script,
globals.installer_metadata,
globals.concurrency,
no_config,
&cache,
workspace_cache,
printer,
globals.preview,
args.output_format,
))
.await
}
ProjectCommand::Lock(args) => {
let args = settings::LockSettings::resolve(args, filesystem, environment);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.clone()
.combine(Refresh::from(args.settings.upgrade.clone())),
);
let script = script
.map(|script| match script {
Pep723Item::Script(script) => script,
Pep723Item::Stdin(..) => unreachable!("`uv add` does not support stdin"),
Pep723Item::Remote(..) => {
unreachable!("`uv add` does not support remote files")
}
})
.map(ScriptPath::Script)
.or(args.script.map(ScriptPath::Path));
Box::pin(commands::lock(
project_dir,
args.lock_check,
args.frozen,
args.dry_run,
args.refresh,
args.python,
args.install_mirrors,
args.settings,
client_builder.subcommand(vec!["lock".to_owned()]),
script,
globals.python_preference,
globals.python_downloads,
globals.concurrency,
no_config,
&cache,
workspace_cache,
printer,
globals.preview,
))
.await
}
ProjectCommand::Add(args) => {
let mut args = settings::AddSettings::resolve(args, filesystem, environment);
show_settings!(args);
let script = script
.map(|script| match script {
Pep723Item::Script(script) => script,
Pep723Item::Stdin(..) => unreachable!("`uv add` does not support stdin"),
Pep723Item::Remote(..) => {
unreachable!("`uv add` does not support remote files")
}
})
.map(ScriptPath::Script)
.or(args.script.map(ScriptPath::Path));
let requirements = args
.packages
.iter()
.map(String::as_str)
.map(RequirementsSource::from_package_argument)
.chain(
args.requirements
.into_iter()
.map(RequirementsSource::from_requirements_file),
)
.collect::<Result<Vec<_>>>()?;
for requirement in &requirements {
let requirement = match requirement {
RequirementsSource::Package(requirement) => requirement,
RequirementsSource::Editable(requirement) => requirement,
_ => continue,
};
match requirement {
RequirementsTxtRequirement::Named(requirement) => {
if let Some(VersionOrUrl::Url(url)) = requirement.version_or_url.as_ref() {
if let ParsedUrl::Directory(ParsedDirectoryUrl {
install_path, ..
}) = &url.parsed_url
{
debug!(
"Marking explicit source tree for reinstall: `{}`",
install_path.display()
);
args.settings.reinstall = args
.settings
.reinstall
.with_package(requirement.name.clone());
}
}
}
RequirementsTxtRequirement::Unnamed(requirement) => {
if let ParsedUrl::Directory(ParsedDirectoryUrl { install_path, .. }) =
&requirement.url.parsed_url
{
debug!(
"Marking explicit source tree for reinstall: `{}`",
install_path.display()
);
args.settings.reinstall =
args.settings.reinstall.with_path(install_path.clone());
}
}
}
}
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.reinstall.clone()))
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
);
let constraints = args
.constraints
.into_iter()
.map(RequirementsSource::from_constraints_txt)
.collect::<Result<Vec<_>, _>>()?;
Box::pin(commands::add(
project_dir,
args.lock_check,
args.frozen,
args.active,
args.no_sync,
args.no_install_project,
args.only_install_project,
args.no_install_workspace,
args.only_install_workspace,
args.no_install_local,
args.only_install_local,
args.no_install_package,
args.only_install_package,
requirements,
constraints,
args.marker,
args.editable,
args.dependency_type,
args.raw,
args.bounds,
args.indexes,
args.rev,
args.tag,
args.branch,
args.lfs,
args.extras,
args.package,
args.python,
args.workspace,
args.install_mirrors,
args.settings,
client_builder.subcommand(vec!["add".to_owned()]),
script,
globals.python_preference,
globals.python_downloads,
globals.installer_metadata,
globals.concurrency,
no_config,
&cache,
printer,
globals.preview,
))
.await
}
ProjectCommand::Remove(args) => {
let args = settings::RemoveSettings::resolve(args, filesystem, environment);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.reinstall.clone()))
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
);
let script = script.map(|script| match script {
Pep723Item::Script(script) => script,
Pep723Item::Stdin(..) => unreachable!("`uv remove` does not support stdin"),
Pep723Item::Remote(..) => unreachable!("`uv remove` does not support remote files"),
});
Box::pin(commands::remove(
project_dir,
args.lock_check,
args.frozen,
args.active,
args.no_sync,
args.packages,
args.dependency_type,
args.package,
args.python,
args.install_mirrors,
args.settings,
client_builder.subcommand(vec!["remove".to_owned()]),
script,
globals.python_preference,
globals.python_downloads,
globals.installer_metadata,
globals.concurrency,
no_config,
&cache,
printer,
globals.preview,
))
.await
}
ProjectCommand::Version(args) => {
let args = settings::VersionSettings::resolve(args, filesystem, environment);
show_settings!(args);
globals
.network_settings
.check_refresh_conflict(&args.refresh);
let cache = cache.init().await?.with_refresh(
args.refresh
.combine(Refresh::from(args.settings.reinstall.clone()))
.combine(Refresh::from(args.settings.resolver.upgrade.clone())),
);
Box::pin(commands::project_version(
args.value,
args.bump,
args.short,
args.output_format,
project_dir,
args.package,
explicit_project,
args.dry_run,
args.lock_check,
args.frozen,
args.active,
args.no_sync,
args.python,
args.install_mirrors,
args.settings,
client_builder.subcommand(vec!["version".to_owned()]),
globals.python_preference,
globals.python_downloads,
globals.installer_metadata,
globals.concurrency,
no_config,
&cache,
workspace_cache,
printer,
globals.preview,
))
.await
}
ProjectCommand::Tree(args) => {
let args = settings::TreeSettings::resolve(args, filesystem, environment);
show_settings!(args);
let cache = cache.init().await?;
let script = script.map(|script| match script {
Pep723Item::Script(script) => script,
Pep723Item::Stdin(..) => unreachable!("`uv tree` does not support stdin"),
Pep723Item::Remote(..) => unreachable!("`uv tree` does not support remote files"),
});
Box::pin(commands::tree(
project_dir,
args.groups,
args.lock_check,
args.frozen,
args.universal,
args.depth,
args.prune,
args.package,
args.no_dedupe,
args.invert,
args.outdated,
args.show_sizes,
args.python_version,
args.python_platform,
args.python,
args.install_mirrors,
args.resolver,
&client_builder.subcommand(vec!["tree".to_owned()]),
script,
globals.python_preference,
globals.python_downloads,
globals.concurrency,
no_config,
&cache,
printer,
globals.preview,
))
.await
}
ProjectCommand::Export(args) => {
let args = settings::ExportSettings::resolve(args, filesystem, environment);
show_settings!(args);
let cache = cache.init().await?;
let script = script.map(|script| match script {
Pep723Item::Script(script) => script,
Pep723Item::Stdin(..) => unreachable!("`uv export` does not support stdin"),
Pep723Item::Remote(..) => unreachable!("`uv export` does not support remote files"),
});
commands::export(
project_dir,
args.format,
args.all_packages,
args.package,
args.prune,
args.hashes,
args.install_options,
args.output_file,
args.extras,
args.groups,
args.editable,
args.lock_check,
args.frozen,
args.include_annotations,
args.include_header,
script,
args.python,
args.install_mirrors,
args.settings,
client_builder.subcommand(vec!["export".to_owned()]),
globals.python_preference,
globals.python_downloads,
globals.concurrency,
no_config,
globals.quiet > 0,
&cache,
printer,
globals.preview,
)
.boxed_local()
.await
}
ProjectCommand::Format(args) => {
let args = settings::FormatSettings::resolve(args, filesystem);
show_settings!(args);
let cache = cache.init().await?;
Box::pin(commands::format(
project_dir,
args.check,
args.diff,
args.extra_args,
args.version,
args.exclude_newer,
args.show_version,
client_builder.subcommand(vec!["format".to_owned()]),
cache,
printer,
globals.preview,
args.no_project,
))
.await
}
ProjectCommand::Audit(audit_args) => {
let args = settings::AuditSettings::resolve(audit_args, filesystem, environment);
show_settings!(args);
let cache = cache.init().await?;
let script = script.map(|script| match script {
Pep723Item::Script(script) => script,
Pep723Item::Stdin(..) => unreachable!("`uv audit` does not support stdin"),
Pep723Item::Remote(..) => unreachable!("`uv audit` does not support remote files"),
});
Box::pin(commands::audit(
project_dir,
args.extras,
args.groups,
args.lock_check,
args.frozen,
script,
args.python_version,
args.python_platform,
args.install_mirrors,
args.settings,
client_builder.subcommand(vec!["audit".to_owned()]),
globals.python_preference,
globals.python_downloads,
globals.concurrency,
no_config,
cache,
printer,
globals.preview,
args.service_format,
args.service_url,
args.ignore,
args.ignore_until_fixed,
))
.await
}
}
}
#[allow(unsafe_code)]
pub unsafe fn main<I, T>(args: I) -> ExitCode
where
I: IntoIterator<Item = T>,
T: Into<OsString> + Clone,
{
#[cfg(windows)]
windows_exception::setup();
if let Ok(current_exe) = std::env::current_exe() {
unsafe {
std::env::set_var(EnvVars::UV, current_exe);
}
}
let cli = match Cli::try_parse_from(args) {
Ok(cli) => cli,
Err(mut err) => {
if let Some(ContextValue::String(subcommand)) = err.get(ContextKind::InvalidSubcommand)
{
match subcommand.as_str() {
"compile" => {
err.insert(
ContextKind::SuggestedSubcommand,
ContextValue::String("uv pip compile".to_string()),
);
}
"install" => {
err.insert(
ContextKind::SuggestedSubcommand,
ContextValue::String("uv pip install".to_string()),
);
}
"uninstall" => {
err.insert(
ContextKind::SuggestedSubcommand,
ContextValue::String("uv pip uninstall".to_string()),
);
}
"freeze" => {
err.insert(
ContextKind::SuggestedSubcommand,
ContextValue::String("uv pip freeze".to_string()),
);
}
"list" => {
err.insert(
ContextKind::SuggestedSubcommand,
ContextValue::String("uv pip list".to_string()),
);
}
"show" => {
err.insert(
ContextKind::SuggestedSubcommand,
ContextValue::String("uv pip show".to_string()),
);
}
_ => {}
}
}
err.exit()
}
};
let min_stack_size = min_stack_size();
let main2 = move || {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.thread_stack_size(min_stack_size)
.build()
.expect("Failed building the Runtime");
let result = runtime.block_on(Box::pin(run(cli)));
runtime.shutdown_background();
result
};
let result = std::thread::Builder::new()
.name("main2".to_owned())
.stack_size(min_stack_size)
.spawn(main2)
.expect("Tokio executor failed, was there a panic?")
.join()
.expect("Tokio executor failed, was there a panic?");
match result {
Ok(code) => code.into(),
Err(err) => {
trace!("Error trace: {err:?}");
let mut causes = err.chain();
eprintln!(
"{}: {}",
"error".red().bold(),
causes.next().unwrap().to_string().trim()
);
for err in causes {
eprintln!(" {}: {}", "Caused by".red().bold(), err.to_string().trim());
}
ExitStatus::Error.into()
}
}
}