验证另一个论点

Validate an argument over another

我有两个额外的选项,我需要先验证第二个选项。

我试过这个:

#!/bin/env python3
# -*- coding: utf-8 -*-

from argparse import ArgumentParser, ArgumentTypeError
from os import getenv, path

def invalidArgument(value, text= None):
    raise ArgumentTypeError("%s %s" % (value, text))

def directory(value):
    if path.isdir(value):
        return value
    invalidArgument(value, "directory not found")

def parsing():
    parser= ArgumentParser("")
    parser.add_argument("-dir", type= directory, action= "store", default= "/home", help= "Base directory")
    parser.add_argument("-loc", action= "store_true", help= "Takes into account locale")
    namespace, other= parser.parse_known_args()
    if namespace.loc:
        l= getenv("LANG", "en")[0:2].lower()
        if l == "en":
            namespace.loc= False
        else:
            if path.isdir(path.join(namespace.dir, l)):
                namespace.loc= path.join(namespace.dir, l)
            else:
                invalidArgument(path.join(namespace.dir, l), "directory not found $LANG not valid")
    return namespace, other

if __name__ == "__main__":
    namespace, other= parsing()
    print("Base directory:", namespace.dir)
    print("Locale directory:", namespace.loc)

然后我得到(使用 ./tst.py -loc):

Traceback (most recent call last):
  File "./tst.py", line 32, in <module>
    namespace, other= parsing()
  File "./tst.py", line 28, in parsing
    invalidArgument(path.join(namespace.dir, l), "directory not found or $LANG not valid")
  File "./tst.py", line 8, in invalidArgument
    raise ArgumentTypeError("%s %s" % (value, text))
argparse.ArgumentTypeError: /usr/share/fr directory not found $LANG not valid

如果我打电话给:

./tst.py

我需要:

Base directory: /home
Locale directory: False

如果我打电话给:

./tst.py -loc

我需要:

Base directory: /home
Locale directory: /home/fr

如果我打电话给:

./tst.py -dir=/home/foo -loc

我需要:

Base directory: /home/foo
Locale directory: /home/foo/fr

有人对我有想法或曲目吗?

您可以使用一个字母参数和一个破折号,以及多个字母参数和两个破折号: -h, --help

如果 /fr 目录不存在,则错误消息有意义。

如果您想要有关使用和退出的错误消息,请使用 parser.error(...),而不仅仅是引发异常。

我已经简化了您的代码,部分是为了适应常见的 argparse 用法,但更重要的是专注于正确解析。因为我的 LANG 是 'en',所以我把那部分测试去掉了。此时针对特定目录的测试会分散注意力。

我认为您的主要问题是 type=directory 参数。该参数应该是一个接受字符串和 returns 的函数。它没有指定您想要的对象类型。由于没有 directory(astr) 函数,该步骤失败。

def parsing():
    parser= ArgumentParser(prog='PROG')
    parser.add_argument('-d',"--dir", default= "/home", help= "Base directory")
    parser.add_argument('-l',"--loc", action= "store_true", help= "Takes into account locale")
    namespace, other= parser.parse_known_args()

    if namespace.loc:
        l = 'fr'
        namespace.loc= path.join(namespace.dir, l)
    return namespace, other

各种测试是:

1139:~/mypy$ python3 stack29283397.py
Base directory: /home
Locale directory: False
1144:~/mypy$ python3 stack29283397.py -l
Base directory: /home
Locale directory: /home/fr
1144:~/mypy$ python3 stack29283397.py --dir=/home/foo -l
Base directory: /home/foo
Locale directory: /home/foo/fr

loc 测试更改为:

if namespace.loc:
    l = 'fr'
    namespace.loc= path.join(namespace.dir, l)
    parser.error('%s directory not found'%namespace.loc)

产生:

1145:~/mypy$ python3 stack29283397.py --dir=/home/foo -l
usage: PROG [-h] [-d DIR] [-l]
PROG: error: /home/foo/fr directory not found

如果你想保留 type=directory,那么你需要找到或编写一个具有该名称的函数,例如

def directory(astring):
    # do something to validate this string
    # or transform it into something else
    return astring
class Locale(Action):
    def __init__(self, loc, **kwargs):
        super().__init__(**kwargs)
    def __call__(self, parser, namespace, value= False, option_string= None):
        l= getenv("LANG", "en")[0:2].lower()
        if l != "en":
            if path.isdir(path.join(namespace.dir, l)):
                value= path.join(namespace.dir, l)
            else:
                parser.error("%s %s" % (option_string, "directory not found or $LANG not valid"))
        namespace.loc= value

def parsing():
    parser= ArgumentParser("")
    parser.add_argument("-dir", type= directory, action= "store", default= "/home")
    parser.add_argument("-loc", action= Locale, loc= None, nargs= "?", default= False)
    namespace, other= parser.parse_known_args()
    return namespace, other