Best way to make argument parser accept absolute number and percentage?

試著忘記壹切 提交于 2019-12-13 22:33:26

问题


I am trying to write a Nagios style check to use with Nagios. I have working script that takes in something like -w 15 -c 10 and interprets that as "Warning at 15%, Critical at 10%". But I just realized that in the built-in Nagios plugins, the same arguments would mean "Warning at 15MB, Critical at 10MB"; I would instead need to enter -w 15% -c 10% to get the above behavior.

So my question is, what is the best way to make my script behave like the built-in Nagios scripts? The only way I can think of is accepting the argument as a string and parsing it, but is there a neater way?


回答1:


You can use your own class as type for the arguments:

import argparse

class Percent(object):
    def __new__(self,  percent_string):
        if not percent_string.endswith('%'):
            raise ValueError('Need percent got {}'.format(percent_string))
        value = float(percent_string[:-1]) * 0.01
        return value

parser = argparse.ArgumentParser(description="with percent")
parser.add_argument('-w', '--warning', type=Percent)
parser.add_argument('-c', '--critcal', type=Percent)

args = parser.parse_args()
print(args.warning)

Output:

python parse_percent.py  -w 15%
0.15

python parse_percent.py  -w 15
usage: parse-percent.py [-h] [-w WARNING] [-c CRITCAL]
parse-percent.py: error: argument -w/--warning: invalid Percent value: '15'

Version that works with percent or MB

class Percent(object):
    def __new__(self,  percent_string):
        if percent_string.endswith('%'):
            return float(percent_string[:-1]), 'percent'
        else:
            return float(percent_string), 'MB'

parser = argparse.ArgumentParser(description="with percent")
parser.add_argument('-w', '--warning', type=Percent)
parser.add_argument('-c', '--critcal', type=Percent)

args = parser.parse_args()
value, unit = args.warning
print('{} {}'.format(value, unit))

Output:

python parse_percent.py -w 15
15.0 MB
python parse_percent.py -w 15%
15.0 percent



回答2:


This is the type function which I believe behaves the same as @Mike's class:

def percent(astr):
    if astr.endswith('%'):
        return float(astr[:-1]), 'percent'
    else:    
        return float(astr), 'MB'

parser = argparse.ArgumentParser(description="with percent")
parser.add_argument('-w', '--warning', type=Percent)
parser.add_argument('-c', '--critcal', type=percent)

args = parser.parse_args()
print(args)

testing:

1058:~/mypy$ python3 stack41741065.py 
Namespace(critcal=None, warning=None)

1059:~/mypy$ python3 stack41741065.py -w 14 -c 14
Namespace(critcal=(14.0, 'MB'), warning=(14.0, 'MB'))

1059:~/mypy$ python3 stack41741065.py -w 14% -c 14%
Namespace(critcal=(14.0, 'percent'), warning=(14.0, 'percent'))

1059:~/mypy$ python3 stack41741065.py -w bad
usage: stack41741065.py [-h] [-w WARNING] [-c CRITCAL]
stack41741065.py: error: argument -w/--warning: invalid Percent value: 'bad'

1100:~/mypy$ python3 stack41741065.py -c bad
usage: stack41741065.py [-h] [-w WARNING] [-c CRITCAL]
stack41741065.py: error: argument -c/--critcal: invalid percent value: 'bad'

type just has to be a callable that takes a string, and returns a value. Here it is returning a tuple, which the store Action just puts in the namespace. If the callable returns a ValueError, TypeError or argparse.ArgumentTypeError, the error display should be the same. In these examples the initial error is the ValueError produced by float('bad'). The default error message is uses the callable's name (Percent v percent).

An example of post-parsing parsing is:

if args.o is not None:
    try:
        args.o = percent(args.o)
    except ValueError:
        parser.error('invalid args.o value')
print(args)

100:~/mypy$ python3 stack41741065.py
Namespace(critcal=None, o=None, warning=None)
Namespace(critcal=None, o=None, warning=None)

1107:~/mypy$ python3 stack41741065.py -o 14
Namespace(critcal=None, o='14', warning=None)
Namespace(critcal=None, o=(14.0, 'MB'), warning=None)

1107:~/mypy$ python3 stack41741065.py -o 14%
Namespace(critcal=None, o='14%', warning=None)
Namespace(critcal=None, o=(14.0, 'percent'), warning=None)

1107:~/mypy$ python3 stack41741065.py -o bad
Namespace(critcal=None, o='bad', warning=None)
usage: stack41741065.py [-h] [-w WARNING] [-c CRITCAL] [-o O]
stack41741065.py: error: invalid args.o value

argparse.FileType is an example of a type function factory class.



来源:https://stackoverflow.com/questions/41741065/best-way-to-make-argument-parser-accept-absolute-number-and-percentage

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!