Add dependency-group cli flags to `uv pip install` and `uv pip compile` (`--group`, `--no-group`, `--only-group`, `--all-groups`) (#10861)

Ultimately this is a lot of settings plumbing and a couple minor pieces
of Actual Logic (which are so simple I have to assume there's something
missing, but maybe not!).

Note this "needlessly" use DevDependencyGroup since it costs nothing, is
more futureproof, and lets us maintain one primary interface (we just
pass `false` for all the dev arguments).

Fixes #8590
Fixes #8969
This commit is contained in:
Aria Desires 2025-01-23 08:47:52 -05:00 committed by GitHub
parent c3a511716a
commit 53706a1864
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
19 changed files with 1253 additions and 100 deletions

View File

@ -1014,6 +1014,40 @@ pub struct PipCompileArgs {
#[arg(long, overrides_with("all_extras"), hide = true)]
pub no_all_extras: bool,
/// Include dependencies from the specified dependency group.
///
/// Only applies to `pyproject.toml` sources.
///
/// May be provided multiple times.
#[arg(long, conflicts_with("only_group"))]
pub group: Vec<GroupName>,
/// Exclude dependencies from the specified dependency group.
///
/// Only applies to `pyproject.toml` sources.
///
/// May be provided multiple times.
#[arg(long)]
pub no_group: Vec<GroupName>,
/// Only include dependencies from the specified dependency group.
///
/// The project itself will also be omitted.
///
/// Only applies to `pyproject.toml` sources.
///
/// May be provided multiple times.
#[arg(long, conflicts_with("group"))]
pub only_group: Vec<GroupName>,
/// Include dependencies from all dependency groups.
///
/// Only applies to `pyproject.toml` sources.
///
/// `--no-group` can be used to exclude specific groups.
#[arg(long, conflicts_with_all = [ "group", "only_group" ])]
pub all_groups: bool,
#[command(flatten)]
pub resolver: ResolverArgs,
@ -1572,6 +1606,40 @@ pub struct PipInstallArgs {
#[arg(long, overrides_with("all_extras"), hide = true)]
pub no_all_extras: bool,
/// Include dependencies from the specified dependency group.
///
/// Only applies to `pyproject.toml` sources.
///
/// May be provided multiple times.
#[arg(long, conflicts_with("only_group"))]
pub group: Vec<GroupName>,
/// Exclude dependencies from the specified dependency group.
///
/// Only applies to `pyproject.toml` sources.
///
/// May be provided multiple times.
#[arg(long)]
pub no_group: Vec<GroupName>,
/// Only include dependencies from the specified dependency group.
///
/// The project itself will also be omitted.
///
/// Only applies to `pyproject.toml` sources.
///
/// May be provided multiple times.
#[arg(long, conflicts_with("group"))]
pub only_group: Vec<GroupName>,
/// Include dependencies from all dependency groups.
///
/// Only applies to `pyproject.toml` sources.
///
/// `--no-group` can be used to exclude specific groups.
#[arg(long, conflicts_with_all = [ "group", "only_group" ])]
pub all_groups: bool,
#[command(flatten)]
pub installer: ResolverInstallerArgs,
@ -2727,9 +2795,9 @@ pub struct RunArgs {
/// Only include dependencies from the specified dependency group.
///
/// May be provided multiple times.
///
/// The project itself will also be omitted.
///
/// May be provided multiple times.
#[arg(long, conflicts_with("group"))]
pub only_group: Vec<GroupName>,
@ -2998,9 +3066,9 @@ pub struct SyncArgs {
/// Only include dependencies from the specified dependency group.
///
/// May be provided multiple times.
///
/// The project itself will also be omitted.
///
/// May be provided multiple times.
#[arg(long, conflicts_with("group"))]
pub only_group: Vec<GroupName>,
@ -3449,9 +3517,9 @@ pub struct TreeArgs {
/// Only include dependencies from the specified dependency group.
///
/// May be provided multiple times.
///
/// The project itself will also be omitted.
///
/// May be provided multiple times.
#[arg(long, conflicts_with("group"))]
pub only_group: Vec<GroupName>,
@ -3619,9 +3687,9 @@ pub struct ExportArgs {
/// Only include dependencies from the specified dependency group.
///
/// May be provided multiple times.
///
/// The project itself will also be omitted.
///
/// May be provided multiple times.
#[arg(long, conflicts_with("group"))]
pub only_group: Vec<GroupName>,

View File

@ -133,7 +133,7 @@ impl GroupsSpecification {
}
}
/// Iterate over all groups referenced in the [`DevGroupsSpecification`].
/// Iterate over all groups referenced in the [`GroupsSpecification`].
pub fn names(&self) -> impl Iterator<Item = &GroupName> {
match self {
GroupsSpecification::Include { include, exclude } => {
@ -157,6 +157,18 @@ impl GroupsSpecification {
GroupsSpecification::Explicit { include } => include.contains(group),
}
}
/// Returns `true` if the specification will have no effect.
pub fn is_empty(&self) -> bool {
let GroupsSpecification::Include {
include: IncludeGroups::Some(includes),
exclude,
} = self
else {
return false;
};
includes.is_empty() && exclude.is_empty()
}
}
#[derive(Debug, Clone)]
@ -316,6 +328,17 @@ impl DevGroupsSpecification {
.as_ref()
.is_some_and(|groups| groups.contains(group))
}
/// Returns `true` if the specification will have no effect.
pub fn is_empty(&self) -> bool {
let groups_empty = self
.groups
.as_ref()
.map(GroupsSpecification::is_empty)
.unwrap_or(true);
let dev_empty = self.dev_mode().is_none();
groups_empty && dev_empty
}
}
impl From<DevMode> for DevGroupsSpecification {

View File

@ -7,7 +7,7 @@ use futures::stream::FuturesOrdered;
use futures::TryStreamExt;
use url::Url;
use uv_configuration::ExtrasSpecification;
use uv_configuration::{DevGroupsSpecification, ExtrasSpecification};
use uv_distribution::{DistributionDatabase, FlatRequiresDist, Reporter, RequiresDist};
use uv_distribution_types::{
BuildableSource, DirectorySourceUrl, HashGeneration, HashPolicy, SourceUrl, VersionId,
@ -18,7 +18,7 @@ use uv_pep508::RequirementOrigin;
use uv_pypi_types::Requirement;
use uv_resolver::{InMemoryIndex, MetadataResponse};
use uv_types::{BuildContext, HashStrategy};
use uv_warnings::warn_user_once;
#[derive(Debug, Clone)]
pub struct SourceTreeResolution {
/// The requirements sourced from the source trees.
@ -36,6 +36,8 @@ pub struct SourceTreeResolution {
pub struct SourceTreeResolver<'a, Context: BuildContext> {
/// The extras to include when resolving requirements.
extras: &'a ExtrasSpecification,
/// The groups to include when resolving requirements.
groups: &'a DevGroupsSpecification,
/// The hash policy to enforce.
hasher: &'a HashStrategy,
/// The in-memory index for resolving dependencies.
@ -48,12 +50,14 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> {
/// Instantiate a new [`SourceTreeResolver`] for a given set of `source_trees`.
pub fn new(
extras: &'a ExtrasSpecification,
groups: &'a DevGroupsSpecification,
hasher: &'a HashStrategy,
index: &'a InMemoryIndex,
database: DistributionDatabase<'a, Context>,
) -> Self {
Self {
extras,
groups,
hasher,
index,
database,
@ -85,7 +89,6 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> {
/// Infer the dependencies for a directory dependency.
async fn resolve_source_tree(&self, path: &Path) -> Result<SourceTreeResolution> {
let metadata = self.resolve_requires_dist(path).await?;
let origin = RequirementOrigin::Project(path.to_path_buf(), metadata.name.clone());
// Determine the extras to include when resolving the requirements.
@ -96,7 +99,7 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> {
.collect::<Vec<_>>();
// Flatten any transitive extras.
let requirements =
let mut requirements =
FlatRequiresDist::from_requirements(metadata.requires_dist, &metadata.name)
.into_iter()
.map(|requirement| Requirement {
@ -106,6 +109,27 @@ impl<'a, Context: BuildContext> SourceTreeResolver<'a, Context> {
})
.collect::<Vec<_>>();
// Apply dependency-groups
for (group_name, group) in &metadata.dependency_groups {
if self.groups.contains(group_name) {
requirements.extend(group.iter().cloned());
}
}
// Complain if dependency groups are named that don't appear.
// This is only a warning because *technically* we support passing in
// multiple pyproject.tomls, but at this level of abstraction we can't see them all,
// so hard erroring on "no pyproject.toml mentions this" is a bit difficult.
if let Some(groups) = self.groups.groups() {
for name in groups.names() {
if !metadata.dependency_groups.contains_key(name) {
warn_user_once!(
"The dependency-group '{name}' is not defined in {}",
path.display()
);
}
}
}
let project = metadata.name;
let extras = metadata.provides_extras;

View File

@ -177,6 +177,11 @@ impl RequirementsSource {
Self::PyprojectToml(_) | Self::SetupPy(_) | Self::SetupCfg(_)
)
}
/// Returns `true` if the source allows groups to be specified.
pub fn allows_groups(&self) -> bool {
matches!(self, Self::PyprojectToml(_))
}
}
impl std::fmt::Display for RequirementsSource {

View File

@ -13,7 +13,7 @@ use uv_distribution_types::{
};
use uv_install_wheel::linker::LinkMode;
use uv_macros::{CombineOptions, OptionsMetadata};
use uv_normalize::{ExtraName, PackageName};
use uv_normalize::{ExtraName, GroupName, PackageName};
use uv_pep508::Requirement;
use uv_pypi_types::{SupportedEnvironments, VerbatimParsedUrl};
use uv_python::{PythonDownloads, PythonPreference, PythonVersion};
@ -1111,6 +1111,50 @@ pub struct PipOptions {
"#
)]
pub no_extra: Option<Vec<ExtraName>>,
/// Include optional dependencies from the specified group; may be provided more than once.
///
/// Only applies to `pyproject.toml` sources.
#[option(
default = "[]",
value_type = "list[str]",
example = r#"
group = ["dev", "docs"]
"#
)]
pub group: Option<Vec<GroupName>>,
/// Exclude optional dependencies from the specified group if `all-groups` are supplied
///
/// Only applies to `pyproject.toml` sources.
#[option(
default = "[]",
value_type = "list[str]",
example = r#"
no-group = ["dev", "docs"]
"#
)]
pub no_group: Option<Vec<GroupName>>,
/// Exclude only dependencies from the specified group.
///
/// Only applies to `pyproject.toml` sources.
#[option(
default = "[]",
value_type = "list[str]",
example = r#"
only-group = ["dev", "docs"]
"#
)]
pub only_group: Option<Vec<GroupName>>,
/// Include all groups.
///
/// Only applies to `pyproject.toml` sources.
#[option(
default = "false",
value_type = "bool",
example = r#"
all-groups = true
"#
)]
pub all_groups: Option<bool>,
/// Ignore package dependencies, instead only add those packages explicitly listed
/// on the command line to the resulting the requirements file.
#[option(

View File

@ -11,8 +11,9 @@ use tracing::debug;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, ExtrasSpecification, IndexStrategy,
LowerBound, NoBinary, NoBuild, PreviewMode, Reinstall, SourceStrategy, TrustedHost, Upgrade,
BuildOptions, Concurrency, ConfigSettings, Constraints, DevGroupsSpecification,
ExtrasSpecification, IndexStrategy, LowerBound, NoBinary, NoBuild, PreviewMode, Reinstall,
SourceStrategy, TrustedHost, Upgrade,
};
use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::{BuildDispatch, SharedState};
@ -55,6 +56,7 @@ pub(crate) async fn pip_compile(
overrides_from_workspace: Vec<Requirement>,
environments: SupportedEnvironments,
extras: ExtrasSpecification,
groups: DevGroupsSpecification,
output_file: Option<&Path>,
resolution_mode: ResolutionMode,
prerelease_mode: PrereleaseMode,
@ -379,6 +381,7 @@ pub(crate) async fn pip_compile(
project,
BTreeSet::default(),
&extras,
&groups,
preferences,
EmptyInstalledPackages,
&hasher,

View File

@ -8,8 +8,9 @@ use tracing::{debug, enabled, Level};
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, ExtrasSpecification, HashCheckingMode,
IndexStrategy, LowerBound, PreviewMode, Reinstall, SourceStrategy, TrustedHost, Upgrade,
BuildOptions, Concurrency, ConfigSettings, Constraints, DevGroupsSpecification,
ExtrasSpecification, HashCheckingMode, IndexStrategy, LowerBound, PreviewMode, Reinstall,
SourceStrategy, TrustedHost, Upgrade,
};
use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::{BuildDispatch, SharedState};
@ -50,6 +51,7 @@ pub(crate) async fn pip_install(
constraints_from_workspace: Vec<Requirement>,
overrides_from_workspace: Vec<Requirement>,
extras: &ExtrasSpecification,
groups: &DevGroupsSpecification,
resolution_mode: ResolutionMode,
prerelease_mode: PrereleaseMode,
dependency_mode: DependencyMode,
@ -115,6 +117,7 @@ pub(crate) async fn pip_install(
constraints,
overrides,
extras,
groups,
&client_builder,
)
.await?;
@ -406,6 +409,7 @@ pub(crate) async fn pip_install(
project,
BTreeSet::default(),
extras,
groups,
preferences,
site_packages.clone(),
&hasher,

View File

@ -13,8 +13,8 @@ use uv_tool::InstalledTools;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, RegistryClient};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, ExtrasSpecification, Overrides,
Reinstall, Upgrade,
BuildOptions, Concurrency, ConfigSettings, Constraints, DevGroupsSpecification,
ExtrasSpecification, Overrides, Reinstall, Upgrade,
};
use uv_dispatch::BuildDispatch;
use uv_distribution::DistributionDatabase;
@ -54,6 +54,7 @@ pub(crate) async fn read_requirements(
constraints: &[RequirementsSource],
overrides: &[RequirementsSource],
extras: &ExtrasSpecification,
groups: &DevGroupsSpecification,
client_builder: &BaseClientBuilder<'_>,
) -> Result<RequirementsSpecification, Error> {
// If the user requests `extras` but does not provide a valid source (e.g., a `pyproject.toml`),
@ -64,6 +65,9 @@ pub(crate) async fn read_requirements(
)
.into());
}
if !groups.is_empty() && !requirements.iter().any(RequirementsSource::allows_groups) {
return Err(anyhow!("Requesting groups requires a `pyproject.toml`.").into());
}
// Read all requirements from the provided sources.
Ok(RequirementsSpecification::from_sources(
@ -96,6 +100,7 @@ pub(crate) async fn resolve<InstalledPackages: InstalledPackagesProvider>(
mut project: Option<PackageName>,
workspace_members: BTreeSet<PackageName>,
extras: &ExtrasSpecification,
groups: &DevGroupsSpecification,
preferences: Vec<Preference>,
installed_packages: InstalledPackages,
hasher: &HashStrategy,
@ -149,6 +154,7 @@ pub(crate) async fn resolve<InstalledPackages: InstalledPackagesProvider>(
if !source_trees.is_empty() {
let resolutions = SourceTreeResolver::new(
extras,
groups,
hasher,
index,
DistributionDatabase::new(client, build_dispatch, concurrency.downloads),

View File

@ -8,8 +8,9 @@ use tracing::debug;
use uv_cache::Cache;
use uv_client::{BaseClientBuilder, Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
BuildOptions, Concurrency, ConfigSettings, Constraints, ExtrasSpecification, HashCheckingMode,
IndexStrategy, LowerBound, PreviewMode, Reinstall, SourceStrategy, TrustedHost, Upgrade,
BuildOptions, Concurrency, ConfigSettings, Constraints, DevGroupsSpecification,
ExtrasSpecification, HashCheckingMode, IndexStrategy, LowerBound, PreviewMode, Reinstall,
SourceStrategy, TrustedHost, Upgrade,
};
use uv_configuration::{KeyringProviderType, TargetTriple};
use uv_dispatch::{BuildDispatch, SharedState};
@ -86,6 +87,7 @@ pub(crate) async fn pip_sync(
// Initialize a few defaults.
let overrides = &[];
let extras = ExtrasSpecification::default();
let groups = DevGroupsSpecification::default();
let upgrade = Upgrade::default();
let resolution_mode = ResolutionMode::default();
let prerelease_mode = PrereleaseMode::default();
@ -110,6 +112,7 @@ pub(crate) async fn pip_sync(
constraints,
overrides,
&extras,
&groups,
&client_builder,
)
.await?;
@ -351,6 +354,7 @@ pub(crate) async fn pip_sync(
project,
BTreeSet::default(),
&extras,
&groups,
preferences,
site_packages.clone(),
&hasher,

View File

@ -12,8 +12,8 @@ use tracing::debug;
use uv_cache::Cache;
use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder};
use uv_configuration::{
Concurrency, Constraints, ExtrasSpecification, LowerBound, PreviewMode, Reinstall, TrustedHost,
Upgrade,
Concurrency, Constraints, DevGroupsSpecification, ExtrasSpecification, LowerBound, PreviewMode,
Reinstall, TrustedHost, Upgrade,
};
use uv_dispatch::{BuildDispatch, SharedState};
use uv_distribution::DistributionDatabase;
@ -513,6 +513,7 @@ async fn do_lock(
let build_constraints = Constraints::default();
let build_hasher = HashStrategy::default();
let extras = ExtrasSpecification::default();
let groups = DevGroupsSpecification::default();
// Resolve the flat indexes from `--find-links`.
let flat_index = {
@ -683,6 +684,7 @@ async fn do_lock(
None,
packages.keys().cloned().collect(),
&extras,
&groups,
preferences,
EmptyInstalledPackages,
&hasher,

View File

@ -1225,6 +1225,7 @@ pub(crate) async fn resolve_environment(
// TODO(charlie): These are all default values. We should consider whether we want to make them
// optional on the downstream APIs.
let extras = ExtrasSpecification::default();
let groups = DevGroupsSpecification::default();
let hasher = HashStrategy::default();
let build_constraints = Constraints::default();
let build_hasher = HashStrategy::default();
@ -1288,6 +1289,7 @@ pub(crate) async fn resolve_environment(
project,
BTreeSet::default(),
&extras,
&groups,
preferences,
EmptyInstalledPackages,
&hasher,
@ -1585,6 +1587,7 @@ pub(crate) async fn update_environment(
let build_hasher = HashStrategy::default();
let dry_run = false;
let extras = ExtrasSpecification::default();
let groups = DevGroupsSpecification::default();
let hasher = HashStrategy::default();
let preferences = Vec::default();
@ -1633,6 +1636,7 @@ pub(crate) async fn update_environment(
project,
BTreeSet::default(),
&extras,
&groups,
preferences,
site_packages.clone(),
&hasher,

View File

@ -365,6 +365,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.overrides_from_workspace,
args.environments,
args.settings.extras,
args.settings.groups,
args.settings.output_file.as_deref(),
args.settings.resolution,
args.settings.prerelease,
@ -535,6 +536,7 @@ async fn run(mut cli: Cli) -> Result<ExitStatus> {
args.constraints_from_workspace,
args.overrides_from_workspace,
&args.settings.extras,
&args.settings.groups,
args.settings.resolution,
args.settings.prerelease,
args.settings.dependency_mode,

View File

@ -1511,6 +1511,10 @@ impl PipCompileSettings {
extra,
all_extras,
no_all_extras,
group,
no_group,
only_group,
all_groups,
build_constraints,
refresh,
no_deps,
@ -1615,6 +1619,10 @@ impl PipCompileSettings {
only_binary,
extra,
all_extras: flag(all_extras, no_all_extras),
group: Some(group),
no_group: Some(no_group),
only_group: Some(only_group),
all_groups: Some(all_groups),
no_deps: flag(no_deps, deps),
output_file,
no_strip_extras: flag(no_strip_extras, strip_extras),
@ -1757,6 +1765,10 @@ impl PipInstallSettings {
extra,
all_extras,
no_all_extras,
group,
no_group,
only_group,
all_groups,
installer,
refresh,
no_deps,
@ -1852,6 +1864,10 @@ impl PipInstallSettings {
strict: flag(strict, no_strict),
extra,
all_extras: flag(all_extras, no_all_extras),
group: Some(group),
no_group: Some(no_group),
only_group: Some(only_group),
all_groups: Some(all_groups),
no_deps: flag(no_deps, deps),
python_version,
python_platform,
@ -2560,6 +2576,7 @@ pub(crate) struct PipSettings {
pub(crate) install_mirrors: PythonInstallMirrors,
pub(crate) system: bool,
pub(crate) extras: ExtrasSpecification,
pub(crate) groups: DevGroupsSpecification,
pub(crate) break_system_packages: bool,
pub(crate) target: Option<Target>,
pub(crate) prefix: Option<Prefix>,
@ -2636,6 +2653,10 @@ impl PipSettings {
extra,
all_extras,
no_extra,
group,
no_group,
only_group,
all_groups,
no_deps,
allow_empty_requirements,
resolution,
@ -2753,6 +2774,16 @@ impl PipSettings {
args.no_extra.combine(no_extra).unwrap_or_default(),
args.extra.combine(extra).unwrap_or_default(),
),
groups: DevGroupsSpecification::from_args(
false,
false,
false,
args.group.combine(group).unwrap_or_default(),
args.no_group.combine(no_group).unwrap_or_default(),
false,
args.only_group.combine(only_group).unwrap_or_default(),
args.all_groups.combine(all_groups).unwrap_or_default(),
),
dependency_mode: if args.no_deps.combine(no_deps).unwrap_or_default() {
DependencyMode::Direct
} else {

View File

@ -14430,3 +14430,297 @@ fn respect_index_preference() -> Result<()> {
Ok(())
}
#[test]
fn dependency_group() -> Result<()> {
fn new_context() -> Result<TestContext> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["typing-extensions"]
[dependency-groups]
foo = ["sortedcontainers"]
bar = ["iniconfig"]
dev = ["sniffio"]
"#,
)?;
Ok(context)
}
let mut context;
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
Resolved 1 package in [TIME]
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml")
.arg("--only-group").arg("bar"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml --only-group bar
iniconfig==2.0.0
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
Resolved 2 packages in [TIME]
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml")
.arg("--group").arg("foo"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml --group foo
sortedcontainers==2.4.0
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
Resolved 2 packages in [TIME]
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml")
.arg("--group").arg("foo")
.arg("--group").arg("bar"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml --group foo --group bar
iniconfig==2.0.0
sortedcontainers==2.4.0
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
Resolved 3 packages in [TIME]
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml")
.arg("--all-groups"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml --all-groups
iniconfig==2.0.0
sniffio==1.3.1
sortedcontainers==2.4.0
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
Resolved 4 packages in [TIME]
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml")
.arg("--all-groups")
.arg("--no-group").arg("bar"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml --all-groups --no-group bar
sniffio==1.3.1
sortedcontainers==2.4.0
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
Resolved 3 packages in [TIME]
"###);
Ok(())
}
#[test]
fn many_pyproject_group() -> Result<()> {
fn new_context() -> Result<TestContext> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["typing-extensions"]
[dependency-groups]
foo = ["sortedcontainers"]
"#,
)?;
let subdir = context.temp_dir.child("subdir");
subdir.create_dir_all()?;
let pyproject_toml2 = subdir.child("pyproject.toml");
pyproject_toml2.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
[dependency-groups]
foo = ["iniconfig"]
bar = ["sniffio"]
"#,
)?;
Ok(context)
}
let mut context;
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml")
.arg("subdir/pyproject.toml"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml subdir/pyproject.toml
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
Resolved 1 package in [TIME]
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml")
.arg("subdir/pyproject.toml")
.arg("--all-groups"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml subdir/pyproject.toml --all-groups
iniconfig==2.0.0
sniffio==1.3.1
sortedcontainers==2.4.0
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
Resolved 4 packages in [TIME]
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml")
.arg("subdir/pyproject.toml")
.arg("--group").arg("foo"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml subdir/pyproject.toml --group foo
iniconfig==2.0.0
sortedcontainers==2.4.0
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
Resolved 3 packages in [TIME]
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml")
.arg("subdir/pyproject.toml")
.arg("--group").arg("bar"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml subdir/pyproject.toml --group bar
sniffio==1.3.1
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
warning: The dependency-group 'bar' is not defined in pyproject.toml
Resolved 2 packages in [TIME]
"###);
context = new_context()?;
uv_snapshot!(context.filters().into_iter().chain([(
"warning: The dependency-group 'lies' is not defined in pyproject.toml\nwarning: The dependency-group 'lies' is not defined in subdir/pyproject.toml",
"warning: The dependency-group 'lies' is not defined in subdir/pyproject.toml\nwarning: The dependency-group 'lies' is not defined in pyproject.toml",
)]).collect::<Vec<_>>(), context.pip_compile()
.arg("pyproject.toml")
.arg("subdir/pyproject.toml")
.arg("--group").arg("lies"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml subdir/pyproject.toml --group lies
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
warning: The dependency-group 'lies' is not defined in subdir/pyproject.toml
warning: The dependency-group 'lies' is not defined in pyproject.toml
Resolved 1 package in [TIME]
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_compile()
.arg("pyproject.toml")
.arg("subdir/pyproject.toml")
.arg("--group").arg("foo")
.arg("--group").arg("bar"), @r###"
success: true
exit_code: 0
----- stdout -----
# This file was autogenerated by uv via the following command:
# uv pip compile --cache-dir [CACHE_DIR] pyproject.toml subdir/pyproject.toml --group foo --group bar
iniconfig==2.0.0
sniffio==1.3.1
sortedcontainers==2.4.0
typing-extensions==4.10.0
# via project (pyproject.toml)
----- stderr -----
warning: The dependency-group 'bar' is not defined in pyproject.toml
Resolved 4 packages in [TIME]
"###);
Ok(())
}

View File

@ -8371,3 +8371,305 @@ fn direct_url_json_direct_url() -> Result<()> {
Ok(())
}
#[test]
fn dependency_group() -> Result<()> {
fn new_context() -> Result<TestContext> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["typing-extensions"]
[dependency-groups]
foo = ["sortedcontainers"]
bar = ["iniconfig"]
dev = ["sniffio"]
"#,
)?;
context.lock().assert().success();
Ok(context)
}
let mut context;
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r").arg("pyproject.toml"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ typing-extensions==4.10.0
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r").arg("pyproject.toml")
.arg("--only-group").arg("bar"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Prepared 2 packages in [TIME]
Installed 2 packages in [TIME]
+ iniconfig==2.0.0
+ typing-extensions==4.10.0
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r").arg("pyproject.toml")
.arg("--group").arg("foo"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 2 packages in [TIME]
Prepared 2 packages in [TIME]
Installed 2 packages in [TIME]
+ sortedcontainers==2.4.0
+ typing-extensions==4.10.0
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r").arg("pyproject.toml")
.arg("--group").arg("foo")
.arg("--group").arg("bar"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 3 packages in [TIME]
Prepared 3 packages in [TIME]
Installed 3 packages in [TIME]
+ iniconfig==2.0.0
+ sortedcontainers==2.4.0
+ typing-extensions==4.10.0
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r").arg("pyproject.toml")
.arg("--all-groups"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 4 packages in [TIME]
Prepared 4 packages in [TIME]
Installed 4 packages in [TIME]
+ iniconfig==2.0.0
+ sniffio==1.3.1
+ sortedcontainers==2.4.0
+ typing-extensions==4.10.0
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r").arg("pyproject.toml")
.arg("--all-groups")
.arg("--no-group").arg("bar"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 3 packages in [TIME]
Prepared 3 packages in [TIME]
Installed 3 packages in [TIME]
+ sniffio==1.3.1
+ sortedcontainers==2.4.0
+ typing-extensions==4.10.0
"###);
Ok(())
}
#[test]
fn many_pyproject_group() -> Result<()> {
fn new_context() -> Result<TestContext> {
let context = TestContext::new("3.12");
let pyproject_toml = context.temp_dir.child("pyproject.toml");
pyproject_toml.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
dependencies = ["typing-extensions"]
[dependency-groups]
foo = ["sortedcontainers"]
"#,
)?;
let subdir = context.temp_dir.child("subdir");
subdir.create_dir_all()?;
let pyproject_toml2 = subdir.child("pyproject.toml");
pyproject_toml2.write_str(
r#"
[project]
name = "project"
version = "0.1.0"
requires-python = ">=3.12"
[dependency-groups]
foo = ["iniconfig"]
bar = ["sniffio"]
"#,
)?;
context.lock().assert().success();
Ok(context)
}
let mut context;
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r").arg("pyproject.toml")
.arg("-r").arg("subdir/pyproject.toml"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 1 package in [TIME]
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ typing-extensions==4.10.0
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r").arg("pyproject.toml")
.arg("-r").arg("subdir/pyproject.toml")
.arg("--all-groups"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 4 packages in [TIME]
Prepared 4 packages in [TIME]
Installed 4 packages in [TIME]
+ iniconfig==2.0.0
+ sniffio==1.3.1
+ sortedcontainers==2.4.0
+ typing-extensions==4.10.0
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r").arg("pyproject.toml")
.arg("-r").arg("subdir/pyproject.toml")
.arg("--group").arg("foo"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
Resolved 3 packages in [TIME]
Prepared 3 packages in [TIME]
Installed 3 packages in [TIME]
+ iniconfig==2.0.0
+ sortedcontainers==2.4.0
+ typing-extensions==4.10.0
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r").arg("pyproject.toml")
.arg("-r").arg("subdir/pyproject.toml")
.arg("--group").arg("bar"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: The dependency-group 'bar' is not defined in pyproject.toml
Resolved 2 packages in [TIME]
Prepared 2 packages in [TIME]
Installed 2 packages in [TIME]
+ sniffio==1.3.1
+ typing-extensions==4.10.0
"###);
context = new_context()?;
uv_snapshot!(context.filters().into_iter().chain([(
"warning: The dependency-group 'lies' is not defined in pyproject.toml\nwarning: The dependency-group 'lies' is not defined in subdir/pyproject.toml",
"warning: The dependency-group 'lies' is not defined in subdir/pyproject.toml\nwarning: The dependency-group 'lies' is not defined in pyproject.toml",
)]).collect::<Vec<_>>(), context.pip_install()
.arg("-r").arg("pyproject.toml")
.arg("-r").arg("subdir/pyproject.toml")
.arg("--group").arg("lies"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: The dependency-group 'lies' is not defined in subdir/pyproject.toml
warning: The dependency-group 'lies' is not defined in pyproject.toml
Resolved 1 package in [TIME]
Prepared 1 package in [TIME]
Installed 1 package in [TIME]
+ typing-extensions==4.10.0
"###);
context = new_context()?;
uv_snapshot!(context.filters(), context.pip_install()
.arg("-r").arg("pyproject.toml")
.arg("-r").arg("subdir/pyproject.toml")
.arg("--group").arg("foo")
.arg("--group").arg("bar"), @r###"
success: true
exit_code: 0
----- stdout -----
----- stderr -----
warning: The dependency-group 'bar' is not defined in pyproject.toml
Resolved 4 packages in [TIME]
Prepared 4 packages in [TIME]
Installed 4 packages in [TIME]
+ iniconfig==2.0.0
+ sniffio==1.3.1
+ sortedcontainers==2.4.0
+ typing-extensions==4.10.0
"###);
Ok(())
}
#[test]
fn group_needs_manifest() {
let context = TestContext::new("3.12");
uv_snapshot!(context.filters(), context.pip_install()
.arg("sniffio")
.arg("--group").arg("foo"), @r###"
success: false
exit_code: 2
----- stdout -----
----- stderr -----
error: Requesting groups requires a `pyproject.toml`.
"###);
}

View File

@ -51,7 +51,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
// Resolution should use the lowest direct version, and generate hashes.
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -144,6 +144,10 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -197,14 +201,14 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Resolution should use the highest version, and generate hashes.
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in")
.arg("--resolution=highest"), @r###"
.arg("--resolution=highest"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -297,6 +301,10 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -350,7 +358,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Resolution should use the highest version, and omit hashes.
@ -358,7 +366,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
.arg("--show-settings")
.arg("requirements.in")
.arg("--resolution=highest")
.arg("--no-generate-hashes"), @r###"
.arg("--no-generate-hashes"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -451,6 +459,10 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -504,7 +516,7 @@ fn resolve_uv_toml() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
Ok(())
@ -544,7 +556,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
// Resolution should use the lowest direct version, and generate hashes.
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -637,6 +649,10 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -690,7 +706,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Remove the `uv.toml` file.
@ -699,7 +715,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
// Resolution should use the highest version, and omit hashes.
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -762,6 +778,10 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -815,7 +835,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Add configuration to the `pyproject.toml` file.
@ -833,7 +853,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
// Resolution should use the lowest direct version, and generate hashes.
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -926,6 +946,10 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -979,7 +1003,7 @@ fn resolve_pyproject_toml() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
Ok(())
@ -1011,7 +1035,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -1133,6 +1157,10 @@ fn resolve_index_url() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -1186,7 +1214,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Providing an additional index URL on the command-line should be merged with the
@ -1195,7 +1223,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
.arg("--show-settings")
.arg("requirements.in")
.arg("--extra-index-url")
.arg("https://test.pypi.org/simple"), @r###"
.arg("https://test.pypi.org/simple"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -1348,6 +1376,10 @@ fn resolve_index_url() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -1401,7 +1433,7 @@ fn resolve_index_url() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
Ok(())
@ -1433,7 +1465,7 @@ fn resolve_find_links() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -1526,6 +1558,10 @@ fn resolve_find_links() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -1579,7 +1615,7 @@ fn resolve_find_links() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
Ok(())
@ -1610,7 +1646,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -1673,6 +1709,10 @@ fn resolve_top_level() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -1726,7 +1766,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Write out to both the top-level (`tool.uv`) and the pip section (`tool.uv.pip`). The
@ -1750,7 +1790,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -1872,6 +1912,10 @@ fn resolve_top_level() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -1925,14 +1969,14 @@ fn resolve_top_level() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// But the command-line should take precedence over both.
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in")
.arg("--resolution=lowest-direct"), @r###"
.arg("--resolution=lowest-direct"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -2054,6 +2098,10 @@ fn resolve_top_level() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -2107,7 +2155,7 @@ fn resolve_top_level() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
Ok(())
@ -2138,7 +2186,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in")
.env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r###"
.env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r#"
success: true
exit_code: 0
----- stdout -----
@ -2201,6 +2249,10 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -2254,7 +2306,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Add a local configuration to generate hashes.
@ -2268,7 +2320,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in")
.env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r###"
.env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r#"
success: true
exit_code: 0
----- stdout -----
@ -2331,6 +2383,10 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -2384,7 +2440,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Add a local configuration to override the user configuration.
@ -2398,7 +2454,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in")
.env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r###"
.env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r#"
success: true
exit_code: 0
----- stdout -----
@ -2461,6 +2517,10 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -2514,7 +2574,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// However, the user-level `tool.uv.pip` settings override the project-level `tool.uv` settings.
@ -2530,7 +2590,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in")
.env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r###"
.env(EnvVars::XDG_CONFIG_HOME, xdg.path()), @r#"
success: true
exit_code: 0
----- stdout -----
@ -2593,6 +2653,10 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -2646,7 +2710,7 @@ fn resolve_user_configuration() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
Ok(())
@ -2840,7 +2904,7 @@ fn resolve_poetry_toml() -> anyhow::Result<()> {
// Resolution should use the lowest direct version, and generate hashes.
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -2903,6 +2967,10 @@ fn resolve_poetry_toml() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -2956,7 +3024,7 @@ fn resolve_poetry_toml() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
Ok(())
@ -2998,7 +3066,7 @@ fn resolve_both() -> anyhow::Result<()> {
// Resolution should succeed, but warn that the `pip` section in `pyproject.toml` is ignored.
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -3091,6 +3159,10 @@ fn resolve_both() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -3145,7 +3217,7 @@ fn resolve_both() -> anyhow::Result<()> {
----- stderr -----
warning: Found both a `uv.toml` file and a `[tool.uv]` section in an adjacent `pyproject.toml`. The `[tool.uv]` section will be ignored in favor of the `uv.toml` file.
"###
"#
);
Ok(())
@ -3274,7 +3346,7 @@ fn resolve_config_file() -> anyhow::Result<()> {
.arg("--show-settings")
.arg("--config-file")
.arg(config.path())
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -3367,6 +3439,10 @@ fn resolve_config_file() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -3420,7 +3496,7 @@ fn resolve_config_file() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Write in `pyproject.toml` schema.
@ -3528,7 +3604,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in")
.current_dir(&child), @r###"
.current_dir(&child), @r#"
success: true
exit_code: 0
----- stdout -----
@ -3591,6 +3667,10 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -3644,7 +3724,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Adding a `tool.uv` section should cause us to ignore the `uv.toml`.
@ -3661,7 +3741,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in")
.current_dir(&child), @r###"
.current_dir(&child), @r#"
success: true
exit_code: 0
----- stdout -----
@ -3724,6 +3804,10 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -3777,7 +3861,7 @@ fn resolve_skip_empty() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
Ok(())
@ -3802,7 +3886,7 @@ fn allow_insecure_host() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("--show-settings")
.arg("requirements.in"), @r###"
.arg("requirements.in"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -3876,6 +3960,10 @@ fn allow_insecure_host() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -3929,7 +4017,7 @@ fn allow_insecure_host() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
Ok(())
@ -3957,7 +4045,7 @@ fn index_priority() -> anyhow::Result<()> {
.arg("requirements.in")
.arg("--show-settings")
.arg("--index-url")
.arg("https://cli.pypi.org/simple"), @r###"
.arg("https://cli.pypi.org/simple"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -4081,6 +4169,10 @@ fn index_priority() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -4134,14 +4226,14 @@ fn index_priority() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
uv_snapshot!(context.filters(), add_shared_args(context.pip_compile(), context.temp_dir.path())
.arg("requirements.in")
.arg("--show-settings")
.arg("--default-index")
.arg("https://cli.pypi.org/simple"), @r###"
.arg("https://cli.pypi.org/simple"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -4265,6 +4357,10 @@ fn index_priority() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -4318,7 +4414,7 @@ fn index_priority() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
let config = context.temp_dir.child("uv.toml");
@ -4331,7 +4427,7 @@ fn index_priority() -> anyhow::Result<()> {
.arg("requirements.in")
.arg("--show-settings")
.arg("--default-index")
.arg("https://cli.pypi.org/simple"), @r###"
.arg("https://cli.pypi.org/simple"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -4455,6 +4551,10 @@ fn index_priority() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -4508,7 +4608,7 @@ fn index_priority() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Prefer the `--index` from the CLI, but treat the index from the file as the default.
@ -4516,7 +4616,7 @@ fn index_priority() -> anyhow::Result<()> {
.arg("requirements.in")
.arg("--show-settings")
.arg("--index")
.arg("https://cli.pypi.org/simple"), @r###"
.arg("https://cli.pypi.org/simple"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -4640,6 +4740,10 @@ fn index_priority() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -4693,7 +4797,7 @@ fn index_priority() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
let config = context.temp_dir.child("uv.toml");
@ -4708,7 +4812,7 @@ fn index_priority() -> anyhow::Result<()> {
.arg("requirements.in")
.arg("--show-settings")
.arg("--index-url")
.arg("https://cli.pypi.org/simple"), @r###"
.arg("https://cli.pypi.org/simple"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -4832,6 +4936,10 @@ fn index_priority() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -4885,7 +4993,7 @@ fn index_priority() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
// Prefer the `--extra-index-url` from the CLI, but not as the default.
@ -4893,7 +5001,7 @@ fn index_priority() -> anyhow::Result<()> {
.arg("requirements.in")
.arg("--show-settings")
.arg("--extra-index-url")
.arg("https://cli.pypi.org/simple"), @r###"
.arg("https://cli.pypi.org/simple"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -5017,6 +5125,10 @@ fn index_priority() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -5070,7 +5182,7 @@ fn index_priority() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
Ok(())
@ -5091,7 +5203,7 @@ fn verify_hashes() -> anyhow::Result<()> {
uv_snapshot!(context.filters(), add_shared_args(context.pip_install(), context.temp_dir.path())
.arg("-r")
.arg("requirements.in")
.arg("--show-settings"), @r###"
.arg("--show-settings"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -5155,6 +5267,10 @@ fn verify_hashes() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -5208,14 +5324,14 @@ fn verify_hashes() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
uv_snapshot!(context.filters(), add_shared_args(context.pip_install(), context.temp_dir.path())
.arg("-r")
.arg("requirements.in")
.arg("--no-verify-hashes")
.arg("--show-settings"), @r###"
.arg("--show-settings"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -5279,6 +5395,10 @@ fn verify_hashes() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -5330,14 +5450,14 @@ fn verify_hashes() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
uv_snapshot!(context.filters(), add_shared_args(context.pip_install(), context.temp_dir.path())
.arg("-r")
.arg("requirements.in")
.arg("--require-hashes")
.arg("--show-settings"), @r###"
.arg("--show-settings"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -5401,6 +5521,10 @@ fn verify_hashes() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -5454,14 +5578,14 @@ fn verify_hashes() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
uv_snapshot!(context.filters(), add_shared_args(context.pip_install(), context.temp_dir.path())
.arg("-r")
.arg("requirements.in")
.arg("--no-require-hashes")
.arg("--show-settings"), @r###"
.arg("--show-settings"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -5525,6 +5649,10 @@ fn verify_hashes() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -5576,14 +5704,14 @@ fn verify_hashes() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
uv_snapshot!(context.filters(), add_shared_args(context.pip_install(), context.temp_dir.path())
.arg("-r")
.arg("requirements.in")
.env(EnvVars::UV_NO_VERIFY_HASHES, "1")
.arg("--show-settings"), @r###"
.arg("--show-settings"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -5647,6 +5775,10 @@ fn verify_hashes() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -5698,7 +5830,7 @@ fn verify_hashes() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
uv_snapshot!(context.filters(), add_shared_args(context.pip_install(), context.temp_dir.path())
@ -5706,7 +5838,7 @@ fn verify_hashes() -> anyhow::Result<()> {
.arg("requirements.in")
.arg("--verify-hashes")
.arg("--no-require-hashes")
.arg("--show-settings"), @r###"
.arg("--show-settings"), @r#"
success: true
exit_code: 0
----- stdout -----
@ -5770,6 +5902,10 @@ fn verify_hashes() -> anyhow::Result<()> {
},
system: false,
extras: None,
groups: DevGroupsSpecification {
dev: None,
groups: None,
},
break_system_packages: false,
target: None,
prefix: None,
@ -5823,7 +5959,7 @@ fn verify_hashes() -> anyhow::Result<()> {
}
----- stderr -----
"###
"#
);
Ok(())

View File

@ -378,10 +378,10 @@ uv run [OPTIONS] [COMMAND]
</dd><dt><code>--only-group</code> <i>only-group</i></dt><dd><p>Only include dependencies from the specified dependency group.</p>
<p>May be provided multiple times.</p>
<p>The project itself will also be omitted.</p>
<p>May be provided multiple times.</p>
</dd><dt><code>--package</code> <i>package</i></dt><dd><p>Run the command in a specific package in the workspace.</p>
<p>If the workspace member does not exist, uv will exit with an error.</p>
@ -1743,10 +1743,10 @@ uv sync [OPTIONS]
</dd><dt><code>--only-group</code> <i>only-group</i></dt><dd><p>Only include dependencies from the specified dependency group.</p>
<p>May be provided multiple times.</p>
<p>The project itself will also be omitted.</p>
<p>May be provided multiple times.</p>
</dd><dt><code>--package</code> <i>package</i></dt><dd><p>Sync for a specific package in the workspace.</p>
<p>The workspace&#8217;s environment (<code>.venv</code>) is updated to reflect the subset of dependencies declared by the specified workspace member package.</p>
@ -2457,10 +2457,10 @@ uv export [OPTIONS]
</dd><dt><code>--only-group</code> <i>only-group</i></dt><dd><p>Only include dependencies from the specified dependency group.</p>
<p>May be provided multiple times.</p>
<p>The project itself will also be omitted.</p>
<p>May be provided multiple times.</p>
</dd><dt><code>--output-file</code>, <code>-o</code> <i>output-file</i></dt><dd><p>Write the exported requirements to the given file</p>
</dd><dt><code>--package</code> <i>package</i></dt><dd><p>Export the dependencies for a specific package in the workspace.</p>
@ -2813,10 +2813,10 @@ uv tree [OPTIONS]
</dd><dt><code>--only-group</code> <i>only-group</i></dt><dd><p>Only include dependencies from the specified dependency group.</p>
<p>May be provided multiple times.</p>
<p>The project itself will also be omitted.</p>
<p>May be provided multiple times.</p>
</dd><dt><code>--outdated</code></dt><dd><p>Show the latest available version of each package in the tree</p>
</dd><dt><code>--package</code> <i>package</i></dt><dd><p>Display only the specified packages</p>
@ -5492,6 +5492,12 @@ uv pip compile [OPTIONS] <SRC_FILE>...
<p>Only applies to <code>pyproject.toml</code>, <code>setup.py</code>, and <code>setup.cfg</code> sources.</p>
</dd><dt><code>--all-groups</code></dt><dd><p>Include dependencies from all dependency groups.</p>
<p>Only applies to <code>pyproject.toml</code> sources.</p>
<p><code>--no-group</code> can be used to exclude specific groups.</p>
</dd><dt><code>--allow-insecure-host</code> <i>allow-insecure-host</i></dt><dd><p>Allow insecure connections to a host.</p>
<p>Can be provided multiple times.</p>
@ -5616,6 +5622,12 @@ uv pip compile [OPTIONS] <SRC_FILE>...
</ul>
</dd><dt><code>--generate-hashes</code></dt><dd><p>Include distribution hashes in the output file</p>
</dd><dt><code>--group</code> <i>group</i></dt><dd><p>Include dependencies from the specified dependency group.</p>
<p>Only applies to <code>pyproject.toml</code> sources.</p>
<p>May be provided multiple times.</p>
</dd><dt><code>--help</code>, <code>-h</code></dt><dd><p>Display the concise help for this command</p>
</dd><dt><code>--index</code> <i>index</i></dt><dd><p>The URLs to use when resolving dependencies, in addition to the default index.</p>
@ -5715,6 +5727,12 @@ uv pip compile [OPTIONS] <SRC_FILE>...
</dd><dt><code>--no-emit-package</code> <i>no-emit-package</i></dt><dd><p>Specify a package to omit from the output resolution. Its dependencies will still be included in the resolution. Equivalent to pip-compile&#8217;s <code>--unsafe-package</code> option</p>
</dd><dt><code>--no-group</code> <i>no-group</i></dt><dd><p>Exclude dependencies from the specified dependency group.</p>
<p>Only applies to <code>pyproject.toml</code> sources.</p>
<p>May be provided multiple times.</p>
</dd><dt><code>--no-header</code></dt><dd><p>Exclude the comment header at the top of the generated output file</p>
</dd><dt><code>--no-index</code></dt><dd><p>Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those provided via <code>--find-links</code></p>
@ -5747,6 +5765,14 @@ uv pip compile [OPTIONS] <SRC_FILE>...
<p>Multiple packages may be provided. Disable binaries for all packages with <code>:all:</code>. Clear previously specified packages with <code>:none:</code>.</p>
</dd><dt><code>--only-group</code> <i>only-group</i></dt><dd><p>Only include dependencies from the specified dependency group.</p>
<p>The project itself will also be omitted.</p>
<p>Only applies to <code>pyproject.toml</code> sources.</p>
<p>May be provided multiple times.</p>
</dd><dt><code>--output-file</code>, <code>-o</code> <i>output-file</i></dt><dd><p>Write the compiled requirements to the given <code>requirements.txt</code> file.</p>
<p>If the file already exists, the existing versions will be preferred when resolving dependencies, unless <code>--upgrade</code> is also specified.</p>
@ -6370,6 +6396,12 @@ uv pip install [OPTIONS] <PACKAGE|--requirements <REQUIREMENTS>|--editable <EDIT
<p>Only applies to <code>pyproject.toml</code>, <code>setup.py</code>, and <code>setup.cfg</code> sources.</p>
</dd><dt><code>--all-groups</code></dt><dd><p>Include dependencies from all dependency groups.</p>
<p>Only applies to <code>pyproject.toml</code> sources.</p>
<p><code>--no-group</code> can be used to exclude specific groups.</p>
</dd><dt><code>--allow-insecure-host</code> <i>allow-insecure-host</i></dt><dd><p>Allow insecure connections to a host.</p>
<p>Can be provided multiple times.</p>
@ -6488,6 +6520,12 @@ uv pip install [OPTIONS] <PACKAGE|--requirements <REQUIREMENTS>|--editable <EDIT
<li><code>requires-python</code>: Optimize for selecting latest supported version of each package, for each supported Python version</li>
</ul>
</dd><dt><code>--group</code> <i>group</i></dt><dd><p>Include dependencies from the specified dependency group.</p>
<p>Only applies to <code>pyproject.toml</code> sources.</p>
<p>May be provided multiple times.</p>
</dd><dt><code>--help</code>, <code>-h</code></dt><dd><p>Display the concise help for this command</p>
</dd><dt><code>--index</code> <i>index</i></dt><dd><p>The URLs to use when resolving dependencies, in addition to the default index.</p>
@ -6586,6 +6624,12 @@ uv pip install [OPTIONS] <PACKAGE|--requirements <REQUIREMENTS>|--editable <EDIT
<p>May also be set with the <code>UV_NO_CONFIG</code> environment variable.</p>
</dd><dt><code>--no-deps</code></dt><dd><p>Ignore package dependencies, instead only installing those packages explicitly listed on the command line or in the requirements files</p>
</dd><dt><code>--no-group</code> <i>no-group</i></dt><dd><p>Exclude dependencies from the specified dependency group.</p>
<p>Only applies to <code>pyproject.toml</code> sources.</p>
<p>May be provided multiple times.</p>
</dd><dt><code>--no-index</code></dt><dd><p>Ignore the registry index (e.g., PyPI), instead relying on direct URL dependencies and those provided via <code>--find-links</code></p>
</dd><dt><code>--no-progress</code></dt><dd><p>Hide all progress outputs.</p>
@ -6613,6 +6657,14 @@ uv pip install [OPTIONS] <PACKAGE|--requirements <REQUIREMENTS>|--editable <EDIT
<p>Multiple packages may be provided. Disable binaries for all packages with <code>:all:</code>. Clear previously specified packages with <code>:none:</code>.</p>
</dd><dt><code>--only-group</code> <i>only-group</i></dt><dd><p>Only include dependencies from the specified dependency group.</p>
<p>The project itself will also be omitted.</p>
<p>Only applies to <code>pyproject.toml</code> sources.</p>
<p>May be provided multiple times.</p>
</dd><dt><code>--overrides</code> <i>overrides</i></dt><dd><p>Override versions using the given requirements files.</p>
<p>Overrides files are <code>requirements.txt</code>-like files that force a specific version of a requirement to be installed, regardless of the requirements declared by any constituent package, and regardless of whether this would be considered an invalid resolution.</p>

View File

@ -1692,6 +1692,34 @@ Only applies to `pyproject.toml`, `setup.py`, and `setup.cfg` sources.
---
#### [`all-groups`](#pip_all-groups) {: #pip_all-groups }
<span id="all-groups"></span>
Include all groups.
Only applies to `pyproject.toml` sources.
**Default value**: `false`
**Type**: `bool`
**Example usage**:
=== "pyproject.toml"
```toml
[tool.uv.pip]
all-groups = true
```
=== "uv.toml"
```toml
[pip]
all-groups = true
```
---
#### [`allow-empty-requirements`](#pip_allow-empty-requirements) {: #pip_allow-empty-requirements }
<span id="allow-empty-requirements"></span>
@ -2238,6 +2266,34 @@ Include distribution hashes in the output file.
---
#### [`group`](#pip_group) {: #pip_group }
<span id="group"></span>
Include optional dependencies from the specified group; may be provided more than once.
Only applies to `pyproject.toml` sources.
**Default value**: `[]`
**Type**: `list[str]`
**Example usage**:
=== "pyproject.toml"
```toml
[tool.uv.pip]
group = ["dev", "docs"]
```
=== "uv.toml"
```toml
[pip]
group = ["dev", "docs"]
```
---
#### [`index-strategy`](#pip_index-strategy) {: #pip_index-strategy }
<span id="index-strategy"></span>
@ -2599,6 +2655,34 @@ Exclude the specified optional dependencies if `all-extras` is supplied.
---
#### [`no-group`](#pip_no-group) {: #pip_no-group }
<span id="no-group"></span>
Exclude optional dependencies from the specified group if `all-groups` are supplied
Only applies to `pyproject.toml` sources.
**Default value**: `[]`
**Type**: `list[str]`
**Example usage**:
=== "pyproject.toml"
```toml
[tool.uv.pip]
no-group = ["dev", "docs"]
```
=== "uv.toml"
```toml
[pip]
no-group = ["dev", "docs"]
```
---
#### [`no-header`](#pip_no-header) {: #pip_no-header }
<span id="no-header"></span>
@ -2772,6 +2856,34 @@ Clear previously specified packages with `:none:`.
---
#### [`only-group`](#pip_only-group) {: #pip_only-group }
<span id="only-group"></span>
Exclude only dependencies from the specified group.
Only applies to `pyproject.toml` sources.
**Default value**: `[]`
**Type**: `list[str]`
**Example usage**:
=== "pyproject.toml"
```toml
[tool.uv.pip]
only-group = ["dev", "docs"]
```
=== "uv.toml"
```toml
[pip]
only-group = ["dev", "docs"]
```
---
#### [`output-file`](#pip_output-file) {: #pip_output-file }
<span id="output-file"></span>

37
uv.schema.json generated
View File

@ -864,6 +864,13 @@
"null"
]
},
"all-groups": {
"description": "Include all groups.\n\nOnly applies to `pyproject.toml` sources.",
"type": [
"boolean",
"null"
]
},
"allow-empty-requirements": {
"description": "Allow `uv pip sync` with empty requirements, which will clear the environment of all packages.",
"type": [
@ -1018,6 +1025,16 @@
"null"
]
},
"group": {
"description": "Include optional dependencies from the specified group; may be provided more than once.\n\nOnly applies to `pyproject.toml` sources.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/GroupName"
}
},
"index-strategy": {
"description": "The strategy to use when resolving against multiple index URLs.\n\nBy default, uv will stop at the first index on which a given package is available, and limit resolutions to those present on that first index (`first-index`). This prevents \"dependency confusion\" attacks, whereby an attacker can upload a malicious package under the same name to an alternate index.",
"anyOf": [
@ -1130,6 +1147,16 @@
"$ref": "#/definitions/ExtraName"
}
},
"no-group": {
"description": "Exclude optional dependencies from the specified group if `all-groups` are supplied\n\nOnly applies to `pyproject.toml` sources.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/GroupName"
}
},
"no-header": {
"description": "Exclude the comment header at the top of output file generated by `uv pip compile`.",
"type": [
@ -1175,6 +1202,16 @@
"$ref": "#/definitions/PackageNameSpecifier"
}
},
"only-group": {
"description": "Exclude only dependencies from the specified group.\n\nOnly applies to `pyproject.toml` sources.",
"type": [
"array",
"null"
],
"items": {
"$ref": "#/definitions/GroupName"
}
},
"output-file": {
"description": "Write the requirements generated by `uv pip compile` to the given `requirements.txt` file.\n\nIf the file already exists, the existing versions will be preferred when resolving dependencies, unless `--upgrade` is also specified.",
"type": [