Python argparse value range help message appearance

前端 未结 4 584
挽巷
挽巷 2021-02-08 07:46

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,

相关标签:
4条回答
  • 2021-02-08 07:55

    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.
    
    0 讨论(0)
  • 2021-02-08 07:59

    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)
    
    0 讨论(0)
  • 2021-02-08 08:04

    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.
    
    0 讨论(0)
  • 2021-02-08 08:15

    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()
    
    0 讨论(0)
提交回复
热议问题