Code Monkey home page Code Monkey logo

argparse's People

Contributors

aleklisi avatar kianmeng avatar max-au avatar

Stargazers

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

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

argparse's Issues

State of unicode support?

The following results in an error when displaying help text:

cli() ->
    #{
        handler => fun display/1,
        arguments => [
            #{
                name => text,
                default => <<""/utf8>>
            }
        ]
    }.
$ ./escript
escript: exception error: bad argument
  in function  io_lib:format/2
     called as io_lib:format("  ~-4s ~s\n",
                             ["text",
                              [116,101,120,116,32,40,
                               [60,60,"\"\x{2605}\"","/utf8>>"],
                               41]])
  in call from argparse:'-format_help/2-lc$^4/1-2-'/2 (/Users/user/tool/_build/tool/lib/argparse/src/argparse.erl, line 1081)
  in call from argparse:format_help/2 (/Users/user/tool/_build/tool/lib/argparse/src/argparse.erl, line 1081)
  in call from argparse:format_error/3 (/Users/user/tool/_build/tool/lib/argparse/src/argparse.erl, line 314)
  in call from cli:dispatch/4 (/Users/user/tool/_build/tool/lib/argparse/src/cli.erl, line 177)
  in call from escript:run/2 (escript.erl, line 750)
  in call from escript:start/1 (escript.erl, line 277)
  in call from init:start_em/1

The script is built with the Rebar argument {escript_emu_args, "%%! +pc unicode"}. I'd expect the unicode string to be printed out in the help text.

This does raise the bigger question, what about unicode support in other places? E.g. something weird like #{name => foo, long => "-★"}?

Invalid handler results in no error

When setting a specific handler on the top level:

main(Args) -> cli:run(Args).

cli() -> #{handler => {?MODULE, foobar}}.

cli(_Args) -> ok.

It is ignored and instead the program returns successfully.

cli:run_options/0 is not a subtype of argparse:parser_options/0

cli:run/2 accepts a run_options() which is later passed directly to functions of argparse expecting a parser_options(). This leads to dialyzer errors when passing keys which are only allowed in run_options(); e.g., error.

Dialyzing the calc example app amended to include the following (in a thingy.erl module):

