mirror of
https://github.com/KeqingMoe/argparse.git
synced 2025-07-03 22:54:39 +00:00
Allow removal of default arguments (i.e. --help and --version)
The help and version arguments are still included by default, but which default arguments to include can be overridden at ArgumentParser creation. argparse generally copies Python argparse behavior. This includes a default `--help`/`-h` argument to print a help message and exit. Some developers using argparse find the automatic exit to be undesirable. The Python argparse has an opt-out parameter when constructing an ArgumentParser. Using `add_help=False` avoids adding a default `--help` argument and allows the developer to implement a custom help. This commit adds a similar opt-out to our C++ argparse, but keeps the current behavior as the default. The `--help`/`-h` and `--version`/`-v` Arguments handle their own output and exit rather than specially treating them in ArgumentParser::parse_args_internal. Closes #119 Closes #138 Closes #139 Signed-off-by: Sean Robinson <sean.robinson@scottsdalecc.edu>
This commit is contained in:
parent
2b05334a3c
commit
ea1f7ef663
21
README.md
21
README.md
@ -455,6 +455,27 @@ The grammar follows `std::from_chars`, but does not exactly duplicate it. For ex
|
||||
| 'u' | decimal (unsigned) |
|
||||
| 'x' or 'X' | hexadecimal (unsigned) |
|
||||
|
||||
### Default Arguments
|
||||
|
||||
`argparse` provides predefined arguments and actions for `-h`/`--help` and `-v`/`--version`. These default actions exit the program after displaying a help or version message, respectively. These defaults arguments can be disabled during `ArgumentParser` creation so that you can handle these arguments in your own way. (Note that a program name and version must be included when choosing default arguments.)
|
||||
|
||||
```cpp
|
||||
argparse::ArgumentParser program("test", "1.0", default_arguments::none);
|
||||
|
||||
program.add_argument("-h", "--help")
|
||||
.action([=](const std::string& s) {
|
||||
std::cout << help().str();
|
||||
})
|
||||
.default_value(false)
|
||||
.help("shows help message")
|
||||
.implicit_value(true)
|
||||
.nargs(0);
|
||||
```
|
||||
|
||||
The above code snippet outputs a help message and continues to run. It does not support a `--version` argument.
|
||||
|
||||
The default is `default_arguments::all` for included arguments. No default arguments will be added with `default_arguments::none`. `default_arguments::help` and `default_arguments::version` will individually add `--help` and `--version`.
|
||||
|
||||
### Gathering Remaining Arguments
|
||||
|
||||
`argparse` supports gathering "remaining" arguments at the end of the command, e.g., for use in a compiler:
|
||||
|
@ -312,6 +312,17 @@ template <class T> struct parse_number<T, chars_format::fixed> {
|
||||
|
||||
} // namespace details
|
||||
|
||||
enum class default_arguments : unsigned int {
|
||||
none = 0,
|
||||
help = 1,
|
||||
version = 2,
|
||||
all = help | version,
|
||||
};
|
||||
|
||||
inline bool operator& (const default_arguments &a, const default_arguments &b) {
|
||||
return static_cast<unsigned int>(a) & static_cast<unsigned int>(b);
|
||||
}
|
||||
|
||||
class ArgumentParser;
|
||||
|
||||
class Argument {
|
||||
@ -814,17 +825,32 @@ private:
|
||||
class ArgumentParser {
|
||||
public:
|
||||
explicit ArgumentParser(std::string aProgramName = {},
|
||||
std::string aVersion = "1.0")
|
||||
std::string aVersion = "1.0",
|
||||
default_arguments aArgs = default_arguments::all)
|
||||
: mProgramName(std::move(aProgramName)), mVersion(std::move(aVersion)) {
|
||||
add_argument("-h", "--help").help("shows help message and exits").nargs(0);
|
||||
#ifndef ARGPARSE_LONG_VERSION_ARG_ONLY
|
||||
add_argument("-v", "--version")
|
||||
#else
|
||||
add_argument("--version")
|
||||
#endif
|
||||
.help("prints version information and exits")
|
||||
if (aArgs & default_arguments::help) {
|
||||
add_argument("-h", "--help")
|
||||
.action([&](const auto &) {
|
||||
std::cout << help().str();
|
||||
std::exit(0);
|
||||
})
|
||||
.default_value(false)
|
||||
.help("shows help message and exits")
|
||||
.implicit_value(true)
|
||||
.nargs(0);
|
||||
}
|
||||
if (aArgs & default_arguments::version) {
|
||||
add_argument("-v", "--version")
|
||||
.action([&](const auto &) {
|
||||
std::cout << mVersion;
|
||||
std::exit(0);
|
||||
})
|
||||
.default_value(false)
|
||||
.help("prints version information and exits")
|
||||
.implicit_value(true)
|
||||
.nargs(0);
|
||||
}
|
||||
}
|
||||
|
||||
ArgumentParser(ArgumentParser &&) noexcept = default;
|
||||
ArgumentParser &operator=(ArgumentParser &&) = default;
|
||||
@ -1051,18 +1077,6 @@ private:
|
||||
auto tIterator = mArgumentMap.find(tCurrentArgument);
|
||||
if (tIterator != mArgumentMap.end()) {
|
||||
auto tArgument = tIterator->second;
|
||||
|
||||
// the first optional argument is --help
|
||||
if (tArgument == mOptionalArguments.begin()) {
|
||||
std::cout << *this;
|
||||
std::exit(0);
|
||||
}
|
||||
// the second optional argument is --version
|
||||
else if (tArgument == std::next(mOptionalArguments.begin(), 1)) {
|
||||
std::cout << mVersion << "\n";
|
||||
std::exit(0);
|
||||
}
|
||||
|
||||
it = tArgument->consume(std::next(it), end, tIterator->first);
|
||||
} else if (const auto &tCompoundArgument = tCurrentArgument;
|
||||
tCompoundArgument.size() > 1 && tCompoundArgument[0] == '-' &&
|
||||
|
@ -30,6 +30,7 @@ file(GLOB ARGPARSE_TEST_SOURCES
|
||||
test_compound_arguments.cpp
|
||||
test_container_arguments.cpp
|
||||
test_const_correct.cpp
|
||||
test_default_args.cpp
|
||||
test_get.cpp
|
||||
test_help.cpp
|
||||
test_invalid_arguments.cpp
|
||||
|
19
test/test_default_args.cpp
Normal file
19
test/test_default_args.cpp
Normal file
@ -0,0 +1,19 @@
|
||||
#include <argparse/argparse.hpp>
|
||||
#include <doctest.hpp>
|
||||
|
||||
using doctest::test_suite;
|
||||
|
||||
TEST_CASE("Include all default arguments" * test_suite("default_args")) {
|
||||
argparse::ArgumentParser parser("test");
|
||||
auto help_msg { parser.help().str() };
|
||||
REQUIRE(help_msg.find("shows help message") != std::string::npos);
|
||||
REQUIRE(help_msg.find("prints version information") != std::string::npos);
|
||||
}
|
||||
|
||||
TEST_CASE("Do not include default arguments" * test_suite("default_args")) {
|
||||
argparse::ArgumentParser parser("test", "1.0",
|
||||
argparse::default_arguments::none);
|
||||
parser.parse_args({"test"});
|
||||
REQUIRE_THROWS_AS(parser.get("--help"), std::logic_error);
|
||||
REQUIRE_THROWS_AS(parser.get("--version"), std::logic_error);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
#include <argparse/argparse.hpp>
|
||||
#include <doctest.hpp>
|
||||
#include <sstream>
|
||||
|
||||
using doctest::test_suite;
|
||||
|
||||
@ -51,3 +52,26 @@ TEST_CASE("Users can override the help options" * test_suite("help")) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST_CASE("Users can disable default -h/--help" * test_suite("help")) {
|
||||
argparse::ArgumentParser program("test", "1.0",
|
||||
argparse::default_arguments::version);
|
||||
REQUIRE_THROWS_AS(program.parse_args({"test", "-h"}), std::runtime_error);
|
||||
}
|
||||
|
||||
TEST_CASE("Users can replace default -h/--help" * test_suite("help")) {
|
||||
argparse::ArgumentParser program("test", "1.0",
|
||||
argparse::default_arguments::version);
|
||||
std::stringstream buffer;
|
||||
program.add_argument("-h", "--help")
|
||||
.action([&](const auto &) {
|
||||
buffer << program;
|
||||
})
|
||||
.default_value(false)
|
||||
.implicit_value(true)
|
||||
.nargs(0);
|
||||
|
||||
REQUIRE(buffer.str().empty());
|
||||
program.parse_args({"test", "--help"});
|
||||
REQUIRE_FALSE(buffer.str().empty());
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
#include <doctest.hpp>
|
||||
#include <argparse/argparse.hpp>
|
||||
#include <sstream>
|
||||
|
||||
using doctest::test_suite;
|
||||
|
||||
@ -11,3 +12,28 @@ TEST_CASE("Users can print version and exit" * test_suite("version")
|
||||
program.parse_args( { "test", "--version" });
|
||||
REQUIRE(program.get("--version") == "1.9.0");
|
||||
}
|
||||
|
||||
TEST_CASE("Users can disable default -v/--version" * test_suite("version")) {
|
||||
argparse::ArgumentParser program("test", "1.0",
|
||||
argparse::default_arguments::help);
|
||||
REQUIRE_THROWS_AS(program.parse_args({"test", "--version"}),
|
||||
std::runtime_error);
|
||||
}
|
||||
|
||||
TEST_CASE("Users can replace default -v/--version" * test_suite("version")) {
|
||||
std::string version { "3.1415" };
|
||||
argparse::ArgumentParser program("test", version,
|
||||
argparse::default_arguments::help);
|
||||
std::stringstream buffer;
|
||||
program.add_argument("-v", "--version")
|
||||
.action([&](const auto &) {
|
||||
buffer << version;
|
||||
})
|
||||
.default_value(true)
|
||||
.implicit_value(false)
|
||||
.nargs(0);
|
||||
|
||||
REQUIRE(buffer.str().empty());
|
||||
program.parse_args({"test", "--version"});
|
||||
REQUIRE_FALSE(buffer.str().empty());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user