如何以特定顺序验证特定参数

时间:2018-04-27 23:44:55

标签: python argparse

我希望能够验证传递给脚本的参数,以便我可以使用以下选项:

test.py user info <user name>
test.py user create <user name> <last name> <first name> <email>
test.py user create batch <file name>
test.py user delete <user name>

test.py room info <room number>
test.py room create <room number> <room name>
test.py room delete <room number

我目前有一个非常复杂的if, elif, else级联:

if len(sys.argv) >= 2:
    if (sys.argv[1]).lower() == "user":
        if len(sys.argv) >= 3:
            if (sys.argv[2]).lower() == "info":
                if len(sys.argv) >= 4:
                    username = sys.argv[3]

                    get_user_info(username)
                else:
                    print("username not specified")

我甚至不打算添加elif,以及其他陈述。

我已经读到使用argparse是一种更好的方法,但我还没有看到如何以满足我需求的方式实现它。

就像现在一样,如果有人只执行test.py文件本身,它会打印出有效的参数。然后,如果它们自己执行test.py user,它会为它们提供下一组有效参数,依此类推,依此类推。一旦进入,就没有对这些进行验证。

请帮忙!并提前感谢。

2 个答案:

答案 0 :(得分:0)

这是使用 argparse 的解决方案。它的灵感来自_catkin_tools_的方式。

方法

  1. 使用parse_config字典字典为<category> <verb> user info创建条目。
  2. 可以在parse_config中找到user info的{​​{1}},其中包含字段parse_config['user']['info']desc(ription)main
  3. prepare_parser是一个可调用对象(即函数),在脚本的最后一行调用,如下所示:main。为此忽略sys.exit(args.main(args))sys.exit(..)是解析从命令行给出的参数后将根据给定的参数指向正确的入口点的函数。这是如何工作的,使用args.main。这意味着如果此特定子分析器被激活,则subparser.set_defaults(main=main_for_this_subparser)指向args.main,这可以是任何功能。
  4. main_for_this_subparser也是一个函数,可以为每个命令自定义以添加更多参数。由于用户始终要求prepare_parser作为第一个参数,我对所有三个动词使用了<user name> info create < / em>,删除)。由于 create 需要更多参数,因此会获得一个特殊的def parser_user_default(parser): parser.add_argument('user_name')函数,其中第一个parser_user_create被调用但随后会添加更多参数。
  5. 进一步阅读

    进一步说明

    到目前为止,我的解决方案无法处理调用catkin build。首先,我认为这实际上不是一个好的CLI,因为用户可能永远不会被称为“批处理”。也许用作test.py user create batch <batch file>会更好。另一方面,我无法直接使用argparse。如果您对此进行了实验,请考虑user create --batch <file>,它可以让您将argparse与手动参数处理混合使用。

    我对我的实施并不完全满意。事后看来,一个递归实现,可以处理任何级别的嵌套字典,将更加清晰。目前,该实现正好处理parse_known_args()

    完整代码

    <category> <verb>

答案 1 :(得分:0)

您可以使用argparse选项来限制前2个字符串的输入。剩余的字符串更加可变,但if测试可以利用共性。

import argparse

def lower(astr):
    return astr.lower()

parser = argparse.ArgumentParser()
parser.add_argument('first', type=lower, choices=['user', 'room'])
parser.add_argument('second', type=lower, choices=['info','create','delete'])
parser.add_argument('rest', nargs='+')
parser.set_defaults(file=[], user=[], room=[])  # defaults

args = parser.parse_args()
print(args)

# partial parse of the `rest` list of strings:

if args.first in ['user']:
    if args.second in ['create']:
         if args.rest[0] in ['batch']:
             args.files=args.rest[1:]
         else:
              args.user = args.rest
    else:
        args.user = args.rest[0]
else:
    args.room = args.rest
args.rest=[]    
print(args)

帮助:

1553:~/mypy$ python stack50071515.py -h
usage: stack50071515.py [-h] {user,room} {info,create,delete} rest [rest ...]

positional arguments:
  {user,room}
  {info,create,delete}
  rest

optional arguments:
  -h, --help            show this help message and exit

测试输入:

1545:~/mypy$ python stack50071515.py user info name
Namespace(file=[], first='user', rest=['name'], room=[], second='info', user=[])
Namespace(file=[], first='user', rest=[], room=[], second='info', user='name')

1549:~/mypy$ python stack50071515.py user create a b c
Namespace(file=[], first='user', rest=['a', 'b', 'c'], room=[], second='create', user=[])
Namespace(file=[], first='user', rest=[], room=[], second='create', user=['a', 'b', 'c'])

1549:~/mypy$ python stack50071515.py user create batch file
Namespace(file=[], first='user', rest=['batch', 'file'], room=[], second='create', user=[])
Namespace(file=[], files=['file'], first='user', rest=[], room=[], second='create', user=[])

1550:~/mypy$ python stack50071515.py user delete name
Namespace(file=[], first='user', rest=['name'], room=[], second='delete', user=[])
Namespace(file=[], first='user', rest=[], room=[], second='delete', user='name')

1550:~/mypy$ python stack50071515.py room info number
Namespace(file=[], first='room', rest=['number'], room=[], second='info', user=[])
Namespace(file=[], first='room', rest=[], room=['number'], second='info', user=[])

1550:~/mypy$ python stack50071515.py room create a b
Namespace(file=[], first='room', rest=['a', 'b'], room=[], second='create', user=[])
Namespace(file=[], first='room', rest=[], room=['a', 'b'], second='create', user=[])

1550:~/mypy$ python stack50071515.py room delete 23
Namespace(file=[], first='room', rest=['23'], room=[], second='delete', user=[])
Namespace(file=[], first='room', rest=[], room=['23'], second='delete', user=[])