question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Mixing multiplicity or required + non-required options in an exclusive ArgGroup gives unexpected results

See original GitHub issue

Related to #870

Tested with latest master. Using multiplicity=“0…*” and exclusive = true with an ArgGroup, or exclusive = true with an ArgGroup that has both optional and required parameters gives unexpected results.

class Group {
    @Option(names = "--name", required = true) String name;
    @Option(names = "--id", required = true) String id;
    @Option(names = "--opt") String opt;
}

@ArgGroup(exclusive = true, multiplicity = "0..*") List<Group> groups;
  1. cli --opt=1 results in one group: {name=null, opt=1}. Even though no required options are provided, validation passes.

  2. cli --name=foo --opt=1 gives Error: --name=<name>, --opt=<opt> are mutually exclusive (specify only one). Even though --opt is optional, it’s still exclusive with --name.

  3. cli --opt=1 --name=foo works and results in [{name=null, opt=1},{name=foo, opt=null}]. Whoa, switching the arg order makes it work? It still seems to be exclusive, but for some reason now it knows to create a second group.

  4. cli --name=foo --id=bar gives Error: --name=<name>, --id=<id> are mutually exclusive (specify only one). This seems like a bug. Those should be two valid groups, right? {name=foo, id=null} and {name=null, id=bar}? Why doesn’t it create a second group now?

I’d think, either (1) only the required arguments are exclusive, and it’s still an error to specify an ArgGroup option without exactly one of the required args, as in #870, or maybe (2) picocli should just immediately error out if using non-required options w/ exclusive = True. I’m leaning heavily toward (1).

In general, I think the logic should be:

(1) Attempt to fit an arg into the previous group, unless it makes the group invalid. * (2) If a new arg cannot be fit into the previous group, start a new group with it, and validate the (now completed) previous group. (3) Now that a new group is started, check if the new number of groups > max multiplicity. (4) exclusive simply changes the validation of required options in a group. exclusive=true means exactly 1 of the required options per group, and exclusive=false means all of the required options per group. Not specifying any required options should always be invalid.

Max multiplicity=1 can be a special case, where we know not to start a new group so the error message is clearer: “–foo, --bar are mutually exclusive”

* Consider making it so that only required args can start a new group. Optional args would always be pushed into the previous group, triggering a validation error if, for example, providing too many of that optional arg, and it would be illegal to start with an optional arg. This makes it always obvious which group an optional arg belongs to: cli --req --opt --opt --req --req --opt --req -> always {req, opt, opt}, {req}, {req, opt}, {req}. Currently, it’s {req, opt}, {opt, req}, {req, opt}, {req} if opt is singular, but {req, opt, opt}, {req}, {req, opt}, {req} if opt is repeatable.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:6 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
remkopcommented, Nov 29, 2019

@hanslovsky I suspect that Paintera is a good use case for repeating subcommands. #454 is on the todo list for picocli 4.2.

@wjohnson5 sorry for my late reply, I had other commitments that took my time. Looking at it again now, I have trouble wrapping my head around it all…

In the context of mutually dependent groups (where all options must co-occur), the notion of optional and required options makes sense. It is useful to be able to define a group as (-a -b [-c])... so that both -a -b -c and -a -b are valid on the command line, but not -a -c for example.

However, what does it mean if an option is not required in an exclusive group? Using the corresponding example: (-a | -b | [-c])..., what behaviour are we trying to achieve by defining the group this way?

I think the simplest thing to do, both from an implementation/maintenance perspective, but also from a usability perspective, is to make all options required in exclusive groups. To ease migration, we can silently make the default to be required=true in exclusive groups, and throw an InitializationException for options that are explicitly defined as required=false in exclusive groups. (The annotation processor can make this a compilation error.)

The example you mention in example 4 looks like a bug. If the max multiplicity is greater than 1, a new group should be created for each option in the exclusive group.

1reaction
wjohnson5commented, Nov 20, 2019

No problem at all, please take your time! Again I really appreciate your work here 😃

Read more comments on GitHub >

github_iconTop Results From Across the Web

CommandLine.ArgGroup (picocli 4.7.0 API)
A Command may define one or more ArgGroups : a group of options, ... For a group of mutually exclusive arguments, making the...
Read more >
picocli : List<> Option, used in @ArgGroup, duplicated in short ...
In non-exclusive groups, options can be required or optional. Groups have a multiplicity . The default is multiplicity = "0..1" meaning the ...
Read more >
RELEASE-NOTES.md · fanwen/picocli - Gitee.com
... group are now automatically considered required , to prevent unexpected results when mixing required and non-required options in exclusive ArgGroups.
Read more >
CommandLine.ArgGroup (owl 21.0 API)
A Command may define one or more ArgGroups : a group of options, ... For a group of mutually exclusive arguments, making the...
Read more >
Picocli is a modern framework for building powerful, user ...
Unique features in picocli include support for negatable options, ... to prevent unexpected results when mixing required and non-required options in ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found