main(Args) ->
    cli:run(Args, #{error => error, progname => "calc"}).

results in:

thingy.erl:5:1: Function main/1 has no local return
thingy.erl:6:19: The call cli:run
         (Args :: any(),
          #{error => error, progname => "calc"}) will never return since it differs in the 2nd argument from the success typing arguments:
         (any(),
          #{'error' => 'ok', _ => _})

Just a line in the README.md

The example in the README.md

has

cli:run(Args, #{progname => "simple").

and should be

cli:run(Args, #{progname => "simple"}).

Feature Request: custom format spec in help text

By default, a long flag named foobar will generate the following text in the command usage section: [--foobar <foobar>]. It would be nice to be able to specify a custom format text so it could be changed to [--foobar <baz>].

Allow progname to be an atom

Perhaps this is a bigger question of if all parameters should allow atoms in many places, but for progname I found it neat if I would be able to do this:

main(Args) -> cli:run(Args, #{progname => ?MODULE}).

Adding --help to command results in badkey error

Given the following configuration:

main(Args) ->
    cli:run(Args).

cli() -> #{commands => #{"foo" => #{}}}.

foo(_Opts) -> ok.

When calling the program with ./progname foo --help this error happens:

escript: exception error: {badkey,"erl"}
  in function  map_get/2
     called as map_get("erl",#{"foo" => #{handler => {progname,foo}}})
  in call from argparse:collect_options/3 (/.../_build/default/lib/argparse/src/argparse.erl, line 1012)
  in call from argparse:format_help/2 (/.../_build/default/lib/argparse/src/argparse.erl, line 970)
  in call from cli:run_impl/4 (/.../_build/default/lib/argparse/src/cli.erl, line 212)
  in call from escript:run/2 (escript.erl, line 758)
  in call from escript:start/1 (escript.erl, line 277)
  in call from init:start_em/1
  in call from init:do_boot/3

Just calling ./progname --help works.

Support named arguments in parameter list

Is there/will there be any support for named arguments in the parameter list before the description? E.g DEPTH in the following example:

  -L, --level DEPTH          limit the depth of recursion

required named args are reported as optional

-module(thingy).

-behaviour(cli).

-export([cli/0, main/1, go/1]).

cli() ->
    #{
        commands => #{
            "go" => #{
                arguments => [
                    #{
                        name => thingy,
                        required => true,
                        long => "-thingy",
                        short => $t,
                        help => "do the thing"
                    }
                ]
            }
        }
    }.

main(Args) ->
    cli:run(Args, #{progname => ?MODULE}).

go(Args) ->
    io:format(user, "~p", [Args]).
$ thingy go
error: thingy go: required argument missing: thingy
usage: thingy go [-t <thingy>] --thingy <thingy>

Optional arguments:
  -t, --thingy do the thing

Incorrect spec for parse_result() type

Code snippet:

-type command_spec() :: {Name :: string(), command()}. %% Command name with command spec

Here "Name" is actually a list of command names (subcommands).

OTP26 adds a module `argparse` to stdlib

With the addition of argparse to stdlib in OTP26 packing up an application using this library fails with:

===> Error generating release: 
Duplicated modules: 
    argparse specified in stdlib and argparse

Not sure what the best solution is - perhaps simply renaming the top level module to arg_parse would be a sensible option?!

Running the same application on OTP23-OTP26 having two different versions of the same thing isn't really an appealing option. But once we reach OTP29 we should be able to drop this.

required=false args with defaults unexpectedly absent on 1.2.1

This works on 1.1.4, but not 1.2.1:

-module(thingy).
-compile([nowarn_export_all, export_all]).

-behaviour(cli).

main(Args) ->
    cli:run(Args, #{progname => ?MODULE}).

cli() ->
    #{handler => {?MODULE, x},
      arguments => [#{name => y,
                      short => $y,
                      required => false,
                      default => 1}]}.

x(#{y := Y}) ->
    {ok, Y}.

failure:

escript: exception error: no function clause matching thingy:x(#{}) (thingy.erl, line 16)
  in function  escript:run/2 (escript.erl, line 750)
  in call from escript:start/1 (escript.erl, line 277)
  in call from init:start_em/1
  in call from init:do_boot/3

Omitting required => false prevents the error on 1.2.1, but it's not clear to me why this should be the case, and so I assume it's a bug.

Support for "--arg=value" form

Is there any plan to add this functionality?

I see that it's in the possible features listed to be done after 1.0.0, so I am wondering if there is any timeline for those.

I am trying to migrate an existing CLI to argparse that already uses this form, and I would prefer not to break all its existing users.

Thanks

"atom choice" types implied but not actually supported

this line implies to me an intent to support "atom choice" args, i.e., args which are interpreted as one of the given atoms and invalid otherwise. e.g.,

#{name => foo, type => {atom, ['bar', 'baz']}}

should allow --foo bar and --foo baz, the corresponding arg values being the atoms 'bar' and 'baz', but should fail with an invalid choice error otherwise.

attempting the above fails / the containing command is not recognized.

Feature Request: Add displayed default value

Currently flags which have custom parsing generate "nonsense" help text. For example, the following argument:

DefaultRange = {{2020, 1, 1}, {2020, 6, 22}},
#{
    arguments => [
        #{
            name => range,
            long => "-range",
            short => $r,
            help => "date range ([<from>]..[<to>])",
            type => {custom, fun(S) -> parse_range(S, DefaultRange) end},
            default => DefaultRange
        }
    ]
}

Generates the following text:

  -r, --range   date range ([<from>]..[<to>]), [{{2020,1,1},{2020,6,22}}]

However, if parse_range(S, DefaultRange) wants to e.g. take ISO dates there should be a way to display a default help string as well:

  -r, --range   date range ([<from>]..[<to>]), [2020-01-01..2020-06-22]

or when the default help string is set to "" (or undefined or something similar):

  -r, --range   date range ([<from>]..[<to>])

Let long/short argument options be atoms (or error out)

It would be nice if the short and long options for arguments could take atoms, or at least throw errors if they won't. I had this configuration:

#{
    arguments => [
        #{name => backgrounds, short => b, long => backgrounds, type => binary, default => "0..8"}
    ]
}

Calling the escript CLI gave this output:

$ ./tool
usage: colortool
$ ./tool -b foo
error: tool: unrecognised argument: -b
usage: tool

Of course, it works if I change it to $b. This one took a long time to debug 😄

If they should take atoms, I think short should only take one letter atoms and error out otherwise, and long should take any string atom and automatically prepend it with "-" so that the default flag format is --flag (since most UNIX CLIs follow that).

handling of default undefined or otherwise non-required args

I am finding it convenient to sometimes define default => undefined args to support handlers like this:

handler(#{foo := Foo, bar := Bar} = Args) -> ...

where bar was defined as default => undefined. I.E., not require use of maps:get(bar, Args, undefined) or defaults merging for optional args. This works, but then help text contains something like this unless overriding the long description:

Optional arguments:
  --bar some bar thing (undefined)

(the default value, undefined, is printed. I think this would just confuse the user.)

I suppose I am asking if one of the following could be done:

  1. Could non-required args be always passed in the args map with undefined values? (Saw a comment describing the current behavior, but not why, and this seems conceptually similar enough if considering undefined as also meaning "absence of value".)
  2. Or, could the default long help text perhaps omit undefined values?

Default types in help are perhaps superfluous

I'm not a fan of how the default types and values currently are displayed:

  -b, --initial-balance Initial balance value, float, 0.0
  -u, --user-email      User email to query, binary
  1. The comma separated list is hard to parse, especially if there's a comma in the original description text too.
  2. The default of binary is not really usable since there is no "binary" type in the shell, only "string"

Not sure what the solution here is...

even with invalid/missing arguments, cli:run/2 returns 'ok' and exit status is 0

When using the cli framework, if invalid arguments are provided or arguments are missing, the exit status code of the program is unexpectedly (to me) 0; e.g., using the readme example:

$ ./erm ; echo $?
error: simple: required argument missing: dir
usage: simple [-fr] <dir>

Arguments:
  dir dir

Optional arguments:
  -f  force (false)
  -r  recursive (false)
0
$ ./erm -f 123 asdf ; echo $?
error: simple: unrecognised argument: asdf
usage: simple [-fr] <dir>

Arguments:
  dir dir

Optional arguments:
  -f  force (false)
  -r  recursive (false)
0

I would expect a nonzero exit status code for these cases (I'm aware of the escript convention wrt crashes and exit codes). Furthermore, cli:run/2 returns ok for these cases. If it instead returned an error tuple (or exception), then at least the user could explicitly halt with a different status code without requiring use of a different "success" value. Although as a "framework", arguably it could be in scope for cli to handle these issues transparently to the user.

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.