1#![deny(clippy::print_stdout, clippy::print_stderr)]
2
3use std::borrow::Cow;
4use std::ffi::OsString;
5use std::fmt::Write;
6use std::io::stdout;
7#[cfg(feature = "self-update")]
8use std::ops::Bound;
9use std::path::Path;
10use std::process::ExitCode;
11use std::str::FromStr;
12use std::sync::atomic::Ordering;
13
14use anyhow::{Result, anyhow, bail};
15use clap::error::{ContextKind, ContextValue};
16use clap::{CommandFactory, Error, Parser};
17use futures::FutureExt;
18use owo_colors::OwoColorize;
19use settings::PipTreeSettings;
20use tokio::task::spawn_blocking;
21use tracing::{debug, instrument, trace};
22
23#[cfg(not(feature = "self-update"))]
24use crate::install_source::InstallSource;
25use uv_cache::{Cache, Refresh};
26use uv_cache_info::Timestamp;
27#[cfg(feature = "self-update")]
28use uv_cli::SelfUpdateArgs;
29use uv_cli::{
30 AuthCommand, AuthHelperCommand, AuthNamespace, BuildBackendCommand, CacheCommand,
31 CacheNamespace, Cli, Commands, PipCommand, PipNamespace, ProjectCommand, PythonCommand,
32 PythonNamespace, SelfCommand, SelfNamespace, ToolCommand, ToolNamespace, TopLevelArgs,
33 WorkspaceCommand, WorkspaceNamespace, compat::CompatArgs,
34};
35use uv_client::BaseClientBuilder;
36use uv_configuration::min_stack_size;
37use uv_flags::EnvironmentFlags;
38use uv_fs::{CWD, Simplified, normalize_path};
39#[cfg(feature = "self-update")]
40use uv_pep440::release_specifiers_to_ranges;
41use uv_pep508::VersionOrUrl;
42use uv_preview::PreviewFeature;
43use uv_pypi_types::{ParsedDirectoryUrl, ParsedUrl};
44use uv_python::PythonRequest;
45use uv_requirements::{GroupsSpecification, RequirementsSource};
46use uv_requirements_txt::RequirementsTxtRequirement;
47use uv_scripts::{Pep723Error, Pep723Item, Pep723Script};
48use uv_settings::{Combine, EnvironmentOptions, FilesystemOptions, Options};
49use uv_static::EnvVars;
50use uv_warnings::{warn_user, warn_user_once};
51use uv_workspace::{DiscoveryOptions, Workspace, WorkspaceCache};
52
53use crate::commands::{
54 ExitStatus, ParsedRunCommand, RunCommand, ScriptPath, ToolRunCommand, UvError,
55};
56use crate::printer::Printer;
57use crate::settings::{
58 CacheSettings, GlobalSettings, PipCheckSettings, PipCompileSettings, PipFreezeSettings,
59 PipInstallSettings, PipListSettings, PipShowSettings, PipSyncSettings, PipUninstallSettings,
60 PublishSettings, resolve_color,
61};
62
63pub(crate) mod child;
64pub mod commands;
65#[cfg(not(feature = "self-update"))]
66mod install_source;
67mod logging;
68pub(crate) mod printer;
69pub(crate) mod settings;
70
71#[derive(Debug, Copy, Clone, Eq, PartialEq)]
73#[doc(hidden)]
74pub enum GlobalInitialization {
75 Initialize,
77 Reuse,
79}
80
81impl GlobalInitialization {
82 const fn needs_initialization(self) -> bool {
83 matches!(self, Self::Initialize)
84 }
85}
86
87#[cfg(not(feature = "self-update"))]
89#[derive(Debug, thiserror::Error)]
90#[error("uv was installed through an external package manager and cannot update itself.")]
91struct ExternallyInstalledError {
92 install_source: Option<InstallSource>,
93}
94
95#[cfg(not(feature = "self-update"))]
96impl uv_errors::Hint for ExternallyInstalledError {
97 fn hints(&self) -> uv_errors::Hints<'_> {
98 if let Some(source) = &self.install_source {
99 uv_errors::Hints::from(format!(
100 "You installed uv using {}. To update uv, run `{}`",
101 source.description(),
102 source.update_instructions(),
103 ))
104 } else {
105 uv_errors::Hints::from("Please use your package manager to update uv")
106 }
107 }
108}
109
110#[instrument(skip_all)]
111#[doc(hidden)]
112pub async fn run(cli: Cli, global_initialization: GlobalInitialization) -> Result<ExitStatus> {
113 if cli.top_level.global_args.quiet == 0 {
115 uv_warnings::enable();
116 }
117
118 let directory =
120 cli.top_level.global_args.directory.clone().or_else(|| {
121 std::env::var_os(EnvVars::UV_WORKING_DIRECTORY).map(std::path::PathBuf::from)
122 });
123
124 if let Some(directory) = directory.as_ref() {
126 std::env::set_current_dir(directory)?;
127 }
128
129 let parsed_run_command = if let Commands::Project(command) = &*cli.command
131 && let ProjectCommand::Run(uv_cli::RunArgs {
132 command: Some(ref command),
133 module,
134 script,
135 gui_script,
136 ..
137 }) = **command
138 {
139 Some(ParsedRunCommand::from_args(
140 command, module, script, gui_script,
141 )?)
142 } else {
143 None
144 };
145
146 let environment = EnvironmentOptions::new()?;
148
149 let early_preview = settings::resolve_preview(&cli.top_level.global_args, None, &environment);
151
152 if global_initialization.needs_initialization() {
153 uv_preview::set(early_preview)?;
155 }
156
157 if global_initialization.needs_initialization() {
158 #[cfg(feature = "tracing-durations-export")]
160 let (durations_layer, _duration_guard) =
161 logging::setup_durations(environment.tracing_durations_file.as_ref())?;
162 #[cfg(not(feature = "tracing-durations-export"))]
163 let durations_layer = None::<tracing_subscriber::layer::Identity>;
164 logging::setup_logging(
165 match cli.top_level.global_args.verbose {
166 0 => logging::Level::Off,
167 1 => logging::Level::DebugUv,
168 2 => logging::Level::TraceUv,
169 3.. => logging::Level::TraceAll,
170 },
171 durations_layer,
172 resolve_color(&cli.top_level.global_args),
173 environment.log_context.unwrap_or_default(),
174 )?;
175 }
176
177 let project_dir: Cow<'_, Path> = if let Some(project) = &cli.top_level.global_args.project {
182 let path = normalize_path(std::path::absolute(project)?);
183 if let Some(name) = path.file_name()
184 && name == "pyproject.toml"
185 && path.is_file()
186 && let Some(parent) = path.parent()
187 {
188 Cow::Owned(parent.to_path_buf())
189 } else {
190 path
191 }
192 } else if let Some(run_command) = &parsed_run_command
193 && early_preview.is_enabled(PreviewFeature::TargetWorkspaceDiscovery)
194 && let Some(dir) = run_command.script_dir()
195 {
196 Cow::Owned(std::path::absolute(dir)?)
199 } else {
200 Cow::Borrowed(&*CWD)
201 };
202
203 let skip_project_validation = matches!(
206 &*cli.command,
207 Commands::Project(command) if matches!(**command, ProjectCommand::Init(_))
208 );
209
210 if !skip_project_validation {
211 if let Some(project_path) = cli.top_level.global_args.project.as_ref() {
212 if !project_dir.exists() {
213 if early_preview.is_enabled(PreviewFeature::ProjectDirectoryMustExist) {
214 bail!(
215 "Project directory `{}` does not exist",
216 project_path.user_display()
217 );
218 }
219 warn_user_once!(
220 "Project directory `{}` does not exist. \
221 This will become an error in a future release. \
222 Use `--preview-features project-directory-must-exist` to error on this now.",
223 project_path.user_display()
224 );
225 } else if !project_dir.is_dir() {
226 if early_preview.is_enabled(PreviewFeature::ProjectDirectoryMustExist) {
229 bail!(
230 "Project path `{}` is not a directory",
231 project_path.user_display()
232 );
233 }
234 warn_user_once!(
235 "Project path `{}` is not a directory. \
236 This will become an error in a future release. \
237 Use `--preview-features project-directory-must-exist` to error on this now.",
238 project_path.user_display()
239 );
240 }
241 }
242 }
243
244 let deprecated_isolated = if cli.top_level.global_args.isolated {
246 match &*cli.command {
247 Commands::Tool(ToolNamespace {
249 command: ToolCommand::Uvx(_) | ToolCommand::Run(_),
250 }) => false,
251
252 Commands::Project(command)
254 if matches!(**command, ProjectCommand::Run(_) | ProjectCommand::Check(_)) =>
255 {
256 false
257 }
258
259 Commands::Project(command) if matches!(**command, ProjectCommand::Init(_)) => {
261 warn_user!(
262 "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."
263 );
264 false
265 }
266
267 Commands::Project(_) | Commands::Tool(_) | Commands::Python(_) => {
269 warn_user!(
270 "The `--isolated` flag is deprecated and has no effect. Instead, use `--no-config` to prevent uv from discovering configuration files."
271 );
272 false
273 }
274
275 _ => {
277 warn_user!(
278 "The `--isolated` flag is deprecated. Instead, use `--no-config` to prevent uv from discovering configuration files."
279 );
280 true
281 }
282 }
283 } else {
284 false
285 };
286
287 let discovery_cache = Cache::from_settings(
296 cli.top_level.cache_args.no_cache,
297 cli.top_level.cache_args.cache_dir.clone(),
298 )?;
299 let workspace_cache = WorkspaceCache::default();
300 let filesystem = if let Some(config_file) = cli.top_level.config_file.as_ref() {
301 if config_file
302 .file_name()
303 .is_some_and(|file_name| file_name == "pyproject.toml")
304 {
305 warn_user!(
306 "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."
307 );
308 }
309 Some(FilesystemOptions::from_file(config_file).map_err(map_settings_error)?)
310 } else if deprecated_isolated || cli.top_level.no_config {
311 None
312 } else if matches!(&*cli.command, Commands::Tool(_) | Commands::Self_(_)) {
313 FilesystemOptions::user()
315 .map_err(map_settings_error)?
316 .combine(FilesystemOptions::system().map_err(map_settings_error)?)
317 } else if let Ok(workspace) = Workspace::discover(
318 &project_dir,
319 &DiscoveryOptions::default(),
320 &discovery_cache,
321 &workspace_cache,
322 )
323 .await
324 {
325 let project =
326 FilesystemOptions::find(workspace.install_path()).map_err(map_settings_error)?;
327 let system = FilesystemOptions::system().map_err(map_settings_error)?;
328 let user = FilesystemOptions::user().map_err(map_settings_error)?;
329 project.combine(user).combine(system)
330 } else {
331 let project = FilesystemOptions::find(&project_dir).map_err(map_settings_error)?;
332 let system = FilesystemOptions::system().map_err(map_settings_error)?;
333 let user = FilesystemOptions::user().map_err(map_settings_error)?;
334 project.combine(user).combine(system)
335 };
336
337 let (run_script, run_command) = if let Some(parsed_run_command) = parsed_run_command {
340 let (script, run_command) = parsed_run_command
341 .resolve(
342 &cli.top_level.global_args,
343 filesystem.as_ref(),
344 &environment,
345 )
346 .await?;
347 (script, Some(run_command))
348 } else {
349 (None, None)
350 };
351 let script = if let Some(run_script) = run_script {
352 Some(run_script)
353 } else if let Commands::Project(command) = &*cli.command {
354 match &**command {
355 ProjectCommand::Add(uv_cli::AddArgs {
358 script: Some(script),
359 ..
360 })
361 | ProjectCommand::Lock(uv_cli::LockArgs {
362 script: Some(script),
363 ..
364 }) => match Pep723Script::read(script).await {
365 Ok(Some(script)) => Some(Pep723Item::Script(script)),
366 Ok(None) => None,
367 Err(err) => return Err(err.into()),
368 },
369 ProjectCommand::Remove(uv_cli::RemoveArgs {
371 script: Some(script),
372 ..
373 })
374 | ProjectCommand::Sync(uv_cli::SyncArgs {
375 script: Some(script),
376 ..
377 })
378 | ProjectCommand::Tree(uv_cli::TreeArgs {
379 script: Some(script),
380 ..
381 })
382 | ProjectCommand::Export(uv_cli::ExportArgs {
383 script: Some(script),
384 ..
385 })
386 | ProjectCommand::Audit(uv_cli::AuditArgs {
387 script: Some(script),
388 ..
389 })
390 | ProjectCommand::Check(uv_cli::CheckArgs {
391 script: Some(script),
392 ..
393 }) => match Pep723Script::read(script).await {
394 Ok(Some(script)) => Some(Pep723Item::Script(script)),
395 Ok(None) => {
396 bail!(
397 "`{}` does not contain a PEP 723 metadata tag; run `{}` to initialize the script",
398 script.user_display().cyan(),
399 format!("uv init --script {}", script.user_display()).green()
400 )
401 }
402 Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
403 bail!(
404 "Failed to read `{}` (not found); run `{}` to create a PEP 723 script",
405 script.user_display().cyan(),
406 format!("uv init --script {}", script.user_display()).green()
407 )
408 }
409 Err(err) => return Err(err.into()),
410 },
411 _ => None,
412 }
413 } else if let Commands::Workspace(WorkspaceNamespace {
414 command: WorkspaceCommand::Metadata(args),
415 }) = &*cli.command
416 && let Some(script) = args.script.as_ref()
417 {
418 match Pep723Script::read(script).await {
419 Ok(Some(script)) => Some(Pep723Item::Script(script)),
420 Ok(None) => {
421 bail!(
422 "`{}` does not contain a PEP 723 metadata tag; run `{}` to initialize the script",
423 script.user_display().cyan(),
424 format!("uv init --script {}", script.user_display()).green()
425 )
426 }
427 Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
428 bail!(
429 "Failed to read `{}` (not found); run `{}` to create a PEP 723 script",
430 script.user_display().cyan(),
431 format!("uv init --script {}", script.user_display()).green()
432 )
433 }
434 Err(err) => return Err(err.into()),
435 }
436 } else if let Commands::Python(uv_cli::PythonNamespace {
437 command:
438 PythonCommand::Find(uv_cli::PythonFindArgs {
439 script: Some(script),
440 ..
441 }),
442 }) = &*cli.command
443 {
444 match Pep723Script::read(&script).await {
445 Ok(Some(script)) => Some(Pep723Item::Script(script)),
446 Ok(None) => {
447 bail!(
448 "`{}` does not contain a PEP 723 metadata tag; run `{}` to initialize the script",
449 script.user_display().cyan(),
450 format!("uv init --script {}", script.user_display()).green()
451 )
452 }
453 Err(Pep723Error::Io(err)) if err.kind() == std::io::ErrorKind::NotFound => {
454 bail!(
455 "Failed to read `{}` (not found); run `{}` to create a PEP 723 script",
456 script.user_display().cyan(),
457 format!("uv init --script {}", script.user_display()).green()
458 )
459 }
460 Err(err) => return Err(err.into()),
461 }
462 } else {
463 None
464 };
465
466 let filesystem = script
468 .as_ref()
469 .map(Pep723Item::metadata)
470 .and_then(|metadata| metadata.tool.as_ref())
471 .and_then(|tool| tool.uv.as_ref())
472 .map(|uv| Options::simple(uv.globals.clone(), uv.top_level.clone()))
473 .map(FilesystemOptions::from)
474 .combine(filesystem);
475
476 let globals = GlobalSettings::resolve(
478 &cli.top_level.global_args,
479 filesystem.as_ref(),
480 &environment,
481 );
482
483 if global_initialization.needs_initialization() {
484 uv_flags::init(EnvironmentFlags::from(&environment))
486 .map_err(|()| anyhow::anyhow!("Flags are already initialized"))?;
487 }
488
489 debug!("uv {}", uv_cli::version::uv_self_version());
490 if let Some(config_file) = cli.top_level.config_file.as_ref() {
491 debug!("Using configuration file: {}", config_file.user_display());
492 }
493 if globals.preview.all_enabled() {
494 debug!("All preview features are enabled");
495 } else if globals.preview.any_enabled() {
496 debug!(
497 "The following preview features are enabled: {}",
498 globals.preview
499 );
500 }
501
502 #[cfg(unix)]
504 if global_initialization.needs_initialization()
505 && globals.preview.is_enabled(PreviewFeature::AdjustUlimit)
506 {
507 match uv_unix::adjust_open_file_limit() {
508 Ok(_) | Err(uv_unix::OpenFileLimitError::AlreadySufficient { .. }) => {}
509 Err(err) => warn_user!("{err}"),
512 }
513 }
514
515 let cache_settings = CacheSettings::resolve(*cli.top_level.cache_args, filesystem.as_ref());
517
518 if global_initialization.needs_initialization() {
519 uv_preview::set(globals.preview)?;
521 uv_preview::finalize()?;
522 }
523
524 if let Some(required_version) = globals.required_version.as_ref() {
526 let package_version = uv_pep440::Version::from_str(uv_version::version())?;
527 if !required_version.contains(&package_version) {
528 return Err(required_version_error(required_version, &package_version));
529 }
530 }
531
532 let printer = Printer::new(globals.quiet, globals.verbose, globals.no_progress);
534
535 if globals.quiet > 0 {
537 uv_warnings::disable();
538 } else {
539 uv_warnings::enable();
540 }
541
542 anstream::ColorChoice::write_global(globals.color.into());
543
544 if global_initialization.needs_initialization() {
545 miette::set_hook(Box::new(|_| {
546 Box::new(
547 miette::MietteHandlerOpts::new()
548 .break_words(false)
549 .word_separator(textwrap::WordSeparator::AsciiSpace)
550 .word_splitter(textwrap::WordSplitter::NoHyphenation)
551 .wrap_lines(std::env::var(EnvVars::UV_NO_WRAP).is_err())
552 .build(),
553 )
554 }))?;
555 }
556
557 uv_configuration::RAYON_PARALLELISM.store(globals.concurrency.installs, Ordering::Relaxed);
559
560 macro_rules! show_settings {
562 ($arg:expr) => {
563 if globals.show_settings {
564 writeln!(printer.stdout(), "{:#?}", $arg)?;
565 return Ok(ExitStatus::Success);
566 }
567 };
568 ($arg:expr, false) => {
569 if globals.show_settings {
570 writeln!(printer.stdout(), "{:#?}", $arg)?;
571 }
572 };
573 }
574 show_settings!(globals, false);
575 show_settings!(cache_settings, false);
576
577 if cache_settings.no_cache {
579 debug!("Disabling the uv cache due to `--no-cache`");
580 }
581 let cache = Cache::from_settings(cache_settings.no_cache, cache_settings.cache_dir)?;
582 let cache_dir = std::path::absolute(cache.root())?;
586 let project_is_in_build_dir =
589 std::env::var_os(EnvVars::UV_INTERNAL__BUILD_DIR).is_some_and(|build_dir| {
590 std::path::absolute(build_dir).is_ok_and(|build_dir| {
591 project_dir.starts_with(&build_dir)
592 || fs_err::canonicalize(&*project_dir).is_ok_and(|project_dir| {
593 fs_err::canonicalize(build_dir)
594 .is_ok_and(|build_dir| project_dir.starts_with(build_dir))
595 })
596 })
597 });
598 if !project_is_in_build_dir {
599 if project_dir.starts_with(&cache_dir) {
600 bail!(
601 "The project directory `{}` is inside the cache directory `{}`",
602 project_dir.user_display(),
603 cache_dir.user_display()
604 );
605 }
606 if let Ok(cache_dir) = fs_err::canonicalize(&cache_dir)
607 && let Ok(project_dir) = fs_err::canonicalize(&*project_dir)
608 && project_dir.starts_with(&cache_dir)
609 {
610 bail!(
611 "The project directory `{}` is inside the cache directory `{}`",
612 project_dir.user_display(),
613 cache_dir.user_display()
614 );
615 }
616 }
617
618 let workspace_cache = WorkspaceCache::default();
619
620 let client_builder = BaseClientBuilder::new(
622 globals.network_settings.connectivity,
623 globals.network_settings.system_certs,
624 globals.network_settings.allow_insecure_host.clone(),
625 globals.preview,
626 globals.network_settings.read_timeout,
627 globals.network_settings.connect_timeout,
628 globals.network_settings.retries,
629 )
630 .http_proxy(globals.network_settings.http_proxy.clone())
631 .https_proxy(globals.network_settings.https_proxy.clone())
632 .no_proxy(globals.network_settings.no_proxy.clone());
633
634 match *cli.command {
635 Commands::Auth(AuthNamespace {
636 command: AuthCommand::Login(args),
637 }) => {
638 let args = settings::AuthLoginSettings::resolve(args);
640 show_settings!(args);
641
642 commands::auth_login(
643 args.service,
644 args.username,
645 args.password,
646 args.token,
647 client_builder,
648 printer,
649 globals.preview,
650 )
651 .await
652 }
653 Commands::Auth(AuthNamespace {
654 command: AuthCommand::Logout(args),
655 }) => {
656 let args = settings::AuthLogoutSettings::resolve(args);
658 show_settings!(args);
659
660 commands::auth_logout(
661 args.service,
662 args.username,
663 client_builder,
664 printer,
665 globals.preview,
666 )
667 .await
668 }
669 Commands::Auth(AuthNamespace {
670 command: AuthCommand::Token(args),
671 }) => {
672 let args = settings::AuthTokenSettings::resolve(args);
674 show_settings!(args);
675
676 commands::auth_token(
677 args.service,
678 args.username,
679 client_builder,
680 printer,
681 globals.preview,
682 )
683 .await
684 }
685 Commands::Auth(AuthNamespace {
686 command: AuthCommand::Dir(args),
687 }) => {
688 commands::auth_dir(args.service.as_ref(), printer)?;
689 Ok(ExitStatus::Success)
690 }
691 Commands::Auth(AuthNamespace {
692 command: AuthCommand::Helper(args),
693 }) => {
694 use uv_cli::AuthHelperProtocol;
695
696 match args.protocol {
698 AuthHelperProtocol::Bazel => {}
699 }
700
701 match args.command {
702 AuthHelperCommand::Get => {
703 commands::auth_helper(client_builder, globals.preview, printer).await
704 }
705 }
706 }
707 Commands::Help(args) => commands::help(
708 args.command.unwrap_or_default().as_slice(),
709 printer,
710 args.no_pager,
711 ),
712 Commands::Pip(PipNamespace {
713 command: PipCommand::Compile(args),
714 }) => {
715 args.compat_args.validate()?;
716
717 let args = PipCompileSettings::resolve(args, filesystem, environment);
719 show_settings!(args);
720
721 globals
723 .network_settings
724 .check_refresh_conflict(&args.refresh);
725
726 let cache = cache.init().await?.with_refresh(
728 args.refresh
729 .combine(Refresh::from(args.settings.reinstall.clone()))
730 .combine(Refresh::from(args.settings.upgrade.clone())),
731 );
732
733 let requirements = args
734 .src_file
735 .into_iter()
736 .map(RequirementsSource::from_requirements_file)
737 .collect::<Result<Vec<_>, _>>()?;
738 let constraints = args
739 .constraints
740 .into_iter()
741 .map(RequirementsSource::from_constraints_txt)
742 .collect::<Result<Vec<_>, _>>()?;
743 let overrides = args
744 .overrides
745 .into_iter()
746 .map(RequirementsSource::from_overrides_txt)
747 .collect::<Result<Vec<_>, _>>()?;
748 let excludes = args
749 .excludes
750 .into_iter()
751 .map(RequirementsSource::from_requirements_txt)
752 .collect::<Result<Vec<_>, _>>()?;
753 let build_constraints = args
754 .build_constraints
755 .into_iter()
756 .map(RequirementsSource::from_constraints_txt)
757 .collect::<Result<Vec<_>, _>>()?;
758 let groups = GroupsSpecification {
759 root: project_dir.to_path_buf(),
760 groups: args.settings.groups,
761 };
762
763 Box::pin(commands::pip_compile(
764 &requirements,
765 &constraints,
766 &overrides,
767 &excludes,
768 &build_constraints,
769 args.constraints_from_workspace,
770 args.overrides_from_workspace,
771 args.excludes_from_workspace,
772 args.build_constraints_from_workspace,
773 args.environments,
774 args.required_environments,
775 args.settings.extras,
776 groups,
777 args.settings.output_file.as_deref(),
778 args.format,
779 args.settings.resolution,
780 args.settings.prerelease,
781 args.settings.fork_strategy,
782 args.settings.dependency_mode,
783 args.settings.upgrade,
784 args.settings.generate_hashes,
785 args.settings.no_emit_package,
786 args.settings.no_strip_extras,
787 args.settings.no_strip_markers,
788 !args.settings.no_annotate,
789 !args.settings.no_header,
790 args.settings.custom_compile_command,
791 args.settings.emit_index_url,
792 args.settings.emit_find_links,
793 args.settings.emit_build_options,
794 args.settings.emit_marker_expression,
795 args.settings.emit_index_annotation,
796 args.settings.index_locations,
797 args.settings.index_strategy,
798 args.settings.torch_backend,
799 args.settings.cuda_driver_version,
800 args.settings.amd_gpu_architecture,
801 args.settings.dependency_metadata,
802 args.settings.keyring_provider,
803 &client_builder.subcommand(vec!["pip".to_owned(), "compile".to_owned()]),
804 args.settings.config_setting,
805 args.settings.config_settings_package,
806 args.settings.build_isolation.clone(),
807 &args.settings.extra_build_dependencies,
808 &args.settings.extra_build_variables,
809 args.settings.build_options,
810 args.settings.install_mirrors,
811 args.settings.python_version,
812 args.settings.python_platform,
813 globals.python_downloads,
814 args.settings.universal,
815 args.settings.exclude_newer,
816 args.settings.sources,
817 args.settings.annotation_style,
818 args.settings.link_mode,
819 args.settings.python,
820 args.settings.system,
821 globals.python_preference,
822 globals.concurrency,
823 globals.quiet > 0,
824 cache,
825 workspace_cache,
826 printer,
827 globals.preview,
828 ))
829 .await
830 }
831 Commands::Pip(PipNamespace {
832 command: PipCommand::Sync(args),
833 }) => {
834 args.compat_args.validate()?;
835
836 let args = PipSyncSettings::resolve(args, filesystem, environment);
838 show_settings!(args);
839
840 globals
842 .network_settings
843 .check_refresh_conflict(&args.refresh);
844
845 let cache = cache.init().await?.with_refresh(
847 args.refresh
848 .combine(Refresh::from(args.settings.reinstall.clone()))
849 .combine(Refresh::from(args.settings.upgrade.clone())),
850 );
851
852 let requirements = args
853 .src_file
854 .into_iter()
855 .map(RequirementsSource::from_requirements_file)
856 .collect::<Result<Vec<_>, _>>()?;
857 let constraints = args
858 .constraints
859 .into_iter()
860 .map(RequirementsSource::from_constraints_txt)
861 .collect::<Result<Vec<_>, _>>()?;
862 let build_constraints = args
863 .build_constraints
864 .into_iter()
865 .map(RequirementsSource::from_constraints_txt)
866 .collect::<Result<Vec<_>, _>>()?;
867 let groups = GroupsSpecification {
868 root: project_dir.to_path_buf(),
869 groups: args.settings.groups,
870 };
871
872 Box::pin(commands::pip_sync(
873 &requirements,
874 &constraints,
875 &build_constraints,
876 &args.settings.extras,
877 &groups,
878 args.settings.reinstall,
879 args.settings.link_mode,
880 args.settings.compile_bytecode,
881 args.settings.hash_checking,
882 args.settings.index_locations,
883 args.settings.index_strategy,
884 args.settings.torch_backend,
885 args.settings.cuda_driver_version,
886 args.settings.amd_gpu_architecture,
887 args.settings.dependency_metadata,
888 args.settings.keyring_provider,
889 &client_builder.subcommand(vec!["pip".to_owned(), "sync".to_owned()]),
890 args.settings.allow_empty_requirements,
891 globals.installer_metadata,
892 &args.settings.config_setting,
893 &args.settings.config_settings_package,
894 args.settings.build_isolation.clone(),
895 &args.settings.extra_build_dependencies,
896 &args.settings.extra_build_variables,
897 args.settings.build_options,
898 args.settings.python_version,
899 args.settings.python_platform,
900 globals.python_downloads,
901 args.settings.install_mirrors,
902 args.settings.strict,
903 args.settings.exclude_newer,
904 args.settings.python,
905 args.settings.system,
906 args.settings.break_system_packages,
907 args.settings.target,
908 args.settings.prefix,
909 args.settings.sources,
910 globals.python_preference,
911 globals.concurrency,
912 cache,
913 workspace_cache,
914 args.dry_run,
915 printer,
916 globals.preview,
917 ))
918 .await
919 }
920 Commands::Pip(PipNamespace {
921 command: PipCommand::Install(args),
922 }) => {
923 args.compat_args.validate()?;
924
925 let mut args = PipInstallSettings::resolve(args, filesystem, environment);
927 show_settings!(args);
928
929 let mut requirements = Vec::with_capacity(
930 args.package.len() + args.editables.len() + args.requirements.len(),
931 );
932 for package in args.package {
933 requirements.push(RequirementsSource::from_package_argument(&package)?);
934 }
935 for package in args.editables {
936 requirements.push(RequirementsSource::from_editable(&package)?);
937 }
938 requirements.extend(
939 args.requirements
940 .into_iter()
941 .map(RequirementsSource::from_requirements_file)
942 .collect::<Result<Vec<_>, _>>()?,
943 );
944 let constraints = args
945 .constraints
946 .into_iter()
947 .map(RequirementsSource::from_constraints_txt)
948 .collect::<Result<Vec<_>, _>>()?;
949 let overrides = args
950 .overrides
951 .into_iter()
952 .map(RequirementsSource::from_overrides_txt)
953 .collect::<Result<Vec<_>, _>>()?;
954 let excludes = args
955 .excludes
956 .into_iter()
957 .map(RequirementsSource::from_requirements_txt)
958 .collect::<Result<Vec<_>, _>>()?;
959 let build_constraints = args
960 .build_constraints
961 .into_iter()
962 .map(RequirementsSource::from_overrides_txt)
963 .collect::<Result<Vec<_>, _>>()?;
964 let groups = GroupsSpecification {
965 root: project_dir.to_path_buf(),
966 groups: args.settings.groups,
967 };
968
969 for requirement in &requirements {
973 let requirement = match requirement {
974 RequirementsSource::Package(requirement) => requirement,
975 RequirementsSource::Editable(requirement) => requirement,
976 _ => continue,
977 };
978 match requirement {
979 RequirementsTxtRequirement::Named(requirement) => {
980 if let Some(VersionOrUrl::Url(url)) = requirement.version_or_url.as_ref() {
981 if let ParsedUrl::Directory(ParsedDirectoryUrl {
982 install_path, ..
983 }) = &url.parsed_url
984 {
985 debug!(
986 "Marking explicit source tree for reinstall: `{}`",
987 install_path.display()
988 );
989 args.settings.reinstall = args
990 .settings
991 .reinstall
992 .with_package(requirement.name.clone());
993 }
994 }
995 }
996 RequirementsTxtRequirement::Unnamed(requirement) => {
997 if let ParsedUrl::Directory(ParsedDirectoryUrl { install_path, .. }) =
998 &requirement.url.parsed_url
999 {
1000 debug!(
1001 "Marking explicit source tree for reinstall: `{}`",
1002 install_path.display()
1003 );
1004 args.settings.reinstall =
1005 args.settings.reinstall.with_path(install_path.clone());
1006 }
1007 }
1008 }
1009 }
1010
1011 globals
1013 .network_settings
1014 .check_refresh_conflict(&args.refresh);
1015
1016 let cache = cache.init().await?.with_refresh(
1018 args.refresh
1019 .combine(Refresh::from(args.settings.reinstall.clone()))
1020 .combine(Refresh::from(args.settings.upgrade.clone())),
1021 );
1022
1023 Box::pin(commands::pip_install(
1024 &requirements,
1025 &constraints,
1026 &overrides,
1027 &excludes,
1028 &build_constraints,
1029 args.constraints_from_workspace,
1030 args.overrides_from_workspace,
1031 args.excludes_from_workspace,
1032 args.build_constraints_from_workspace,
1033 args.editable,
1034 &args.settings.extras,
1035 &groups,
1036 args.settings.resolution,
1037 args.settings.prerelease,
1038 args.settings.dependency_mode,
1039 args.settings.upgrade,
1040 args.settings.index_locations,
1041 args.settings.index_strategy,
1042 args.settings.torch_backend,
1043 args.settings.cuda_driver_version,
1044 args.settings.amd_gpu_architecture,
1045 args.settings.dependency_metadata,
1046 args.settings.keyring_provider,
1047 &client_builder.subcommand(vec!["pip".to_owned(), "install".to_owned()]),
1048 args.settings.reinstall,
1049 args.settings.link_mode,
1050 args.settings.compile_bytecode,
1051 args.settings.hash_checking,
1052 globals.installer_metadata,
1053 &args.settings.config_setting,
1054 &args.settings.config_settings_package,
1055 args.settings.build_isolation.clone(),
1056 &args.settings.extra_build_dependencies,
1057 &args.settings.extra_build_variables,
1058 args.settings.build_options,
1059 args.modifications,
1060 args.settings.python_version,
1061 args.settings.python_platform,
1062 globals.python_downloads,
1063 args.settings.install_mirrors,
1064 args.settings.strict,
1065 args.settings.exclude_newer,
1066 args.settings.sources,
1067 args.settings.python,
1068 args.settings.system,
1069 args.settings.break_system_packages,
1070 args.settings.target,
1071 args.settings.prefix,
1072 globals.python_preference,
1073 globals.concurrency,
1074 cache,
1075 workspace_cache,
1076 args.dry_run,
1077 printer,
1078 globals.preview,
1079 ))
1080 .await
1081 }
1082 Commands::Pip(PipNamespace {
1083 command: PipCommand::Uninstall(args),
1084 }) => {
1085 args.compat_args.validate()?;
1086
1087 let args = PipUninstallSettings::resolve(args, filesystem, environment);
1089 show_settings!(args);
1090
1091 let cache = cache.init().await?;
1093
1094 let mut sources = Vec::with_capacity(args.package.len() + args.requirements.len());
1095 for package in args.package {
1096 sources.push(RequirementsSource::from_package_argument(&package)?);
1097 }
1098 sources.extend(
1099 args.requirements
1100 .into_iter()
1101 .map(RequirementsSource::from_requirements_file)
1102 .collect::<Result<Vec<_>, _>>()?,
1103 );
1104 commands::pip_uninstall(
1105 &sources,
1106 args.settings.python,
1107 args.settings.system,
1108 args.settings.break_system_packages,
1109 args.settings.target,
1110 args.settings.prefix,
1111 cache,
1112 args.settings.keyring_provider,
1113 &client_builder.subcommand(vec!["pip".to_owned(), "uninstall".to_owned()]),
1114 args.dry_run,
1115 printer,
1116 )
1117 .await
1118 }
1119 Commands::Pip(PipNamespace {
1120 command: PipCommand::Freeze(args),
1121 }) => {
1122 let args = PipFreezeSettings::resolve(args, filesystem, environment);
1124 show_settings!(args);
1125
1126 let cache = cache.init().await?;
1128
1129 commands::pip_freeze(
1130 args.exclude_editable,
1131 &args.exclude,
1132 args.settings.strict,
1133 &args.settings.dependency_metadata,
1134 args.settings.python.as_deref(),
1135 args.settings.system,
1136 args.settings.target,
1137 args.settings.prefix,
1138 args.paths,
1139 &cache,
1140 printer,
1141 )
1142 }
1143 Commands::Pip(PipNamespace {
1144 command: PipCommand::List(args),
1145 }) => {
1146 args.compat_args.validate()?;
1147
1148 let args = PipListSettings::resolve(args, filesystem, environment);
1150 show_settings!(args);
1151
1152 let cache = cache.init().await?;
1154
1155 commands::pip_list(
1156 args.editable,
1157 &args.exclude,
1158 &args.format,
1159 args.outdated,
1160 args.settings.prerelease,
1161 args.settings.index_locations,
1162 args.settings.index_strategy,
1163 args.settings.keyring_provider,
1164 &client_builder.subcommand(vec!["pip".to_owned(), "list".to_owned()]),
1165 globals.concurrency,
1166 args.settings.strict,
1167 args.settings.exclude_newer,
1168 &args.settings.dependency_metadata,
1169 args.settings.python.as_deref(),
1170 args.settings.system,
1171 args.settings.target,
1172 args.settings.prefix,
1173 &cache,
1174 printer,
1175 )
1176 .await
1177 }
1178 Commands::Pip(PipNamespace {
1179 command: PipCommand::Show(args),
1180 }) => {
1181 let args = PipShowSettings::resolve(args, filesystem, environment);
1183 show_settings!(args);
1184
1185 let cache = cache.init().await?;
1187
1188 commands::pip_show(
1189 args.package,
1190 args.settings.strict,
1191 &args.settings.dependency_metadata,
1192 args.settings.python.as_deref(),
1193 args.settings.system,
1194 args.settings.target,
1195 args.settings.prefix,
1196 args.files,
1197 &cache,
1198 printer,
1199 )
1200 }
1201 Commands::Pip(PipNamespace {
1202 command: PipCommand::Tree(args),
1203 }) => {
1204 let args = PipTreeSettings::resolve(args, filesystem, environment);
1206
1207 let cache = cache.init().await?;
1209
1210 commands::pip_tree(
1211 args.show_version_specifiers,
1212 args.depth,
1213 &args.prune,
1214 &args.package,
1215 args.no_dedupe,
1216 args.invert,
1217 args.outdated,
1218 args.settings.prerelease,
1219 args.settings.index_locations,
1220 args.settings.index_strategy,
1221 args.settings.keyring_provider,
1222 client_builder.subcommand(vec!["pip".to_owned(), "tree".to_owned()]),
1223 globals.concurrency,
1224 args.settings.strict,
1225 args.settings.exclude_newer,
1226 &args.settings.dependency_metadata,
1227 args.settings.python.as_deref(),
1228 args.settings.system,
1229 &cache,
1230 printer,
1231 )
1232 .await
1233 }
1234 Commands::Pip(PipNamespace {
1235 command: PipCommand::Check(args),
1236 }) => {
1237 let args = PipCheckSettings::resolve(args, filesystem, environment);
1239 show_settings!(args);
1240
1241 let cache = cache.init().await?;
1243
1244 commands::pip_check(
1245 args.settings.python.as_deref(),
1246 args.settings.system,
1247 args.settings.python_version.as_ref(),
1248 args.settings.python_platform.as_ref(),
1249 &args.settings.dependency_metadata,
1250 &cache,
1251 printer,
1252 )
1253 }
1254 Commands::Pip(PipNamespace {
1255 command: PipCommand::Debug(_),
1256 }) => Err(anyhow!(
1257 "pip's `debug` is unsupported (consider using `uvx pip debug` instead)"
1258 )),
1259 Commands::Cache(CacheNamespace {
1260 command: CacheCommand::Clean(args),
1261 })
1262 | Commands::Clean(args) => {
1263 show_settings!(args);
1264 commands::cache_clean(&args.package, args.force, cache, printer).await
1265 }
1266 Commands::Cache(CacheNamespace {
1267 command: CacheCommand::Prune(args),
1268 }) => {
1269 show_settings!(args);
1270 commands::cache_prune(args.ci, args.force, cache, printer).await
1271 }
1272 Commands::Cache(CacheNamespace {
1273 command: CacheCommand::Dir,
1274 }) => commands::cache_dir(&cache, printer),
1275 Commands::Cache(CacheNamespace {
1276 command: CacheCommand::Size(args),
1277 }) => commands::cache_size(&cache, args.human, printer, globals.preview),
1278 Commands::Build(args) => {
1279 let args = settings::BuildSettings::resolve(args, filesystem, environment);
1281 show_settings!(args);
1282
1283 globals
1285 .network_settings
1286 .check_refresh_conflict(&args.refresh);
1287
1288 let cache = cache.init().await?.with_refresh(
1290 args.refresh
1291 .combine(Refresh::from(args.settings.upgrade.clone())),
1292 );
1293
1294 let build_constraints = args
1296 .build_constraints
1297 .into_iter()
1298 .map(RequirementsSource::from_constraints_txt)
1299 .collect::<Result<Vec<_>, _>>()?;
1300
1301 commands::build_frontend(
1302 &project_dir,
1303 args.src,
1304 args.package,
1305 args.all_packages,
1306 args.out_dir,
1307 args.sdist,
1308 args.wheel,
1309 args.list,
1310 args.build_logs,
1311 args.gitignore,
1312 args.force_pep517,
1313 args.clear,
1314 build_constraints,
1315 args.build_constraints_from_workspace,
1316 args.hash_checking,
1317 args.python,
1318 args.install_mirrors,
1319 &args.settings,
1320 &client_builder.subcommand(vec!["build".to_owned()]),
1321 cli.top_level.no_config,
1322 globals.python_preference,
1323 globals.python_downloads,
1324 globals.concurrency,
1325 &cache,
1326 &workspace_cache,
1327 printer,
1328 globals.preview,
1329 )
1330 .await
1331 }
1332 Commands::Venv(args) => {
1333 args.compat_args.validate()?;
1334
1335 if args.no_system {
1336 warn_user_once!(
1337 "The `--no-system` flag has no effect, `uv venv` always ignores virtual environments when finding a Python interpreter; did you mean `--managed-python`?"
1338 );
1339 }
1340
1341 if args.system {
1342 warn_user_once!(
1343 "The `--system` flag has no effect, `uv venv` always ignores virtual environments when finding a Python interpreter; did you mean `--no-managed-python`?"
1344 );
1345 }
1346
1347 let args = settings::VenvSettings::resolve(args, filesystem, environment);
1349 show_settings!(args);
1350
1351 globals
1353 .network_settings
1354 .check_refresh_conflict(&args.refresh);
1355
1356 let cache = cache.init().await?.with_refresh(
1358 args.refresh
1359 .combine(Refresh::from(args.settings.reinstall.clone()))
1360 .combine(Refresh::from(args.settings.upgrade.clone())),
1361 );
1362
1363 let prompt = args.prompt.or_else(|| {
1365 if args.path.is_none() {
1366 Some(".".to_string())
1367 } else {
1368 None
1369 }
1370 });
1371
1372 let python_request: Option<PythonRequest> =
1373 args.settings.python.as_deref().map(PythonRequest::parse);
1374
1375 let on_existing = uv_virtualenv::OnExisting::from_args(
1376 args.allow_existing,
1377 args.clear,
1378 args.no_clear,
1379 if args.force {
1380 uv_virtualenv::ClearNonVirtualenv::Allow
1381 } else if globals.preview.is_enabled(PreviewFeature::VenvSafeClear) {
1382 uv_virtualenv::ClearNonVirtualenv::Error
1383 } else {
1384 uv_virtualenv::ClearNonVirtualenv::Warn
1385 },
1386 );
1387
1388 Box::pin(commands::venv(
1389 &project_dir,
1390 args.path,
1391 python_request,
1392 args.settings.install_mirrors,
1393 globals.python_preference,
1394 globals.python_downloads,
1395 args.settings.link_mode,
1396 &args.settings.index_locations,
1397 args.settings.index_strategy,
1398 args.settings.dependency_metadata,
1399 args.settings.keyring_provider,
1400 &client_builder.subcommand(vec!["venv".to_owned()]),
1401 uv_virtualenv::Prompt::from_args(prompt),
1402 args.system_site_packages,
1403 args.seed,
1404 on_existing,
1405 args.settings.exclude_newer,
1406 globals.concurrency,
1407 cli.top_level.no_config,
1408 args.no_project,
1409 &cache,
1410 &workspace_cache,
1411 printer,
1412 args.relocatable
1413 || (globals
1414 .preview
1415 .is_enabled(PreviewFeature::RelocatableEnvsDefault)
1416 && !args.no_relocatable),
1417 globals.preview,
1418 ))
1419 .await
1420 }
1421 Commands::Project(project) => {
1422 Box::pin(run_project(
1423 project,
1424 &project_dir,
1425 run_command,
1426 script,
1427 globals,
1428 cli.top_level.no_config,
1429 cli.top_level.global_args.project.is_some(),
1430 client_builder,
1431 filesystem,
1432 cache,
1433 &workspace_cache,
1434 printer,
1435 ))
1436 .await
1437 }
1438 #[cfg(feature = "self-update")]
1439 Commands::Self_(SelfNamespace {
1440 command:
1441 SelfCommand::Update(SelfUpdateArgs {
1442 target_version,
1443 token,
1444 dry_run,
1445 }),
1446 }) => {
1447 commands::self_update(
1448 target_version,
1449 token,
1450 dry_run,
1451 printer,
1452 client_builder.subcommand(vec!["self".to_owned(), "update".to_owned()]),
1453 )
1454 .await
1455 }
1456 Commands::Self_(SelfNamespace {
1457 command:
1458 SelfCommand::Version {
1459 short,
1460 output_format,
1461 },
1462 }) => {
1463 commands::self_version(short, output_format, printer)?;
1464 Ok(ExitStatus::Success)
1465 }
1466 #[cfg(not(feature = "self-update"))]
1467 Commands::Self_(_) => {
1468 return Err(ExternallyInstalledError {
1469 install_source: InstallSource::detect(),
1470 }
1471 .into());
1472 }
1473 Commands::GenerateShellCompletion(args) => {
1474 args.shell.generate(&mut Cli::command(), &mut stdout());
1475 Ok(ExitStatus::Success)
1476 }
1477 Commands::Tool(ToolNamespace {
1478 command: run_variant @ (ToolCommand::Uvx(_) | ToolCommand::Run(_)),
1479 }) => {
1480 let (args, invocation_source) = match run_variant {
1481 ToolCommand::Uvx(args) => (args.tool_run, ToolRunCommand::Uvx),
1482 ToolCommand::Run(args) => (args, ToolRunCommand::ToolRun),
1483 _ => unreachable!(),
1485 };
1486
1487 if let Some(shell) = args.generate_shell_completion {
1488 let mut uvx = Cli::command()
1490 .find_subcommand("tool")
1491 .unwrap()
1492 .find_subcommand("uvx")
1493 .unwrap()
1494 .clone()
1495 .disable_help_flag(true)
1498 .disable_version_flag(true);
1499
1500 for arg in TopLevelArgs::command().get_arguments() {
1503 if arg.get_id() != "isolated" && arg.get_id() != "version" {
1504 uvx = uvx.arg(arg);
1505 }
1506 }
1507 shell.generate(&mut uvx, &mut stdout());
1508 return Ok(ExitStatus::Success);
1509 }
1510
1511 let args = settings::ToolRunSettings::resolve(
1513 args,
1514 filesystem,
1515 invocation_source,
1516 environment,
1517 );
1518 show_settings!(args);
1519
1520 globals
1522 .network_settings
1523 .check_refresh_conflict(&args.refresh);
1524
1525 let cache = cache.init().await?.with_refresh(
1527 args.refresh
1528 .combine(Refresh::from(args.settings.reinstall.clone()))
1529 .combine(Refresh::from(args.settings.resolver.upgrade.clone())),
1530 );
1531
1532 let requirements = {
1533 let mut requirements = Vec::with_capacity(
1534 args.with.len() + args.with_editable.len() + args.with_requirements.len(),
1535 );
1536 for package in args.with {
1537 requirements.push(RequirementsSource::from_with_package_argument(&package)?);
1538 }
1539 for package in args.with_editable {
1540 requirements.push(RequirementsSource::from_editable(&package)?);
1541 }
1542 requirements.extend(
1543 args.with_requirements
1544 .into_iter()
1545 .map(RequirementsSource::from_requirements_file)
1546 .collect::<Result<Vec<_>, _>>()?,
1547 );
1548 requirements
1549 };
1550 let constraints = args
1551 .constraints
1552 .into_iter()
1553 .map(RequirementsSource::from_constraints_txt)
1554 .collect::<Result<Vec<_>, _>>()?;
1555 let overrides = args
1556 .overrides
1557 .into_iter()
1558 .map(RequirementsSource::from_overrides_txt)
1559 .collect::<Result<Vec<_>, _>>()?;
1560
1561 let build_constraints = args
1562 .build_constraints
1563 .into_iter()
1564 .map(RequirementsSource::from_constraints_txt)
1565 .collect::<Result<Vec<_>, _>>()?;
1566
1567 let client_builder = match invocation_source {
1568 ToolRunCommand::Uvx => client_builder.subcommand(vec!["uvx".to_owned()]),
1569 ToolRunCommand::ToolRun => {
1570 client_builder.subcommand(vec!["tool".to_owned(), "run".to_owned()])
1571 }
1572 };
1573
1574 Box::pin(commands::tool_run(
1575 args.command,
1576 args.from,
1577 &requirements,
1578 &constraints,
1579 &overrides,
1580 &build_constraints,
1581 args.show_resolution || globals.verbose > 0,
1582 args.lfs,
1583 args.python,
1584 args.python_platform,
1585 args.install_mirrors,
1586 args.options,
1587 args.settings,
1588 client_builder,
1589 invocation_source,
1590 args.isolated,
1591 globals.python_preference,
1592 globals.python_downloads,
1593 globals.installer_metadata,
1594 globals.concurrency,
1595 cache,
1596 workspace_cache,
1597 printer,
1598 args.env_file,
1599 args.no_env_file,
1600 globals.preview,
1601 ))
1602 .await
1603 }
1604 Commands::Tool(ToolNamespace {
1605 command: ToolCommand::Install(args),
1606 }) => {
1607 let args = settings::ToolInstallSettings::resolve(args, filesystem, environment);
1609 show_settings!(args);
1610
1611 globals
1613 .network_settings
1614 .check_refresh_conflict(&args.refresh);
1615
1616 let refresh = args
1618 .refresh
1619 .combine(Refresh::from(args.settings.reinstall.clone()))
1620 .combine(Refresh::from(args.settings.resolver.upgrade.clone()));
1621 let cache = cache.init().await?.with_refresh(refresh.clone());
1622
1623 let mut entrypoints = Vec::with_capacity(args.with_executables_from.len());
1624 let mut requirements = Vec::with_capacity(
1625 args.with.len()
1626 + args.with_editable.len()
1627 + args.with_requirements.len()
1628 + args.with_executables_from.len(),
1629 );
1630 for pkg in args.with {
1631 requirements.push(RequirementsSource::from_with_package_argument(&pkg)?);
1632 }
1633 for pkg in args.with_editable {
1634 requirements.push(RequirementsSource::from_editable(&pkg)?);
1635 }
1636 for path in args.with_requirements {
1637 requirements.push(RequirementsSource::from_requirements_file(path)?);
1638 }
1639 for pkg in &args.with_executables_from {
1640 let source = RequirementsSource::from_with_package_argument(pkg)?;
1641 let RequirementsSource::Package(RequirementsTxtRequirement::Named(requirement)) =
1642 &source
1643 else {
1644 bail!(
1645 "Expected a named package for `--with-executables-from`, but got: {}",
1646 source.to_string().cyan()
1647 )
1648 };
1649 entrypoints.push(requirement.name.clone());
1650 requirements.push(source);
1651 }
1652
1653 let constraints = args
1654 .constraints
1655 .into_iter()
1656 .map(RequirementsSource::from_constraints_txt)
1657 .collect::<Result<Vec<_>, _>>()?;
1658 let overrides = args
1659 .overrides
1660 .into_iter()
1661 .map(RequirementsSource::from_overrides_txt)
1662 .collect::<Result<Vec<_>, _>>()?;
1663 let excludes = args
1664 .excludes
1665 .into_iter()
1666 .map(RequirementsSource::from_requirements_txt)
1667 .collect::<Result<Vec<_>, _>>()?;
1668 let build_constraints = args
1669 .build_constraints
1670 .into_iter()
1671 .map(RequirementsSource::from_constraints_txt)
1672 .collect::<Result<Vec<_>, _>>()?;
1673
1674 Box::pin(commands::tool_install(
1675 args.package,
1676 args.editable,
1677 args.from,
1678 &requirements,
1679 &constraints,
1680 &overrides,
1681 &excludes,
1682 &build_constraints,
1683 &entrypoints,
1684 args.lfs,
1685 args.python,
1686 args.python_platform,
1687 args.install_mirrors,
1688 args.force,
1689 args.options,
1690 args.settings,
1691 client_builder.subcommand(vec!["tool".to_owned(), "install".to_owned()]),
1692 globals.python_preference,
1693 globals.python_downloads,
1694 globals.installer_metadata,
1695 globals.concurrency,
1696 cli.top_level.no_config,
1697 cache,
1698 refresh,
1699 &workspace_cache,
1700 printer,
1701 globals.preview,
1702 ))
1703 .await
1704 }
1705 Commands::Tool(ToolNamespace {
1706 command: ToolCommand::List(args),
1707 }) => {
1708 let args = settings::ToolListSettings::resolve(args, filesystem);
1710 show_settings!(args);
1711
1712 let cache = cache.init().await?;
1714
1715 commands::tool_list(
1716 args.show_paths,
1717 args.show_version_specifiers,
1718 args.show_with,
1719 args.show_extras,
1720 args.show_python,
1721 args.outdated,
1722 args.args,
1723 args.filesystem,
1724 client_builder.subcommand(vec!["tool".to_owned(), "list".to_owned()]),
1725 globals.concurrency,
1726 &cache,
1727 printer,
1728 )
1729 .await
1730 }
1731 Commands::Tool(ToolNamespace {
1732 command: ToolCommand::Upgrade(args),
1733 }) => {
1734 let args = settings::ToolUpgradeSettings::resolve(args, filesystem, &environment);
1736 show_settings!(args);
1737
1738 let cache = cache
1740 .init()
1741 .await?
1742 .with_refresh(Refresh::All(Timestamp::now()));
1743
1744 Box::pin(commands::tool_upgrade(
1745 args.names,
1746 args.python,
1747 args.python_platform,
1748 args.install_mirrors,
1749 args.args,
1750 args.filesystem,
1751 client_builder.subcommand(vec!["tool".to_owned(), "upgrade".to_owned()]),
1752 globals.python_preference,
1753 globals.python_downloads,
1754 globals.installer_metadata,
1755 globals.concurrency,
1756 &cache,
1757 &workspace_cache,
1758 printer,
1759 globals.preview,
1760 ))
1761 .await
1762 }
1763 Commands::Tool(ToolNamespace {
1764 command: ToolCommand::Uninstall(args),
1765 }) => {
1766 let args = settings::ToolUninstallSettings::resolve(args, filesystem);
1768 show_settings!(args);
1769
1770 commands::tool_uninstall(args.name, printer).await
1771 }
1772 Commands::Tool(ToolNamespace {
1773 command: ToolCommand::UpdateShell,
1774 }) => {
1775 commands::tool_update_shell(printer).await?;
1776 Ok(ExitStatus::Success)
1777 }
1778 Commands::Tool(ToolNamespace {
1779 command: ToolCommand::Dir(args),
1780 }) => {
1781 let args = settings::ToolDirSettings::resolve(args, filesystem);
1783 show_settings!(args);
1784
1785 commands::tool_dir(args.bin, globals.preview, printer)?;
1786 Ok(ExitStatus::Success)
1787 }
1788 Commands::Python(PythonNamespace {
1789 command: PythonCommand::List(args),
1790 }) => {
1791 let args = settings::PythonListSettings::resolve(args, filesystem, environment);
1793 show_settings!(args);
1794
1795 let cache = cache.init().await?;
1797
1798 commands::python_list(
1799 args.request,
1800 args.kinds,
1801 args.all_versions,
1802 args.all_platforms,
1803 args.all_arches,
1804 args.show_urls,
1805 args.output_format,
1806 args.python_downloads_json_url,
1807 args.python_install_mirror,
1808 args.pypy_install_mirror,
1809 globals.python_preference,
1810 globals.python_downloads,
1811 &client_builder.subcommand(vec!["python".to_owned(), "list".to_owned()]),
1812 &cache,
1813 printer,
1814 )
1815 .await
1816 }
1817 Commands::Python(PythonNamespace {
1818 command: PythonCommand::Install(args),
1819 }) => {
1820 let args = settings::PythonInstallSettings::resolve(args, filesystem, environment);
1822 show_settings!(args);
1823
1824 let cache = cache.init().await?;
1826
1827 commands::python_install(
1828 &project_dir,
1829 args.install_dir,
1830 args.targets,
1831 args.reinstall,
1832 args.upgrade,
1833 args.bin,
1834 args.registry,
1835 args.force,
1836 args.python_install_mirror,
1837 args.pypy_install_mirror,
1838 args.python_downloads_json_url,
1839 client_builder.subcommand(vec!["python".to_owned(), "install".to_owned()]),
1840 args.default,
1841 globals.python_downloads,
1842 cli.top_level.no_config,
1843 args.compile_bytecode,
1844 &globals.concurrency,
1845 &cache,
1846 globals.preview,
1847 printer,
1848 )
1849 .await
1850 }
1851 Commands::Python(PythonNamespace {
1852 command: PythonCommand::Upgrade(args),
1853 }) => {
1854 let args = settings::PythonUpgradeSettings::resolve(args, filesystem, environment);
1856 show_settings!(args);
1857 let upgrade = commands::PythonUpgrade::Enabled(commands::PythonUpgradeSource::Upgrade);
1858
1859 let cache = cache.init().await?;
1861
1862 commands::python_install(
1863 &project_dir,
1864 args.install_dir,
1865 args.targets,
1866 args.reinstall,
1867 upgrade,
1868 args.bin,
1869 args.registry,
1870 args.force,
1871 args.python_install_mirror,
1872 args.pypy_install_mirror,
1873 args.python_downloads_json_url,
1874 client_builder.subcommand(vec!["python".to_owned(), "upgrade".to_owned()]),
1875 args.default,
1876 globals.python_downloads,
1877 cli.top_level.no_config,
1878 args.compile_bytecode,
1879 &globals.concurrency,
1880 &cache,
1881 globals.preview,
1882 printer,
1883 )
1884 .await
1885 }
1886 Commands::Python(PythonNamespace {
1887 command: PythonCommand::Uninstall(args),
1888 }) => {
1889 let args = settings::PythonUninstallSettings::resolve(args, filesystem);
1891 show_settings!(args);
1892
1893 commands::python_uninstall(args.install_dir, args.targets, args.all, printer).await
1894 }
1895 Commands::Python(PythonNamespace {
1896 command: PythonCommand::Find(args),
1897 }) => {
1898 let args = settings::PythonFindSettings::resolve(args, filesystem, environment);
1900
1901 let cache = cache.init().await?;
1903
1904 if let Some(Pep723Item::Script(script)) = script {
1905 commands::python_find_script(
1906 (&script).into(),
1907 args.show_version,
1908 args.resolve_links,
1909 &client_builder.subcommand(vec!["python".to_owned(), "find".to_owned()]),
1911 globals.python_preference,
1912 globals.python_downloads,
1913 cli.top_level.no_config,
1914 &cache,
1915 printer,
1916 )
1917 .await
1918 } else {
1919 commands::python_find(
1920 &project_dir,
1921 args.request,
1922 args.show_version,
1923 args.resolve_links,
1924 args.no_project,
1925 cli.top_level.no_config,
1926 args.system,
1927 globals.python_preference,
1928 args.python_downloads_json_url.as_deref(),
1929 &client_builder.subcommand(vec!["python".to_owned(), "find".to_owned()]),
1930 &cache,
1931 &workspace_cache,
1932 printer,
1933 )
1934 .await
1935 }
1936 }
1937 Commands::Python(PythonNamespace {
1938 command: PythonCommand::Pin(args),
1939 }) => {
1940 let args = settings::PythonPinSettings::resolve(args, filesystem, environment);
1942
1943 let cache = cache.init().await?;
1945
1946 Box::pin(commands::python_pin(
1947 &project_dir,
1948 args.request,
1949 args.resolved,
1950 globals.python_preference,
1951 globals.python_downloads,
1952 args.no_project,
1953 args.global,
1954 args.rm,
1955 args.install_mirrors,
1956 client_builder.subcommand(vec!["python".to_owned(), "pin".to_owned()]),
1957 &cache,
1958 &workspace_cache,
1959 printer,
1960 ))
1961 .await
1962 }
1963 Commands::Python(PythonNamespace {
1964 command: PythonCommand::Dir(args),
1965 }) => {
1966 let args = settings::PythonDirSettings::resolve(args, filesystem);
1968 show_settings!(args);
1969
1970 commands::python_dir(args.bin, printer)?;
1971 Ok(ExitStatus::Success)
1972 }
1973 Commands::Python(PythonNamespace {
1974 command: PythonCommand::UpdateShell,
1975 }) => {
1976 commands::python_update_shell(printer).await?;
1977 Ok(ExitStatus::Success)
1978 }
1979 Commands::Publish(args) => {
1980 show_settings!(args);
1981
1982 if args.skip_existing {
1983 bail!(
1984 "`uv publish` does not support `--skip-existing` because there is not a \
1985 reliable way to identify when an upload fails due to an existing \
1986 distribution. Instead, use `--check-url` to provide the URL to the simple \
1987 API for your index. uv will check the index for existing distributions before \
1988 attempting uploads."
1989 );
1990 }
1991
1992 let PublishSettings {
1994 files,
1995 username,
1996 password,
1997 dry_run,
1998 no_attestations,
1999 direct,
2000 publish_url,
2001 trusted_publishing,
2002 keyring_provider,
2003 check_url,
2004 index,
2005 index_locations,
2006 } = PublishSettings::resolve(args, filesystem);
2007
2008 commands::publish(
2009 files,
2010 publish_url,
2011 trusted_publishing,
2012 keyring_provider,
2013 &environment,
2014 &client_builder.subcommand(vec!["publish".to_owned()]),
2015 username,
2016 password,
2017 check_url,
2018 index,
2019 index_locations,
2020 dry_run,
2021 no_attestations,
2022 direct,
2023 globals.preview,
2024 &cache,
2025 printer,
2026 )
2027 .await
2028 }
2029 Commands::Workspace(WorkspaceNamespace { command }) => match command {
2030 WorkspaceCommand::Metadata(args) => {
2031 let args = settings::MetadataSettings::resolve(args, filesystem, environment);
2033 show_settings!(args);
2034
2035 globals
2037 .network_settings
2038 .check_refresh_conflict(&args.refresh);
2039
2040 let cache = cache.init().await?.with_refresh(
2042 args.refresh
2043 .clone()
2044 .combine(Refresh::from(args.settings.upgrade.clone())),
2045 );
2046
2047 let script = script.and_then(|script| match script {
2048 Pep723Item::Script(script) => Some(script),
2049 Pep723Item::Remote(..) | Pep723Item::Stdin(..) => None,
2050 });
2051
2052 Box::pin(commands::metadata(
2053 &project_dir,
2054 args.lock_check,
2055 args.frozen,
2056 args.dry_run,
2057 args.refresh,
2058 args.sync,
2059 args.python,
2060 args.install_mirrors,
2061 args.malware_settings,
2062 args.settings,
2063 client_builder.subcommand(vec!["workspace".to_owned(), "metadata".to_owned()]),
2064 script,
2065 globals.python_preference,
2066 globals.python_downloads,
2067 globals.concurrency,
2068 cli.top_level.no_config,
2069 &cache,
2070 &workspace_cache,
2071 printer,
2072 globals.preview,
2073 ))
2074 .await
2075 }
2076 WorkspaceCommand::Dir(args) => {
2077 commands::dir(
2078 args.package,
2079 &project_dir,
2080 &cache,
2081 &workspace_cache,
2082 printer,
2083 )
2084 .await
2085 }
2086 WorkspaceCommand::List(args) => {
2087 commands::list(
2088 &project_dir,
2089 args.paths,
2090 args.scripts,
2091 &cache,
2092 &workspace_cache,
2093 printer,
2094 globals.preview,
2095 )
2096 .await
2097 }
2098 },
2099 Commands::BuildBackend { command } => spawn_blocking(move || match command {
2100 BuildBackendCommand::BuildSdist { sdist_directory } => {
2101 commands::build_backend::build_sdist(&sdist_directory)
2102 }
2103 BuildBackendCommand::BuildWheel {
2104 wheel_directory,
2105 metadata_directory,
2106 } => commands::build_backend::build_wheel(
2107 &wheel_directory,
2108 metadata_directory.as_deref(),
2109 ),
2110 BuildBackendCommand::BuildEditable {
2111 wheel_directory,
2112 metadata_directory,
2113 } => commands::build_backend::build_editable(
2114 &wheel_directory,
2115 metadata_directory.as_deref(),
2116 ),
2117 BuildBackendCommand::GetRequiresForBuildSdist => {
2118 commands::build_backend::get_requires_for_build_sdist()
2119 }
2120 BuildBackendCommand::GetRequiresForBuildWheel => {
2121 commands::build_backend::get_requires_for_build_wheel()
2122 }
2123 BuildBackendCommand::PrepareMetadataForBuildWheel { wheel_directory } => {
2124 commands::build_backend::prepare_metadata_for_build_wheel(&wheel_directory)
2125 }
2126 BuildBackendCommand::GetRequiresForBuildEditable => {
2127 commands::build_backend::get_requires_for_build_editable()
2128 }
2129 BuildBackendCommand::PrepareMetadataForBuildEditable { wheel_directory } => {
2130 commands::build_backend::prepare_metadata_for_build_editable(&wheel_directory)
2131 }
2132 })
2133 .await
2134 .expect("tokio threadpool exited unexpectedly"),
2135 }
2136}
2137
2138fn map_settings_error(err: uv_settings::Error) -> anyhow::Error {
2139 match err {
2140 uv_settings::Error::RequiredVersion {
2141 required_version,
2142 package_version,
2143 } => required_version_error(&required_version, &package_version),
2144 err => err.into(),
2145 }
2146}
2147
2148fn required_version_error(
2149 required_version: &uv_configuration::RequiredVersion,
2150 package_version: &uv_pep440::Version,
2151) -> anyhow::Error {
2152 #[cfg(feature = "self-update")]
2153 let hint = {
2154 let ranges = release_specifiers_to_ranges(required_version.specifiers().clone());
2157
2158 if let Some(singleton) = ranges.as_singleton() {
2159 format!(
2160 ". Update `uv` by running `{}`.",
2161 format!("uv self update {singleton}").green()
2162 )
2163 } else if ranges
2164 .bounding_range()
2165 .iter()
2166 .any(|(lowest, _highest)| match lowest {
2167 Bound::Included(version) => **version > *package_version,
2168 Bound::Excluded(version) => **version > *package_version,
2169 Bound::Unbounded => false,
2170 })
2171 {
2172 format!(". Update `uv` by running `{}`.", "uv self update".cyan())
2173 } else {
2174 String::new()
2175 }
2176 };
2177 #[cfg(not(feature = "self-update"))]
2178 let hint = "";
2179
2180 anyhow!(
2181 "Required uv version `{required_version}` does not match the running version `{package_version}`{hint}",
2182 )
2183}
2184
2185async fn run_project(
2187 project_command: Box<ProjectCommand>,
2188 project_dir: &Path,
2189 command: Option<RunCommand>,
2190 script: Option<Pep723Item>,
2191 globals: GlobalSettings,
2192 no_config: bool,
2194 explicit_project: bool,
2195 client_builder: BaseClientBuilder<'_>,
2196 filesystem: Option<FilesystemOptions>,
2197 cache: Cache,
2198 workspace_cache: &WorkspaceCache,
2199 printer: Printer,
2200) -> Result<ExitStatus> {
2201 macro_rules! show_settings {
2203 ($arg:expr) => {
2204 if globals.show_settings {
2205 writeln!(printer.stdout(), "{:#?}", $arg)?;
2206 return Ok(ExitStatus::Success);
2207 }
2208 };
2209 }
2210
2211 let environment = EnvironmentOptions::new()?;
2213
2214 match *project_command {
2215 ProjectCommand::Init(args) => {
2216 let args =
2218 settings::InitSettings::resolve(args, filesystem, environment, globals.preview)?;
2219 show_settings!(args);
2220
2221 if explicit_project {
2223 if globals.preview.is_enabled(PreviewFeature::InitProjectFlag) {
2224 bail!(
2225 "The `--project` option cannot be used in `uv init`. {}",
2226 if args.path.is_some() {
2227 "Use `--directory` instead."
2228 } else {
2229 "Use `--directory` or a positional path instead."
2230 }
2231 )
2232 }
2233
2234 warn_user!(
2235 "Use of the `--project` option in `uv init` is deprecated and will be removed in a future release. {}",
2236 if args.path.is_some() {
2237 "Since a positional path was provided, the `--project` option has no effect. Consider using `--directory` instead."
2238 } else {
2239 "Consider using `uv init <PATH>` instead."
2240 }
2241 );
2242 }
2243
2244 let cache = cache.init().await?;
2246
2247 Box::pin(commands::init(
2248 project_dir,
2249 args.path,
2250 args.name,
2251 args.package,
2252 args.kind,
2253 args.bare,
2254 args.description,
2255 args.no_description,
2256 args.vcs,
2257 args.build_backend,
2258 args.no_readme,
2259 args.author_from,
2260 args.pin_python,
2261 args.python,
2262 args.install_mirrors,
2263 args.no_workspace,
2264 &client_builder.subcommand(vec!["init".to_owned()]),
2265 globals.python_preference,
2266 globals.python_downloads,
2267 no_config,
2268 &cache,
2269 printer,
2270 ))
2271 .await
2272 }
2273 ProjectCommand::Run(args) => {
2274 let args = settings::RunSettings::resolve(args, filesystem, environment);
2276 show_settings!(args);
2277
2278 globals
2280 .network_settings
2281 .check_refresh_conflict(&args.refresh);
2282
2283 let cache = cache.init().await?.with_refresh(
2285 args.refresh
2286 .combine(Refresh::from(args.settings.reinstall.clone()))
2287 .combine(Refresh::from(args.settings.resolver.upgrade.clone())),
2288 );
2289
2290 let mut requirements = Vec::with_capacity(
2291 args.with.len() + args.with_editable.len() + args.with_requirements.len(),
2292 );
2293 for package in args.with {
2294 requirements.push(RequirementsSource::from_with_package_argument(&package)?);
2295 }
2296 for package in args.with_editable {
2297 requirements.push(RequirementsSource::from_editable(&package)?);
2298 }
2299 requirements.extend(
2300 args.with_requirements
2301 .into_iter()
2302 .map(RequirementsSource::from_requirements_file)
2303 .collect::<Result<Vec<_>, _>>()?,
2304 );
2305
2306 Box::pin(commands::run(
2307 project_dir,
2308 script,
2309 command,
2310 requirements,
2311 args.show_resolution || globals.verbose > 0,
2312 args.lock_check,
2313 args.frozen,
2314 args.active,
2315 args.no_sync,
2316 args.isolated,
2317 args.all_packages,
2318 args.package,
2319 args.no_project,
2320 no_config,
2321 args.extras,
2322 args.groups,
2323 args.editable,
2324 args.modifications,
2325 args.python,
2326 args.python_platform,
2327 args.install_mirrors,
2328 args.settings,
2329 client_builder.subcommand(vec!["run".to_owned()]),
2330 globals.python_preference,
2331 globals.python_downloads,
2332 globals.installer_metadata,
2333 globals.concurrency,
2334 cache,
2335 workspace_cache,
2336 printer,
2337 args.env_file,
2338 globals.preview,
2339 args.max_recursion_depth,
2340 args.malware_settings,
2341 ))
2342 .await
2343 }
2344 ProjectCommand::Sync(args) => {
2345 let args = settings::SyncSettings::resolve(args, filesystem, environment);
2347 show_settings!(args);
2348
2349 globals
2351 .network_settings
2352 .check_refresh_conflict(&args.refresh);
2353
2354 let cache = cache.init().await?.with_refresh(
2356 args.refresh
2357 .combine(Refresh::from(args.settings.reinstall.clone()))
2358 .combine(Refresh::from(args.settings.resolver.upgrade.clone())),
2359 );
2360
2361 let script = script.map(|script| match script {
2363 Pep723Item::Script(script) => script,
2364 Pep723Item::Stdin(..) => unreachable!("`uv lock` does not support stdin"),
2365 Pep723Item::Remote(..) => unreachable!("`uv lock` does not support remote files"),
2366 });
2367
2368 Box::pin(commands::sync(
2369 project_dir,
2370 args.lock_check,
2371 args.frozen,
2372 args.dry_run,
2373 args.active,
2374 args.all_packages,
2375 args.package,
2376 args.extras,
2377 args.groups,
2378 args.editable,
2379 args.install_options,
2380 args.modifications,
2381 args.python,
2382 args.python_platform,
2383 args.install_mirrors,
2384 globals.python_preference,
2385 globals.python_downloads,
2386 args.settings,
2387 client_builder.subcommand(vec!["sync".to_owned()]),
2388 script,
2389 globals.installer_metadata,
2390 globals.concurrency,
2391 no_config,
2392 &cache,
2393 workspace_cache,
2394 printer,
2395 globals.preview,
2396 args.output_format,
2397 args.malware_settings,
2398 ))
2399 .await
2400 }
2401 ProjectCommand::Lock(args) => {
2402 let args = settings::LockSettings::resolve(args, filesystem, environment);
2404 show_settings!(args);
2405
2406 globals
2408 .network_settings
2409 .check_refresh_conflict(&args.refresh);
2410
2411 let cache = cache.init().await?.with_refresh(
2413 args.refresh
2414 .clone()
2415 .combine(Refresh::from(args.settings.upgrade.clone())),
2416 );
2417
2418 let script = script
2421 .map(|script| match script {
2422 Pep723Item::Script(script) => script,
2423 Pep723Item::Stdin(..) => unreachable!("`uv add` does not support stdin"),
2424 Pep723Item::Remote(..) => {
2425 unreachable!("`uv add` does not support remote files")
2426 }
2427 })
2428 .map(ScriptPath::Script)
2429 .or(args.script.map(ScriptPath::Path));
2430
2431 Box::pin(commands::lock(
2432 project_dir,
2433 args.lock_check,
2434 args.frozen,
2435 args.dry_run,
2436 args.refresh,
2437 args.python,
2438 args.install_mirrors,
2439 args.settings,
2440 client_builder.subcommand(vec!["lock".to_owned()]),
2441 script,
2442 globals.python_preference,
2443 globals.python_downloads,
2444 globals.concurrency,
2445 no_config,
2446 &cache,
2447 workspace_cache,
2448 printer,
2449 globals.preview,
2450 ))
2451 .await
2452 }
2453 ProjectCommand::Upgrade(args) => {
2454 let args = settings::UpgradeSettings::resolve(args, filesystem, environment);
2456 show_settings!(args);
2457
2458 let cache = cache
2460 .init()
2461 .await?
2462 .with_refresh(Refresh::from(args.settings.upgrade.clone()));
2463
2464 Box::pin(commands::upgrade(
2465 project_dir,
2466 args.package,
2467 args.install_mirrors,
2468 args.settings,
2469 client_builder.subcommand(vec!["upgrade".to_owned()]),
2470 globals.python_preference,
2471 globals.python_downloads,
2472 globals.concurrency,
2473 no_config,
2474 &cache,
2475 workspace_cache,
2476 printer,
2477 globals.preview,
2478 ))
2479 .await
2480 }
2481 ProjectCommand::Add(args) => {
2482 let mut args = settings::AddSettings::resolve(args, filesystem, environment);
2484 show_settings!(args);
2485
2486 let script = script
2489 .map(|script| match script {
2490 Pep723Item::Script(script) => script,
2491 Pep723Item::Stdin(..) => unreachable!("`uv add` does not support stdin"),
2492 Pep723Item::Remote(..) => {
2493 unreachable!("`uv add` does not support remote files")
2494 }
2495 })
2496 .map(ScriptPath::Script)
2497 .or(args.script.map(ScriptPath::Path));
2498
2499 let requirements = args
2500 .packages
2501 .iter()
2502 .map(String::as_str)
2503 .map(RequirementsSource::from_package_argument)
2504 .chain(
2505 args.requirements
2506 .into_iter()
2507 .map(RequirementsSource::from_requirements_file),
2508 )
2509 .collect::<Result<Vec<_>>>()?;
2510
2511 for requirement in &requirements {
2514 let requirement = match requirement {
2515 RequirementsSource::Package(requirement) => requirement,
2516 RequirementsSource::Editable(requirement) => requirement,
2517 _ => continue,
2518 };
2519 match requirement {
2520 RequirementsTxtRequirement::Named(requirement) => {
2521 if let Some(VersionOrUrl::Url(url)) = requirement.version_or_url.as_ref() {
2522 if let ParsedUrl::Directory(ParsedDirectoryUrl {
2523 install_path, ..
2524 }) = &url.parsed_url
2525 {
2526 debug!(
2527 "Marking explicit source tree for reinstall: `{}`",
2528 install_path.display()
2529 );
2530 args.settings.reinstall = args
2531 .settings
2532 .reinstall
2533 .with_package(requirement.name.clone());
2534 }
2535 }
2536 }
2537 RequirementsTxtRequirement::Unnamed(requirement) => {
2538 if let ParsedUrl::Directory(ParsedDirectoryUrl { install_path, .. }) =
2539 &requirement.url.parsed_url
2540 {
2541 debug!(
2542 "Marking explicit source tree for reinstall: `{}`",
2543 install_path.display()
2544 );
2545 args.settings.reinstall =
2546 args.settings.reinstall.with_path(install_path.clone());
2547 }
2548 }
2549 }
2550 }
2551
2552 globals
2554 .network_settings
2555 .check_refresh_conflict(&args.refresh);
2556
2557 let cache = cache.init().await?.with_refresh(
2559 args.refresh
2560 .combine(Refresh::from(args.settings.reinstall.clone()))
2561 .combine(Refresh::from(args.settings.resolver.upgrade.clone())),
2562 );
2563
2564 let constraints = args
2565 .constraints
2566 .into_iter()
2567 .map(RequirementsSource::from_constraints_txt)
2568 .collect::<Result<Vec<_>, _>>()?;
2569
2570 Box::pin(commands::add(
2571 project_dir,
2572 args.lock_check,
2573 args.frozen,
2574 args.active,
2575 args.no_sync,
2576 args.no_install_project,
2577 args.only_install_project,
2578 args.no_install_workspace,
2579 args.only_install_workspace,
2580 args.no_install_local,
2581 args.only_install_local,
2582 args.no_install_package,
2583 args.only_install_package,
2584 requirements,
2585 constraints,
2586 args.marker,
2587 args.editable,
2588 args.dependency_type,
2589 args.raw,
2590 args.bounds,
2591 args.indexes,
2592 args.rev,
2593 args.tag,
2594 args.branch,
2595 args.lfs,
2596 args.extras,
2597 args.package,
2598 args.python,
2599 args.workspace,
2600 args.install_mirrors,
2601 args.settings,
2602 client_builder.subcommand(vec!["add".to_owned()]),
2603 script,
2604 globals.python_preference,
2605 globals.python_downloads,
2606 globals.installer_metadata,
2607 globals.concurrency,
2608 no_config,
2609 &cache,
2610 printer,
2611 globals.preview,
2612 &args.malware_settings,
2613 ))
2614 .await
2615 }
2616 ProjectCommand::Remove(args) => {
2617 let args = settings::RemoveSettings::resolve(args, filesystem, environment);
2619 show_settings!(args);
2620
2621 globals
2623 .network_settings
2624 .check_refresh_conflict(&args.refresh);
2625
2626 let cache = cache.init().await?.with_refresh(
2628 args.refresh
2629 .combine(Refresh::from(args.settings.reinstall.clone()))
2630 .combine(Refresh::from(args.settings.resolver.upgrade.clone())),
2631 );
2632
2633 let script = script.map(|script| match script {
2635 Pep723Item::Script(script) => script,
2636 Pep723Item::Stdin(..) => unreachable!("`uv remove` does not support stdin"),
2637 Pep723Item::Remote(..) => unreachable!("`uv remove` does not support remote files"),
2638 });
2639
2640 Box::pin(commands::remove(
2641 project_dir,
2642 args.lock_check,
2643 args.frozen,
2644 args.active,
2645 args.no_sync,
2646 args.packages,
2647 args.dependency_type,
2648 args.package,
2649 args.python,
2650 args.install_mirrors,
2651 args.settings,
2652 client_builder.subcommand(vec!["remove".to_owned()]),
2653 script,
2654 globals.python_preference,
2655 globals.python_downloads,
2656 globals.installer_metadata,
2657 globals.concurrency,
2658 no_config,
2659 &cache,
2660 printer,
2661 globals.preview,
2662 args.malware_settings,
2663 ))
2664 .await
2665 }
2666 ProjectCommand::Version(args) => {
2667 let args = settings::VersionSettings::resolve(args, filesystem, environment);
2669 show_settings!(args);
2670
2671 globals
2673 .network_settings
2674 .check_refresh_conflict(&args.refresh);
2675
2676 let cache = cache.init().await?.with_refresh(
2678 args.refresh
2679 .combine(Refresh::from(args.settings.reinstall.clone()))
2680 .combine(Refresh::from(args.settings.resolver.upgrade.clone())),
2681 );
2682
2683 Box::pin(commands::project_version(
2684 args.value,
2685 args.bump,
2686 args.short,
2687 args.output_format,
2688 project_dir,
2689 args.package,
2690 explicit_project,
2691 args.dry_run,
2692 args.lock_check,
2693 args.frozen,
2694 args.active,
2695 args.no_sync,
2696 args.python,
2697 args.install_mirrors,
2698 args.settings,
2699 client_builder.subcommand(vec!["version".to_owned()]),
2700 globals.python_preference,
2701 globals.python_downloads,
2702 globals.installer_metadata,
2703 globals.concurrency,
2704 no_config,
2705 &cache,
2706 workspace_cache,
2707 printer,
2708 globals.preview,
2709 args.malware_settings,
2710 ))
2711 .await
2712 }
2713 ProjectCommand::Tree(args) => {
2714 let args = settings::TreeSettings::resolve(args, filesystem, environment);
2716 show_settings!(args);
2717
2718 let cache = cache.init().await?;
2720
2721 let script = script.map(|script| match script {
2723 Pep723Item::Script(script) => script,
2724 Pep723Item::Stdin(..) => unreachable!("`uv tree` does not support stdin"),
2725 Pep723Item::Remote(..) => unreachable!("`uv tree` does not support remote files"),
2726 });
2727
2728 Box::pin(commands::tree(
2729 project_dir,
2730 args.groups,
2731 args.lock_check,
2732 args.frozen,
2733 args.universal,
2734 args.depth,
2735 args.prune,
2736 args.package,
2737 args.no_dedupe,
2738 args.invert,
2739 args.outdated,
2740 args.show_sizes,
2741 args.python_version,
2742 args.python_platform,
2743 args.python,
2744 args.install_mirrors,
2745 args.resolver,
2746 &client_builder.subcommand(vec!["tree".to_owned()]),
2747 script,
2748 globals.python_preference,
2749 globals.python_downloads,
2750 globals.concurrency,
2751 no_config,
2752 &cache,
2753 printer,
2754 globals.preview,
2755 ))
2756 .await
2757 }
2758 ProjectCommand::Export(args) => {
2759 let args = settings::ExportSettings::resolve(args, filesystem, environment);
2761 show_settings!(args);
2762
2763 let cache = cache.init().await?;
2765
2766 let script = script.map(|script| match script {
2768 Pep723Item::Script(script) => script,
2769 Pep723Item::Stdin(..) => unreachable!("`uv export` does not support stdin"),
2770 Pep723Item::Remote(..) => unreachable!("`uv export` does not support remote files"),
2771 });
2772
2773 commands::export(
2774 project_dir,
2775 args.format,
2776 args.all_packages,
2777 args.package,
2778 args.prune,
2779 args.hashes,
2780 args.install_options,
2781 args.output_file,
2782 args.extras,
2783 args.groups,
2784 args.editable,
2785 args.lock_check,
2786 args.frozen,
2787 args.include_annotations,
2788 args.include_header,
2789 args.include_index_url,
2790 args.include_find_links,
2791 script,
2792 args.python,
2793 args.install_mirrors,
2794 args.settings,
2795 client_builder.subcommand(vec!["export".to_owned()]),
2796 globals.python_preference,
2797 globals.python_downloads,
2798 globals.concurrency,
2799 no_config,
2800 globals.quiet > 0,
2801 &cache,
2802 printer,
2803 globals.preview,
2804 )
2805 .boxed_local()
2806 .await
2807 }
2808 ProjectCommand::Format(args) => {
2809 let args = settings::FormatSettings::resolve(args, filesystem, environment);
2811 show_settings!(args);
2812
2813 let cache = cache.init().await?;
2815
2816 Box::pin(commands::format(
2817 project_dir,
2818 args.ruff_path,
2819 args.check,
2820 args.diff,
2821 args.extra_args,
2822 args.version,
2823 args.exclude_newer,
2824 args.show_version,
2825 client_builder.subcommand(vec!["format".to_owned()]),
2826 cache,
2827 printer,
2828 globals.preview,
2829 args.no_project,
2830 ))
2831 .await
2832 }
2833 ProjectCommand::Check(args) => {
2834 let args = settings::CheckSettings::resolve(args, filesystem, environment);
2836 show_settings!(args);
2837
2838 globals
2840 .network_settings
2841 .check_refresh_conflict(&args.refresh);
2842
2843 let cache = cache.init().await?.with_refresh(
2845 args.refresh
2846 .combine(Refresh::from(args.settings.reinstall.clone()))
2847 .combine(Refresh::from(args.settings.resolver.upgrade.clone())),
2848 );
2849
2850 let script = script.and_then(|script| match script {
2851 Pep723Item::Script(script) => Some(script),
2852 Pep723Item::Remote(..) | Pep723Item::Stdin(..) => None,
2853 });
2854
2855 Box::pin(commands::check(
2856 project_dir,
2857 args.ty_path,
2858 args.lock_check,
2859 args.frozen,
2860 args.no_sync,
2861 args.isolated,
2862 args.extras,
2863 args.groups,
2864 args.python,
2865 args.install_mirrors,
2866 args.settings,
2867 args.ty_version,
2868 args.show_version,
2869 script,
2870 client_builder.subcommand(vec!["check".to_owned()]),
2871 globals.python_preference,
2872 globals.python_downloads,
2873 globals.installer_metadata,
2874 globals.concurrency,
2875 &cache,
2876 workspace_cache,
2877 printer,
2878 globals.preview,
2879 args.no_project,
2880 no_config,
2881 args.malware_settings,
2882 ))
2883 .await
2884 }
2885 ProjectCommand::Audit(audit_args) => {
2886 let args = settings::AuditSettings::resolve(audit_args, filesystem, environment);
2887 show_settings!(args);
2888
2889 let cache = cache.init().await?;
2891
2892 let script = script.map(|script| match script {
2894 Pep723Item::Script(script) => script,
2895 Pep723Item::Stdin(..) => unreachable!("`uv audit` does not support stdin"),
2896 Pep723Item::Remote(..) => unreachable!("`uv audit` does not support remote files"),
2897 });
2898
2899 Box::pin(commands::audit(
2900 project_dir,
2901 args.extras,
2902 args.groups,
2903 args.lock_check,
2904 args.frozen,
2905 script,
2906 args.python_version,
2907 args.python_platform,
2908 args.install_mirrors,
2909 args.settings,
2910 client_builder.subcommand(vec!["audit".to_owned()]),
2911 globals.python_preference,
2912 globals.python_downloads,
2913 globals.concurrency,
2914 no_config,
2915 cache,
2916 printer,
2917 globals.preview,
2918 args.output_format,
2919 args.service_format,
2920 args.service_url,
2921 args.ignore,
2922 args.ignore_until_fixed,
2923 ))
2924 .await
2925 }
2926 }
2927}
2928
2929fn suggest_subcommand(err: &mut Error) {
2931 if let Some(ContextValue::String(subcommand)) = err.get(ContextKind::InvalidSubcommand) {
2932 match subcommand.as_str() {
2933 "compile" => {
2934 err.insert(
2935 ContextKind::SuggestedSubcommand,
2936 ContextValue::String("uv pip compile".to_string()),
2937 );
2938 }
2939 "install" => {
2940 err.insert(
2941 ContextKind::SuggestedSubcommand,
2942 ContextValue::String("uv pip install".to_string()),
2943 );
2944 }
2945 "uninstall" => {
2946 err.insert(
2947 ContextKind::SuggestedSubcommand,
2948 ContextValue::String("uv pip uninstall".to_string()),
2949 );
2950 }
2951 "freeze" => {
2952 err.insert(
2953 ContextKind::SuggestedSubcommand,
2954 ContextValue::String("uv pip freeze".to_string()),
2955 );
2956 }
2957 "list" => {
2958 err.insert(
2959 ContextKind::SuggestedSubcommand,
2960 ContextValue::String("uv pip list".to_string()),
2961 );
2962 }
2963 "show" => {
2964 err.insert(
2965 ContextKind::SuggestedSubcommand,
2966 ContextValue::String("uv pip show".to_string()),
2967 );
2968 }
2969 _ => {}
2970 }
2971 }
2972}
2973
2974#[allow(unsafe_code)]
2989pub unsafe fn main<I, T>(args: I) -> ExitCode
2990where
2991 I: IntoIterator<Item = T>,
2992 T: Into<OsString> + Clone,
2993{
2994 #[cfg(windows)]
2995 uv_windows::install_unhandled_exception_handler();
2996
2997 if let Ok(current_exe) = std::env::current_exe() {
3000 unsafe {
3002 std::env::set_var(EnvVars::UV, current_exe);
3005 }
3006 }
3007
3008 let cli = match Cli::try_parse_from(args) {
3011 Ok(cli) => cli,
3012 Err(mut err) => {
3013 suggest_subcommand(&mut err);
3014 err.exit()
3015 }
3016 };
3017
3018 let printer = Printer::new(
3021 cli.top_level.global_args.quiet,
3022 cli.top_level.global_args.verbose,
3023 cli.top_level.global_args.no_progress,
3024 );
3025
3026 let min_stack_size = min_stack_size();
3028 let main2 = move || {
3029 let runtime = tokio::runtime::Builder::new_current_thread()
3030 .enable_all()
3031 .thread_stack_size(min_stack_size)
3032 .build()
3033 .expect("Failed building the Runtime");
3034 let result = runtime.block_on(Box::pin(run(cli, GlobalInitialization::Initialize)));
3036 runtime.shutdown_background();
3042 result
3043 };
3044 let result = std::thread::Builder::new()
3045 .name("main2".to_owned())
3046 .stack_size(min_stack_size)
3047 .spawn(main2)
3048 .expect("Tokio executor failed, was there a panic?")
3049 .join()
3050 .expect("Tokio executor failed, was there a panic?");
3051
3052 match result {
3053 Ok(code) => code.into(),
3054 Err(err) => {
3055 let error = match err.downcast::<UvError>() {
3056 Ok(error) => error,
3057 Err(err) => UvError::unexpected(err),
3058 };
3059 match error {
3060 UvError::User(err) => {
3061 commands::diagnostics::write_error_chain(&err, printer)
3062 .expect("writing to stderr should not fail");
3063 ExitStatus::Failure.into()
3064 }
3065 UvError::Unexpected(err) => {
3066 trace!(
3067 "Error chain:\n{}",
3068 uv_errors::debug_error_chain(err.as_ref())
3069 );
3070 if err.backtrace().status() == std::backtrace::BacktraceStatus::Captured {
3071 trace!("Error backtrace:\n{}", err.backtrace());
3072 }
3073 commands::diagnostics::write_error_chain(&err, printer)
3074 .expect("writing to stderr should not fail");
3075 ExitStatus::Error.into()
3076 }
3077 }
3078 }
3079 }
3080}