Add a --project argument to run a command from a project (#7603)

## Summary

`uv run --project ./path/to/project` now uses the provided directory as
the starting point for any file discovery. However, relative paths are
still resolved relative to the current working directory.

Closes https://github.com/astral-sh/uv/issues/5613.
This commit is contained in:
Charlie Marsh 2024-09-21 16:19:49 -04:00 committed by GitHub
parent d9a5f5ca1c
commit 35d6274c31
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
21 changed files with 591 additions and 88 deletions

View file

@ -235,6 +235,19 @@ pub struct GlobalArgs {
/// Change to the given directory prior to running the command.
#[arg(global = true, long, hide = true)]
pub directory: Option<PathBuf>,
/// Run the command within the given project directory.
///
/// All `pyproject.toml`, `uv.toml`, and `.python-version` files will be discovered by walking
/// up the directory tree from the project root, as will the project's virtual environment
/// (`.venv`).
///
/// Other command-line arguments (such as relative paths) will be resolved relative
/// to the current working directory.
///
/// This setting has no effect when used in the `uv pip` interface.
#[arg(global = true, long)]
pub project: Option<PathBuf>,
}
#[derive(Debug, Copy, Clone, clap::ValueEnum)]

View file

@ -63,8 +63,8 @@ impl FilesystemOptions {
///
/// The search starts at the given path and goes up the directory tree until a `uv.toml` file or
/// `pyproject.toml` file is found.
pub fn find(path: impl AsRef<Path>) -> Result<Option<Self>, Error> {
for ancestor in path.as_ref().ancestors() {
pub fn find(path: &Path) -> Result<Option<Self>, Error> {
for ancestor in path.ancestors() {
match Self::from_directory(ancestor) {
Ok(Some(options)) => {
return Ok(Some(options));
@ -91,9 +91,9 @@ impl FilesystemOptions {
/// Load a [`FilesystemOptions`] from a directory, preferring a `uv.toml` file over a
/// `pyproject.toml` file.
pub fn from_directory(dir: impl AsRef<Path>) -> Result<Option<Self>, Error> {
pub fn from_directory(dir: &Path) -> Result<Option<Self>, Error> {
// Read a `uv.toml` file in the current directory.
let path = dir.as_ref().join("uv.toml");
let path = dir.join("uv.toml");
match fs_err::read_to_string(&path) {
Ok(content) => {
let options: Options = toml::from_str(&content)
@ -101,7 +101,7 @@ impl FilesystemOptions {
// If the directory also contains a `[tool.uv]` table in a `pyproject.toml` file,
// warn.
let pyproject = dir.as_ref().join("pyproject.toml");
let pyproject = dir.join("pyproject.toml");
if let Some(pyproject) = fs_err::read_to_string(pyproject)
.ok()
.and_then(|content| toml::from_str::<PyProjectToml>(&content).ok())
@ -121,7 +121,7 @@ impl FilesystemOptions {
}
// Read a `pyproject.toml` file in the current directory.
let path = dir.as_ref().join("pyproject.toml");
let path = dir.join("pyproject.toml");
match fs_err::read_to_string(&path) {
Ok(content) => {
// Parse, but skip any `pyproject.toml` that doesn't have a `[tool.uv]` section.
@ -130,14 +130,14 @@ impl FilesystemOptions {
let Some(tool) = pyproject.tool else {
debug!(
"Skipping `pyproject.toml` in `{}` (no `[tool]` section)",
dir.as_ref().display()
dir.display()
);
return Ok(None);
};
let Some(options) = tool.uv else {
debug!(
"Skipping `pyproject.toml` in `{}` (no `[tool.uv]` section)",
dir.as_ref().display()
dir.display()
);
return Ok(None);
};

View file

@ -15,7 +15,7 @@ use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{BuildKind, BuildOutput, Concurrency, Constraints, HashCheckingMode};
use uv_dispatch::BuildDispatch;
use uv_fs::{Simplified, CWD};
use uv_fs::Simplified;
use uv_normalize::PackageName;
use uv_python::{
EnvironmentPreference, PythonDownloads, PythonEnvironment, PythonInstallation,
@ -29,6 +29,7 @@ use uv_workspace::{DiscoveryOptions, Workspace};
/// Build source distributions and wheels.
#[allow(clippy::fn_params_excessive_bools)]
pub(crate) async fn build(
project_dir: &Path,
src: Option<PathBuf>,
package: Option<PackageName>,
output_dir: Option<PathBuf>,
@ -48,6 +49,7 @@ pub(crate) async fn build(
printer: Printer,
) -> Result<ExitStatus> {
let assets = build_impl(
project_dir,
src.as_deref(),
package.as_ref(),
output_dir.as_deref(),
@ -89,6 +91,7 @@ pub(crate) async fn build(
#[allow(clippy::fn_params_excessive_bools)]
async fn build_impl(
project_dir: &Path,
src: Option<&Path>,
package: Option<&PackageName>,
output_dir: Option<&Path>,
@ -149,7 +152,7 @@ async fn build_impl(
Source::Directory(Cow::Owned(src))
}
} else {
Source::Directory(Cow::Borrowed(&*CWD))
Source::Directory(Cow::Borrowed(project_dir))
};
// Attempt to discover the workspace; on failure, save the error for later.

View file

@ -21,7 +21,7 @@ use uv_configuration::{
};
use uv_dispatch::BuildDispatch;
use uv_distribution::DistributionDatabase;
use uv_fs::{Simplified, CWD};
use uv_fs::Simplified;
use uv_git::{GitReference, GIT_STORE};
use uv_normalize::PackageName;
use uv_python::{
@ -51,6 +51,7 @@ use crate::settings::{ResolverInstallerSettings, ResolverInstallerSettingsRef};
/// Add one or more packages to the project requirements.
#[allow(clippy::fn_params_excessive_bools)]
pub(crate) async fn add(
project_dir: &Path,
locked: bool,
frozen: bool,
no_sync: bool,
@ -131,7 +132,7 @@ pub(crate) async fn add(
let python_request = if let Some(request) = python.as_deref() {
// (1) Explicit request from user
PythonRequest::parse(request)
} else if let Some(request) = PythonVersionFile::discover(&*CWD, false, false)
} else if let Some(request) = PythonVersionFile::discover(project_dir, false, false)
.await?
.and_then(PythonVersionFile::into_version)
{
@ -162,7 +163,7 @@ pub(crate) async fn add(
let python_request = if let Some(request) = python.as_deref() {
// (1) Explicit request from user
Some(PythonRequest::parse(request))
} else if let Some(request) = PythonVersionFile::discover(&*CWD, false, false)
} else if let Some(request) = PythonVersionFile::discover(project_dir, false, false)
.await?
.and_then(PythonVersionFile::into_version)
{
@ -196,13 +197,13 @@ pub(crate) async fn add(
// Find the project in the workspace.
let project = if let Some(package) = package {
VirtualProject::Project(
Workspace::discover(&CWD, &DiscoveryOptions::default())
Workspace::discover(project_dir, &DiscoveryOptions::default())
.await?
.with_current_project(package.clone())
.with_context(|| format!("Package `{package}` not found in workspace"))?,
)
} else {
VirtualProject::discover(&CWD, &DiscoveryOptions::default()).await?
VirtualProject::discover(project_dir, &DiscoveryOptions::default()).await?
};
// For non-project workspace roots, allow dev dependencies, but nothing else.

View file

@ -3,7 +3,7 @@ use std::env;
use anyhow::{Context, Result};
use itertools::Itertools;
use owo_colors::OwoColorize;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use uv_cache::Cache;
use uv_client::Connectivity;
@ -11,7 +11,6 @@ use uv_configuration::{
Concurrency, DevMode, DevSpecification, EditableMode, ExportFormat, ExtrasSpecification,
InstallOptions,
};
use uv_fs::CWD;
use uv_normalize::{PackageName, DEV_DEPENDENCIES};
use uv_python::{PythonDownloads, PythonPreference, PythonRequest};
use uv_resolver::RequirementsTxtExport;
@ -27,6 +26,7 @@ use crate::settings::ResolverSettings;
/// Export the project's `uv.lock` in an alternate format.
#[allow(clippy::fn_params_excessive_bools)]
pub(crate) async fn export(
project_dir: &Path,
format: ExportFormat,
package: Option<PackageName>,
hashes: bool,
@ -51,14 +51,14 @@ pub(crate) async fn export(
// Identify the project.
let project = if let Some(package) = package {
VirtualProject::Project(
Workspace::discover(&CWD, &DiscoveryOptions::default())
Workspace::discover(project_dir, &DiscoveryOptions::default())
.await?
.with_current_project(package.clone())
.with_context(|| format!("Package `{package}` not found in workspace"))?,
)
} else if frozen {
VirtualProject::discover(
&CWD,
project_dir,
&DiscoveryOptions {
members: MemberDiscovery::None,
..DiscoveryOptions::default()
@ -66,7 +66,7 @@ pub(crate) async fn export(
)
.await?
} else {
VirtualProject::discover(&CWD, &DiscoveryOptions::default()).await?
VirtualProject::discover(project_dir, &DiscoveryOptions::default()).await?
};
let VirtualProject::Project(project) = project else {

View file

@ -8,7 +8,7 @@ use pep508_rs::PackageName;
use tracing::{debug, warn};
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity};
use uv_fs::{Simplified, CWD};
use uv_fs::Simplified;
use uv_python::{
EnvironmentPreference, PythonDownloads, PythonInstallation, PythonPreference, PythonRequest,
PythonVersionFile, VersionRequest,
@ -25,6 +25,7 @@ use crate::printer::Printer;
/// Add one or more packages to the project requirements.
#[allow(clippy::single_match_else, clippy::fn_params_excessive_bools)]
pub(crate) async fn init(
project_dir: &Path,
explicit_path: Option<String>,
name: Option<PackageName>,
package: bool,
@ -42,7 +43,7 @@ pub(crate) async fn init(
) -> Result<ExitStatus> {
// Default to the current directory if a path was not provided.
let path = match explicit_path {
None => CWD.to_path_buf(),
None => project_dir.to_path_buf(),
Some(ref path) => std::path::absolute(path)?,
};

View file

@ -1,11 +1,11 @@
#![allow(clippy::single_match_else)]
use std::collections::BTreeSet;
use std::fmt::Write;
use anstream::eprint;
use owo_colors::OwoColorize;
use rustc_hash::{FxBuildHasher, FxHashMap};
use std::collections::BTreeSet;
use std::fmt::Write;
use std::path::Path;
use tracing::debug;
use distribution_types::{
@ -22,7 +22,6 @@ use uv_configuration::{
};
use uv_dispatch::BuildDispatch;
use uv_distribution::DistributionDatabase;
use uv_fs::CWD;
use uv_git::ResolvedRepositoryReference;
use uv_normalize::{PackageName, DEV_DEPENDENCIES};
use uv_python::{Interpreter, PythonDownloads, PythonEnvironment, PythonPreference, PythonRequest};
@ -68,6 +67,7 @@ impl LockResult {
/// Resolve the project requirements into a lockfile.
pub(crate) async fn lock(
project_dir: &Path,
locked: bool,
frozen: bool,
python: Option<String>,
@ -81,7 +81,7 @@ pub(crate) async fn lock(
printer: Printer,
) -> anyhow::Result<ExitStatus> {
// Find the project requirements.
let workspace = Workspace::discover(&CWD, &DiscoveryOptions::default()).await?;
let workspace = Workspace::discover(project_dir, &DiscoveryOptions::default()).await?;
// Find an interpreter for the project
let interpreter = FoundInterpreter::discover(

View file

@ -1,13 +1,13 @@
use std::fmt::Write;
use anyhow::{Context, Result};
use std::fmt::Write;
use std::path::Path;
use owo_colors::OwoColorize;
use pep508_rs::PackageName;
use uv_cache::Cache;
use uv_client::Connectivity;
use uv_configuration::{Concurrency, DevMode, EditableMode, ExtrasSpecification, InstallOptions};
use uv_fs::{Simplified, CWD};
use uv_fs::Simplified;
use uv_python::{PythonDownloads, PythonPreference, PythonRequest};
use uv_scripts::Pep723Script;
use uv_warnings::{warn_user, warn_user_once};
@ -24,6 +24,7 @@ use crate::settings::ResolverInstallerSettings;
/// Remove one or more packages from the project requirements.
#[allow(clippy::fn_params_excessive_bools)]
pub(crate) async fn remove(
project_dir: &Path,
locked: bool,
frozen: bool,
no_sync: bool,
@ -68,13 +69,13 @@ pub(crate) async fn remove(
// Find the project in the workspace.
let project = if let Some(package) = package {
VirtualProject::Project(
Workspace::discover(&CWD, &DiscoveryOptions::default())
Workspace::discover(project_dir, &DiscoveryOptions::default())
.await?
.with_current_project(package.clone())
.with_context(|| format!("Package `{package}` not found in workspace"))?,
)
} else {
VirtualProject::discover(&CWD, &DiscoveryOptions::default()).await?
VirtualProject::discover(project_dir, &DiscoveryOptions::default()).await?
};
Target::Project(project)

View file

@ -18,7 +18,7 @@ use uv_configuration::{
Concurrency, DevMode, EditableMode, ExtrasSpecification, InstallOptions, SourceStrategy,
};
use uv_distribution::LoweredRequirement;
use uv_fs::{PythonExt, Simplified, CWD};
use uv_fs::{PythonExt, Simplified};
use uv_installer::{SatisfiesResult, SitePackages};
use uv_normalize::PackageName;
use uv_python::{
@ -47,6 +47,7 @@ use crate::settings::ResolverInstallerSettings;
/// Run a command.
#[allow(clippy::fn_params_excessive_bools)]
pub(crate) async fn run(
project_dir: &Path,
script: Option<Pep723Script>,
command: RunCommand,
requirements: Vec<RequirementsSource>,
@ -113,7 +114,7 @@ pub(crate) async fn run(
let source = PythonRequestSource::UserRequest;
let request = Some(PythonRequest::parse(request));
(source, request)
} else if let Some(file) = PythonVersionFile::discover(&*CWD, false, false).await? {
} else if let Some(file) = PythonVersionFile::discover(&project_dir, false, false).await? {
// (2) Request from `.python-version`
let source = PythonRequestSource::DotPythonVersion(file.file_name().to_string());
let request = file.into_version();
@ -309,13 +310,13 @@ pub(crate) async fn run(
// We need a workspace, but we don't need to have a current package, we can be e.g. in
// the root of a virtual workspace and then switch into the selected package.
Some(VirtualProject::Project(
Workspace::discover(&CWD, &DiscoveryOptions::default())
Workspace::discover(project_dir, &DiscoveryOptions::default())
.await?
.with_current_project(package.clone())
.with_context(|| format!("Package `{package}` not found in workspace"))?,
))
} else {
match VirtualProject::discover(&CWD, &DiscoveryOptions::default()).await {
match VirtualProject::discover(project_dir, &DiscoveryOptions::default()).await {
Ok(project) => {
if no_project {
debug!("Ignoring discovered project due to `--no-project`");
@ -537,7 +538,7 @@ pub(crate) async fn run(
Some(PythonRequest::parse(request))
// (2) Request from `.python-version`
} else {
PythonVersionFile::discover(&*CWD, no_config, false)
PythonVersionFile::discover(&project_dir, no_config, false)
.await?
.and_then(PythonVersionFile::into_version)
};

View file

@ -13,6 +13,7 @@ use pypi_types::{
LenientRequirement, ParsedArchiveUrl, ParsedGitUrl, ParsedUrl, VerbatimParsedUrl,
};
use std::borrow::Cow;
use std::path::Path;
use std::str::FromStr;
use uv_cache::Cache;
use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder};
@ -21,7 +22,6 @@ use uv_configuration::{
HashCheckingMode, InstallOptions,
};
use uv_dispatch::BuildDispatch;
use uv_fs::CWD;
use uv_installer::SitePackages;
use uv_normalize::{PackageName, DEV_DEPENDENCIES};
use uv_python::{PythonDownloads, PythonEnvironment, PythonPreference, PythonRequest};
@ -34,6 +34,7 @@ use uv_workspace::{DiscoveryOptions, InstallTarget, MemberDiscovery, VirtualProj
/// Sync the project environment.
#[allow(clippy::fn_params_excessive_bools)]
pub(crate) async fn sync(
project_dir: &Path,
locked: bool,
frozen: bool,
package: Option<PackageName>,
@ -55,7 +56,7 @@ pub(crate) async fn sync(
// Identify the project.
let project = if frozen {
VirtualProject::discover(
&CWD,
project_dir,
&DiscoveryOptions {
members: MemberDiscovery::None,
..DiscoveryOptions::default()
@ -64,13 +65,13 @@ pub(crate) async fn sync(
.await?
} else if let Some(package) = package.as_ref() {
VirtualProject::Project(
Workspace::discover(&CWD, &DiscoveryOptions::default())
Workspace::discover(project_dir, &DiscoveryOptions::default())
.await?
.with_current_project(package.clone())
.with_context(|| format!("Package `{package}` not found in workspace"))?,
)
} else {
VirtualProject::discover(&CWD, &DiscoveryOptions::default()).await?
VirtualProject::discover(project_dir, &DiscoveryOptions::default()).await?
};
// Identify the target.

View file

@ -1,12 +1,11 @@
use std::fmt::Write;
use anyhow::Result;
use std::fmt::Write;
use std::path::Path;
use pep508_rs::PackageName;
use uv_cache::Cache;
use uv_client::Connectivity;
use uv_configuration::{Concurrency, TargetTriple};
use uv_fs::CWD;
use uv_python::{PythonDownloads, PythonPreference, PythonRequest, PythonVersion};
use uv_resolver::TreeDisplay;
use uv_workspace::{DiscoveryOptions, Workspace};
@ -21,6 +20,7 @@ use crate::settings::ResolverSettings;
/// Run a command.
#[allow(clippy::fn_params_excessive_bools)]
pub(crate) async fn tree(
project_dir: &Path,
locked: bool,
frozen: bool,
universal: bool,
@ -42,7 +42,7 @@ pub(crate) async fn tree(
printer: Printer,
) -> Result<ExitStatus> {
// Find the project requirements.
let workspace = Workspace::discover(&CWD, &DiscoveryOptions::default()).await?;
let workspace = Workspace::discover(project_dir, &DiscoveryOptions::default()).await?;
// Find an interpreter for the project
let interpreter = FoundInterpreter::discover(

View file

@ -1,8 +1,9 @@
use anstream::println;
use anyhow::Result;
use std::path::Path;
use uv_cache::Cache;
use uv_fs::{Simplified, CWD};
use uv_fs::Simplified;
use uv_python::{
EnvironmentPreference, PythonInstallation, PythonPreference, PythonRequest, PythonVersionFile,
VersionRequest,
@ -15,6 +16,7 @@ use crate::commands::{project::find_requires_python, ExitStatus};
/// Find a Python interpreter.
pub(crate) async fn find(
project_dir: &Path,
request: Option<String>,
no_project: bool,
no_config: bool,
@ -33,14 +35,15 @@ pub(crate) async fn find(
// (2) Request from `.python-version`
if request.is_none() {
request = PythonVersionFile::discover(&*CWD, no_config, false)
request = PythonVersionFile::discover(project_dir, no_config, false)
.await?
.and_then(PythonVersionFile::into_version);
}
// (3) `Requires-Python` in `pyproject.toml`
if request.is_none() && !no_project {
let project = match VirtualProject::discover(&CWD, &DiscoveryOptions::default()).await {
let project =
match VirtualProject::discover(project_dir, &DiscoveryOptions::default()).await {
Ok(project) => Some(project),
Err(WorkspaceError::MissingProject(_)) => None,
Err(WorkspaceError::MissingPyprojectToml) => None,

View file

@ -1,15 +1,14 @@
use std::collections::BTreeSet;
use std::fmt::Write;
use anyhow::Result;
use fs_err as fs;
use futures::stream::FuturesUnordered;
use futures::StreamExt;
use itertools::Itertools;
use owo_colors::OwoColorize;
use std::collections::BTreeSet;
use std::fmt::Write;
use std::path::Path;
use uv_client::Connectivity;
use uv_fs::CWD;
use uv_python::downloads::{DownloadResult, ManagedPythonDownload, PythonDownloadRequest};
use uv_python::managed::{ManagedPythonInstallation, ManagedPythonInstallations};
use uv_python::{PythonDownloads, PythonRequest, PythonVersionFile};
@ -21,6 +20,7 @@ use crate::printer::Printer;
/// Download and install Python versions.
pub(crate) async fn install(
project_dir: &Path,
targets: Vec<String>,
reinstall: bool,
python_downloads: PythonDownloads,
@ -38,9 +38,9 @@ pub(crate) async fn install(
let targets = targets.into_iter().collect::<BTreeSet<_>>();
let requests: Vec<_> = if targets.is_empty() {
PythonVersionFile::discover(&*CWD, no_config, true)
PythonVersionFile::discover(project_dir, no_config, true)
.await?
.map(uv_python::PythonVersionFile::into_versions)
.map(PythonVersionFile::into_versions)
.unwrap_or_else(|| vec![PythonRequest::Default])
} else {
targets

View file

@ -1,4 +1,5 @@
use std::fmt::Write;
use std::path::Path;
use std::str::FromStr;
use anyhow::{bail, Result};
@ -6,7 +7,7 @@ use owo_colors::OwoColorize;
use tracing::debug;
use uv_cache::Cache;
use uv_fs::{Simplified, CWD};
use uv_fs::Simplified;
use uv_python::{
EnvironmentPreference, PythonInstallation, PythonPreference, PythonRequest, PythonVersionFile,
PYTHON_VERSION_FILENAME,
@ -19,6 +20,7 @@ use crate::printer::Printer;
/// Pin to a specific Python version.
pub(crate) async fn pin(
project_dir: &Path,
request: Option<String>,
resolved: bool,
python_preference: PythonPreference,
@ -29,7 +31,7 @@ pub(crate) async fn pin(
let virtual_project = if no_project {
None
} else {
match VirtualProject::discover(&CWD, &DiscoveryOptions::default()).await {
match VirtualProject::discover(project_dir, &DiscoveryOptions::default()).await {
Ok(virtual_project) => Some(virtual_project),
Err(err) => {
debug!("Failed to discover virtual project: {err}");
@ -38,7 +40,7 @@ pub(crate) async fn pin(
}
};
let version_file = PythonVersionFile::discover(&*CWD, false, false).await;
let version_file = PythonVersionFile::discover(project_dir, false, false).await;
let Some(request) = request else {
// Display the current pinned Python version
@ -124,8 +126,8 @@ pub(crate) async fn pin(
let existing = version_file.ok().flatten();
// TODO(zanieb): Allow updating the discovered version file with an `--update` flag.
let new =
PythonVersionFile::new(CWD.join(PYTHON_VERSION_FILENAME)).with_versions(vec![request]);
let new = PythonVersionFile::new(project_dir.join(PYTHON_VERSION_FILENAME))
.with_versions(vec![request]);
new.write().await?;

View file

@ -20,7 +20,7 @@ use uv_configuration::{
NoBinary, NoBuild, SourceStrategy, TrustedHost,
};
use uv_dispatch::BuildDispatch;
use uv_fs::{Simplified, CWD};
use uv_fs::Simplified;
use uv_python::{
EnvironmentPreference, PythonDownloads, PythonInstallation, PythonPreference, PythonRequest,
PythonVersionFile, VersionRequest,
@ -41,6 +41,7 @@ use crate::printer::Printer;
/// Create a virtual environment.
#[allow(clippy::unnecessary_wraps, clippy::fn_params_excessive_bools)]
pub(crate) async fn venv(
project_dir: &Path,
path: Option<PathBuf>,
python_request: Option<&str>,
python_preference: PythonPreference,
@ -66,6 +67,7 @@ pub(crate) async fn venv(
relocatable: bool,
) -> Result<ExitStatus> {
match venv_impl(
project_dir,
path,
python_request,
link_mode,
@ -122,6 +124,7 @@ enum VenvError {
/// Create a virtual environment.
#[allow(clippy::fn_params_excessive_bools)]
async fn venv_impl(
project_dir: &Path,
path: Option<PathBuf>,
python_request: Option<&str>,
link_mode: LinkMode,
@ -149,7 +152,7 @@ async fn venv_impl(
let project = if no_project {
None
} else {
match VirtualProject::discover(&CWD, &DiscoveryOptions::default()).await {
match VirtualProject::discover(project_dir, &DiscoveryOptions::default()).await {
Ok(project) => Some(project),
Err(WorkspaceError::MissingProject(_)) => None,
Err(WorkspaceError::MissingPyprojectToml) => None,
@ -169,7 +172,8 @@ async fn venv_impl(
// Only use the project environment path if we're invoked from the root
// This isn't strictly necessary and we may want to change it later, but this
// avoids a breaking change when adding project environment support to `uv venv`.
(project.workspace().install_path() == &*CWD).then(|| project.workspace().venv())
(project.workspace().install_path() == project_dir)
.then(|| project.workspace().venv())
})
.unwrap_or(PathBuf::from(".venv")),
);
@ -185,7 +189,7 @@ async fn venv_impl(
// (2) Request from `.python-version`
if interpreter_request.is_none() {
interpreter_request = PythonVersionFile::discover(&*CWD, no_config, false)
interpreter_request = PythonVersionFile::discover(project_dir, no_config, false)
.await
.into_diagnostic()?
.and_then(PythonVersionFile::into_version);

View file

@ -1,6 +1,8 @@
use std::borrow::Cow;
use std::ffi::OsString;
use std::fmt::Write;
use std::io::stdout;
use std::path::Path;
use std::process::ExitCode;
use anstream::eprintln;
@ -67,6 +69,17 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
std::env::set_current_dir(directory)?;
}
// Determine the project directory.
let project_dir = cli
.top_level
.global_args
.project
.as_deref()
.map(std::path::absolute)
.transpose()?
.map(Cow::Owned)
.unwrap_or_else(|| Cow::Borrowed(&*CWD));
// The `--isolated` argument is deprecated on preview APIs, and warns on non-preview APIs.
let deprecated_isolated = if cli.top_level.global_args.isolated {
match &*cli.command {
@ -111,7 +124,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
.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 `--directory` argument instead.");
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 {
@ -119,12 +132,14 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
} else if matches!(&*cli.command, Commands::Tool(_)) {
// For commands that operate at the user-level, ignore local configuration.
FilesystemOptions::user()?
} else if let Ok(workspace) = Workspace::discover(&CWD, &DiscoveryOptions::default()).await {
} else if let Ok(workspace) =
Workspace::discover(&project_dir, &DiscoveryOptions::default()).await
{
let project = FilesystemOptions::find(workspace.install_path())?;
let user = FilesystemOptions::user()?;
project.combine(user)
} else {
let project = FilesystemOptions::find(&*CWD)?;
let project = FilesystemOptions::find(&project_dir)?;
let user = FilesystemOptions::user()?;
project.combine(user)
};
@ -680,6 +695,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
.collect::<Vec<_>>();
commands::build(
&project_dir,
args.src,
args.package,
args.out_dir,
@ -728,6 +744,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
});
commands::venv(
&project_dir,
args.path,
args.settings.python.as_deref(),
globals.python_preference,
@ -757,6 +774,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
Commands::Project(project) => {
Box::pin(run_project(
project,
&project_dir,
run_command,
script,
globals,
@ -1001,6 +1019,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
show_settings!(args);
commands::python_install(
&project_dir,
args.targets,
args.reinstall,
globals.python_downloads,
@ -1030,6 +1049,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
let cache = cache.init()?;
commands::python_find(
&project_dir,
args.request,
args.no_project,
cli.top_level.no_config,
@ -1049,6 +1069,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
let cache = cache.init()?;
commands::python_pin(
&project_dir,
args.request,
args.resolved,
globals.python_preference,
@ -1070,6 +1091,7 @@ async fn run(cli: Cli) -> Result<ExitStatus> {
/// Run a [`ProjectCommand`].
async fn run_project(
project_command: Box<ProjectCommand>,
project_dir: &Path,
command: Option<RunCommand>,
script: Option<Pep723Script>,
globals: GlobalSettings,
@ -1104,6 +1126,7 @@ async fn run_project(
let cache = cache.init()?;
commands::init(
project_dir,
args.path,
args.name,
args.package,
@ -1153,6 +1176,7 @@ async fn run_project(
let command = command.expect("run command is required");
Box::pin(commands::run(
project_dir,
script,
command,
requirements,
@ -1192,6 +1216,7 @@ async fn run_project(
);
commands::sync(
project_dir,
args.locked,
args.frozen,
args.package,
@ -1224,6 +1249,7 @@ async fn run_project(
);
commands::lock(
project_dir,
args.locked,
args.frozen,
args.python,
@ -1262,6 +1288,7 @@ async fn run_project(
.collect::<Vec<_>>();
Box::pin(commands::add(
project_dir,
args.locked,
args.frozen,
args.no_sync,
@ -1300,6 +1327,7 @@ async fn run_project(
);
commands::remove(
project_dir,
args.locked,
args.frozen,
args.no_sync,
@ -1328,6 +1356,7 @@ async fn run_project(
let cache = cache.init()?;
commands::tree(
project_dir,
args.locked,
args.frozen,
args.universal,
@ -1359,6 +1388,7 @@ async fn run_project(
let cache = cache.init()?;
commands::export(
project_dir,
args.format,
args.package,
args.hashes,

View file

@ -750,7 +750,7 @@ impl TestContext {
}
/// Generate various escaped regex patterns for the given path.
pub(crate) fn path_patterns(path: impl AsRef<Path>) -> Vec<String> {
pub fn path_patterns(path: impl AsRef<Path>) -> Vec<String> {
let mut patterns = Vec::new();
// We can only canonicalize paths that exist already

View file

@ -55,6 +55,7 @@ fn help() {
certificate store [env: UV_NATIVE_TLS=]
--offline Disable network access
--no-progress Hide all progress outputs
--project <PROJECT> Run the command within the given project directory
--config-file <CONFIG_FILE> The path to a `uv.toml` file to use for configuration [env:
UV_CONFIG_FILE=]
--no-config Avoid discovering configuration files (`pyproject.toml`,
@ -119,6 +120,7 @@ fn help_flag() {
certificate store [env: UV_NATIVE_TLS=]
--offline Disable network access
--no-progress Hide all progress outputs
--project <PROJECT> Run the command within the given project directory
--config-file <CONFIG_FILE> The path to a `uv.toml` file to use for configuration [env:
UV_CONFIG_FILE=]
--no-config Avoid discovering configuration files (`pyproject.toml`,
@ -182,6 +184,7 @@ fn help_short_flag() {
certificate store [env: UV_NATIVE_TLS=]
--offline Disable network access
--no-progress Hide all progress outputs
--project <PROJECT> Run the command within the given project directory
--config-file <CONFIG_FILE> The path to a `uv.toml` file to use for configuration [env:
UV_CONFIG_FILE=]
--no-config Avoid discovering configuration files (`pyproject.toml`,
@ -333,6 +336,18 @@ fn help_subcommand() {
For example, spinners or progress bars.
--project <PROJECT>
Run the command within the given project directory.
All `pyproject.toml`, `uv.toml`, and `.python-version` files will be discovered by walking
up the directory tree from the project root, as will the project's virtual environment
(`.venv`).
Other command-line arguments (such as relative paths) will be resolved relative to the
current working directory.
This setting has no effect when used in the `uv pip` interface.
--config-file <CONFIG_FILE>
The path to a `uv.toml` file to use for configuration.
@ -482,6 +497,18 @@ fn help_subsubcommand() {
For example, spinners or progress bars.
--project <PROJECT>
Run the command within the given project directory.
All `pyproject.toml`, `uv.toml`, and `.python-version` files will be discovered by walking
up the directory tree from the project root, as will the project's virtual environment
(`.venv`).
Other command-line arguments (such as relative paths) will be resolved relative to the
current working directory.
This setting has no effect when used in the `uv pip` interface.
--config-file <CONFIG_FILE>
The path to a `uv.toml` file to use for configuration.
@ -550,6 +577,7 @@ fn help_flag_subcommand() {
certificate store [env: UV_NATIVE_TLS=]
--offline Disable network access
--no-progress Hide all progress outputs
--project <PROJECT> Run the command within the given project directory
--config-file <CONFIG_FILE> The path to a `uv.toml` file to use for configuration [env:
UV_CONFIG_FILE=]
--no-config Avoid discovering configuration files (`pyproject.toml`,
@ -602,6 +630,7 @@ fn help_flag_subsubcommand() {
certificate store [env: UV_NATIVE_TLS=]
--offline Disable network access
--no-progress Hide all progress outputs
--project <PROJECT> Run the command within the given project directory
--config-file <CONFIG_FILE> The path to a `uv.toml` file to use for configuration [env:
UV_CONFIG_FILE=]
--no-config Avoid discovering configuration files (`pyproject.toml`,
@ -740,6 +769,7 @@ fn help_with_global_option() {
certificate store [env: UV_NATIVE_TLS=]
--offline Disable network access
--no-progress Hide all progress outputs
--project <PROJECT> Run the command within the given project directory
--config-file <CONFIG_FILE> The path to a `uv.toml` file to use for configuration [env:
UV_CONFIG_FILE=]
--no-config Avoid discovering configuration files (`pyproject.toml`,
@ -841,6 +871,7 @@ fn help_with_no_pager() {
certificate store [env: UV_NATIVE_TLS=]
--offline Disable network access
--no-progress Hide all progress outputs
--project <PROJECT> Run the command within the given project directory
--config-file <CONFIG_FILE> The path to a `uv.toml` file to use for configuration [env:
UV_CONFIG_FILE=]
--no-config Avoid discovering configuration files (`pyproject.toml`,

View file

@ -5,6 +5,7 @@ use anyhow::Result;
use assert_cmd::assert::OutputAssertExt;
use assert_fs::{fixture::ChildPath, prelude::*};
use indoc::indoc;
use std::path::Path;
use uv_python::PYTHON_VERSION_FILENAME;
@ -1319,10 +1320,9 @@ fn run_editable() -> Result<()> {
#[test]
fn run_from_directory() -> Result<()> {
// default 3.11 so that the .python-version is meaningful
let context = TestContext::new_with_versions(&["3.11", "3.12"]);
let context = TestContext::new_with_versions(&["3.10", "3.11", "3.12"]);
let project_dir = context.temp_dir.child("project");
project_dir.create_dir_all()?;
project_dir
.child(PYTHON_VERSION_FILENAME)
.write_str("3.12")?;
@ -1332,7 +1332,7 @@ fn run_from_directory() -> Result<()> {
[project]
name = "foo"
version = "1.0.0"
requires-python = ">=3.11, <4"
requires-python = ">=3.10"
dependencies = []
[project.scripts]
@ -1343,6 +1343,7 @@ fn run_from_directory() -> Result<()> {
build-backend = "setuptools.build_meta"
"#
})?;
let main_script = project_dir.child("main.py");
main_script.write_str(indoc! { r"
import platform
@ -1352,10 +1353,56 @@ fn run_from_directory() -> Result<()> {
"
})?;
let mut command = context.run();
let command_with_args = command.arg("--directory").arg("project").arg("main");
let filters = TestContext::path_patterns(Path::new("project").join(".venv"))
.into_iter()
.map(|pattern| (pattern, "[PROJECT_VENV]/".to_string()))
.collect::<Vec<_>>();
let error = regex::escape("The system cannot find the path specified. (os error 3)");
let filters = context
.filters()
.into_iter()
.chain(
filters
.iter()
.map(|(pattern, replacement)| (pattern.as_str(), replacement.as_str())),
)
.chain(std::iter::once((
error.as_str(),
"No such file or directory (os error 2)",
)))
.collect::<Vec<_>>();
uv_snapshot!(context.filters(), command_with_args, @r###"
// Use `--project`, which resolves configuration relative to the provided directory, but paths
// relative to the current working directory.
uv_snapshot!(filters.clone(), context.run().arg("--project").arg("project").arg("main"), @r###"
success: true
exit_code: 0
----- stdout -----
3.12.[X]
----- stderr -----
warning: `VIRTUAL_ENV=.venv` does not match the project environment path `[PROJECT_VENV]/` and will be ignored
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
Creating virtual environment at: [PROJECT_VENV]/
Resolved 1 package in [TIME]
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ foo==1.0.0 (from file://[TEMP_DIR]/project)
"###);
uv_snapshot!(filters.clone(), context.run().arg("--project").arg("project").arg("./project/main.py"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `VIRTUAL_ENV=.venv` does not match the project environment path `[PROJECT_VENV]/` and will be ignored
Resolved 1 package in [TIME]
Audited 1 package in [TIME]
"###);
// Use `--directory`, which switches to the provided directory entirely.
uv_snapshot!(filters.clone(), context.run().arg("--directory").arg("project").arg("main"), @r###"
success: true
exit_code: 0
----- stdout -----
@ -1363,14 +1410,73 @@ fn run_from_directory() -> Result<()> {
----- stderr -----
warning: `VIRTUAL_ENV=[VENV]/` does not match the project environment path `.venv` and will be ignored
Using Python 3.12.[X] interpreter at: [PYTHON-3.12]
Creating virtual environment at: .venv
Resolved 1 package in [TIME]
Prepared 1 package in [TIME]
Audited 1 package in [TIME]
"###);
uv_snapshot!(filters.clone(), context.run().arg("--directory").arg("project").arg("./main.py"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: `VIRTUAL_ENV=[VENV]/` does not match the project environment path `.venv` and will be ignored
Resolved 1 package in [TIME]
Audited 1 package in [TIME]
"###);
uv_snapshot!(filters.clone(), context.run().arg("--directory").arg("project").arg("./project/main.py"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
warning: `VIRTUAL_ENV=[VENV]/` does not match the project environment path `.venv` and will be ignored
Resolved 1 package in [TIME]
Audited 1 package in [TIME]
error: Failed to spawn: `./project/main.py`
Caused by: No such file or directory (os error 2)
"###);
// Even if we write a `.python-version` file in the current directory, we should prefer the
// one in the project directory in both cases.
context
.temp_dir
.child(PYTHON_VERSION_FILENAME)
.write_str("3.11")?;
project_dir
.child(PYTHON_VERSION_FILENAME)
.write_str("3.10")?;
uv_snapshot!(filters.clone(), context.run().arg("--project").arg("project").arg("main"), @r###"
success: true
exit_code: 0
----- stdout -----
3.10.[X]
----- stderr -----
warning: `VIRTUAL_ENV=.venv` does not match the project environment path `[PROJECT_VENV]/` and will be ignored
Using Python 3.10.[X] interpreter at: [PYTHON-3.10]
Removed virtual environment at: [PROJECT_VENV]/
Creating virtual environment at: [PROJECT_VENV]/
Resolved 1 package in [TIME]
Installed 1 package in [TIME]
+ foo==1.0.0 (from file://[TEMP_DIR]/project)
"###);
uv_snapshot!(filters.clone(), context.run().arg("--directory").arg("project").arg("main"), @r###"
success: true
exit_code: 0
----- stdout -----
3.10.[X]
----- stderr -----
warning: `VIRTUAL_ENV=[VENV]/` does not match the project environment path `.venv` and will be ignored
Resolved 1 package in [TIME]
Audited 1 package in [TIME]
"###);
Ok(())
}

View file

@ -3180,7 +3180,7 @@ fn resolve_config_file() -> anyhow::Result<()> {
----- stdout -----
----- stderr -----
warning: 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 `--directory` argument instead.
warning: 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.
error: Failed to parse: `[CACHE_DIR]/pyproject.toml`
Caused by: TOML parse error at line 9, column 3
|

View file

@ -301,6 +301,14 @@ uv run [OPTIONS] <COMMAND>
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to use for the run environment.</p>
<p>If the interpreter request is satisfied by a discovered environment, the environment will be used.</p>
@ -493,6 +501,14 @@ uv init [OPTIONS] [PATH]
<p>When using <code>--app</code>, this will include a <code>[project.scripts]</code> entrypoint and use a <code>src/</code> project structure.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to use to determine the minimum supported Python version.</p>
<p>See <a href="#uv-python">uv python</a> to view supported request formats.</p>
@ -763,6 +779,14 @@ uv add [OPTIONS] <PACKAGES|--requirements <REQUIREMENTS>>
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to use for resolving and syncing.</p>
<p>See <a href="#uv-python">uv python</a> for details on Python discovery and supported request formats.</p>
@ -1059,6 +1083,14 @@ uv remove [OPTIONS] <PACKAGES>...
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to use for resolving and syncing.</p>
<p>See <a href="#uv-python">uv python</a> for details on Python discovery and supported request formats.</p>
@ -1371,6 +1403,14 @@ uv sync [OPTIONS]
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to use for the project environment.</p>
<p>By default, the first interpreter that meets the project&#8217;s <code>requires-python</code> constraint is used.</p>
@ -1628,6 +1668,14 @@ uv lock [OPTIONS]
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to use during resolution.</p>
<p>A Python interpreter is required for building source distributions to determine package metadata when there are not wheels.</p>
@ -1931,6 +1979,14 @@ uv export [OPTIONS]
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to use during resolution.</p>
<p>A Python interpreter is required for building source distributions to determine package metadata when there are not wheels.</p>
@ -2191,6 +2247,14 @@ uv tree [OPTIONS]
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--prune</code> <i>prune</i></dt><dd><p>Prune the given package from the display of the dependency tree</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to use for locking and filtering.</p>
@ -2536,6 +2600,14 @@ uv tool run [OPTIONS] [COMMAND]
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to use to build the run environment.</p>
<p>See <a href="#uv-python">uv python</a> for details on Python discovery and supported request formats.</p>
@ -2806,6 +2878,14 @@ uv tool install [OPTIONS] <PACKAGE>
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to use to build the tool environment.</p>
<p>See <a href="#uv-python">uv python</a> for details on Python discovery and supported request formats.</p>
@ -3070,6 +3150,14 @@ uv tool upgrade [OPTIONS] <NAME>...
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -3177,6 +3265,14 @@ uv tool list [OPTIONS]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--quiet</code>, <code>-q</code></dt><dd><p>Do not print any output</p>
</dd><dt><code>--show-paths</code></dt><dd><p>Whether to display the path to each tool environment and installed executable</p>
@ -3260,6 +3356,14 @@ uv tool uninstall [OPTIONS] <NAME>...
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -3353,6 +3457,14 @@ uv tool update-shell [OPTIONS]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -3464,6 +3576,14 @@ uv tool dir [OPTIONS]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -3635,6 +3755,14 @@ uv python list [OPTIONS]
<p>By default, available downloads for the current platform are shown.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -3742,6 +3870,14 @@ uv python install [OPTIONS] [TARGETS]...
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -3849,6 +3985,14 @@ uv python find [OPTIONS] [REQUEST]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -3961,6 +4105,14 @@ uv python pin [OPTIONS] [REQUEST]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -4058,6 +4210,14 @@ uv python dir [OPTIONS]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -4155,6 +4315,14 @@ uv python uninstall [OPTIONS] <TARGETS>...
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -4485,6 +4653,14 @@ uv pip compile [OPTIONS] <SRC_FILE>...
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code> <i>python</i></dt><dd><p>The Python interpreter to use during resolution.</p>
<p>A Python interpreter is required for building source distributions to determine package metadata when there are not wheels.</p>
@ -4808,6 +4984,14 @@ uv pip sync [OPTIONS] <SRC_FILE>...
<p>In general, prefer the use of <code>--python</code> to install into an alternate environment, as scripts and other artifacts installed via <code>--prefix</code> will reference the installing interpreter, rather than any interpreter added to the <code>--prefix</code> directory, rendering them non-portable.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter into which packages should be installed.</p>
<p>By default, syncing requires a virtual environment. A path to an alternative Python can be provided, but it is only recommended in continuous integration (CI) environments and should be used with caution, as it can modify the system Python installation.</p>
@ -5170,6 +5354,14 @@ uv pip install [OPTIONS] <PACKAGE|--requirement <REQUIREMENT>|--editable <EDITAB
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter into which packages should be installed.</p>
<p>By default, installation requires a virtual environment. A path to an alternative Python can be provided, but it is only recommended in continuous integration (CI) environments and should be used with caution, as it can modify the system Python installation.</p>
@ -5406,6 +5598,14 @@ uv pip uninstall [OPTIONS] <PACKAGE|--requirement <REQUIREMENT>>
</dd><dt><code>--prefix</code> <i>prefix</i></dt><dd><p>Uninstall packages from the specified <code>--prefix</code> directory</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter from which packages should be uninstalled.</p>
<p>By default, uninstallation requires a virtual environment. A path to an alternative Python can be provided, but it is only recommended in continuous integration (CI) environments and should be used with caution, as it can modify the system Python installation.</p>
@ -5513,6 +5713,14 @@ uv pip freeze [OPTIONS]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter for which packages should be listed.</p>
<p>By default, uv lists packages in a virtual environment but will show packages in a system Python environment if no virtual environment is found.</p>
@ -5634,6 +5842,14 @@ uv pip list [OPTIONS]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter for which packages should be listed.</p>
<p>By default, uv lists packages in a virtual environment but will show packages in a system Python environment if no virtual environment is found.</p>
@ -5743,6 +5959,14 @@ uv pip show [OPTIONS] [PACKAGE]...
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to find the package in.</p>
<p>By default, uv looks for packages in a virtual environment but will look for packages in a system Python environment if no virtual environment is found.</p>
@ -5855,6 +6079,14 @@ uv pip tree [OPTIONS]
</dd><dt><code>--package</code> <i>package</i></dt><dd><p>Display only the specified packages</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--prune</code> <i>prune</i></dt><dd><p>Prune the given package from the display of the dependency tree</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter for which packages should be listed.</p>
@ -5962,6 +6194,14 @@ uv pip check [OPTIONS]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter for which packages should be checked.</p>
<p>By default, uv checks packages in a virtual environment but will check packages in a system Python environment if no virtual environment is found.</p>
@ -6173,6 +6413,14 @@ uv venv [OPTIONS] [PATH]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--prompt</code> <i>prompt</i></dt><dd><p>Provide an alternative prompt prefix for the virtual environment.</p>
<p>By default, the prompt is dependent on whether a path was provided to <code>uv venv</code>. If provided (e.g, <code>uv venv project</code>), the prompt is set to the directory name. If not provided (<code>uv venv</code>), the prompt is set to the current directory&#8217;s name.</p>
@ -6445,6 +6693,14 @@ uv build [OPTIONS] [SRC]
<li><code>if-necessary-or-explicit</code>: Allow pre-release versions if all versions of a package are pre-release, or if the package has an explicit pre-release marker in its version requirements</li>
</ul>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python</code>, <code>-p</code> <i>python</i></dt><dd><p>The Python interpreter to use for the build environment.</p>
<p>By default, builds are executed in isolated virtual environments. The discovered interpreter will be used to create those environments, and will be symlinked or copied in depending on the platform.</p>
@ -6607,6 +6863,14 @@ uv cache clean [OPTIONS] [PACKAGE]...
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -6700,6 +6964,14 @@ uv cache prune [OPTIONS]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -6795,6 +7067,14 @@ uv cache dir [OPTIONS]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -6882,7 +7162,15 @@ uv version [OPTIONS]
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--output-format</code> <i>output-format</i></dt><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
</dd><dt><code>--output-format</code> <i>output-format</i></dt><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>
@ -6915,7 +7203,7 @@ Generate shell completion
<h3 class="cli-reference">Usage</h3>
```
uv generate-shell-completion <SHELL>
uv generate-shell-completion [OPTIONS] <SHELL>
```
<h3 class="cli-reference">Arguments</h3>
@ -6924,7 +7212,17 @@ uv generate-shell-completion <SHELL>
</dd></dl>
<h3 class="cli-reference">Options</h3>
<dl class="cli-reference"><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd></dl>
## uv help
@ -6993,6 +7291,14 @@ uv help [OPTIONS] [COMMAND]...
<p>When disabled, uv will only use locally cached data and locally available files.</p>
</dd><dt><code>--project</code> <i>project</i></dt><dd><p>Run the command within the given project directory.</p>
<p>All <code>pyproject.toml</code>, <code>uv.toml</code>, and <code>.python-version</code> files will be discovered by walking up the directory tree from the project root, as will the project&#8217;s virtual environment (<code>.venv</code>).</p>
<p>Other command-line arguments (such as relative paths) will be resolved relative to the current working directory.</p>
<p>This setting has no effect when used in the <code>uv pip</code> interface.</p>
</dd><dt><code>--python-preference</code> <i>python-preference</i></dt><dd><p>Whether to prefer uv-managed or system Python installations.</p>
<p>By default, uv prefers using Python versions it manages. However, it will use system Python installations if a uv-managed Python is not installed. This option allows prioritizing or ignoring system Python installations.</p>