Clap: v3 App Options no longer work on subcommand arguments

Created on 8 May 2020  路  5Comments  路  Source: clap-rs/clap

Make sure you completed the following tasks

  • [x] Searched the discussions
  • [x] Searched the closes issues

Code

use clap::{App, Arg, AppSettings};

fn main() {
    let cli = App::new("foo")
        .setting(AppSettings::SubcommandRequired)
        .arg(Arg::with_name("v")
                .short('v')
                .multiple(true)
                .about("Sets the level of verbosity"))
        .subcommand(App::new("bar")
                .arg(Arg::with_name("baz")
                        .long("baz")
                    )).get_matches();

    let log_level = cli.occurrences_of("v");
    println!("{}", log_level);
    if let Some(bar) = cli.subcommand_matches("bar") {
        if bar.is_present("baz") {
            println!("Hello World");
        }
    }
}

### Steps to reproduce the issue 1. Run `cargo run -- -v bar --baz` error: Found argument '--baz' which wasn't expected, or isn't valid in this context ### Version * **Rust**: rustc 1.44.0-nightly * **Clap**: master ### Actual Behavior Summary 1. Run `cargo run -- bar` = 0 (expected) 2. Run `cargo run -- bar --baz` = 0 Hello World (expected) 3. Run `cargo run -- -v bar` = 1 (expected) 4. Run `cargo run -- -v bar --baz` error: Found argument '--baz' which wasn't expected, or isn't valid in this context I'm using clap-rs in https://github.com/publicarray/BunnyCLI ### Expected Behavior Summary From run number 4 the output should be:
1
Hello World
### Additional context ### Debug output Compile clap with `debug` feature:
[dependencies]
clap = { version = "*", features = ["debug"] }
The output may be very long, so feel free to link to a gist or attach a text file
Debug Output


     Running `target/debug/my-test -v bar --baz`
[            clap::build::app]  App::_do_parse
[            clap::build::app]  App::_build
[            clap::build::app]  App::_derive_display_order:foo
[            clap::build::app]  App::_derive_display_order:bar
[            clap::build::app]  App::_create_help_and_version
[            clap::build::app]  App::_create_help_and_version: Building --help
[            clap::build::app]  App::_create_help_and_version: Building --version
[            clap::build::app]  App::_create_help_and_version: Building help
[            clap::build::app]  App::_debug_asserts
[            clap::build::arg]  Arg::_debug_asserts:v
[            clap::build::arg]  Arg::_debug_asserts:help
[            clap::build::arg]  Arg::_debug_asserts:version
[         clap::parse::parser]  Parser::get_matches_with
[         clap::parse::parser]  Parser::_build
[         clap::parse::parser]  Parser::_verify_positionals
[         clap::parse::parser]  Parser::get_matches_with: Begin parsing '"-v"' ([45, 118])
[         clap::parse::parser]  Parser::is_new_arg: "-v":NotFound
[         clap::parse::parser]  Parser::is_new_arg: arg_allows_tac=false
[         clap::parse::parser]  Parser::is_new_arg: - found
[         clap::parse::parser]  Parser::is_new_arg: starts_new_arg=true
[         clap::parse::parser]  Parser::possible_subcommand: arg="-v"
[         clap::parse::parser]  Parser::get_matches_with: possible_sc=false, sc=None
[         clap::parse::parser]  Parser::parse_short_arg: full_arg="-v"
[         clap::parse::parser]  Parser::parse_short_arg:iter:v
[         clap::parse::parser]  Parser::parse_short_arg:iter:v: Found valid opt or flag
[          clap::util::argstr]  ArgSplit::next: self=ArgSplit { sep: [118, 0, 0, 0], sep_len: 1, val: [118], pos: 0 }
[         clap::parse::parser]  Parser::parse_short_arg:iter:v: i=1, arg_os="v"
[         clap::parse::parser]  Parser::parse_opt; opt=v, val=None
[         clap::parse::parser]  Parser::parse_opt; opt.settings=ArgFlags(MULTIPLE_OCC | TAKES_VAL | DELIM_NOT_SET | MULTIPLE_VALS)
[         clap::parse::parser]  Parser::parse_opt; Checking for val...
[         clap::parse::parser]  None
[    clap::parse::arg_matcher]  ArgMatcher::inc_occurrence_of: arg=v
[    clap::parse::arg_matcher]  ArgMatcher::inc_occurrence_of: first instance
[         clap::parse::parser]  groups_for_arg: name=v
[         clap::parse::parser]  Parser::parse_opt: More arg vals required...
[         clap::parse::parser]  Parser::get_matches_with: After parse_short_arg Opt(v)
[         clap::parse::parser]  Parser::maybe_inc_pos_counter: arg = v
[         clap::parse::parser]  Parser::maybe_inc_pos_counter: is it positional?
[         clap::parse::parser]  No
[         clap::parse::parser]  groups_for_arg: name=v
[         clap::parse::parser]  Parser::get_matches_with: Begin parsing '"bar"' ([98, 97, 114])
[         clap::parse::parser]  Parser::is_new_arg: "bar":Opt(v)
[         clap::parse::parser]  Parser::is_new_arg: arg_allows_tac=false
[         clap::parse::parser]  Parser::is_new_arg: probably value
[         clap::parse::parser]  Parser::is_new_arg: starts_new_arg=false
[         clap::parse::parser]  Parser::add_val_to_arg; arg=v, val="bar"
[         clap::parse::parser]  Parser::add_val_to_arg; trailing_vals=false, DontDelimTrailingVals=false
[         clap::parse::parser]  Parser::add_single_val_to_arg: adding val..."bar"
[         clap::parse::parser]  groups_for_arg: name=v
[    clap::parse::arg_matcher]  ArgMatcher::needs_more_vals: o=v
[         clap::parse::parser]  Parser::get_matches_with: Begin parsing '"--baz"' ([45, 45, 98, 97, 122])
[         clap::parse::parser]  Parser::is_new_arg: "--baz":Opt(v)
[         clap::parse::parser]  Parser::is_new_arg: arg_allows_tac=false
[         clap::parse::parser]  Parser::is_new_arg: -- found
[         clap::parse::parser]  Parser::is_new_arg: starts_new_arg=true
[         clap::parse::parser]  Parser::parse_long_arg
[         clap::parse::parser]  Parser::parse_long_arg: Does it contain '='...
[         clap::parse::parser]  No
[         clap::parse::parser]  Parser::parse_long_arg: Didn't match anything
[         clap::parse::parser]  Parser::did_you_mean_error: arg=baz
[         clap::parse::parser]  Parser::did_you_mean_error: longs=["help", "version"]
[            clap::build::app]  App::_build
[            clap::build::app]  App::_derive_display_order:bar
[            clap::build::app]  App::_create_help_and_version
[            clap::build::app]  App::_create_help_and_version: Building --help
[            clap::build::app]  App::_create_help_and_version: Building --version
[            clap::build::app]  App::_debug_asserts
[            clap::build::arg]  Arg::_debug_asserts:baz
[            clap::build::arg]  Arg::_debug_asserts:help
[            clap::build::arg]  Arg::_debug_asserts:version
[         clap::output::usage]  Usage::create_usage_with_title
[         clap::output::usage]  Usage::create_usage_no_title
[         clap::output::usage]  Usage::create_smart_usage
[         clap::output::usage]  Usage::get_required_usage_from: incls=[v], matcher=false, incl_last=true
[         clap::output::usage]  Usage::get_required_usage_from:iter:v
[         clap::output::usage]  Usage::get_required_usage_from: ret_val=["-v ..."]
[            clap::build::app]  App::color: Color setting...
[            clap::build::app]  Auto
[           clap::output::fmt]  is_a_tty: stderr=true
error: Found argument '--baz' which wasn't expected, or isn't valid in this context

    Did you mean to put '--baz' after the subcommand 'bar'?

If you tried to supply `--baz` as a PATTERN use `-- --baz`

USAGE:
    my-test -v ...

For more information try --help



bug

All 5 comments

This is because bar is considered as a value for -v instead of subcommand. See https://github.com/clap-rs/clap/issues/1721, https://github.com/clap-rs/clap/issues/1031, and https://github.com/clap-rs/clap/pull/1834.

TL;DR: use SubcommandPrecedenceOverArg settings.

Personally, I would recommend you to redesign the CLI. This kind of "values vs subcommand" may cause more harm than goon in long term.

Thanks very @CreepySkeleton, that works nicely & Thanks for the advice. Any ideas on how to design it better ?

goon

I'm going to have some wine now 馃ぃ

Well, if you truly intend -v to take value, I recommend to go cargo --features "f1 f2" way. Can be achieved via value_delimiter(" ") and require_delimiter(true).

But I bet your intention was to allow multiple number of occurrences, not values. multiple(true) means _both_ multiple values (requiring at least one value) and multiple occurrences while you only need the latter. Use multiple_occurrences(true) and you'll live happily ever after.

goon

I must have been a comedian in a previous life, don't you think? Even when my mind isn't up to it, my muscle memory knows better and bony fingers hit the right button.

Unfortunately, I can't share the wine with you. Skeletons don't have much of taste, after all.

Thank you! I'm going to pick live happily ever after multiple_occurrences(true). Your comment does have lots of useful information and I did not find this in the manual. Maybe this can be included or maybe I need to get my eye sight checked.

Haha, well played..

True, You could give it go but it might stain your ribs: https://www.youtube.com/watch?v=1fzXmJyolfY&t=33

We are still working on changelog and documentation. You are not supposed to use v3 yet.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

CAD97 picture CAD97  路  21Comments

jojva picture jojva  路  18Comments

casey picture casey  路  25Comments

pickfire picture pickfire  路  21Comments

Licenser picture Licenser  路  25Comments