【问题标题】:argparse argument dependencyargparse 参数依赖
【发布时间】:2014-03-19 17:37:39
【问题描述】:

如果我使用以下选项调用以下脚本:

--user u1 --password p1 --foo f1   --user u2   --user u3 --password p3

然后它会打印:

Namespace(foo=['bar', 'f1'], password=['p1', 'p3'], user=['u1', 'u2', 'u3'])

问题:我有什么方法可以设置用户和密码之间的依赖关系,所以它会抛出错误,因为没有指定用户 u2 的密码?

不太相关的问题:如何为所有用户指定默认的 foo 值?使用给定的输入,我希望 foo 等于 ['f1','bar','bar']。

我的主要问题的解决方案是检查列表用户和密码是否具有相同的长度,但这并不是我想要的。

这是脚本:

import argparse
parser = argparse.ArgumentParser()
group = parser.add_argument_group('authentication')
group.add_argument('--user', action='append', required=True)
group.add_argument('--password', action='append', required=True)
group.add_argument('--foo', action='append', default=['bar'])
print(parser.parse_args())

【问题讨论】:

  • 在命令行输入密码可能存在安全隐患。例如,它们可能会被运行 ps 的人窃取。
  • 谢谢@unutbu。 “真正的”参数实际上不是用户名和密码。我对安全一无所知。
  • @unutbu,你能解释一下安全风险是什么以及ps是如何被恶意使用的吗?和汤米一样,我对安全一无所知。
  • @RyanDay:ps axuwww 显示所有当前进程的完整命令(包括任何参数)。如果用户要键入密码作为脚本的参数,那么同一台计算机上的任何其他用户都可以通过在脚本运行时运行 ps axuwww 来查看这些密码。

标签: python python-3.x argparse


【解决方案1】:

在您的情况下,由于选项必须始终一起指定,或者一个都不能指定,您可以使用 nargs=2 将它们连接到具有两个参数的唯一 --user-and-password 选项中。这将大大简化值的处理。

实际上您希望能够提供多对,但required=True 在找到第一个选项时就满足了,因此在您的设置中检查您想要的内容几乎没有用处。

另一种方法是使用自定义操作。例如:

import argparse


class UserAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        if len(namespace.passwords) < len(namespace.users):
            parser.error('Missing password')
        else:
            namespace.users.append(values)


class PasswordAction(argparse.Action):
    def __call__(self, parser, namespace, values, option_string=None):
        if len(namespace.users) <= len(namespace.passwords):
            parser.error('Missing user')
        else:
            namespace.passwords.append(values)


parser = argparse.ArgumentParser()
parser.add_argument('--password', dest='passwords', default=[], action=PasswordAction, required=True)
parser.add_argument('--user', dest='users', default=[], action=UserAction, required=True)

print(parser.parse_args())

用作:

$python3 ./test_argparse.py --user 1 --password 2 --password 2 --user 3 --password 3
usage: test_argparse.py [-h] --password PASSWORDS --user USERS
test_argparse.py: error: Missing user

还有:

$python3 ./test_argparse.py --user 1 --password 2 --user 2 --user 3 --password 3
usage: test_argparse.py [-h] --password PASSWORDS --user USERS
test_argparse.py: error: Missing password

(请注意,此解决方案要求 --user 位于 --password 之前,否则列表的长度无法提供足够的信息来了解何时缺少选项。)

最后的解决方案是简单地使用action='append' 并在最后测试值列表。但是,这将允许像 --user A --user B --password A --password B 这样的事情,这可能是您想要允许的,也可能不是。

【讨论】:

  • 我会选择您的简单 --user-and-password 选项,因为在我的情况下,所有参数/关键字都用于每个用户。但是,如果将参数依赖项添加到 argparse 中,那肯定会很棒。谢谢。
【解决方案2】:

定义一个包含用户名和密码的自定义用户类型。

def user(s):
    try:
        username, password = s.split()
    except:
        raise argparse.ArgumentTypeError('user must be (username, password)')

group.add_argument('--user', type=user, action='append')

【讨论】:

  • 伟大而简单的解决方案。
  • 这将要求用户使用引号:python script.py --user 'name passwd'。否则,shell 会将这两个单词拆分成单独的字符串。
【解决方案3】:

感谢您的回答。我会接受巴库留的那个。这是一种解决方案(test_argparse2.py):

import argparse
parser = argparse.ArgumentParser()
parser.add_argument('--upf', action='append', nargs=3)
print(parser.parse_args())

正确用法:

$python3 ./test_argparse2.py --upf u1 p1 bar1 --upf u2 p2 bar2
Namespace(upf=[['u1', 'p1', 'bar1'], ['u2', 'p2', 'bar2']])

这是另一个允许输入参数随机顺序的解决方案 (test_argparse3.py):

import argparse
import sys
parser = argparse.ArgumentParser()
parser.add_argument('--upf', nargs='+')
set_required = set(['user','pass','foo',])
for s in parser.parse_args().upf:
    set_present = set(argval.split(':')[0] for argval in s.split(','))
    set_miss = set_required-set_present
    bool_error = False
    if len(set_miss)>0:
        print(set_miss, 'missing for', s)
        bool_error = True
    if bool_error:
        sys.exit()

错误用法:

$python3 ./test_argparse3.py --upf user:u1,pass:p1,foo:bar1 foo:bar,pass:p2
{'user'} missing for foo:bar,pass:p2

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2015-02-09
    • 2020-03-04
    • 2012-10-09
    • 2011-05-26
    • 1970-01-01
    • 2017-10-16
    • 1970-01-01
    • 2023-03-09
    相关资源
    最近更新 更多