我需要根据给定的字符串创建自定义对象的实例(下例中的Bar)。如果我不将类型更改为Bar
并运行以下代码:
import argparse
VALID_BAR_NAMES = ['alfa', 'beta', 'gamma', 'delta']
class Bar:
def __init__(self, name):
if not name in VALID_BAR_NAMES:
raise RuntimeError('Bar can not be {n}, '
'it must be one of {m}'.format(
n=name, m=', '.join(VALID_BAR_NAMES)))
self.name = name
if __name__ == '__main__':
parser = argparse.ArgumentParser()
parser.add_argument('foo', help='Specify the foo!')
parser.add_argument('-b', '--bar', nargs='*',
choices=VALID_BAR_NAMES,
type=str, # SELECTED TYPE
help=('Specify one or many valid bar(s)'))
parsed_arguments = parser.parse_args()
在将无效的段hello
传递给-b
时,我得到了相当不错的输出:
usage: Example.py [-h]
[-b [{alfa,beta,gamma,delta} [{alfa,beta,gamma,delta} ...]]]
foo
Example.py: error: argument -b/--bar: invalid choice: 'hello' (choose from 'alfa', 'beta', 'gamma', 'delta')
但是,如果我将type=str
更改为type=Bar
并再次运行该示例,我会得到此输出:
Traceback (most recent call last):
File "C:\PyTest\Example.py", line 25, in <module>
parsed_arguments = parser.parse_args()
File "C:\Python27\lib\argparse.py", line 1688, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "C:\Python27\lib\argparse.py", line 1720, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "C:\Python27\lib\argparse.py", line 1926, in _parse_known_args
start_index = consume_optional(start_index)
File "C:\Python27\lib\argparse.py", line 1866, in consume_optional
take_action(action, args, option_string)
File "C:\Python27\lib\argparse.py", line 1778, in take_action
argument_values = self._get_values(action, argument_strings)
File "C:\Python27\lib\argparse.py", line 2218, in _get_values
value = [self._get_value(action, v) for v in arg_strings]
File "C:\Python27\lib\argparse.py", line 2233, in _get_value
result = type_func(arg_string)
File "C:\PyTest\Example.py", line 12, in __init__
n=name, m=', '.join(VALID_BAR_NAMES)))
RuntimeError: Bar can not be hello, it must be one of alfa, beta, gamma, delta
哪个看起来很糟糕。我知道这是由于在检查之前发生的类型转换,对可用选项进行了检查。处理这个问题的最佳方法是什么?
答案 0 :(得分:2)
您需要创建自定义操作(未经测试):
class Bar:
...
class BarAction(argparse.Action):
def __call__(self,parser,namespace,values,option_string=None):
try: #Catch the runtime error if it occures.
l=[Bar(v) for v in values] #Create Bars, raise RuntimeError if bad arg passed.
except RuntimeError as E:
#Optional: Print some other error here. for example: `print E; exit(1)`
parser.error()
setattr(namespace,self.dest,l) #add the list to the namespace
...
parser.add_argument('-b', '--bar', nargs='*',
choices=VALID_BAR_NAMES,
action=BarAction, # SELECTED TYPE -- The action does all the type conversion instead of the type keyword.
help=('Specify one or many valid bar(s)'))
...
答案 1 :(得分:1)
将参数保留为字符串,直到解析完成。解析完成后首先将它们转换为域对象。
答案 2 :(得分:0)
不知道是否有帮助,但我将argparse.FileType视为参考:
class Bar:
def __call__(self, strting):
if not name in VALID_BAR_NAMES:
raise argparse.ArgumentError(None,'Bar can not be {n}, '
'it must be one of {m}'.format(
n=name, m=', '.join(VALID_BAR_NAMES)))
self.name = string
def __init__(self):
pass
def __repr__(self):
return name
parser.add_argument('-b', '--bar', nargs='*',
choices=VALID_BAR_NAMES,
type=Bar(), # SELECTED TYPE
help=('Specify one or many valid bar(s)'))