AK4*_*K47 15 python validation argparse
是否可以在解析参数时使用argparse模块添加验证?
from argparse import ArgumentParser
parser = ArgumentParser(description='Argument parser for PG restore')
parser.add_argument('--database', dest='database',
default=None, required=False, help='Database to restore')
parser.add_argument('--backup', dest='backup',
required=True, help='Location of the backup file')
parsed_args = parser.parse_args()
Run Code Online (Sandbox Code Playgroud)
是否可以在此参数解析器中添加验证检查,以确保备份文件/数据库存在?而不是必须在此之后为每个参数添加额外的检查,例如:
from os.path import exists
if not database_exists(parsed_args.database):
raise DatabaseNotFoundError
if not exists(parsed_args.backup):
raise FileNotFoundError
Run Code Online (Sandbox Code Playgroud)
hpa*_*ulj 16
这argparse.FileType是一个type可以打开文件的工厂类,当然,如果文件不存在或无法创建,则会在此过程中引发错误.您可以查看其代码,了解如何创建自己的类(或函数)来测试输入.
参数type参数是一个可调用的(函数等),它接受一个字符串,根据需要对其进行测试,并将其(根据需要)转换为您要保存到args命名空间的值.所以它可以做任何你想要的测试.如果type引发错误,则解析器会创建错误消息(和用法)并退出.
现在,这是否适合进行测试取决于您的情况.有时打开文件FileType很好,但是你必须自己关闭它,或者等待程序结束.您不能在with open(filename) as f:上下文中使用该打开文件.这同样适用于您的数据库.在复杂的程序中,您可能不想立即打开或创建文件.
我为Python bug /问题写了一个变体FileType,创建了context一个可以在with上下文中使用的对象.我还使用os测试来检查文件是否存在或是否可以创建,而实际上并没有这样做.但是,需要进一步的技巧,如果file是stdin/out,你不想关闭.有时尝试做这样的事情argparse只是工作而不是它的价值.
无论如何,如果你有一个简单的测试方法,你可以将它包装在一个type像这样的简单函数中:
def database(astring):
from os.path import exists
if not database_exists(astring):
raise ValueError # or TypeError, or `argparse.ArgumentTypeError
return astring
parser.add_argument('--database', dest='database',
type = database,
default=None, required=False, help='Database to restore')
Run Code Online (Sandbox Code Playgroud)
我不认为你是否在typeor或者这样实施这样的测试很重要Action.我认为这type更简单,更符合开发人员的意图.
Ult*_*nct 12
一定!您只需将自定义操作指定为类,然后覆盖__call__(..).链接到文档.
就像是:
import argparse
class FooAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if values != "bar":
print "Got value:", values
raise ValueError("Not a bar!")
setattr(namespace, self.dest, values)
parser = argparse.ArgumentParser()
parser.add_argument("--foo", action=FooAction)
parsed_args = parser.parse_args()
Run Code Online (Sandbox Code Playgroud)
在你的特殊情况下,我想你会拥有DatabaseAction和FileAction(或类似的东西).
hpa*_*ulj 12
通过这个脚本,我可以测试建议的替代方案。
import argparse
class ValidateUrl(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if values != "bar":
parser.error(f"Please enter a valid. Got: {values}")
setattr(namespace, self.dest, values)
class FooAction(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
if values != "bar":
print("Got value:", values)
#raise ValueError("Not a bar!") # shows a traceback, not usage
raise argparse.ArgumentError(self, 'Not a bar')
setattr(namespace, self.dest, values)
def database(astring):
if astring != "bar":
#raise argparse.ArgumentTypeError("not a bar") # sustom message
raise ValueError('not a bar') # standard error
# error: argument --data: invalid database value: 'xxx'
return astring
parser = argparse.ArgumentParser()
parser.add_argument("--url", action=ValidateUrl)
parser.add_argument("--foo", action = FooAction)
parser.add_argument('--data', type = database)
if __name__=='__main__':
args = parser.parse_args()
print(args)
Run Code Online (Sandbox Code Playgroud)
一个工作案例:
1254:~/mypy$ python3 stack37471636.py --url bar --foo bar --data bar
Namespace(data='bar', foo='bar', url='bar')
Run Code Online (Sandbox Code Playgroud)
parser.error案例的使用和退出
1255:~/mypy$ python3 stack37471636.py --url xxx
usage: stack37471636.py [-h] [--url URL] [--foo FOO] [--data DATA]
stack37471636.py: error: Please enter a valid. Got: xxx
Run Code Online (Sandbox Code Playgroud)
函数ValueError中来自 a 的标准化消息type
1256:~/mypy$ python3 stack37471636.py --data xxx
usage: stack37471636.py [-h] [--url URL] [--foo FOO] [--data DATA]
stack37471636.py: error: argument --data: invalid database value: 'xxx'
Run Code Online (Sandbox Code Playgroud)
使用 时ArgumentTypeError,消息显示如下:
1246:~/mypy$ python3 stack37471636.py --url bar --foo bar --data xxx
usage: stack37471636.py [-h] [--url URL] [--foo FOO] [--data DATA]
stack37471636.py: error: argument --data: not a bar
Run Code Online (Sandbox Code Playgroud)
FooAction和ArgumentError:
1257:~/mypy$ python3 stack37471636.py --foo xxx
Got value: xxx
usage: stack37471636.py [-h] [--url URL] [--foo FOO] [--data DATA]
stack37471636.py: error: argument --foo: Not a bar
Run Code Online (Sandbox Code Playgroud)
type转换为ArgumentError. 请注意,ArgumentError标识argument. 打电话parser.error不行。
如果FooAction引发ValueError,则显示常规回溯,但不使用。
1246:~/mypy$ python3 stack37471636.py --url bar --foo xxx --data bar
Got value: xxx
Traceback (most recent call last):
File "stack37471636.py", line 27, in <module>
args = parser.parse_args()
File "/usr/lib/python3.8/argparse.py", line 1780, in parse_args
args, argv = self.parse_known_args(args, namespace)
File "/usr/lib/python3.8/argparse.py", line 1812, in parse_known_args
namespace, args = self._parse_known_args(args, namespace)
File "/usr/lib/python3.8/argparse.py", line 2018, in _parse_known_args
start_index = consume_optional(start_index)
File "/usr/lib/python3.8/argparse.py", line 1958, in consume_optional
take_action(action, args, option_string)
File "/usr/lib/python3.8/argparse.py", line 1886, in take_action
action(self, namespace, argument_values, option_string)
File "stack37471636.py", line 13, in __call__
raise ValueError("Not a bar!")
ValueError: Not a bar!
Run Code Online (Sandbox Code Playgroud)
我相信ArgumentError和ArgumentTypeError是首选,或者至少是有意的选择。自动生成的错误使用这些。
通常parser.error在解析后使用,例如导致
1301:~/mypy$ python3 stack37471636.py
Namespace(data=None, foo=None, url=None)
usage: stack37471636.py [-h] [--url URL] [--foo FOO] [--data DATA]
stack37471636.py: error: not a bar
Run Code Online (Sandbox Code Playgroud)