Skip to content

ArgMatches.grouped_values_of() does not support groups #4372

@etemesi254

Description

@etemesi254

Please complete the following tasks

Rust Version

rustc 1.65.0-nightly (20ffea693 2022-08-11)

Clap Version

4.0.13

Minimal reproducible code

use clap::{Arg, ArgAction, Command};

fn build_cli() -> Command {
    Command::new("myprog")
        .arg(Arg::new("exec")
            .short('x')
            .group("gf")
            .action(ArgAction::Append)
        ).arg(Arg::new("vr")
            .short('f')
            .action(ArgAction::Append)
            .group("gf")
    )
}
#[test]
fn test_cli(){
    build_cli().debug_assert();
}
fn main() {
    let m = build_cli()
        .get_matches_from(vec![
            "myprog", "-x", "=g"]);
    let vals: Vec<Vec<&str>> = m.grouped_values_of("gf").unwrap().collect();
    println!("{:?}", vals);
}

Steps to reproduce the bug with the above code

cargo run

Actual Behaviour

thread 'main' panicked at 'Must use _os lookups with Arg::allow_invalid_utf8', /rustc/20ffea6938b5839c390252e07940b99e3b6a889a/library/core/src/ops/function.rs:164:5

Expected Behaviour

  • It should return argument + value passed.

I might have mis-understood the docs but it does mention in the panic section and quoting

Panics
If the value is invalid UTF-8.
If id is not a valid argument or group id.

Hence I assume it should work with groups.

It does actually parse groups i.e

if let Some(counts) = args.grouped_values_of("group_counts") {     
            println!("{:?}",counts.len());
           // works
            for op in operations{
}

Prints actual number of arguments for that group but the panic comes when looping, and it corresponds to

#[cfg(feature = "unstable-grouped")]
#[cfg_attr(debug_assertions, track_caller)]
#[inline]
fn unwrap_string(value: &AnyValue) -> &str {
    match value.downcast_ref::<String>() {
        Some(value) => value,
        None => {
            panic!("Must use `_os` lookups with `Arg::allow_invalid_utf8`",)
        }
    }
}

Part of the code

Additional Context

Also ArgMatches::grouped_values_of doesn't work with Action::SetTrue arguments.

Thanks for the library btw

Debug Output

[ clap::builder::command] Command::_do_parse
[ clap::builder::command] Command::_build: name="myprog"
[ clap::builder::command] Command::_propagate:myprog
[ clap::builder::command] Command::_check_help_and_version:myprog expand_help_tree=false
[ clap::builder::command] Command::long_help_exists
[ clap::builder::command] Command::_check_help_and_version: Building default --help
[ clap::builder::command] Command::_propagate_global_args:myprog
[clap::builder::debug_asserts] Command::_debug_asserts
[clap::builder::debug_asserts] Arg::_debug_asserts:exec
[clap::builder::debug_asserts] Arg::_debug_asserts:vr
[clap::builder::debug_asserts] Arg::_debug_asserts:help
[clap::builder::debug_asserts] Command::_verify_positionals
[ clap::parser::parser] Parser::get_matches_with
[ clap::parser::parser] Parser::get_matches_with: Begin parsing 'RawOsStr("-x")' ([45, 120])
[ clap::parser::parser] Parser::possible_subcommand: arg=Ok("-x")
[ clap::parser::parser] Parser::get_matches_with: sc=None
[ clap::parser::parser] Parser::parse_short_arg: short_arg=ShortFlags { inner: RawOsStr("x"), utf8_prefix: CharIndices { front_offset: 0, iter: Chars(['x']) }, invalid_suffix: None }
[ clap::parser::parser] Parser::parse_short_arg:iter:x
[ clap::parser::parser] Parser::parse_short_arg:iter:x: Found valid opt or flag
[ clap::parser::parser] Parser::react action=SetTrue, identifier=Some(Short), source=CommandLine
[ clap::parser::parser] Parser::react: has default_missing_vals
[ clap::parser::parser] Parser::remove_overrides: id="exec"
[ clap::parser::arg_matcher] ArgMatcher::start_custom_arg: id="exec", source=CommandLine
[ clap::builder::command] Command::groups_for_arg: id="exec"
[ clap::parser::arg_matcher] ArgMatcher::start_custom_arg: id="gf", source=CommandLine
[ clap::parser::parser] Parser::push_arg_values: ["true"]
[ clap::parser::parser] Parser::add_single_val_to_arg: cur_idx:=1
[ clap::builder::command] Command::groups_for_arg: id="exec"
[ clap::parser::parser] Parser::get_matches_with: After parse_short_arg ValuesDone
[ clap::parser::parser] Parser::add_defaults
[ clap::parser::parser] Parser::add_defaults:iter:exec:
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:exec: has default vals
[ clap::parser::parser] Parser::add_default_value:iter:exec: was used
[ clap::parser::parser] Parser::add_defaults:iter:vr:
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:vr: doesn't have default vals
[ clap::parser::parser] Parser::add_defaults:iter:help:
[ clap::parser::parser] Parser::add_default_value: doesn't have conditional defaults
[ clap::parser::parser] Parser::add_default_value:iter:help: doesn't have default vals
[ clap::parser::validator] Validator::validate
[ clap::parser::validator] Validator::validate_conflicts
[ clap::parser::validator] Validator::validate_exclusive
[ clap::parser::validator] Validator::validate_exclusive:iter:"exec"
[ clap::parser::validator] Validator::validate_exclusive:iter:"gf"
[ clap::parser::validator] Validator::validate_conflicts::iter: id="exec"
[ clap::parser::validator] Conflicts::gather_conflicts: arg="exec"
[ clap::builder::command] Command::groups_for_arg: id="exec"
[ clap::parser::validator] Conflicts::gather_direct_conflicts id="exec", conflicts=[]
[ clap::parser::validator] Conflicts::gather_direct_conflicts id="gf", conflicts=[]
[ clap::parser::validator] Conflicts::gather_conflicts: conflicts=[]
[ clap::parser::validator] Validator::validate_required: required=ChildGraph([])
[ clap::parser::validator] Validator::gather_requires
[ clap::parser::validator] Validator::gather_requires:iter:"exec"
[ clap::parser::validator] Validator::gather_requires:iter:"gf"
[ clap::parser::validator] Validator::gather_requires:iter:"gf":group
[ clap::parser::validator] Validator::validate_required: is_exclusive_present=false
[ clap::parser::arg_matcher] ArgMatcher::get_global_values: global_arg_vec=[]

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-parsingArea: Parser's logic and needs it changed somehow.C-bugCategory: bugS-waiting-on-designStatus: Waiting on user-facing design to be resolved before implementing

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions