Add --group and --only-group to uv sync and includes all groups in uv lock (#8110)
Part of #8090 Adds the ability to include a group (`--group`) in the sync or _only_ sync a group (`--only-group`). Includes all groups in the resolution, which will have the same limitations as extras as described in #6981. There's a great deal of refactoring of the "development" concept into "groups" behind the scenes that I am continuing to defer here to minimize the diff. Additionally, this does not yet resolve interactions with the existing `dev` group — we'll tackle that separately as well. I probably won't merge the stack until that design is resolved. The current proposal is that we'll just "combine' the `dev-dependencies` contents into the `dev` group.
This commit is contained in:
@@ -2788,6 +2788,20 @@ pub struct SyncArgs {
|
||||
#[arg(long, conflicts_with("no_dev"))]
|
||||
pub only_dev: bool,
|
||||
|
||||
/// Include dependencies from the specified local dependency group.
|
||||
///
|
||||
/// May be provided multiple times.
|
||||
#[arg(long, conflicts_with("only_group"))]
|
||||
pub group: Vec<GroupName>,
|
||||
|
||||
/// Only include dependencies from the specified local dependency group.
|
||||
///
|
||||
/// May be provided multiple times.
|
||||
///
|
||||
/// The project itself will also be omitted.
|
||||
#[arg(long, conflicts_with("group"))]
|
||||
pub only_group: Vec<GroupName>,
|
||||
|
||||
/// Install any editable dependencies, including the project and any workspace members, as
|
||||
/// non-editable.
|
||||
#[arg(long)]
|
||||
|
||||
@@ -61,3 +61,39 @@ impl From<DevMode> for DevSpecification {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DevSpecification {
|
||||
/// Determine the [`DevSpecification`] policy from the command-line arguments.
|
||||
pub fn from_args(
|
||||
dev: bool,
|
||||
no_dev: bool,
|
||||
only_dev: bool,
|
||||
group: Vec<GroupName>,
|
||||
only_group: Vec<GroupName>,
|
||||
) -> Self {
|
||||
let from_mode = DevSpecification::from(DevMode::from_args(dev, no_dev, only_dev));
|
||||
if !group.is_empty() {
|
||||
match from_mode {
|
||||
DevSpecification::Exclude => Self::Include(group),
|
||||
DevSpecification::Include(dev) => {
|
||||
Self::Include(group.into_iter().chain(dev).collect())
|
||||
}
|
||||
DevSpecification::Only(_) => {
|
||||
unreachable!("cannot specify both `--only-dev` and `--group`")
|
||||
}
|
||||
}
|
||||
} else if !only_group.is_empty() {
|
||||
match from_mode {
|
||||
DevSpecification::Exclude => Self::Only(only_group),
|
||||
DevSpecification::Only(dev) => {
|
||||
Self::Only(only_group.into_iter().chain(dev).collect())
|
||||
}
|
||||
// TODO(zanieb): `dev` defaults to true we can't tell if `--dev` was provided in
|
||||
// conflict with `--only-group` here
|
||||
DevSpecification::Include(_) => Self::Only(only_group),
|
||||
}
|
||||
} else {
|
||||
from_mode
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -302,7 +302,13 @@ async fn do_lock(
|
||||
let requirements = workspace.non_project_requirements().collect::<Vec<_>>();
|
||||
let overrides = workspace.overrides().into_iter().collect::<Vec<_>>();
|
||||
let constraints = workspace.constraints();
|
||||
let dev = vec![DEV_DEPENDENCIES.clone()];
|
||||
let dev: Vec<_> = workspace
|
||||
.pyproject_toml()
|
||||
.dependency_groups
|
||||
.iter()
|
||||
.flat_map(|groups| groups.keys().cloned())
|
||||
.chain(std::iter::once(DEV_DEPENDENCIES.clone()))
|
||||
.collect();
|
||||
let source_trees = vec![];
|
||||
|
||||
// Collect the list of members.
|
||||
|
||||
@@ -8,7 +8,7 @@ use uv_auth::store_credentials;
|
||||
use uv_cache::Cache;
|
||||
use uv_client::{Connectivity, FlatIndexClient, RegistryClientBuilder};
|
||||
use uv_configuration::{
|
||||
Concurrency, Constraints, DevMode, DevSpecification, EditableMode, ExtrasSpecification,
|
||||
Concurrency, Constraints, DevSpecification, EditableMode, ExtrasSpecification,
|
||||
HashCheckingMode, InstallOptions, LowerBound,
|
||||
};
|
||||
use uv_dispatch::BuildDispatch;
|
||||
@@ -43,7 +43,7 @@ pub(crate) async fn sync(
|
||||
frozen: bool,
|
||||
package: Option<PackageName>,
|
||||
extras: ExtrasSpecification,
|
||||
dev: DevMode,
|
||||
dev: DevSpecification,
|
||||
editable: EditableMode,
|
||||
install_options: InstallOptions,
|
||||
modifications: Modifications,
|
||||
@@ -155,7 +155,7 @@ pub(crate) async fn sync(
|
||||
&venv,
|
||||
&lock,
|
||||
&extras,
|
||||
&DevSpecification::from(dev),
|
||||
&dev,
|
||||
editable,
|
||||
install_options,
|
||||
modifications,
|
||||
|
||||
@@ -19,10 +19,10 @@ use uv_cli::{
|
||||
};
|
||||
use uv_client::Connectivity;
|
||||
use uv_configuration::{
|
||||
BuildOptions, Concurrency, ConfigSettings, DevMode, EditableMode, ExportFormat,
|
||||
ExtrasSpecification, HashCheckingMode, IndexStrategy, InstallOptions, KeyringProviderType,
|
||||
NoBinary, NoBuild, PreviewMode, ProjectBuildBackend, Reinstall, SourceStrategy, TargetTriple,
|
||||
TrustedHost, TrustedPublishing, Upgrade, VersionControlSystem,
|
||||
BuildOptions, Concurrency, ConfigSettings, DevMode, DevSpecification, EditableMode,
|
||||
ExportFormat, ExtrasSpecification, HashCheckingMode, IndexStrategy, InstallOptions,
|
||||
KeyringProviderType, NoBinary, NoBuild, PreviewMode, ProjectBuildBackend, Reinstall,
|
||||
SourceStrategy, TargetTriple, TrustedHost, TrustedPublishing, Upgrade, VersionControlSystem,
|
||||
};
|
||||
use uv_distribution_types::{DependencyMetadata, Index, IndexLocations};
|
||||
use uv_install_wheel::linker::LinkMode;
|
||||
@@ -693,7 +693,7 @@ pub(crate) struct SyncSettings {
|
||||
pub(crate) locked: bool,
|
||||
pub(crate) frozen: bool,
|
||||
pub(crate) extras: ExtrasSpecification,
|
||||
pub(crate) dev: DevMode,
|
||||
pub(crate) dev: DevSpecification,
|
||||
pub(crate) editable: EditableMode,
|
||||
pub(crate) install_options: InstallOptions,
|
||||
pub(crate) modifications: Modifications,
|
||||
@@ -714,6 +714,8 @@ impl SyncSettings {
|
||||
dev,
|
||||
no_dev,
|
||||
only_dev,
|
||||
group,
|
||||
only_group,
|
||||
no_editable,
|
||||
inexact,
|
||||
exact,
|
||||
@@ -741,7 +743,7 @@ impl SyncSettings {
|
||||
flag(all_extras, no_all_extras).unwrap_or_default(),
|
||||
extra.unwrap_or_default(),
|
||||
),
|
||||
dev: DevMode::from_args(dev, no_dev, only_dev),
|
||||
dev: DevSpecification::from_args(dev, no_dev, only_dev, group, only_group),
|
||||
editable: EditableMode::from_args(no_editable),
|
||||
install_options: InstallOptions::new(
|
||||
no_install_project,
|
||||
|
||||
@@ -4247,8 +4247,12 @@ fn add_group() -> Result<()> {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 1 package in [TIME]
|
||||
Audited in [TIME]
|
||||
Resolved 4 packages in [TIME]
|
||||
Prepared 3 packages in [TIME]
|
||||
Installed 3 packages in [TIME]
|
||||
+ anyio==3.7.0
|
||||
+ idna==3.6
|
||||
+ sniffio==1.3.1
|
||||
"###);
|
||||
|
||||
let pyproject_toml = context.read("pyproject.toml");
|
||||
@@ -4272,14 +4276,19 @@ fn add_group() -> Result<()> {
|
||||
);
|
||||
});
|
||||
|
||||
uv_snapshot!(context.filters(), context.add().arg("trio").arg("--group").arg("test"), @r###"
|
||||
uv_snapshot!(context.filters(), context.add().arg("requests").arg("--group").arg("test"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 1 package in [TIME]
|
||||
Audited in [TIME]
|
||||
Resolved 8 packages in [TIME]
|
||||
Prepared 4 packages in [TIME]
|
||||
Installed 4 packages in [TIME]
|
||||
+ certifi==2024.2.2
|
||||
+ charset-normalizer==3.3.2
|
||||
+ requests==2.31.0
|
||||
+ urllib3==2.2.1
|
||||
"###);
|
||||
|
||||
let pyproject_toml = context.read("pyproject.toml");
|
||||
@@ -4298,7 +4307,7 @@ fn add_group() -> Result<()> {
|
||||
[dependency-groups]
|
||||
test = [
|
||||
"anyio==3.7.0",
|
||||
"trio",
|
||||
"requests>=2.31.0",
|
||||
]
|
||||
"###
|
||||
);
|
||||
@@ -4310,8 +4319,8 @@ fn add_group() -> Result<()> {
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 1 package in [TIME]
|
||||
Audited in [TIME]
|
||||
Resolved 8 packages in [TIME]
|
||||
Audited 3 packages in [TIME]
|
||||
"###);
|
||||
|
||||
let pyproject_toml = context.read("pyproject.toml");
|
||||
@@ -4330,7 +4339,7 @@ fn add_group() -> Result<()> {
|
||||
[dependency-groups]
|
||||
test = [
|
||||
"anyio==3.7.0",
|
||||
"trio",
|
||||
"requests>=2.31.0",
|
||||
]
|
||||
second = [
|
||||
"anyio==3.7.0",
|
||||
|
||||
@@ -12846,7 +12846,7 @@ fn lock_named_index_cli() -> Result<()> {
|
||||
|
||||
----- stderr -----
|
||||
error: Failed to build: `project @ file://[TEMP_DIR]/`
|
||||
Caused by: Failed to parse entry for: `jinja2`
|
||||
Caused by: Failed to parse entry: `jinja2`
|
||||
Caused by: Package `jinja2` references an undeclared index: `pytorch`
|
||||
"###);
|
||||
|
||||
|
||||
@@ -1012,6 +1012,88 @@ fn sync_dev() -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_group() -> Result<()> {
|
||||
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 = ["anyio"]
|
||||
bar = ["requests"]
|
||||
"#,
|
||||
)?;
|
||||
|
||||
context.lock().assert().success();
|
||||
|
||||
uv_snapshot!(context.filters(), context.sync(), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 9 packages in [TIME]
|
||||
Prepared 1 package in [TIME]
|
||||
Installed 1 package in [TIME]
|
||||
+ typing-extensions==4.10.0
|
||||
"###);
|
||||
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--group").arg("foo"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 9 packages in [TIME]
|
||||
Prepared 3 packages in [TIME]
|
||||
Installed 3 packages in [TIME]
|
||||
+ anyio==4.3.0
|
||||
+ idna==3.6
|
||||
+ sniffio==1.3.1
|
||||
"###);
|
||||
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--only-group").arg("bar"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 9 packages in [TIME]
|
||||
Prepared 4 packages in [TIME]
|
||||
Uninstalled 3 packages in [TIME]
|
||||
Installed 4 packages in [TIME]
|
||||
- anyio==4.3.0
|
||||
+ certifi==2024.2.2
|
||||
+ charset-normalizer==3.3.2
|
||||
+ requests==2.31.0
|
||||
- sniffio==1.3.1
|
||||
- typing-extensions==4.10.0
|
||||
+ urllib3==2.2.1
|
||||
"###);
|
||||
|
||||
uv_snapshot!(context.filters(), context.sync().arg("--group").arg("foo").arg("--group").arg("bar"), @r###"
|
||||
success: true
|
||||
exit_code: 0
|
||||
----- stdout -----
|
||||
|
||||
----- stderr -----
|
||||
Resolved 9 packages in [TIME]
|
||||
Installed 3 packages in [TIME]
|
||||
+ anyio==4.3.0
|
||||
+ sniffio==1.3.1
|
||||
+ typing-extensions==4.10.0
|
||||
"###);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Regression test for <https://github.com/astral-sh/uv/issues/6316>.
|
||||
///
|
||||
/// Previously, we would read metadata statically from pyproject.toml and write that to `uv.lock`. In
|
||||
|
||||
@@ -1416,6 +1416,10 @@ uv sync [OPTIONS]
|
||||
<p>Instead of checking if the lockfile is up-to-date, uses the versions in the lockfile as the source of truth. If the lockfile is missing, uv will exit with an error. If the <code>pyproject.toml</code> includes changes to dependencies that have not been included in the lockfile yet, they will not be present in the environment.</p>
|
||||
|
||||
<p>May also be set with the <code>UV_FROZEN</code> environment variable.</p>
|
||||
</dd><dt><code>--group</code> <i>group</i></dt><dd><p>Include dependencies from the specified local dependency group.</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>
|
||||
@@ -1555,6 +1559,12 @@ uv sync [OPTIONS]
|
||||
|
||||
<p>The project itself will also be omitted.</p>
|
||||
|
||||
</dd><dt><code>--only-group</code> <i>only-group</i></dt><dd><p>Only include dependencies from the specified local dependency group.</p>
|
||||
|
||||
<p>May be provided multiple times.</p>
|
||||
|
||||
<p>The project itself will also be omitted.</p>
|
||||
|
||||
</dd><dt><code>--package</code> <i>package</i></dt><dd><p>Sync for a specific package in the workspace.</p>
|
||||
|
||||
<p>The workspace’s environment (<code>.venv</code>) is updated to reflect the subset of dependencies declared by the specified workspace member package.</p>
|
||||
|
||||
Reference in New Issue
Block a user