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

新手上路,请多包涵

是否可以在解析参数时使用 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

原文由 AK47 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 369
2 个回答

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

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

现在是否是进行测试的正确位置取决于您的情况。有时用 FileType 打开文件没问题,但你必须自己关闭它,或者等待程序结束。您不能在 with open(filename) as f: 上下文中使用该打开的文件。这同样适用于您的数据库。在复杂的程序中,您可能不想立即打开或创建文件。

我为 Python 错误/问题写了一个变体 FileType 创建了一个 context 一个可以在 with 中使用的对象我还使用了 os 测试来检查文件是否存在或是否可以创建,但实际上并没有这样做。但如果 filestdin/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')

我认为是否在 typeAction 中实施这样的测试并不重要。我觉得 type 更简单,更符合开发者的意图。

原文由 hpaulj 发布,翻译遵循 CC BY-SA 3.0 许可协议

一定!您只需将自定义操作指定为类,并覆盖 __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()


在你的特殊情况下,我想你会有 DatabaseActionFileAction (或类似的东西)。

原文由 UltraInstinct 发布,翻译遵循 CC BY-SA 4.0 许可协议

推荐问题