docopt.rs
docopt.rs copied to clipboard
When repeated short and long =value flags are aliases, only one is deserialised
Sorry for the title... essentially when [-a... | --long-a=<val>] the value is only deserialised for the one specified in the struct. Contrast [-b | --bee] as Boolean flags, when the value of whichever is given is available as e.g. flag_bee; flag_b need not be specified.
Here's a reproduction:
[dependencies]
docopt = { version = "1.0.1"}
log = {version = "0.4.5"}
serde = { version = "1.0.76" }
serde_derive = { version = "1.0.76" }
stderrlog = { version = "0.4.1"}
extern crate docopt;
#[macro_use]
extern crate log;
#[macro_use]
extern crate serde_derive;
extern crate stderrlog;
use docopt::Docopt;
const USAGE: &'static str = "
Reproduction.
Usage:
repro [-q | --quiet | -v... | --verbosity=<v>]
Options:
-q --quiet Disable stderr logging.
-v... --verbosity=<v> Verbosity of stderr logging.
";
#[derive(Debug, Deserialize)]
struct Args {
flag_quiet: bool,
flag_verbosity: usize,
}
fn main() {
let args: Args = Docopt::new(USAGE)
.and_then(|d| d.deserialize())
.unwrap_or_else(|e| e.exit());
println!("{:?}", args);
stderrlog::new()
.module(module_path!())
.quiet(args.flag_quiet)
.timestamp(stderrlog::Timestamp::Second)
.verbosity(args.flag_verbosity)
.init()
.unwrap();
trace!("trace message");
debug!("debug message");
info!("info message");
warn!("warn message");
error!("error message");
}
Then:
$ cargo run -- --verbosity=2
Args { flag_quiet: false, flag_verbosity: 2 }
2018-09-03T20:50:56+01:00 - INFO - info message
2018-09-03T20:50:56+01:00 - WARN - warn message
2018-09-03T20:50:56+01:00 - ERROR - error message
so far so good.
$ cargo run -- -vvv
Args { flag_quiet: false, flag_verbosity: 0 }
2018-09-03T20:51:43+01:00 - ERROR - error message
Not so good. I thought maybe the issue was using the short while deserialising the long name, but:
$ cargo run -- -q
Args { flag_quiet: true, flag_verbosity: 0 }
so it does appear to be the interaction between ... and =<v>.
Less-than-ideal workaround with particular respect to integer flags, just in case someone stumbles here with a similar use case:
- separate lines in
Options - add
flag_v: usize,toArgs .verbosity(args.flag_verbosity + args.flag_v)(since docopt takes care of at most one being non-zero)
I don't think this is a bug. A flag can't both simultaneously accept a value and be a countable switch AFAIK.
Thanks for the fast response. I could readily accept that, when you put it like that, but it does seem to work in the Python implementation.
See here - not allowed both, but works when you delete one or other.
Of course, the python implementation (and by extension the online thing) differ in not having serde build a struct of args and flags.
So I suppose it's really a question for you & team whether it should be allowed or not.
If I may advocate for my desired behaviour: I'd say it's consistent with:
-q --quiet Be quiet.
implying that either flag can be used and be accessible on Args#<either>.
Supporting it would of course mean that it'd only work for integer value flags; not a mix of countable switch and string flag, for example.
Feel free to close if not something you want to support, understood.