-
Notifications
You must be signed in to change notification settings - Fork 431
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ArgGroup with optional positional parameters #1384
Comments
I am looking into this issue. @mattjlewis being relatively new to picoCLI, to clarify, is this a bug or new functionality? I want to make sure I understand as I dig into this. Currently both test files fail for me, is that expected? |
CliTest1 runs without issues for me. For CliTest2, I am getting the following error message:
@mattjlewis, @kurtkaiser This looks like a bug; when all required elements of a group have been matched, there is some parser logic to determine whether a newly encountered parameter should start a new group or should be added to the group that is "in progress". It looks like the parser makes the wrong decision and creates a new group. When all args have been parsed, the parser thinks 3 separate occurrences of the group have been matched and decides that the input is invalid because the group is defined as multiplicity=1 (max one occurrence). The logic in this method: I added a test |
Thanks @remkop, I have modified how I am running the application and can now replicate what you see. It has taken a bit to understand the application, even watched a few YouTube videos in foreign languages. I am trying to understand the different behavior ocurring between the two test files. Not sure I comprehend the matching and so that is what I am looking at now. Hopefully I can get this bug taken care of, tips and good vibes are appreciated. |
@kurtkaiser Thanks for spending the time to look into this. Good vibes are going your way! 📡 Not sure if this constitutes as a tip, but here is some background: 😅 Groups can have required and optional elements. The parser will "start a new group" and add arguments to it when the previous group did not exist or was fully populated. The logic for determining whether a group is "fully populated" is different for options and positional parameters. For positional parameters, the intention was to allow groups containing positional parameters. I don't think I considered the case where multiple positional parameters are optional or created tests for that prior to this issue. |
@remkop My understanding is when a positional parameter is optional and no value is passed it is given a fallback value, correct? Therefore it is expected that fallback values are used for each optional positional parameter? Or am I getting my wires crossed? Trying to nail down what I should expect versus the data I am seeing. By the way, this project/repo/picoCLI is ambitious, impressive. |
@kurtkaiser There is a difference between fallback values and default values. Fallback values pretty much only apply to named options (not to positional parameters): they are the value that is applied when the option name is specified on the command line, without an option parameter following the option name. So, assuming we are talking about default values, yes, if positional parameters have a default value, then that default value is applied when no value is specified for that positional parameter. However, argument groups are somewhat exceptional: if no element of the group was matched on the command line, then picocli will not instantiate the Does that answer your question? |
Thank you for looking into this. |
Been able to go through more of the documentation and spend time debugging this weekend. The idea of parsing and new group creation along with matching could be tripping me up. If "myCreateNewMatch" that will impact if a new group is created, correct? The idea of a match space is being evalulated and if sufficient it can match and be added. However, if last minimum element, if the arg block is full then a group must be created? If that is the case, group creation is not being referenced directly in canMatchPositionalParam, correct? IYou original and super helpful response referenced that method. @remkop thanks for all your input thus far. Also, if anyone curious, some of the debug logs I'm going through. |
Hi @kurtkaiser thanks for continuing the investigation! Are you interested in doing some pair debugging session, maybe using Code With Me? |
(Note to self) While doing a pair debugging session, @kurtkaiser and I noticed that the problem does not occur when the last positional parameter in the group is required: class OkGroup { // the problem does not occur with this group
@Parameters(index = "0", arity = "0..1") String param0; // optional
@Parameters(index = "1", arity = "0..1") String param1; // optional
@Parameters(index = "2", arity = "1") String param2; // required
} Also, we noticed that the cause of the problem seems related to the way positional parameters are processed in When the group is defined like this: class ProblemGroup { // the problem *does* occur with this group
@Parameters(index = "0", arity = "1") String param0; // required
@Parameters(index = "1", arity = "0..1") String param1; // optional
@Parameters(index = "2", arity = "0..1") String param2; // optional
} Suppose the input provided is Starting with the first argument, Next, During our debugging session we were running out of time at this point and did not look at possible solutions. |
The bug may be in However, for our group with only 1 required param and 2 optional params, this results in a total sum of 1 for this group. This is incorrect: we should be able to fit 3 positional parameters in this group. Changing the
|
Great details, I took last week off and plan to work more on the issue this week. |
When the bug appears, if the arg group has the last parameter as optional, the following line evaluates to true. Having done some debugging, boolean mayCreateNewMatch = !matches.isEmpty() && lastMatch().matchedMinElements(); The last match matchedMinElements evaluating to true is the issue, I am trying to hunt down how that gets set. |
@kurtkaiser I actually thought (maybe being overly optimistic), that the code change to the I was going to ask you to also take a look and see if you could find any edge case(s) where that fix would be insufficient. If I follow what you are saying correctly, you are saying that, even with that change, you have found a scenario that gives incorrect result? Can you give more details about that scenario (like a failing test)? |
Oh, I will test this, interesting. I had some concerns about edge cases and then got into the weeds as I went. |
PositionalParamSpec changed to max remkop#1384
I threw a bunch of stuff at this and didnt see edge cases. Not sure if needed but I just pr'ed with the branch I created to do this new round of testing. |
Perfect, thank you! |
PositionalParamSpec changed to max #1384
Multiple positional parameters, some of which have arity "0..1" work outside of an ArgGroup but not within. Example:
Test is run with e.g. "a b c".
I appreciate that I could use String[] with arity "1..3", but that doesn't fit my scenario - I have simplified the test case to reproduce the issue.
Things get even stranger when param0 is change to int (as per my scenario) - the numeric command line parameter gets dropped altogether when running with, e.g. "1 a b" with the ArgGroup example, but not the non-ArgGroup one.
Note I've read the limitations.
Test case attached.
test.zip
The text was updated successfully, but these errors were encountered: