Giter Site home page Giter Site logo

rue-ryuzaki / argparse Goto Github PK

View Code? Open in Web Editor NEW
14.0 5.0 3.0 2.7 MB

Argument parser for C++

Home Page: https://launchpad.net/~golubchikov-mihail/+archive/ubuntu/cpp-argparse

License: MIT License

CMake 1.06% C++ 98.94%
cpp11 argument-parser header-only cpp argparse cpp-argparse command-line-parser cpp-argparse-dev bash-completion

argparse's Introduction

Argument Parser for C++

Language Ubuntu macOS Windows Coverity Scan Build Status GitHub license GitHub releases GitHub downloads GitHub issues Ubuntu PPA package AUR package MacPorts package Try it on godbolt online

ArgumentParser

Python-like argument parser for C++ projects (with similar syntax).

This project is a C++ adaptation of Python argparse and supports most of its features (actions, nargs, subparsers, argument groups, help formatting, auto-generated usage and help, and more).

Supported compilers

C++ support compiler (see C++ standard support):

  • gcc: 4.4 or higher
  • clang: 2.7 or higher
  • other compilers: no actual data

The work of the parser on older versions of compilers is not guaranteed.

Official repositories:

cpp-argparse-dev PPA

cpp-argparse-dev AUR

cpp-argparse-dev MacPorts

Available macros:

Can be set

ARGPARSE_IMPLEMENTATION - Use to build argparse library to object. To avoid multiple definition of ... use argparse declaration header.

ARGPARSE_DECLARATION - Use argparse library as a declaration header. You can use #include <argparse/argparse_decl.hpp> instead of #include <argparse/argparse.hpp>

ARGPARSE_DISABLE_TERMINAL_SIZE_DETECTION - If you don't want to use terminal size auto-detection feature (for example to avoid using platform specific header files, namely <Windows.h> on OS Windows). Does not make sense to use with ARGPARSE_DECLARATION

Can be read

ARGPARSE_VERSION_MAJOR - Major version of the argparse library

ARGPARSE_VERSION_MINOR - Minor version of the argparse library

ARGPARSE_VERSION_PATCH - Patch level of the argparse library

ARGPARSE_VERSION_NUM(X, Y, Z) - Turns the argparse version numbers into a numeric value

ARGPARSE_VERSION_COMPILED - Current argparse library version

ARGPARSE_VERSION_AT_LEAST(X, Y, Z) - True if compiled with argparse library at least X.Y.Z

Overview

Additional documentation can be found on the argparse Wiki

Code example

  • create parser: auto parser = argparse::ArgumentParser(...);
  • add arguments: parser.add_argument(...);
  • parse arguments: auto const args = parser.parse_args();
  • get parsed argument values: args.get<...>(...);
#include <iostream>

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser(argc, argv)
            .prog("FooBar")
            .description("foo description")
            .epilog("bar epilog");
    parser.add_argument("-f", "--foo").help("FOO help").default_value("foo");
    parser.add_argument("-b", "--bar").help("BAR help").default_value("42");
    parser.add_argument("baz").help("BAZ help");
    parser.print_help();

    auto const args = parser.parse_args();

    std::cout << std::endl << "Parse data:" << std::endl;
    std::cout << "foo: " << args.get<std::string>("-f") << std::endl;
    std::cout << "bar: " << args.get<int>("--bar") << std::endl;
    std::cout << "baz: " << args.get<std::string>("baz") << std::endl;
    return 0;
}

Usage example

./a.out -f=foobar -b 101 baaz

Output

usage: FooBar [-h] [-f FOO] [-b BAR] baz

foo description

positional arguments:
  baz                BAZ help

options:
  -h, --help         show this help message and exit
  -f FOO, --foo FOO  FOO help
  -b BAR, --bar BAR  BAR help

bar epilog

Parse data:
foo: foobar
bar: 101
baz: baaz

Actions example

See supported actions

#include <iostream>

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser(argc, argv).add_help(false);

    parser.add_argument("--store").action("store");
    parser.add_argument("--store_const").action("store_const").const_value("const_value");
    parser.add_argument("--store_true").action("store_true");
    parser.add_argument("--store_false").action("store_false");
    parser.add_argument("--append").action("append");
    parser.add_argument("--append_const").action("append_const").const_value("const_value");
    parser.add_argument("--count").action("count");
    parser.add_argument("--extend").action("extend");
    parser.add_argument("--version").action("version").version("1.0");
    parser.add_argument("--help").action("help").help("show help and exit");

    auto args = parser.parse_args();

    std::cout << args.get<std::string>("store") << std::endl;
    std::cout << args.get<std::string>("store_const") << std::endl;
    std::cout << args.get<std::string>("store_true") << std::endl;
    std::cout << args.get<std::string>("store_false") << std::endl;
    std::cout << args.get<std::string>("append") << std::endl;
    std::cout << args.get<std::string>("append_const") << std::endl;
    std::cout << args.get<std::string>("count") << std::endl;
    std::cout << args.get<std::string>("extend") << std::endl;

    return 0;
}

Nargs example

Supported nargs:

  • "?" or zero_ore_one() or optional(), argument must have zero or one value
  • "*" or zero_or_more(), argument must have zero or more values
  • "+" or one_or_more(), argument must have one or more values
  • N (positive number), argument must have N values
  • argparse::REMAINDER or remainder(), all the remaining command-line arguments are gathered into a list
#include <iostream>

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser(argc, argv);

    parser.add_argument("--nargs?").action("store").nargs("?");
    parser.add_argument("--nargs*").action("store").nargs("*");
    parser.add_argument("--nargs+").action("store").nargs("+");
    parser.add_argument("--nargs2").action("store").nargs(2);
    parser.add_argument("--nargs3").action("store").nargs(3);

    auto args = parser.parse_args();

    std::cout << args.get<std::string>("nargs?") << std::endl;
    std::cout << args.get<std::string>("nargs*") << std::endl;
    std::cout << args.get<std::string>("nargs+") << std::endl;
    std::cout << args.get<std::string>("nargs2") << std::endl;
    std::cout << args.get<std::string>("nargs3") << std::endl;

    return 0;
}

Subparsers example

If you want to use subcommands with arguments (like git commands: git clone URL -b BRANCH, git merge --ff, git status), use subparsers.

If you need to get the subparsers's parser name, set dest value to the subparsers, or use handle in parsers.

Note:

If subparsers not selected in parsed arguments, it is not added to the Namespace, like the arguments of its parsers.

Check if value exists first (Namespace::exists()), or use Namespace::try_get<>() instead of Namespace::get<>() (since C++17).

You can use parser groups inside subparsers, see parser groups

#include <iostream>

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser(argc, argv);
    parser.add_argument("--foo").action("store_true").help("foo help");

    auto& subparsers = parser.add_subparsers().dest("sub").help("sub-command help");

    auto& parser_a = subparsers.add_parser("a").help("a help");
    parser_a.add_argument("bar").help("bar help");

    auto& parser_b = subparsers.add_parser("b").help("b help");
    parser_b.add_argument("--baz").choices("XYZ").help("baz help");

    auto const args = parser.parse_args();

    std::cout << "foo: " << args.get<bool>("foo") << std::endl;
    std::cout << "foo: " << args.to_string("foo") << std::endl;
    if (args.exists("sub")) {
        std::cout << "sub: " << args.get<std::string>("sub") << std::endl;
    }
    if (args.exists("bar")) {
        std::cout << "bar: " << args.get<uint32_t>("bar") << std::endl;
    }
    if (args.exists("baz")) {
        std::cout << "baz: " << args.get<std::string>("baz") << std::endl;
    }

    return 0;
}

Argument groups example

You can group arguments into groups, each with its own title and description.

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser(argc, argv).add_help(false);

    auto& group1 = parser.add_argument_group("group 1", "group1 description");
    group1.add_argument("--foo").action("store").help("foo help");

    auto& group2 = parser.add_argument_group("group 2", "group2 description");
    group2.add_argument("bar").action("store").help("bar help");
    group2.add_argument("--baz").action("store").help("baz help");

    parser.print_help();

    return 0;
}

Namespace::get<> types support (+ try_get with std::optional, since C++17)

  • base types (bool, integral types, floating point types, std::string)
  • byte types (char, signed/unsigned char, int8_t, uint8_t, std::byte (since C++17), char8_t (since C++20))
  • containers (std::array (since C++11), std::deque, std::forward_list (since C++11), std::list, std::multiset, std::priority_queue, std::queue, std::set, std::stack, std::vector, std::unordered_multiset (since C++11), std::unordered_set (since C++11))
  • containers with std::pair/std::tuple (since C++11)
  • 2 dimensional containers
  • mapped types (std::map, std::multimap, std::unordered_map (since C++11), std::unordered_multimap (since C++11))
  • std::pair
  • std::tuple (since C++11)
  • custom types and containers with custom types

Don't work:

  • pointer and reference types
  • plain C arrays
  • non-own C++17+ types and containers (std::string_view, std::span)

Note:

For types with std::pair and std::tuple (also for std::map) needs to specify delimiter (by default it '=') between key and value (for std::pair/std::map) / values (for std::tuple). For space delimiter ' ' all values are parsed from separated command line arguments, otherwise from individual command line argument.

For example:

  • ':' : auto args = parser.parse_args("--foo key1:value1 'key2':'value2'"); args.get<std::map<std::string, std::string> >("foo", ':');
  • ' ' : auto args = parser.parse_args("--foo key1 value1 'key2' 'value2'"); args.get<std::vector<std::pair<std::string, std::string> > >("foo", ' ');

Custom type example

Namespace::get<>

Required std::istream& operator >>(std::istream& is, Type& t) or Argument::type(std::function<void(std::istream&, void*)>) conversion function.

Argument::default_value<> and Argument::const_value<>

Required std::ostream& operator <<(std::ostream& os, Type const& t).

#include <iostream>

#include <argparse/argparse.hpp>

struct Coord
{
    Coord()
        : x(),
          y(),
          z()
    { }

    explicit Coord(int x, int y, int z)
        : x(x),
          y(y),
          z(z)
    { }

    inline void print() const
    {
        std::cout << "x=" << x << ";y=" << y << ";z=" << z << std::endl;
    }

    int x;
    int y;
    int z;
};

inline std::istream& operator >>(std::istream& is, Coord& c)
{
    is >> c.x >> c.y >> c.z;
    return is;
}

inline std::ostream& operator <<(std::ostream& os, Coord const& c)
{
    os << c.x << " " << c.y << " " << c.z;
    return os;
}

inline void coord_type_builder(std::string const& str, void* res)
{
    std::stringstream ss(str);
    // just use operator >>
    ss >> *reinterpret_cast<Coord*>(res);
}

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser();
    // it's recommended to pass each custom type value in quotes: 'value1 value2 ...'
    parser.add_argument("--coord").type(&coord_type_builder).help("coord help");
    parser.add_argument("--const_coord").action("store_const").default_value(Coord(0, 0, 0))
            .const_value(Coord(1, 1, 1)).help("const coord help");

    auto const args = parser.parse_args("--coord='1 2 3'");

    auto c = args.get<Coord>("coord");
    c.print();
    auto c2 = args.get<Coord>("const_coord");
    c2.print();

    return 0;
}

Features

Handle

ArgumentParser::handle(std::function<void(argparse::Namespace const&)> func)

Called when the parser is executed and passed the namespace of the parser.

#include <iostream>

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser(argc, argv);
    parser.add_argument("--foo").action("store_true").help("foo help");

    auto& subparsers = parser.add_subparsers().help("sub-command help");

    auto& parser_a = subparsers.add_parser("a").help("a help");
    parser_a.add_argument("bar").help("bar help");
    parser_a.handle([] (argparse::Namespace const& args)
    {
        std::cout << "bar: " << args.get<uint32_t>("bar") << std::endl;
    });

    auto& parser_b = subparsers.add_parser("b").help("b help");
    parser_b.add_argument("--baz").choices("XYZ").help("baz help");
    parser_b.handle([] (argparse::Namespace const& args)
    {
        std::cout << "baz: " << args.get<std::string>("baz") << std::endl;
    });

    auto const args = parser.parse_args();

    std::cout << "foo: " << args.get<bool>("foo") << std::endl;

    return 0;
}

ArgumentParser::handle(std::function<void(std::string const&)> func)

Called when the parser is executed and passed the value of the parser.

#include <iostream>

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser(argc, argv);
    parser.add_argument("--foo").action("store_true").help("foo help");

    auto& subparsers = parser.add_subparsers().help("sub-command help");

    auto& parser_a = subparsers.add_parser("a").help("a help")
            .handle([] (std::string const&) { std::cout << "Parser A handle" << std::endl; });
    parser_a.add_argument("bar").help("bar help");

    auto& parser_b = subparsers.add_parser("b").help("b help")
            .handle([] (std::string const& value) { std::cout << "Parser B handle " << value << std::endl; });
    parser_b.add_argument("--baz").choices("XYZ").help("baz help");

    auto const args = parser.parse_args();

    std::cout << "foo: " << args.get<bool>("foo") << std::endl;
    if (args.exists("bar")) {
        std::cout << "bar: " << args.get<uint32_t>("bar") << std::endl;
    }
    if (args.exists("baz")) {
        std::cout << "baz: " << args.get<std::string>("baz") << std::endl;
    }

    return 0;
}

Argument::handle(std::function<void(std::string const&)> func)

Called when the argument is present and passed the value of the argument. Preferably for value-dependent arguments (Action: "store", "language", "store_const", "append", "append_const" or "extend")

For value-independent arguments gets const value (Action: "store_true", "store_false") or empty string (Action: "count")

#include <iostream>

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser(argc, argv);
    parser.add_argument("--foo").action("store").help("foo help")
            .handle([] (std::string const& value)
    { std::cout << "Handle value '" << value << "'" << std::endl; });

    parser.parse_args();

    return 0;
}

Terminal size auto-detection

By default, help output is positioned based on the terminal's width. But you can manually specify the width of the available area using the ArgumentParser::output_width(...) method.

Environment variables

ArgumentParser can hold environment variables (from envp[]) and have has_env, get_env and list_env functions to work with them

#include <iostream>

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[], char const* const envp[])
{
    auto parser = argparse::ArgumentParser(argc, argv, envp);
    if (parser.has_env("FOO")) {
        std::cout << parser.get_env("FOO") << std::endl;
    }
    return 0;
}

Operand argument

Operand arguments is position independent with required = true (by default). To create operand argument use flag with suffix = (indicates, that argument will be operand):

parser.add_argument("flag=");

Operand argument restrictions:

  • argument can have only one flag
  • actions "store" and "language" is allowed
  • nargs is not allowed
  • const_value is not allowed
  • metavar with single value is allowed

Usage example:

auto parser = argparse::ArgumentParser("test");

parser.add_argument("bar").help("positional argument bar");
parser.add_argument("--foo").help("optional argument foo");
parser.add_argument(argparse::Argument("if=").metavar("INPUT").dest("in").help("required operand if"));
parser.add_argument("of=").required(false).help("operand of");

parser.print_help();

auto args = parser.parse_args("--foo=a if=input of=output bar");

std::cout << args << std::endl;
std::cout << args.get<std::string>("of") << std::endl;

with output:

usage: test [-h] [--foo FOO] if=INPUT [of=OF] bar

positional arguments:
  bar         positional argument bar

operands:
  if=INPUT    required operand if
  of=OF       operand of

options:
  -h, --help  show this help message and exit
  --foo FOO   optional argument foo
Namespace(bar='bar', foo='a', in='input', of='output')
output

Argument::implicit_value

The implicit_value argument of add_argument() is used to hold implicit values that are not read from the command line (use with nargs = "?" and "*").

This is an alternative for the const_value (for optional arguments it works only for nargs = "?").

example:

#include <iostream>

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser(argc, argv);
    parser.add_argument("--foo").nargs("?").implicit_value("bar").default_value("foo");

    auto const args = parser.parse_args();

    std::cout << "  foo = '" << args.get<std::string>("foo") << "'" << std::endl;

    return 0;
}

with usage:

// here will be default value (if presented)
./a.out
  foo = 'foo'

// here will be implicit value (if presented)
./a.out --foo
  foo = 'bar'

// here will be parsed command line value
./a.out --foo=baz
  foo = 'baz'

Combined nargs

Nargs "?", "*" or "+" can be combined with N (an integer):

  • nargs("?", N) - 0 or N arguments
  • nargs("*", N) - 0 or more (1N, 2N, 3N, 4N ...) arguments
  • nargs("+", N) - N or more (2N, 3N, 4N, 5N ...) arguments

Action::language

Allows you to add support for displaying help in multiple languages.

example:

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser(argc, argv)
            .prog("prog")
            .add_help(false)
            .description("description")
            .description("la description", "fr")
            .description("beschreibung", "de")
            .description("popis", "cz")
            .optionals_title("arguments facultatifs", "fr")
            .optionals_title("optionale argumente", "de")
            .optionals_title("volitelnΓ© argumenty", "cz")
            .epilog("epilog")
            .epilog("Γ©pilogue", "fr")
            .epilog("epilog", "de")
            .epilog("epilog", "cz");
    parser.add_argument("-h", "--help")
            .action("help")
            .help("show this help message and exit")
            .help("afficher ce message d'aide et quitter", "fr")
            .help("diese hilfemeldung anzeigen und beenden", "de")
            .help("zobrazit tuto nΓ‘povΔ›du a odejΓ­t", "cz");
    parser.add_argument("-l", "--lang")
            .action("language")
            .choices("fr", "de", "cz")
            .help("set language")
            .help("dΓ©finir la langue", "fr")
            .help("sprache einstellen", "de")
            .help("nastavit jazyk", "cz");
    parser.add_argument("--foo")
            .help("foo help")
            .help("foo aider", "fr")
            .help("foo hilfe", "de")
            .help("foo pomoc", "cz");

    parser.parse_args();

    return 0;
}

with usage:

// default usage
./a.out -h
usage: prog [-h] [-l {fr,de,cz}] [--foo FOO]

description

options:
  -h, --help            show this help message and exit
  -l {fr,de,cz}, --lang {fr,de,cz}
                        set language
  --foo FOO             foo help

epilog

// -l fr
./a.out -l fr -h
usage: prog [-h] [-l {fr,de,cz}] [--foo FOO]

la description

arguments facultatifs:
  -h, --help            afficher ce message d'aide et quitter
  -l {fr,de,cz}, --lang {fr,de,cz}
                        dΓ©finir la langue
  --foo FOO             foo aider

Γ©pilogue

// -l de
./a.out -l de -h
usage: prog [-h] [-l {fr,de,cz}] [--foo FOO]

beschreibung

optionale argumente:
  -h, --help            diese hilfemeldung anzeigen und beenden
  -l {fr,de,cz}, --lang {fr,de,cz}
                        sprache einstellen
  --foo FOO             foo hilfe

epilog

// -l cz
./a.out -l cz -h
usage: prog [-h] [-l {fr,de,cz}] [--foo FOO]

popis

volitelnΓ© argumenty:
  -h, --help            zobrazit tuto nΓ‘povΔ›du a odejΓ­t
  -l {fr,de,cz}, --lang {fr,de,cz}
                        nastavit jazyk
  --foo FOO             foo pomoc

epilog

comment_prefix_chars

ArgumentParser allows you to load command line arguments from a file. But sometimes situations may arise when you need to disable some arguments or add comments.

You can create new parser class and override convert_arg_line_to_args function:

class CommentArgumentParser : public argparse::ArgumentParser
{
public:
    using argparse::ArgumentParser::ArgumentParser;

    inline std::vector<std::string>
    convert_arg_line_to_args(
            std::string const& arg_line) const override
    {
        if (arg_line.starts_with("#")) {
            return {};
        }
        return ArgumentParser::convert_arg_line_to_args(arg_line);
    }
};

