-
Notifications
You must be signed in to change notification settings - Fork 423
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
Customize value assigned when option specified without value #280
Comments
Any chance to have this in 2.x release ? |
I have very little time so I need to focus on the 3.0 stream. I’m planning to only do 2.x releases if there’s a bug to be fixed. For this feature request, I’m not ready to commit to any of the potential solutions I’ve seen/thought of so far. It often happens that feedback or questions from other users result in ideas for solving different existing tickets so (hoping that this will happen here also) I’m going to give this one some time. My understanding is that the solution for #279 solves your immediate requirement so I didn’t think this was urgent. Is my understanding correct? |
Hi, that could work but I still feel it more like a workaround. I'm planning to migrate nextflow to picocli, but I would like to do that when it provides all features needed. However no hurry, just wanted to know what's the status of this, and thanks for this nice piece of software. |
Hi there, I was thinking something like this. How that sounds to you ? |
I'm open to this in principle but I have a few concerns:
|
Hi, I've read #261 and frankly I've no understood what Anyhow in this case I think I will keep using the fork and wait to see how the project evolve. |
#261 raised a good point that options annotated with So the idea was born to introduce a With the field default value it is not always possible to tell wether the field value was intended as a default or not. |
I've been thinking about a good name. ... I found these discussions for the same feature request in a different CLI parser:
Some possible names from that discussion: "tri-state option", "smart default", "optional argument for switches", "option without value" Looking at your original description
Perhaps |
Frankly, adding two extra settings ( I would just leave the user the choice to use primitive and non-primitive types accordingly:
|
Until recently I was reluctant to provide any picocli functionality for default values (see https://github.com/remkop/picocli/wiki/picocli-vs-JCommander#picocli-is-simpler-than-jcommander). #261 convinced me that at least a |
For 2.x, would it be possible to pass an empty string to ITypeConverter when no value is present? |
Hi @jesselong, yes, #279 was included in picocli-2.3 so that is already available. |
@jesselong Ah yes, I see what you mean now. I will fix this on master so it will be in the next 3.0-alpha release, which will likely be soon. I am iterating rapidly with the 3.0 stream to get #258 ready in time for the Groovy 2.5 release. The 3.0 stream is my main focus now, and I won't be able to do a 2.3 release for this. @pditommaso would Jesse's idea to use a custom converter for empty values meet your requirement? If not I will create another ticket to fix the problem Jesse pointed out, and keep this ticket open. |
Basically the idea is to use a |
Yes. Would that work for you, or should we keep this ticket open? |
It could be a workaround, but still thinking that a proper annotation would be a much better solution here. |
Ok, then we'll keep this ticket open. I created #325 for Jesse's suggestion. |
This feature turns out to be more popular than I thought: #490 is the 3rd time this is requested. Planning to implement this in picocli 3.7. As for the name for this attribute, I'm currently thinking either |
|
Perhaps |
What's the difference between |
A default value can be specified by
Examples:
|
The |
Interesting idea to introduce a new type for this. Thinking out loud a bit to explore this... Client code would look something like this: class App implements Runnable {
@Option(names = "-x")
OptionalValue<Integer> x = OptionalValue.empty(); // value=null, implicitValue=null
@Option(names = "-y")
OptionalValue<Integer> y = OptionalValue.of(123); // value=123, implicitValue=null
@Option(names = "-z")
OptionalValue<Integer> z = // value=123, implicitValue=345
OptionalValue.of(123).withImplicitValue(345);
public void run() {
if (x.isMatchedWithoutValue()) {
doStuffWithImplicitValue(x.get());
} else {
doStuffWithSpecifiedValue(x.get());
}
}
}
public static class OptionalValue<T> {
private T value;
private T implicitValue;
private boolean matchedWithoutValue;
private OptionalValue(T value) { this.value = value; }
private OptionalValue(T value, T implicitValue) {
this.value = value; this.implicitValue = implicitValue;
}
// invoked by picocli when parser matched option with a value,
// or when option was annotated with @Option(defaultValue = "...")
void matchedValue(T matchedValue) { value = matchedValue; }
// invoked by picocli when parser matched option without value
void matchedWithoutValue() { matchedWithoutValue = true; }
// public API
public static <T> OptionalValue<T> empty() { return of((T) null); }
public static <T> OptionalValue<T> of(T value) { return new OptionalValue<T>(value); }
public OptionalValue<T> withImplicitValue(T implicit) {
return new OptionalValue<T>(this.value, implicit);
}
public boolean isMatchedWithoutValue() { return matchedWithoutValue; }
public T get() { return matchedWithoutValue ? implicitValue : value; }
public T getMatchedValue() { return value; }
public T getImplicitValue() { return implicitValue; }
} Thoughts? |
This looks good to me! Does this interact with arity at all? E.g., would you need to say something like
Not that it's important (to me) to support that in the first version if it's not easy. |
Very good point. The above In the current version of picocli (3.6.1), only single-value options allow you to distinguish between the option not being specified (value = default value) and option specified without a value (value is empty string). This example demonstrates the current behaviour (without class Current implements Runnable {
@Option(names = "-x", arity = "0..*")
String single
@Option(names = "-s", arity = "0..*")
String[] strings
@Option(names = "-l", arity = "0..*")
List<String> list
@Option(names = "-m", arity = "0..*")
Map<String,String> map
public static void main(String[] args) {
println args
CommandLine.run(new Current(), args)
}
@Override
void run() {
println "single value=$single"
println "array=$strings"
println "list=$list"
println "map=$map"
}
} Current result:
Note that for multi-value options, when the option is specified without a value, simply nothing is added to the array/collection/map, so the application cannot detect whether the option was specified without a value. With class After implements Runnable {
@Option(names = "-x", arity = "0..*")
OptionalValue<String> single = OptionalValue.of(null).withImplicit("X")
@Option(names = "-s", arity = "0..*")
OptionalValue<String[]> strings = OptionalValue.of(null).withImplicit(new String[]{"S", "T"})
@Option(names = "-l", arity = "0..*")
OptionalValue<List<String>> list = OptionalValue.of(null).withImplicit(Arrays.asList("L", "M"))
@Option(names = "-m", arity = "0..*")
OptionalValue<Map<String,String>> strings =
OptionalValue.of(null).withImplicit(["KEY1":"VAL1", "KEY2":"VAL2"])
public static void main(String[] args) {
println args
CommandLine.run(new After(), args)
}
@Override
void run() {
println "single value=$single"
println "array=$strings"
println "list=$list"
println "map=$map"
}
} Expected result (for the same input):
Thoughts? |
For some aspect is tempting but thinking twice IMO it appears to me over engineered and would require the use of picocli domain classes in the application logic. It would be better to keep an annotation only approach. I would take a simpler approach, add the Also it would be important to support the implicit flag for field having aritiy > 1. |
In my view, this complexity is needed in this case -- as it is now, I have to inject the Perhaps a compromise would be to support both: @remkop That behavior for collections looks reasonable to me. To be clear, I don't have an immediate need for this ability, so if you'd rather leave it for a future release, that would be ok with me. But if it's not too difficult to include, it would be a more complete implementation. |
This issue has been sitting here too long, waiting for a decision... :-) A simple annotation attribute ( The Applications that do need to know this can find out via the About naming: I've looked at prior art and found very little, but lisp CLON supports this feature and calls it the From the CLON documentation on value sources:
Difference with CLON: in CLON, when an option’s argument is optional, the option is required to provide at least a fallback or a default value. If no fallback value is specified the default value is assigned. Picocli will behave differently:
I will also take a look at what is involved in assigning the fallback value for multi-value options with |
This sounds good to me! |
…gn this value when the option was specified on the command line without parameter.
This is now in master. Please verify whether this meets your needs. The user manual is updated here and here. From the release notes:
|
I also added support for multi-value options (array, List and Map type annotated elements). |
@pditommaso , @marinier it would be great if you could verify that this meets your requirements. |
This looks great. Thank you! |
@pditommaso, @jesselong, @marinier Sorry it took so long. 😓 |
@pditommaso picocli 4.0 GA was released in July with support for this feature: There's also a bunch of other new features in picocli 4.0 that may be of interest: mutually exclusive options, co-dependent options, repeating argument groups, variable expansion, a cleaner API for executing commands with better exit code support, and more. If there are any other blockers to migrating the Nextflow CLI to picocli, please let me know. |
Hi Remko, thanks for keeping me updated on this. I'll explore these new features at my earliest convenience. |
The goal of the feature request is to provide the ability to specify a custom value to be used when a command line option is specified without any value.
See #279.
The text was updated successfully, but these errors were encountered: