Command help (via -h), where `argparse` is the input port input range

I use argparseto analyze the input of my python3 program. I was recently asked to check the range of some numerical inputs, a seemingly good idea. Argparse has the ability to do this.

Numeric inputs are port numbers in the normal range of 0-65535, so I changed the parsing command line to:

import argparse
cmd_parser = argparse.ArgumentParser()
cmd_parser = add_argument('-p', help='Port number to connect to', dest='cmd_port', default=1234, type=int, choices=range(0,65536))
cmd_parser.parse_args(['-h'])

However, now when I request help, all possible values ​​from argparse are bombarding me. eg.

optional arguments:
    -h, --help            show this help message and exit
    -p {0,1,2,3,4,5,6,7,8,9,10,11,12,13 ...
    65478,65479,65480,65481,65482,65483,65484,65485,65486,65487,65488,65489,
    65490,65491,65492,65493,65494,65495,65496,65497,65498,65499,65500,65501,
    65502,65503,65504,65505,65506,65507,65508,65509,65510,65511,65512,65513,
    65514,65515,65516,65517,65518,65519,65520,65521,65522,65523,65524,65525,
    65526,65527,65528,65529,65530,65531,65532,65533,65534,65535}
                    Port number to connect to
...

. (0-65535) - , ? if?

, , argparse . argparse, . https://docs.python.org/2/library/argparse.html

+5
6

...

import argparse

class PortAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        if not 0 < values < 2**16:
            raise argparse.ArgumentError(self, "port numbers must be between 0 and 2**16")
        setattr(namespace, self.dest, values)

cmd_parser = argparse.ArgumentParser()
cmd_parser.add_argument('-p',
                        help='Port number to connect to',
                        dest='cmd_port',
                        default=1234,
                        type=int,
                        action=PortAction,
                        metavar="{0..65535}")

ArgumentError. 65536, :

error: argument -p: port numbers must be between 0 and 2**16

+3

int type add_argument . , , , __int__ :

class portnumber:
    def __init__(self, string):
        self._val = int(string)
        if (not self._val > 0) or (not self.val < 2**16):
            raise argparse.ArgumentTypeError("port numbers must be integers between 0 and 2**16")
    def __int__(self):
        return self._val

...

parser.add_argument("-p",type=portnumber)
+2

metavar , argparse .

cmd_parser.add_argument('-p',
                        help='Port number to connect to',
                        dest='cmd_port',
                        default=1234,
                        type=int,
                        choices=range(0,65536),
                        metavar="{0..65535}")
+2

/ Python choices . choices

    def _metavar_formatter: ...
        choice_strs = [str(choice) for choice in action.choices]
        result = '{%s}' % ','.join(choice_strs)

:

def _check_value(self, action, value):
    # converted value must be one of the choices (if specified)
    if action.choices is not None and value not in action.choices:
        args = {'value': value,
                'choices': ', '.join(map(repr, action.choices))}
        msg = _('invalid choice: %(value)r (choose from %(choices)s)')
        raise ArgumentError(action, msg % args)

, choices , , . , value not in action.choices. choices - .

SO-: http://bugs.python.org/issue16468. , .

type, choices. .

def myrange(astring):
   anint = int(astring)
   if anint in range(0,1000):
        return anint
   else:
        raise ValueError()
        # or for a custom error message
        # raise argparse.ArgumentTypeError('valid range is ...')

parser.add_argument('value',type=myrange,metavar='INT',help='...')

(2012) SO, . help-formatter,

Python

Python

============================

range. ( step) in, .

class Range(object):
    def __init__(self, start, stop, n=3):
        self.start = start
        self.stop = stop
        self.n = n
    def __contains__(self, key):
        return self.start<=key<self.stop   
    def __iter__(self):
        if self.stop<(self.start+(self.n*3)):
            for i in range(self.start, self.stop):
                yield i
        else:
            for i in range(self.start, self.start+self.n):
                yield i
            yield '...'
            for i in range(self.stop-self.n, self.stop):
                yield i

parser.add_argument("-p",type=int, choices=Range(2,10,2))

1455:~/mypy$ python stack37680645.py -p 3
Namespace(p=3)

1458:~/mypy$ python stack37680645.py -h
usage: stack37680645.py [-h] [-p {2,3,...,8,9}]

optional arguments:
  -h, --help        show this help message and exit
  -p {2,3,...,8,9}

, ,

1458:~/mypy$ python stack37680645.py -p 30
usage: stack37680645.py [-h] [-p {2,3,...,8,9}]
stack37680645.py: error: argument -p: invalid choice: 30 (choose from 2, 3, '...', 8, 9)

, choices action.choices str repr.

iter , ( ):

def __iter__(self):
    yield 'a custom list'

metavar /, __iter__ .

metavar. usage , , , (') ' [] ', 2 . /.

+2

print_help,

def my_help(): print "0-65535 range"
cmd_parser = argparse.ArgumentParser()
cmd_parser.add_argument('-p', help='Port number to connect to',   dest='cmd_port', default=1234, type=int, choices=range(0,65536))
cmd_parser.print_help = my_help
cmd_parser.parse_args()
0

, , @hpaulj. , , argparse. SO , , .

hpaulj 'Range' , . .

class ArgRange(object):
    from decimal import Decimal
    huge = Decimal('+infinity')
    huge_str = '{:.4E}'.format(huge)

    def __init__(self, start, stop=huge, n=3):
        self.start = start
        self.stop = stop
        self.n = n

    def __contains__(self, key):
        return self.start <= key < self.stop

    def __iter__(self):
        if self.stop < self.start+(self.n*3):
            for i in range(self.start, self.stop):
                yield i
        else:
            for i in range(self.start, self.start+self.n):
                yield I
            if self.stop is self.huge:
                yield '...' + huge_str
            else:
                yield '...'
                for i in range(self.stop - self.n, self.stop):
                    yield i

bounds = ArgRange(2)
balance = ArgRange(0, 1000)
parser = argparse.ArgumentParser(description="Do something fun")
parser.add_argument("width", type=int, choices=bounds,  default=9)
parser.add_argument("height", type=int, choices=balance, default=200)

:

argument width: invalid choice: 1 (choose from 2, 3, 4, '...infinity')

argument height: invalid choice: 2000 (choose from 0, 1, 2, '...', 997, 998, 999)

:

usage: test.py 
           {2,3,4,...infinity} {0,1,2,...,997,998,999}
0

All Articles