mirror of https://github.com/astral-sh/uv
Add conflict detection between --only-group and --extra flags (#15788)
<!-- Thank you for contributing to uv! To help us out with reviewing, please consider the following: - Does this pull request include a summary of the change? (See below.) - Does this pull request include a descriptive title? - Does this pull request include references to any relevant issues? --> ## Summary - Added `conflicts_with = "only_group"` to `--extra` arguments in `SyncArgs`, `RunArgs`, and `ExportArgs` - Added tests to verify proper conflict detection and error messages **Before:** The `--extra` flag was silently ignored when used with `--only-group` **After:** Clear error message: `error: the argument '--only-group <ONLY_GROUP>' cannot be used with '--extra <EXTRA>'` fixes: #15676 ## Test Plan - Tests confirm proper error message format when `--only-group` and `--extra` are used together - Verified existing functionality remains unchanged when flags are used independently
This commit is contained in:
parent
5f2871e695
commit
a0f8359012
|
|
@ -3077,7 +3077,7 @@ pub struct RunArgs {
|
||||||
/// Optional dependencies are defined via `project.optional-dependencies` in a `pyproject.toml`.
|
/// Optional dependencies are defined via `project.optional-dependencies` in a `pyproject.toml`.
|
||||||
///
|
///
|
||||||
/// This option is only available when running in a project.
|
/// This option is only available when running in a project.
|
||||||
#[arg(long, conflicts_with = "all_extras", value_parser = extra_name_with_clap_error)]
|
#[arg(long, conflicts_with = "all_extras", conflicts_with = "only_group", value_parser = extra_name_with_clap_error)]
|
||||||
pub extra: Option<Vec<ExtraName>>,
|
pub extra: Option<Vec<ExtraName>>,
|
||||||
|
|
||||||
/// Include all optional dependencies.
|
/// Include all optional dependencies.
|
||||||
|
|
@ -3085,7 +3085,7 @@ pub struct RunArgs {
|
||||||
/// Optional dependencies are defined via `project.optional-dependencies` in a `pyproject.toml`.
|
/// Optional dependencies are defined via `project.optional-dependencies` in a `pyproject.toml`.
|
||||||
///
|
///
|
||||||
/// This option is only available when running in a project.
|
/// This option is only available when running in a project.
|
||||||
#[arg(long, conflicts_with = "extra")]
|
#[arg(long, conflicts_with = "extra", conflicts_with = "only_group")]
|
||||||
pub all_extras: bool,
|
pub all_extras: bool,
|
||||||
|
|
||||||
/// Exclude the specified optional dependencies, if `--all-extras` is supplied.
|
/// Exclude the specified optional dependencies, if `--all-extras` is supplied.
|
||||||
|
|
@ -3396,7 +3396,7 @@ pub struct SyncArgs {
|
||||||
///
|
///
|
||||||
/// Note that all optional dependencies are always included in the resolution; this option only
|
/// Note that all optional dependencies are always included in the resolution; this option only
|
||||||
/// affects the selection of packages to install.
|
/// affects the selection of packages to install.
|
||||||
#[arg(long, conflicts_with = "all_extras", value_parser = extra_name_with_clap_error)]
|
#[arg(long, conflicts_with = "all_extras", conflicts_with = "only_group", value_parser = extra_name_with_clap_error)]
|
||||||
pub extra: Option<Vec<ExtraName>>,
|
pub extra: Option<Vec<ExtraName>>,
|
||||||
|
|
||||||
/// Select the output format.
|
/// Select the output format.
|
||||||
|
|
@ -3410,7 +3410,7 @@ pub struct SyncArgs {
|
||||||
///
|
///
|
||||||
/// Note that all optional dependencies are always included in the resolution; this option only
|
/// Note that all optional dependencies are always included in the resolution; this option only
|
||||||
/// affects the selection of packages to install.
|
/// affects the selection of packages to install.
|
||||||
#[arg(long, conflicts_with = "extra")]
|
#[arg(long, conflicts_with = "extra", conflicts_with = "only_group")]
|
||||||
pub all_extras: bool,
|
pub all_extras: bool,
|
||||||
|
|
||||||
/// Exclude the specified optional dependencies, if `--all-extras` is supplied.
|
/// Exclude the specified optional dependencies, if `--all-extras` is supplied.
|
||||||
|
|
@ -4247,11 +4247,11 @@ pub struct ExportArgs {
|
||||||
/// Include optional dependencies from the specified extra name.
|
/// Include optional dependencies from the specified extra name.
|
||||||
///
|
///
|
||||||
/// May be provided more than once.
|
/// May be provided more than once.
|
||||||
#[arg(long, conflicts_with = "all_extras", value_parser = extra_name_with_clap_error)]
|
#[arg(long, conflicts_with = "all_extras", conflicts_with = "only_group", value_parser = extra_name_with_clap_error)]
|
||||||
pub extra: Option<Vec<ExtraName>>,
|
pub extra: Option<Vec<ExtraName>>,
|
||||||
|
|
||||||
/// Include all optional dependencies.
|
/// Include all optional dependencies.
|
||||||
#[arg(long, conflicts_with = "extra")]
|
#[arg(long, conflicts_with = "extra", conflicts_with = "only_group")]
|
||||||
pub all_extras: bool,
|
pub all_extras: bool,
|
||||||
|
|
||||||
/// Exclude the specified optional dependencies, if `--all-extras` is supplied.
|
/// Exclude the specified optional dependencies, if `--all-extras` is supplied.
|
||||||
|
|
|
||||||
|
|
@ -4467,3 +4467,55 @@ fn no_editable_env_var() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn export_only_group_and_extra_conflict() -> 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 = []
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
test = ["pytest"]
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = ["ruff"]
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Using --only-group and --extra together should error.
|
||||||
|
uv_snapshot!(context.filters(), context.export().arg("--only-group").arg("dev").arg("--extra").arg("test"), @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: the argument '--only-group <ONLY_GROUP>' cannot be used with '--extra <EXTRA>'
|
||||||
|
|
||||||
|
Usage: uv export --cache-dir [CACHE_DIR] --only-group <ONLY_GROUP> --exclude-newer <EXCLUDE_NEWER>
|
||||||
|
|
||||||
|
For more information, try '--help'.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// Using --only-group and --all-extras together should also error.
|
||||||
|
uv_snapshot!(context.filters(), context.export().arg("--only-group").arg("dev").arg("--all-extras"), @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: the argument '--only-group <ONLY_GROUP>' cannot be used with '--all-extras'
|
||||||
|
|
||||||
|
Usage: uv export --cache-dir [CACHE_DIR] --only-group <ONLY_GROUP> --exclude-newer <EXCLUDE_NEWER>
|
||||||
|
|
||||||
|
For more information, try '--help'.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -6039,3 +6039,55 @@ fn isolate_child_environment() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn run_only_group_and_extra_conflict() -> 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 = []
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
test = ["pytest"]
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = ["ruff"]
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Using --only-group and --extra together should error.
|
||||||
|
uv_snapshot!(context.filters(), context.run().arg("--only-group").arg("dev").arg("--extra").arg("test").arg("python").arg("-c").arg("print('hello')"), @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: the argument '--only-group <ONLY_GROUP>' cannot be used with '--extra <EXTRA>'
|
||||||
|
|
||||||
|
Usage: uv run --cache-dir [CACHE_DIR] --only-group <ONLY_GROUP> --exclude-newer <EXCLUDE_NEWER>
|
||||||
|
|
||||||
|
For more information, try '--help'.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// Using --only-group and --all-extras together should also error.
|
||||||
|
uv_snapshot!(context.filters(), context.run().arg("--only-group").arg("dev").arg("--all-extras").arg("python").arg("-c").arg("print('hello')"), @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: the argument '--only-group <ONLY_GROUP>' cannot be used with '--all-extras'
|
||||||
|
|
||||||
|
Usage: uv run --cache-dir [CACHE_DIR] --only-group <ONLY_GROUP> --exclude-newer <EXCLUDE_NEWER>
|
||||||
|
|
||||||
|
For more information, try '--help'.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -14093,3 +14093,55 @@ fn workspace_editable_conflict() -> Result<()> {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn only_group_and_extra_conflict() -> 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 = []
|
||||||
|
|
||||||
|
[project.optional-dependencies]
|
||||||
|
test = ["pytest"]
|
||||||
|
|
||||||
|
[dependency-groups]
|
||||||
|
dev = ["ruff"]
|
||||||
|
"#,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
// Using --only-group and --extra together should error.
|
||||||
|
uv_snapshot!(context.filters(), context.sync().arg("--only-group").arg("dev").arg("--extra").arg("test"), @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: the argument '--only-group <ONLY_GROUP>' cannot be used with '--extra <EXTRA>'
|
||||||
|
|
||||||
|
Usage: uv sync --cache-dir [CACHE_DIR] --only-group <ONLY_GROUP> --exclude-newer <EXCLUDE_NEWER>
|
||||||
|
|
||||||
|
For more information, try '--help'.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
// Using --only-group and --all-extras together should also error.
|
||||||
|
uv_snapshot!(context.filters(), context.sync().arg("--only-group").arg("dev").arg("--all-extras"), @r###"
|
||||||
|
success: false
|
||||||
|
exit_code: 2
|
||||||
|
----- stdout -----
|
||||||
|
|
||||||
|
----- stderr -----
|
||||||
|
error: the argument '--only-group <ONLY_GROUP>' cannot be used with '--all-extras'
|
||||||
|
|
||||||
|
Usage: uv sync --cache-dir [CACHE_DIR] --only-group <ONLY_GROUP> --exclude-newer <EXCLUDE_NEWER>
|
||||||
|
|
||||||
|
For more information, try '--help'.
|
||||||
|
"###);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue