-
-
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
AppSettings::SubcommandsNegateReqs may cause panic in Clap::parse(), Clap::try_parse() #2255
Comments
What's the panic message you were getting? |
thread 'main' panicked at 'called |
Try changing to the following and describe what happens (with error message): #[clap(required = true)]
req_str: Option<String>, |
Definitely needs to be documented though. |
Oh wait. Haha, sorry. No it still panics. Sorry. $ cargo run -- ex-sub
|
It's probably better to find a way to get this working though. |
Huh, you haven't done |
This does not compile. #[clap(required = true)]
req_str: Option<String>,
this does compile but req_str is no longer required req_str: Option<String>
|
At the very least it might be a good idea to make a try_from_arg_matches() fn which can bubble up any issues so try_parse doesn't panic |
found this related issue in structopt repo TeXitoi/structopt#124 |
One of the challenges with clap-rs#2255 is for the user to discover whats going wrong. This helps by at least telling people how they got into a bad state and we can search for the code within the derive.
tl;dr
Did a quick update to this to clarify things for me use clap::AppSettings;
use clap::Clap;
use clap::FromArgMatches;
use clap::IntoApp;
#[derive(Debug, clap::Clap)]
#[clap(setting(AppSettings::SubcommandsNegateReqs))]
struct ExOpts {
req_str: String,
#[clap(subcommand)]
pub cmd: Option<SubCommands>,
}
#[derive(Debug, clap::Subcommand)]
enum SubCommands {
ExSub {
#[clap(short, long, parse(from_occurrences))]
verbose: u8,
},
}
fn main() {
// Reproduction cases
// - `cargo run -- ex-sub`
if true {
// We cant use Clap::parse or try_parse because we have SubcommandsNegateReqs enabled
// this would cause a panic when Clap attempts to parse the req_str arg that isn't there
let opts = ExOpts::parse(); // panics
let opts = ExOpts::try_parse(); // panics
} else {
// Instead we need to check to see if a subcommand exists before we run from_arg_matches on ExOpts
let matches = ExOpts::into_app().get_matches();
if matches.subcommand_name().is_none() {
// If no subcommand we can derive ExOpts
let opts = ExOpts::from_arg_matches(&matches);
println!("{:?}", opts);
} else {
// If subcommand we need derive the subcommands instead
let cmd_opts = SubCommands::from_arg_matches(&matches);
println!("{:?}", cmd_opts);
}
}
} The big problem is we have no way to instantiate If we switch to
There is no longer a panic but a field is no longer required! Clap will error though if you do #[derive(Debug, clap::Clap)]
#[clap(setting(AppSettings::SubcommandsNegateReqs))]
struct ExOpts {
#[clap(required = true)]
req_str: Option<String>,
#[clap(subcommand)]
pub cmd: Option<SubCommands>,
} with
Apparently, its not meaningless. I do however feel that we should have a non-panicing way of doing our derive but for a different use case. I maintain |
IMO the correct way forward here is to allow The hard hard becomes how do we detect that and not panic? Or rather, I'm OK with For now, that validation phase would only include a single check of is |
Just recording some thoughts in looking at the code. At the moment, the key signature here is fn from_arg_matches(matches: &ArgMatches) -> Option<Self>; The However, unless we start attaching stack traces to our errors, this will make debugging a development time issue pretty difficult (no indication of what is causing the failure). Maybe we should attach that as part of the |
Before there was no way to make `SubcommandsNegateReqs` with `clap_derive` because it required a required field with a sentinel value for when the required part was negated. We blocked that. This turned out simpler than I expected. This came out of the discussion for clap-rs#2255 but that issue is more specifically about the panic, so not closing it.
Before there was no way to make `SubcommandsNegateReqs` with `clap_derive` because it required a required field with a sentinel value for when the required part was negated. We blocked that. This turned out simpler than I expected. This came out of the discussion for clap-rs#2255 but that issue is more specifically about the panic, so not closing it.
Pulling this over from #2820
For the message "app should verify arg is required", all we know is something didn't work right and we expected a
We could a combination of
|
This message is emitted if the developer doesn't use an #[derive(Debug, Clap)]
#[clap(setting(AppSettings::SubcommandsNegateReqs))]
struct ExOpts {
#[clap(required = true)]
req_str: String,
#[clap(subcommand)]
pub cmd: Option<SubCommands>,
}
#[derive(Debug, Clap)]
enum SubCommands{
ExSub {
#[clap(short, long, parse(from_occurrences))]
verbose: u8
},
} Which is why I think the "you should verify arg is required" leaves one like....wut? 😄 |
I know its easy to miss but its "app", not "you", as in we expect we created the |
This is gated behind the `debug` feature flag so only explicit debugging cases pay the build time and runtime costs. The builder API's stack traces are generally not too interesting. Where this really helps is with `clap_derive`. We currently panic on unexpected conditions which at least gives us a backtrace. We'd like to turn these into errors but to do so would lose those debuggin backtraces, which is where this comes in. This is a part of clap-rs#2255
This is gated behind the `debug` feature flag so only explicit debugging cases pay the build time and runtime costs. The builder API's stack traces are generally not too interesting. Where this really helps is with `clap_derive`. We currently panic on unexpected conditions which at least gives us a backtrace. We'd like to turn these into errors but to do so would lose those debuggin backtraces, which is where this comes in. This is a part of clap-rs#2255
Our goal is to not panic inside of the macro (e.g. clap-rs#2255). Currently, we `.unwrap()` everywhere except when turning an `ArgMatches` into an `enum`. To handle `flatten`, we walk through each `flatten`ed enum to see if it can be instantiated. We don't want to mix this up with any of the other eror cases (including further nested versions of this). If we went straight to `Result<T>`, we'd have to differentiate this case through the `ErrorKind` and `map_err` it in all other cases to prevent it from bubbling up and confusing us. Alternatively, we could do a more complicated type `Result<Option<T>>` where the `Option` exists purely for this case and we can use type checking to make sure we properly turn the `None`s into errors when needed. Or we can bypass all of this and just ask the `flatten`ed` subcommand if it supports the current command.
This gives users the basic error template for quick and dirty messages. In addition to the lack of customization, they are not given anything to help them with coloring or for programmayic use (info, source). This is something I've wanted many times for one-off validation that can't be expressed with clap's validation or it just wasn't worth the hoops. The more pressing need is for clap-rs#2255, I need `clap_derive` to be able to create error messages and `Error::with_description` seemed too disjoint from the rest of the clap experience that it seemed like users would immediately create issues about it showing up. With this available, I've gone ahead and deprecated `Error::with_description`, assuming this will be sufficient for users needs (or they can use IO Errors as a back door). I did so according to the pattern in clap-rs#2718 despite us not being fully resolved on that approach yet.
This gives users the basic error template for quick and dirty messages. In addition to the lack of customization, they are not given anything to help them with coloring or for programmayic use (info, source). This is something I've wanted many times for one-off validation that can't be expressed with clap's validation or it just wasn't worth the hoops. The more pressing need is for clap-rs#2255, I need `clap_derive` to be able to create error messages and `Error::with_description` seemed too disjoint from the rest of the clap experience that it seemed like users would immediately create issues about it showing up. With this available, I've gone ahead and deprecated `Error::with_description` (added in 58512f2), assuming this will be sufficient for users needs (or they can use IO Errors as a back door). I did so according to the pattern in clap-rs#2718 despite us not being fully resolved on that approach yet.
This gives users the basic error template for quick and dirty messages. In addition to the lack of customization, they are not given anything to help them with coloring or for programmayic use (info, source). This is something I've wanted many times for one-off validation that can't be expressed with clap's validation or it just wasn't worth the hoops. The more pressing need is for clap-rs#2255, I need `clap_derive` to be able to create error messages and `Error::with_description` seemed too disjoint from the rest of the clap experience that it seemed like users would immediately create issues about it showing up. With this available, I've gone ahead and deprecated `Error::with_description` (added in 58512f2), assuming this will be sufficient for users needs (or they can use IO Errors as a back door). I did so according to the pattern in clap-rs#2718 despite us not being fully resolved on that approach yet.
This gives users the basic error template for quick and dirty messages. In addition to the lack of customization, they are not given anything to help them with coloring or for programmayic use (info, source). This is something I've wanted many times for one-off validation that can't be expressed with clap's validation or it just wasn't worth the hoops. The more pressing need is for clap-rs#2255, I need `clap_derive` to be able to create error messages and `Error::with_description` seemed too disjoint from the rest of the clap experience that it seemed like users would immediately create issues about it showing up. With this available, I've gone ahead and deprecated `Error::with_description` (added in 58512f2), assuming this will be sufficient for users needs (or they can use IO Errors as a back door). I did so according to the pattern in clap-rs#2718 despite us not being fully resolved on that approach yet.
This gives users the basic error template for quick and dirty messages. In addition to the lack of customization, they are not given anything to help them with coloring or for programmayic use (info, source). This is something I've wanted many times for one-off validation that can't be expressed with clap's validation or it just wasn't worth the hoops. The more pressing need is for clap-rs#2255, I need `clap_derive` to be able to create error messages and `Error::with_description` seemed too disjoint from the rest of the clap experience that it seemed like users would immediately create issues about it showing up. With this available, I've gone ahead and deprecated `Error::with_description` (added in 58512f2), assuming this will be sufficient for users needs (or they can use IO Errors as a back door). I did so according to the pattern in clap-rs#2718 despite us not being fully resolved on that approach yet.
Part of clap-rs#2255 and in general will make it easier for people using the builder API to reuse logic from derive crates.
The derive is generating `Error::raw` (from scratch or by converting existing erors) and then the inherent `Parser` methods format them. Fixes clap-rs#2255
Clap version
3.0.0-beta.2
Where
https://docs.rs/clap/3.0.0-beta.2/clap/enum.AppSettings.html#variant.SubcommandsNegateReqs
What's wrong
There's no mention that this AppSetting can cause the Clap derive macro to panic on parse() and try_parse()
How to fix
The text was updated successfully, but these errors were encountered: