In argparse, a choice argument can be created by using code like this:
parser = argparse.ArgumentParser()
parser.add_argument("action", type=str,
help="The action to do. Eligible values:\ninstall, remove, version", choices=['install', 'remove', 'version'])
When parser is an instance of argparse.ArgumentParser()
However, when displaying the help, instead of the arg being specified as its name, it is specified as {install,remove,version}, the whole output being
positional arguments:
{install,remove,version}
The action to do. Eligible values: install, remove,
version
optional arguments:
-h, --help show this help message and exit
How can i get his to display the name of the arg, so the output is more like
positional arguments:
action The action to do. Eligible values: install, remove,
version
optional arguments:
-h, --help show this help message and exit
The metavar parameter to add_argument is what you're looking for:
parser = argparse.ArgumentParser()
parser.add_argument(
"action",
type=str,
help="The action to do. Eligible values:\ninstall, remove, version",
choices=['install', 'remove', 'version'],
metavar="action",
)
Calling parser.print_help() yields:
usage: [-h] action
positional arguments:
action The action to do. Eligible values: install, remove, version
optional arguments:
-h, --help show this help message and exit
You can specify metavar
When ArgumentParser generates help messages, it needs some way to refer to each expected argument. By default, [...] An alternative name can be specified with metavar:
parser = argparse.ArgumentParser()
parser.add_argument("action", type=str, metavar='action',
help="The action to do. Eligible values:\ninstall, remove, version", choices=['install', 'remove', 'version'])
Related
Python argparse keep putting space and three-dots ( ...) at the end of usage: line, example: usage: program.sh [-h] command [<options>...] .... Would it be possible to remove them?
Example code:
def helper():
parser = argparse.ArgumentParser(
"program.py",
)
subparsers = parser.add_subparsers(dest="command", metavar="command [<options>...]")
driver = subparsers.add_parser(
"driver", help="Example script")
driver.add_argument("--bn", type=int, default=0, help="Block number to start fetch blocks from")
return parser
Output:
$ ./program.sh --help
usage: program.sh [-h] command [<options>...] ...
Direct answer: you could write your own usage summary:
parser = argparse.ArgumentParser(
"program.py",
usage="usage: %(prog)s [-h] command [<options>...]",
)
However, there is something that does not make sense to me.
The ... is caused by using subparsers. There is usually one subparser per command, for example: 3 commands, i.e. 3 subparsers:
Usage:
myprog cmd1 [options and args specific for cmd1]
myprog cmd2 [different options and args for cmd2]
myprog cmd3 [yet another set of options and args]
And that can be hardly summarized in one line except with:
Usage: myprog command ...
unless you are not using any options and args for the commands, which means there is nothing to parse.
So, if you want to get rid of the trailing ... and still have a valid usage synopsis, you probably do not need subparsers at all.
That usage is produced by the implied nargs of the subparsers argument, 'A...'.
I get the same thing if I create a positional argument with the same nargs:
In [393]: import argparse
In [394]: p = argparse.ArgumentParser()
In [395]: p.add_argument('foo',nargs=argparse.PARSER)
Out[395]: _StoreAction(option_strings=[], dest='foo', nargs='A...', const=None, default=None, type=None, choices=None, help=None, metavar=None)
In [396]: p.print_help()
usage: ipython3 [-h] foo ...
positional arguments:
foo
optional arguments:
-h, --help show this help message and exit
Note the nargs string in Out[395]. add_subparsers creates a positional argument with 'A...' nargs value.
In [403]: p = argparse.ArgumentParser()
In [404]: p.add_subparsers(dest='foo', metavar='FOO')
Out[404]: _SubParsersAction(option_strings=[], dest='foo', nargs='A...', const=None, default=None, type=None, choices={}, help=None, metavar='FOO')
In [405]: p.print_help()
usage: ipython3 [-h] FOO ...
positional arguments:
FOO
optional arguments:
-h, --help show this help message and exit
That nargs takes all the remaining strings while requiring at least one. The add_parser lines add choices to that subparser Action.
In formatting its usage the main parser "knows nothing" about what the sub-parsers do. To it, the subparsers argument is just another positional argument with choices. The same applies when parsing. It just does the suparsers.__call__ with the remaining argv strings. That in turn passes those to the chosen parser.
I'm using a custom action for argument parser to allow key=value options for specific arguments.
test.py --arg2 input1=something input2=something_else
The custom action works fine, but when I use metavar to list all of the custom options, I get duplicates.
Here is my custom action:
class KeyValue(argparse.Action):
def __call__(self, parser, namespace,
values, option_string=None):
setattr(namespace, self.dest, dict())
for value in values:
# split it into key and value
key, value = value.split('=')
# assign into dictionary
getattr(namespace, self.dest)[key] = value
Here is the utilization:
sub_1.add_argument(
"--arg2",
action=KeyValue,
nargs="*",
default=NoArgumentProvided(),
help='arg 2 help',
metavar="key1=val1 key2=val2"
)
What the help looks like, with duplicates showing up:
usage: arg_issue.py test [-h] [--arg1]
[--arg2 [key1=val1 key2=val2 [key1=val1 key2=val2 ...]]]
test description
optional arguments:
-h, --help show this help message and exit
--arg1 arg1 help
--arg2 [key1=val1 key2=val2 [key1=val1 key2=val2 ...]]
arg 2 help
Any ideas why I'm getting duplicates? It's clearly from the custom Action, but I'm not sure why?
Full Code:
import argparse
class NoArgumentProvided(object):
pass
class KeyValue(argparse.Action):
def __call__(self, parser, namespace,
values, option_string=None):
setattr(namespace, self.dest, dict())
for value in values:
# split it into key and value
key, value = value.split('=')
# assign into dictionary
getattr(namespace, self.dest)[key] = value
def main():
parser = argparse.ArgumentParser(
description='parser',
formatter_class=argparse.RawTextHelpFormatter,
)
# top-level args.
parser.add_argument('--verbose',
help='Verbose mode',
action='store_true',
required=False,
default=NoArgumentProvided())
# Add the main sub parsers
subparsers = parser.add_subparsers(dest='action')
sub_1 = subparsers.add_parser(
'test',
help='test help',
description='test description')
sub_1.add_argument(
"--arg1",
action='store_true',
required=False,
default=NoArgumentProvided(),
help='arg1 help'
)
sub_1.add_argument(
"--arg2",
action=KeyValue,
nargs="*",
default=NoArgumentProvided(),
help='arg 2 help',
metavar="key1=val1 key2=val2"
)
subparsers.required = True
args = parser.parse_args()
if __name__=="__main__":
main()
If the metavar is a tuple of strings
p.add_argument('--foo', nargs='*', metavar=('one','two'))
the help will be
usage: ipython3 [-h] [--foo [one [two ...]]]
optional arguments:
-h, --help show this help message and exit
--foo [one [two ...]]
With nargs='*', the usage is 2 parts, [one [two ...]]. Use of a custom action class doesn't change that display.
Keep the metavar simple, and elaborate in the help as needed. description can also add details.
edit
A patch a couple of years ago has simplified the * help.
https://bugs.python.org/issue38438
argparse "usage" overly-complex with nargs="*"
With Python 3.10
In [218]: import argparse310 as argparse
In [219]: p=argparse.ArgumentParser()
In [220]: p.add_argument('--foo',nargs='*');
In [221]: p.print_help()
usage: ipython3 [-h] [--foo [FOO ...]]
optional arguments:
-h, --help show this help message and exit
--foo [FOO ...]
The tuple version is still available:
In [226]: p._actions[1].metavar=('one','two')
In [227]: p.print_help()
usage: ipython3 [-h] [--foo [one [two ...]]]
optional arguments:
-h, --help show this help message and exit
--foo [one [two ...]]
I'm building a command line argparser for my program and I try to give much detail in the -h option
I have the following code:
import argparse
legal_actions = ['act1', 'act2', 'act3']
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(help='available commands')
parser_cmd = subparsers.add_parser("cmd")
parser_cmd.add_argument("-a", "--action", type=str, metavar="", choices=legal_actions, required=True,
help='list of actions: {%(choices)s}')
parser_cmd.add_argument("nargs", type=str, nargs='*',
help="the rest of the arguments required to perform an action")
parser_cmd.set_defaults(func=cmd_handler)
python prog.py cmd -h will result the following prints in the command line
usage: cmd [-h] -a [nargs [nargs ...]]
positional arguments:
nargs the rest of the arguments required to perform an action
optional arguments:
-h, --help show this help message and exit
-a , --action list of actions: {act1, act2, act3}
Every action requires a different number of arguments, so I want to add something that will describe the actions (from the list of actions) like:
actions availble:
act1: requires 2 arguments (arg1, arg2)
act2: requires 0 arguments ()
act3: requires 1 arguments (arg1)
And I want it to have any link with the above "optional arguments", so it'll be easy to see the "acts" are under the -a option
If you want to add more information, you can use the epilog-parameter:
from argparse import RawDescriptionHelpFormatter # This is used to enable newlines in epilogs and descriptions(\n)
from argparse import ArgumentParser
description = 'Some description of program'
epilog = 'actions availble:\n\t'
epilog += 'act1: requires 2 arguments (arg1, arg2)\n\t'
epilog += 'act2: requires 0 arguments ()\n\t'
epilog += 'act3: requires 1 arguments (arg1)'
parser = argparse.ArgumentParser(description=description, epilog=epilog,
formatter_class=RawTextHelpFormatter)
This will print out
actions availble:
act1: requires 2 arguments (arg1, arg2)
act2: requires 0 arguments ()
act3: requires 1 arguments (arg1)
At the end of help output. The epilog-parameter can also be included in the add_parser() when using add_subparsers():
This object has a single method, add_parser(), which takes a command name and any ArgumentParser constructor arguments, and returns an ArgumentParser object that can be modified as usual.
NOTE: the default formatter will ignore newlines, so take a look at Python argparse: How to insert newline in the help text? where this is addressed, which describe how to replace the formatter á la:
ArgumentParser(..., formatter_class=RawDescriptionHelpFormatter)
Read more about the epilog-parameter in docs.
I am trying to write usage/help for my python script using the argparse library.
This is my sample code:
import argparse
parser = argparse.ArgumentParser(
description='My description')
parser.add_argument(
"-r", "--remote",
help="help message")
parser.print_help()
Output:
usage: [-h] [-r REMOTE]
My description
optional arguments:
-h, --help show this help message and exit
-r REMOTE, --remote REMOTE
help message
I have no idea why it is printing REMOTE after the -r and --remote switches in the above output.
Can anyone tell me what am I doing wrong here or what should I do to get rid of it?
You are looking at the metavar; it is autogenerated from the option string to form a placeholder. It tells the user that it is there that they need to fill in a value.
You can set an explicit metavar value with the metavar keyword argument:
When ArgumentParser generates help messages, it needs some way to refer to each expected argument. By default, ArgumentParser objects use the dest value as the “name” of each object. By default, for positional argument actions, the dest value is used directly, and for optional argument actions, the dest value is uppercased.
You see it because your argument takes a value; if you expected it to be a toggle, use action='store_true'; in that case the option defaults to False unless the user specifies the switch.
Demo of the latter:
>>> import argparse
>>> parser = argparse.ArgumentParser(
... description='My description')
>>> parser.add_argument("-r", "--remote", action='store_true', help="help message")
_StoreTrueAction(option_strings=['-r', '--remote'], dest='remote', nargs=0, const=True, default=False, type=None, choices=None, help='help message', metavar=None)
>>> parser.print_help()
usage: [-h] [-r]
My description
optional arguments:
-h, --help show this help message and exit
-r, --remote help message
>>> opts = parser.parse_args([])
>>> opts.remote
False
>>> opts = parser.parse_args(['-r'])
>>> opts.remote
True
You are missing action.
import argparse
parser = argparse.ArgumentParser(
description='My description')
parser.add_argument(
"-r", "--remote", action="store_true", # add action
help="help message")
parser.print_help()
usage: -c [-h] [-r]
My description
optional arguments:
-h, --help show this help message and exit
-r, --remote help message
I'm using the Python argparse module for command line subcommands in my program. My code basically looks like this:
import argparse
parser = argparse.ArgumentParser()
subparsers = parser.add_subparsers(title="subcommands", metavar="<command>")
subparser = subparsers.add_parser("this", help="do this")
subparser = subparsers.add_parser("that", help="do that")
parser.parse_args()
When running "python test.py --help" I would like to list the available subcommands. Currently I get this output:
usage: test.py [-h] <command> ...
optional arguments:
-h, --help show this help message and exit
subcommands:
<command>
this do this
that do that
Can I somehow remove the <command> line in the subcommands listing and still keep it in the usage line? I have tried to give help=argparse.SUPPRESS as argument to add_subparsers, but that just hides all the subcommands in the help output.
I solved it by adding a new HelpFormatter that just removes the line if formatting a PARSER action:
class SubcommandHelpFormatter(argparse.RawDescriptionHelpFormatter):
def _format_action(self, action):
parts = super(argparse.RawDescriptionHelpFormatter, self)._format_action(action)
if action.nargs == argparse.PARSER:
parts = "\n".join(parts.split("\n")[1:])
return parts