-
-
Notifications
You must be signed in to change notification settings - Fork 1k
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
Optional positional arguments that get skipped if corresponding validation fails #2122
Comments
Might be related to #975 |
This is reminding me of #3035 Currently, value validation happens in a distinct phase. We are looking at modifying it so people are more likely to put in more type information, see #2683. Granted, relying on value validation can only work in fairly limited cases. Personally, I think I'd provide custom usage statements and parse as all I am curious how HTTPie, an app built on argparse, is doing this. Understanding other parsers provides us opportunities to learn from others rather than reinvent the wheel. |
Yes. In the end, we ended up with something like that #[derive(StructOpt, Debug)]
#[structopt(
name = "xh",
long_version = long_version(),
settings = &[
AppSettings::AllArgsOverrideSelf,
],
)]
pub struct Cli {
/// HTTP version to use
#[structopt(long, value_name = "VERSION", possible_values = &["1", "1.0", "1.1", "2"])]
pub http_version: Option<HttpVersion>,
/// The request URL, preceded by an optional HTTP method.
///
/// METHOD can be `get`, `post`, `head`, `put`, `patch`, `delete` or `options`.
/// If omitted, either a GET or a POST will be done depending on whether the
/// request sends data.
/// {n}{n}{n}
#[structopt(value_name = "[METHOD] URL")]
raw_method_or_url: String,
/// Optional key-value pairs to be included in the request
///
/// - key==value to add a parameter to the URL
/// - key=value to add a JSON field (--json) or form field (--form)
/// - key:=value to add a complex JSON value (e.g. `numbers:=[1,2,3]`)
/// - key@filename to upload a file from filename (with --form)
/// - @filename to use a file as the request body
/// - header:value to add a header
/// - header: to unset a header
/// - header; to add a header with an empty value
///
/// A backslash can be used to escape special characters (e.g. weird\:key=value).
#[structopt(value_name = "REQUEST_ITEM", verbatim_doc_comment)]
raw_rest_args: Vec<String>,
/// The HTTP method, if supplied.
#[structopt(skip)]
pub method: Option<Method>,
/// The request URL.
#[structopt(skip = ("http://placeholder".parse::<Url>().unwrap()))]
pub url: String,
/// Optional key-value pairs to be included in the request.
#[structopt(skip)]
pub request_items: RequestItems,
} Notice how pub fn from_iter_safe<I>(iter: I) -> clap::Result<Self>
where
I: IntoIterator,
I::Item: Into<OsString> + Clone,
{
let mut app = Self::clap();
let matches = app.get_matches_from_safe_borrow(iter)?;
let mut cli = Self::from_clap(&matches);
let mut rest_args = mem::take(&mut cli.raw_rest_args).into_iter();
let raw_url = match parse_method(&cli.raw_method_or_url) {
Some(method) => {
cli.method = Some(method);
rest_args.next().ok_or_else(|| {
Error::with_description("Missing URL", ErrorKind::MissingArgumentOrSubcommand)
})?
}
None => {
cli.method = None;
mem::take(&mut cli.raw_method_or_url)
}
};
for request_item in rest_args {
cli.request_items.items.push(request_item.parse()?);
}
} This is the file that contains all sorts of workarounds around structopt/clap: https://github.com/ducaale/xh/blob/master/src/cli.rs |
Describe your use case
I am trying re-implement HTTPie cli using clap-rs/structopt. I would like to have something like this
where
METHOD
is an optional positional arg enum with a default valueDescribe the solution you'd like
It would be good if clap-rs allowed multiple optional positional arguments that get filled with a default value whenever the corresponding value fails to parse. For example, if we had:
where:
arg1
has a type ofenum Arg1 { Foo, Bar }
and defaults toArg1::Bar
arg2
has a type ofu32
and defaults to 0arg3
has a type ofVec<String>
a user can use the CLI app in the following ways:
test.exe
:arg1
=default_value
,arg2
=default_value
,arg3
=default_value
test.exe foo
:arg1
=foo
,arg2
=default_value
,arg3
=default_value
test.exe 1
:arg1
=default_value
,arg2
=1
,arg3
=default_value
test.exe hello
:arg1
=default_value
,arg2
=default_value
,arg3
=[hello]
test.exe foo hello
:arg1
=foo
,arg2
=default_value
,arg3
=[hello]
Alternatives, if applicable
I tried using the following but they didn't fit my use case:
AllowMissingPositional
can only be used when the last positional argument is requiredAdditional context
#2120
The text was updated successfully, but these errors were encountered: