使参数解析器接受绝对数字和百分比的最佳方法?

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

我正在尝试编写 Nagios 样式检查以与 Nagios 一起使用。我有一个工作脚本,它接收 -w 15 -c 10 之类的东西并将其解释为 "Warning at 15%, Critical at 10%"。但我刚刚意识到,在内置的 Nagios 插件中,相同的参数将意味着 "Warning at 15MB, Critical at 10MB";相反,我需要输入 -w 15% -c 10% 才能获得上述行为。

所以我的问题是,使我的脚本表现得像内置 Nagios 脚本的最佳方法是什么?我能想到的唯一方法是将参数作为字符串接受并解析它,但是有没有更简洁的方法?

您可以使用自己的 class 作为参数类型:

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)

输出:

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'

适用于百分比或 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))

输出:

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

这是 type 函数,我认为它的行为与 @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)

测试:

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 必须是一个接受字符串的可调用对象,returns 是一个值。这里它返回一个元组,store Action 只是将其放入 namespace。如果可调用 returns 一个 ValueError、TypeError 或 argparse.ArgumentTypeError,错误显示应该是相同的。在这些示例中,初始错误是由 float('bad') 产生的 ValueError。默认错误消息是使用可调用的名称 (Percent v percent).

post-parsing解析的一个例子是:

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.FileTypetype 函数工厂 class 的示例。