Python:参数解析验证最佳实践

时间:2016-05-26 21:51:56

标签: 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()

是否可以在此参数解析器中添加验证检查,以确保备份文件/数据库存在?而不是必须在此之后为每个参数添加额外的检查,例如:

from os.path import exists
if not database_exists(parsed_args.database):
    raise DatabaseNotFoundError
if not exists(parsed_args.backup):
    raise FileNotFoundError

2 个答案:

答案 0 :(得分:14)

argparse.FileType是一个可以打开文件的type工厂类,当然,如果文件不存在或无法创建,则会在此过程中引发错误。您可以查看其代码,了解如何创建自己的类(或函数)来测试输入。

参数type参数是一个可调用的(函数等),它接受一个字符串,根据需要对其进行测试,并将其(根据需要)转换为您想要保存到{{1命名空间。所以它可以做任何你想要的测试。如果args引发错误,则解析器会创建错误消息(和使用情况)并退出。

现在是否适合进行测试取决于您的情况。有时用type打开文件很好,但是你必须自己关闭它,或者等待程序结束。您无法在FileType上下文中使用该打开文件。这同样适用于您的数据库。在复杂的程序中,您可能不想立即打开或创建文件。

我写了一篇关于Python错误/问题的with open(filename) as f:的变体,它创建了一个FileType,一个可以在context上下文中使用的对象。我还使用with测试来检查文件是否存在或是否可以创建,而实际上并没有这样做。但如果osfile您不想关闭,则需要进一步的操作。有时候尝试在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') type中实施这样的测试并不重要。我认为Action更简单,更符合开发人员的意图。

答案 1 :(得分:12)

当然!您只需将自定义操作指定为类,并覆盖__call__(..)Link to documentation.

类似的东西:

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()

在您的特定情况下,我认为您有DatabaseActionFileAction(或类似的东西)。