clap
clap copied to clipboard
#[command(flatten)] on optional field makes it required
Please complete the following tasks
- [X] I have searched the discussions
- [X] I have searched the open and rejected issues
Rust Version
1.72
Clap Version
4.3.4
Minimal reproducible code
use clap::{Args, Parser};
fn main() {
MainArgs::parse();
}
#[derive(Parser, Debug)]
pub struct MainArgs {
#[arg(short = 'V', long)]
pub version: bool,
#[command(flatten)]
pub specific_args: Option<SpecificArgs>,
}
#[derive(Args, Debug)]
pub struct SpecificArgs {
pub positional: String,
}
Steps to reproduce the bug with the above code
cargo r -- --version
Actual Behaviour
error: the following required arguments were not provided:
<POSITIONAL>
Usage: test-executable --version <POSITIONAL>
For more information, try '--help'.
Expected Behaviour
No error because the SpecificArgs is optional.
Additional Context
I want to use this to have a top level Parser with a few global args (e.g. --version but also some others), and I want to reuse this across different CLI tools, each with their own ConcreteArgs. The ConcreteArgs are usually written as mandatory in their corresponding #[derive(Args)] parser, but they should only be mandatory if none of the global flags are present. To do this, I made SpecificArgs optional in the #[command(flatten)] but that doesn't seem to have the intended effect.
Similar discussion: https://github.com/clap-rs/clap/discussions/4954
Debug Output
No response
We have a discrepancy in how we treat Option between Arg (required, no required) and ArgGroup (no-op, track whether present).
A lot of this depends on how people are using an ArgGroup
- Composing structs: lack of
Optionshouldn't mean anything - Require or don't require an
ArgGroup - Override required Args within an
ArgGroup(what this issue wants
Can we pick a one-size-fits all option? If not, how do we allow variability of this?
Is there a workaround?
The way to workaround this heavily depends on your use case. If you want one argument to be present when the group is, you can use ArgGroup::requires.
As an example, let's take the reproduction case and change it to use that:
use clap::{Args, Parser};
fn main() {
MainArgs::parse();
}
#[derive(Parser, Debug)]
pub struct MainArgs {
#[arg(short = 'V', long)]
pub version: bool,
#[command(flatten)]
pub specific_args: Option<SpecificArgs>,
}
#[derive(Args, Debug)]
#[group(requires = "positional")]
pub struct SpecificArgs {
#[arg(required = false)]
pub positional: String,
}
SpecificArgs will only be instantiated if the group is present and if the group is present then positional must be present as well, so you can skip using Option for it and just override the default required = true with required = false.