python / cpython

The Python programming language
https://www.python.org/
Other
60.83k stars 29.36k forks source link

``argparse`` Prints options per flag name when only once is necessary #101599

Open Harrison-O opened 1 year ago

Harrison-O commented 1 year ago

Bug report

When running a command line program with the --help/-h flag with argparse, if another flag has multiple names and choices to pick from, the options are printed multiple times instead of just once. For example, the program below:

import argparse

if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument('-m', '--metric', choices=["accuracy", "precision", "recall"])
    parser.parse_args(["-h"])

Will print

usage: argparse_test.py [-h] [-m {accuracy,precision,recall}]

options:
  -h, --help            show this help message and exit
  -m {accuracy,precision,recall}, --metric {accuracy,precision,recall}

Notice that the flag choices are printed out twice, once for each flag name. This is redundant and negatively impacts readability. The program should output:

usage: argparse_test.py [-h] [-m {accuracy,precision,recall}]

options:
  -h, --help            show this help message and exit
  -m, --metric {accuracy,precision,recall}

Your environment

Linked PRs

arhadthedev commented 1 year ago

I agree that such a verbosity clutters the help output so it should be deduplicated into a description column. Also, there is no corresponding example in https://docs.python.org/3/library/argparse.html.

I mark it as a feature request, not a bug because such a verbosity explains things in direct, dumb, undesirable but working way.

arhadthedev commented 1 year ago

@bethard, @bitdancer as prominent contributors into argparse according to git log.

ferdnyc commented 1 year ago

Not just multiple choices, it does the same thing for metavar placeholders:

import argparse

if __name__ == "__main__":
    parser = argparse.ArgumentParser()
    parser.add_argument(
            '-m', '--metric',
            choices=["accuracy", "precision", "recall"],
            help="By which metric trick'd be thee met, Ric?")
    parser.add_argument(
            '-d', '--debug', metavar='DEBUG_LEVEL',
            action='store', type=int,
            help="Set the debug level (default: 0)")
    parser.parse_args(["-h"])
$ python3 ./ap.py --help
usage: ap.py [-h] [-m {accuracy,precision,recall}] [-d DEBUG_LEVEL]

options:
  -h, --help            show this help message and exit
  -m {accuracy,precision,recall}, --metric {accuracy,precision,recall}
                        By which metric trick'd be thee met, Ric?
  -d DEBUG_LEVEL, --debug DEBUG_LEVEL
                        Set the debug level (default: 0)

Points for consistency, I guess, but "-d DEBUG_LEVEL, --debug DEBUG_LEVEL" is pretty unnecessarily redundant as well.

hugovk commented 5 months ago

And update the docs?

For example, at least:

  -v {0,1,2}, --verbosity {0,1,2}

https://docs.python.org/3.13/howto/argparse.html#combining-positional-and-optional-arguments

I didn't spot any in the library reference, but it needs checking too:

https://docs.python.org/3.13/library/argparse.html#module-argparse

cc @Jokimax