Reputation: 4119
I have an argument for a program that is an integer from 1-100 and I just don't like the way that it shows up in the -h help message when using argparse (it literally lists 0, 1, 2, 3, 4, 5,... etc)
Is there any way to change this or have it represented in another way?
Thanks
EDIT:
Here is the code for those who asked:
norse = parser.add_argument_group('Norse')
norse.add_argument('-n', '--norse', required=False, help='Run the Norse IPViking scan.', action='store_true')
norse.add_argument('--threshold', required=False, type=int, choices=range(0,101), help='Threshold (0-100) denoting at what threat level to provide additional data on an IP \
address. Default is 49.', default=49)
Upvotes: 21
Views: 27226
Reputation: 71
I have written a library for this: argparse-range
>>> from argparse import ArgumentParser
>>> from argparse_range import range_action
>>> parser = ArgumentParser()
>>> parser.add_argument("rangedarg", action=range_action(0, 10), help="An argument")
>>> args = parser.parse_args(["0"])
>>> args.rangedarg
0
>>> parser.parse_args(["20"])
Traceback (most recent call last):
....
argparse.ArgumentTypeError: Invalid choice: 20 (must be in range 0..=10)
Helptext is added transparently:
foo.py --help
usage: foo.py [-h] rangedarg
positional arguments:
rangedarg An argument (must be in range 0..=10)
optional arguments:
-h, --help show this help message and exit
Other features include:
default
, metavar
, and nargs
consistently with default argparse handlingtype
argumentUpvotes: 0
Reputation: 315
You can customize action, e.g:
#!/usr/bin/env python
import argparse
class Range(argparse.Action):
def __init__(self, minimum=None, maximum=None, *args, **kwargs):
self.min = minimum
self.max = maximum
kwargs["metavar"] = "[%d-%d]" % (self.min, self.max)
super(Range, self).__init__(*args, **kwargs)
def __call__(self, parser, namespace, value, option_string=None):
if not (self.min <= value <= self.max):
msg = 'invalid choice: %r (choose from [%d-%d])' % \
(value, self.min, self.max)
raise argparse.ArgumentError(self, msg)
setattr(namespace, self.dest, value)
norse = argparse.ArgumentParser('Norse')
norse.add_argument('--threshold', required=False, type=int, min=0, max=100,
action=Range,
help='Threshold [%(min)d-%(max)d] denoting at what threat \
level to provide additional data on an IP address. \
Default is %(default)s.', default=49)
args = norse.parse_args()
print args
Test it:
~: user$ ./test.py --threshold 10
Namespace(threshold=10)
~: user$ ./test.py --threshold -1
usage: Norse [-h] [--threshold [0-100]]
Norse: error: argument --threshold: invalid choice: -1 (choose from [0-100])
~: user$ ./test.py -h
usage: Norse [-h] [--threshold [0-100]]
optional arguments:
-h, --help show this help message and exit
--threshold [0-100] Threshold [0-100] denoting at what threat level to
provide additional data on an IP address. Default is
49.
Upvotes: 8
Reputation: 231355
With a custom type
, it is easier to control the error message (via the ArgumentTypeError
). I still need the metavar
to control the usage display.
import argparse
def range_type(astr, min=0, max=101):
value = int(astr)
if min<= value <= max:
return value
else:
raise argparse.ArgumentTypeError('value not in range %s-%s'%(min,max))
parser = argparse.ArgumentParser()
norse = parser.add_argument_group('Norse')
...
norse.add_argument('--range', type=range_type,
help='Value in range: Default is %(default)s.',
default=49, metavar='[0-101]')
parser.print_help()
print parser.parse_args()
producing:
2244:~/mypy$ python2.7 stack25295487.py --ran 102
usage: stack25295487.py [-h] [-n] [--threshold [0:101]] [--range [0-101]]
optional arguments:
-h, --help show this help message and exit
Norse:
...
--range [0-101] Value in range: Default is 49.
usage: stack25295487.py [-h] [-n] [--threshold [0:101]] [--range [0-101]]
stack25295487.py: error: argument --range: value not in range 0-101
I could use functools.partial
to customize the range values:
type=partial(range_type, min=10, max=90)
Upvotes: 8
Reputation: 4071
Here are a couple ways you can do it instead
def parseCommandArgs():
parser = argparse.ArgumentParser()
parser.add_argument('-i', dest='myDest', choices=range(1,101), type=int, required=True, metavar='INT[1,100]', help='my help message')
return parser.parse_args()
You can also use action
instead, which I highly recommend since it allows more customization
def verify():
class Validity(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if values < 1 or values > 100:
# do something
pass
return Validity
def parseCommandArgs():
parser = argparse.ArgumentParser()
parser.add_argument('-i', dest='myDest', required=True, metavar='INT[1,100]', help='my help message', action=verify())
return parser.parse_args()
Upvotes: 2
Reputation: 2936
Use the metavar
parameter of add_argument()
.
For example:
norse = parser.add_argument_group('Norse')
norse.add_argument('-n', '--norse', required=False, help='Run the Norse IPViking scan.', action='store_true')
norse.add_argument('--threshold', required=False, type=int, choices=range(0,101),
metavar="[0-100]",
help='Threshold (0-100) denoting at what threat level to provide additional data on an IP \
address. Default is 49.', default=49)
Test:
from argparse import ArgumentParser
norse = ArgumentParser()
norse.add_argument('-n', '--norse', required=False, help='Run the Norse IPViking scan.', action='store_true')
norse.add_argument('--threshold', required=False, type=int, choices=range(0,101), metavar="[0-100]", help='Threshold (0-100) denoting at what threat level to provide additional data on an IP address. Default is 49.', default=49)
norse.print_help()
Results
usage: -c [-h] [-n] [--threshold [0-100]]
optional arguments:
-h, --help show this help message and exit
-n, --norse Run the Norse IPViking scan.
--threshold [0-100] Threshold (0-100) denoting at what threat level to
provide additional data on an IP address. Default is
49.
Upvotes: 36