or use comment_prefix_chars (this will also skip command line arguments if your shell doesn't use those special characters):

auto parser = argparse::ArgumentParser(argc, argv)
            .prog("prog")
            .fromfile_prefix_chars("@")
            .comment_prefix_chars("#");

Parser groups

This library allows you to create groups of parsers in your SubParsers. By default, all parsers created in the main subparsers group constitute the main parser group. You can create a new parser group using ```add_parser_group(title, description)`` and group other parsers into it.

#include <iostream>

#include <argparse/argparse.hpp>

int main(int argc, char const* const argv[])
{
    auto parser = argparse::ArgumentParser(argc, argv);
    parser.add_argument("--foo").action("store_true").help("foo help");

    auto& subparsers = parser.add_subparsers().help("sub-command help");

    auto& parser_a = subparsers.add_parser("a").help("a help")
            .handle([] (std::string const&) { std::cout << "Parser A handle" << std::endl; });
    parser_a.add_argument("bar").help("bar help");

    auto& parsers_group = subparsers.add_parser_group().help("next sub-commands help");

    auto& parser_b = parsers_group.add_parser("b").help("b help")
            .handle([] (std::string const& value) { std::cout << "Parser B handle " << value << std::endl; });
    parser_b.add_argument("--baz").choices("XYZ").help("baz help");

    auto const args = parser.parse_args();

    std::cout << "foo: " << args.get<bool>("foo") << std::endl;
    if (args.exists("bar")) {
        std::cout << "bar: " << args.get<uint32_t>("bar") << std::endl;
    }
    if (args.exists("baz")) {
        std::cout << "baz: " << args.get<std::string>("baz") << std::endl;
    }

    return 0;
}

ArgumentParser objects support

  • prog - The name of the program (default: argv[0] or "untitled")
  • usage - The string describing the program usage (default: generated from arguments added to parser)
  • description - Text to display before the argument help (default: "")
  • epilog - Text to display after the argument help (default: "")
  • parents - A list of ArgumentParser objects whose arguments should also be included
  • formatter_class - A class for customizing the help output
  • prefix_chars - The set of characters that prefix optional arguments (default: "-")
  • fromfile_prefix_chars - The set of characters that prefix files from which additional arguments should be read (default: "")
  • argument_default - The global default value for arguments (default: "")
  • conflict_handler - The strategy for resolving conflicting optionals (usually unnecessary, otherwise set "resolve")
  • add_help - Add a -h/--help option to the parser (default: true)
  • allow_abbrev - Allows long options to be abbreviated if the abbreviation is unambiguous. (default: true)
  • exit_on_error - Determines whether or not ArgumentParser exits with error info when an error occurs. (default: true)

The add_argument(name or flags) method support

  • name or flags - Either a name or a list of option strings, e.g. foo, foo= or -f, --foo.
  • action - The basic type of action to be taken when this argument is encountered at the command line.
  • nargs - The number of command-line arguments that should be consumed.
  • const - A constant value required by some action and nargs selections.
  • default - The value produced if the argument is absent from the command line and if it is absent from the namespace object.
  • type - The type to which the command-line argument should be converted (for MetavarTypeHelpFormatter and Namespace::get type check).
  • choices - A container of the allowable values for the argument.
  • required - Whether or not the command-line option may be omitted (optionals and operands only).
  • help - A brief description of what the argument does.
  • metavar - A name for the argument in usage messages.
  • dest - The name of the attribute to be added to the object returned by parse_args().

The add_argument() actions support

  • "store" - This just stores the argument’s value. This is the default action.
  • "store_const" - This stores the value specified by the const keyword argument.
  • "store_true" and "store_false" - These are special cases of "store_const" used for storing the values true and false respectively. In addition, they create default values of false and true respectively.
  • "append" - This stores a list, and appends each argument value to the list. This is useful to allow an option to be specified multiple times.
  • "append_const" - This stores a list, and appends the value specified by the const keyword argument to the list.
  • "count" - This counts the number of times a keyword argument occurs.
  • "help" - This prints a complete help message for all the options in the current parser and then exits.
  • "version" - This expects a version= keyword argument in the add_argument() call, and prints version information and exits when invoked.
  • "extend" - This stores a list, and extends each argument value to the list.
  • argparse::BooleanOptionalAction - Adds support for boolean actions such as --foo and --no-foo

Bash completion

ArgumentParser can help you to create bash completion file for your program (this function is experimental):

std::ofstream file;
file.open("path-to-script.sh", std::ios::trunc);
parser.print_bash_completion(file);

and add to your .bashrc file:

. path-to-script.sh

Self test

You can check that you parser is created correctly by calling the self_test function.

parser.self_test();

Execute unit tests

To compile and run the tests, you need to execute

$ mkdir build
$ cd build
$ cmake ..
$ cmake --build .
$ ctest --output-on-failure

License

The class is licensed under the MIT License:

Copyright Β© 2021-2024 Golubchikov Mihail

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


argparse's People

Contributors

arsenic-atg avatar lgtm-migrator avatar rue-ryuzaki avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar

argparse's Issues

GitHub actions: mingw job for Windows workflow

Current mingw job:

  mingw:
    runs-on: windows-latest
    strategy:
      fail-fast: false
      matrix:
        architecture: [x64, x86]
        standard: [98, 11, 14, 17, 20]

    steps:
    - uses: actions/checkout@v2

    - name: Set up MinGW
      uses: egor-tensin/setup-mingw@v2
      with:
        platform: ${{ matrix.architecture }}

    - name: Configure CMake
      run: cmake -B ${{github.workspace}}/build -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DCMAKE_CXX_STANDARD=${{ matrix.standard }}

    - name: Build
      run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}

    - name: Test
      working-directory: ${{github.workspace}}/build
      run: ctest -C ${{env.BUILD_TYPE}}

often falls is Set up MinGW step with error:

Chocolatey v1.1.0
Upgrading the following packages:
mingw
By upgrading, you accept licenses for the packages.

mingw v8.1.0 [Approved]
mingw package files upgrade completed. Performing other installation steps.
Downloading mingw 64 bit
  from 'https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/8.1.0/threads-posix/seh/x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z/download'
ERROR: The remote file either doesn't exist, is unauthorized, or is forbidden for url 'https://sourceforge.net/projects/mingw-w64/files/Toolchains%20targetting%20Win64/Personal%20Builds/mingw-builds/8.1.0/threads-posix/seh/x86_64-8.1.0-release-posix-seh-rt_v6-rev0.7z/download'. Exception calling "GetResponse" with "0" argument(s): "The request was aborted: Could not create SSL/TLS secure channel." 
This package is likely not broken for licensed users - see https://docs.chocolatey.org/en-us/features/private-cdn.
The upgrade of mingw was NOT successful.
Error while running 'C:\ProgramData\chocolatey\lib\mingw\tools\chocolateyinstall.ps1'.
 See log for details.

Chocolatey upgraded 0/1 packages. 1 packages failed.
 See the log for details (C:\ProgramData\chocolatey\logs\chocolatey.log).

Failures
 - mingw (exited 404) - Error while running 'C:\ProgramData\chocolatey\lib\mingw\tools\chocolateyinstall.ps1'.
 See log for details.

Other configurations are required to build with mingw for Windows

unknown warning group '-Wimplicit-fallthrough='

I am getting this warning with clang 13.0.0 on macos

../libs/argparse/include/argparse/argparse.hpp:97:32: warning: unknown warning group '-Wimplicit-fallthrough=', ignored [-Wunknown-warning-option]
#pragma GCC diagnostic ignored "-Wimplicit-fallthrough="
                               ^
1 warning generated.
% clang++ --version
Homebrew clang version 13.0.0
Target: x86_64-apple-darwin21.1.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin

πŸ› Attribute names for optional arguments

Description

Hi there!

It's been a while, happy holidays πŸ‘‹

I recently came across an integration detail that does not conform to the specification.

It seems that it is not possible to use internal values for attribute names in calls like args.exists("long_option") instead of args.exists("--long-option") for an argument specified as --long-option.

Excerpt from https://docs.python.org/3/library/argparse.html#dest

For optional argument actions, the value of dest is normally inferred from the option strings. ArgumentParser generates the value of dest by taking the first long option string and stripping away the initial -- string. If no long option strings were supplied, dest will be derived from the first short option string by stripping the initial - character. Any internal - characters will be converted to _ characters to make sure the string is a valid attribute name.

Reproduction steps

Make a call to a function that requires an attribute name for an optional compound argument using explicit and internal values

Expected vs. actual results

I expected the calls to accept this subtlety

Minimal code example

No response

Error messages

No response

Compiler and operating system

g++ (Ubuntu 11.3.0-1ubuntu1~22.04) 11.3.0

Library version

1.6.5

Validation

✨ add support for implicit values

Hello there!

A very useful library πŸ‘

Do you plan to incorporate implicit value support in the near future?

These implicit values behave like flags and allow you to use a predefined value or specify a custom one on activation.

This is slightly different from a default value, since when the argument is not specified on the command line, no value (or a null value) is assigned to the argument.

./mybin
# where arg is disabled

./mybin --arg
# where arg is "mypredefinedvalue"

./mybin --arg mycustomvalue
# where arg is "mycustomvalue"

This is an alternative to having 2 arguments for this task using a default and a flag, such as:

./mybin --no-arg
# where arg is disabled

./mybin
# where arg is "mypredefinedvalue"

./mybin --arg mycustomvalue
# where arg is "mycustomvalue"

How to access parsed args from within a handle lambda?

Is there a pattern to access the parsed args from within a handle lambda? I thought something like this might work but it doesn't seem to.

#include <argparse/argparse.hpp>
#include <iostream>

int main(int argc, char* argv[]) {
    argparse::ArgumentParser::Namespace space;
    auto parser = argparse::ArgumentParser(argc, argv);
    auto& subparsers = parser.add_subparsers();
    auto& parser_a = subparsers.add_parser("a")
                         .handle([&]() {
                             std::cout << "bar: " << space.get<uint32_t>("bar") << std::endl;
                         });
    parser_a.add_argument("bar");
    space = parser.parse_args();
    return 0;
}
AttributeError: 'Namespace' object has no attribute 'bar'

πŸ› arguments parsing should be reviewed

Hello!

Implicit values (from 80ab3cc ) do not work if they are followed by other positional arguments (or subparsers), the following value might have to be compared to next available arguments in order to assert if that's a custom value or another argument.

Given a parser with an implicit value optional argument --arg and a positional argument value:

./mybin --arg mycustomvalue 42
# works
./mybin --arg 42
# fails

The same behavior occurs in the context of subparsers.

Given a parser with an implicit value optional argument --arg and a subparser a:

./mybin --arg mycustomvalue a
# works
./mybin --arg a
# fails

Typos detected

These are the typos detected by codespell in the project

README.md:34: macroses ==> macros
README.md:35: setted ==> set
./include/argparse/argparse.hpp:85: compability ==> compatibility
./include/argparse/argparse.hpp:2499: missmatch ==> mismatch

Allow share dest storage

Description

First, thanks for awesome library. I use Python argparse a lot, then now I can use it in C++.

I have similar issue to #4, specially the second case.
The goal is use default value without any option and allow override it or disable it (or change same predefined).

./mybin
# a) default arg "a"

./mybin --no-arg
# b) where arg is disabled, set to "b" for better view

./mybin --arg x
# x) where custom arg is "x"

Python version.

p = argparse.ArgumentParser()
p.add_argument('--arg', default='a')
# _StoreAction(option_strings=['--arg'], dest='arg', nargs=None, const=None, default='a', type=None, choices=None, required=False, help=None, metavar=None)
p.add_argument('--no-arg', dest='arg', action='store_const', const='b')
# _StoreConstAction(option_strings=['--no-arg'], dest='arg', nargs=0, const='b', default=None, type=None, choices=None, required=False, help=None, metavar=None)

p.parse_args(''.split())
# Namespace(arg='a')

p.parse_args('--arg x'.split())
# Namespace(arg='x')

p.parse_args('--no-arg'.split())
# Namespace(arg='b')

I have a problem with dest. There is a conflict or second argument overrides the first.
Of course I can use an another name add add if to override dest in my code after parsing. Than it's not so important issue.
Just note Python differs.

Reproduction steps

Compile and run.

Expected vs. actual results

Actual results

For dest("--arg") I have:

argparse::ArgumentError: argument --no-arg: conflicting dest string: --arg

For dest("arg") I have:

./mybin 
(empty)  arg is ''

./mybin --no-arg
(exists) arg is 'b'

./mybin --arg x
(empty)  arg is ''

Expected results

In both cases.

./mybin 
(exists) arg is 'a'

./mybin --no-arg
(exists) arg is 'b'

./mybin --arg x
(exists)  arg is 'x'

Minimal code example

#include "argparse.hpp"

int main(int argc, char *argv[])
{
	auto parser = argparse::ArgumentParser(argc, argv);
	parser.add_argument("--arg").default_value("a");
	parser.add_argument("--no-arg").action("store_const").dest("arg").const_value("b");
	auto const args = parser.parse_args();
	std::cout << (args.exists("arg") ? "(exists)" : "(empty) ") << " arg is '" << args.get<std::string>("arg") << "'" << std::endl;
	return 0;
}

Error messages

argparse::ArgumentError: argument --no-arg: conflicting dest string: --arg

Compiler and operating system

c++ -o mybin aa.cc
Debian testing.

Library version

1.6.4

Validation

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.