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,
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.
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)
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.
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()