Skip to content Skip to sidebar Skip to footer

Best Way To Make Argument Parser Accept Absolute Number And Percentage?

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%

Solution 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

classPercent(object):
    def__new__(self,  percent_string):
        if percent_string.endswith('%'):
            returnfloat(percent_string[:-1]), 'percent'else:
            returnfloat(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 1515.0 MB
python parse_percent.py -w 15%15.0percent

Solution 2:

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

defpercent(astr):
    if astr.endswith('%'):
        returnfloat(astr[:-1]), 'percent'else:    
        returnfloat(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 notNone: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.

Post a Comment for "Best Way To Make Argument Parser Accept Absolute Number And Percentage?"